Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1308 lines
31 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ipinip\send.c
Abstract:
The file contains the part of interface of the IP in IP tunnel driver
to the TCP/IP stack that deals with sending data
The code is a cleaned up version of wanarp\ipif.c which in turn
was derived from HenrySa's ip\arp.c
Revision History:
AmritanR
--*/
#define __FILE_SIG__ SEND_SIG
#include "inc.h"
NDIS_STATUS
WanIpTransmit(
PVOID pvContext,
NDIS_PACKET **ppPacketArray,
UINT uiNumPackets,
DWORD dwDestAddr,
RouteCacheEntry *pRce,
PVOID pvLinkContext
)
/*++
Routine Description:
Function called by IP to send an array of packets. We allocate
one ETH_HEADER for each packet. The adapter (which is the pvContext)
is locked. If the adapter is not mapped, we fail the send, otherwise
we lock the interface. If
Locks:
Arguments:
pvContext Our context to IP for the interface - the PTUNNEL
ppPacketArray The array of NDIS_PACKETs to send
uiNumPackets The number of packets in the array
dwDestAddr The destination (next hop) address
pRce Pointer to RCE.
Return Value:
NDIS_STATUS_SUCCESS
--*/
{
PADAPTER pAdapter;
PUMODE_INTERFACE pInterface;
PADDRESS_CONTEXT pAddrContext;
PCONN_ENTRY pConnEntry;
KIRQL kiIrql;
NDIS_STATUS nsResult;
UINT i;
LIST_ENTRY leBufferList;
TraceEnter(SEND, "IpTransmit");
Trace(SEND,TRACE,
("IpTransmit: %d packet(s) over %p/%p to %d.%d.%d.%d\n",
uiNumPackets,
pvContext,
pvLinkContext,
PRINT_IPADDR(dwDestAddr)));
if(g_nhNdiswanBinding is NULL)
{
//
// In the process of shutting down, return
//
return NDIS_STATUS_ADAPTER_NOT_READY;
}
//
// Get the ethernet headers for each packet
//
if(!GetBufferListFromPool(&g_bpHeaderBufferPool,
uiNumPackets,
&leBufferList))
{
//
// Couldnt get headers for all the buffers
//
Trace(SEND, ERROR,
("IpTransmit: couldnt allocate %d header buffers\n",
uiNumPackets));
return NDIS_STATUS_RESOURCES;
}
//
// This function is not guaranteed to be at dispatch
// The context given to us is a pointer to our adapter
//
pConnEntry = NULL;
pAdapter = (PADAPTER)pvContext;
RtAcquireSpinLock(&(pAdapter->rlLock),
&kiIrql);
if(pAdapter->byState isnot AS_MAPPED)
{
//
// If the adapter is unmapped, the connection is disconnected
//
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
FreeBufferListToPool(&g_bpHeaderBufferPool,
&leBufferList);
Trace(SEND, INFO,
("IpTransmit: Send on %x which is unmapped\n",
pAdapter));
//
// Cant increment stats because we dont have an interface
//
return NDIS_STATUS_ADAPTER_NOT_READY;
}
//
// Since the adapter is mapped, it must have an interface
//
pInterface = pAdapter->pInterface;
RtAssert(pInterface);
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
//
// If interface is not yet connected (for demand dial case) the copy the
// packet and succeed the send.
//
if(pInterface->dwOperState isnot IF_OPER_STATUS_CONNECTED)
{
if(pInterface->duUsage isnot DU_ROUTER)
{
//
// Just a race condition
//
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
FreeBufferListToPool(&g_bpHeaderBufferPool,
&leBufferList);
return NDIS_STATUS_ADAPTER_NOT_READY;
}
//
// If IP is transmitting on us, he must have called out to
// connect
//
RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTING);
Trace(SEND, INFO,
("IpTransmit: I/F not connected, queueing packet\n"));
//
// New function which queues the whole packet array
//
nsResult = WanpCopyAndQueuePackets(pAdapter,
ppPacketArray,
&leBufferList,
uiNumPackets);
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
if(nsResult isnot STATUS_SUCCESS)
{
FreeBufferListToPool(&g_bpHeaderBufferPool,
&leBufferList);
}
return nsResult;
}
//
// Find the connection entry for this send
//
if(pAdapter is g_pServerAdapter)
{
pConnEntry = (PCONN_ENTRY)pvLinkContext;
//RtAssert(pConnEntry);
//
// Hack for multicast
//
if(pConnEntry is NULL)
{
pConnEntry = WanpGetConnEntryGivenAddress(dwDestAddr);
}
//
// We are dont with the adapter lock. All we need is to lock down
// the connection entry
// It is important that we release the locks since for dial-in
// clients the locking hierarchy is CONN_ENTRY->ADAPTER->INTERFACE
//
if(pConnEntry)
{
ReferenceConnEntry(pConnEntry);
}
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
//
// NOTE: The state of the connection can change in this window
//
if(pConnEntry)
{
RtAcquireSpinLockAtDpcLevel(&(pConnEntry->rlLock));
//
// Not a useful assert because (i) we add static routes to clients
// and (ii) we have that hack for netbt broadcasts
//
// RtAssert((pConnEntry->dwRemoteAddr is dwDestAddr) or
// (dwAddress is 0xFFFFFFFF));
}
}
else
{
//
// This send is on some adapter other than the server adapter
// Such an adapter has only one connection. For these sends we
// lock the adapter instead of the connection
//
pConnEntry = pAdapter->pConnEntry;
if(pConnEntry)
{
ReferenceConnEntry(pConnEntry);
RtAssert(pConnEntry->pAdapter is pAdapter);
}
}
//
// So now we have a locked connection entry (if client)
// or a locked adapter (for dial out and router)
//
if((pConnEntry is NULL) or
(pConnEntry->byState isnot CS_CONNECTED))
{
if((ULONG)(dwDestAddr & 0x000000FF) < (ULONG) 0x000000E0)
{
Trace(SEND, ERROR,
("IpTransmit: Could not find conn entry for %d.%d.%d.%d\n",
PRINT_IPADDR(dwDestAddr)));
}
for(i = 0; i < uiNumPackets; i++)
{
PLIST_ENTRY pleNode;
PNDIS_BUFFER pnbBuffer;
PVOID pvFirstBuffer;
UINT uiFirstBufLen, uiTotalLen;
PIP_HEADER pIpHeader;
NdisGetFirstBufferFromPacket(ppPacketArray[i],
&pnbBuffer,
&pvFirstBuffer,
&uiFirstBufLen,
&uiTotalLen);
pIpHeader = (PIP_HEADER)pvFirstBuffer;
RtAssert(pIpHeader);
RtAssert(uiFirstBufLen >= sizeof(IP_HEADER));
if(IsUnicastAddr(pIpHeader->dwDest))
{
pInterface->ulOutUniPkts++;
}
else
{
pInterface->ulOutNonUniPkts++;
}
}
//
// The entry has been disconnected.
// This is just a window in the timing
//
pInterface->ulOutDiscards += uiNumPackets;
if(pAdapter is g_pServerAdapter)
{
if(pConnEntry isnot NULL)
{
RtReleaseSpinLock(&(pConnEntry->rlLock),
kiIrql);
}
else
{
KeLowerIrql(kiIrql);
}
}
else
{
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
RtReleaseSpinLock(&(pInterface->rlLock),
kiIrql);
}
FreeBufferListToPool(&g_bpHeaderBufferPool,
&leBufferList);
if(pConnEntry)
{
DereferenceConnEntry(pConnEntry);
}
return NDIS_STATUS_ADAPTER_NOT_READY;
}
#if DBG
Trace(SEND, TRACE,
("IpTransmit: Send on %s\n",
pAdapter->asDeviceNameA.Buffer));
for(i = 0; i < uiNumPackets; i++)
{
PacketContext *pPC;
pPC = (PacketContext *)((ppPacketArray[i])->ProtocolReserved);
RtAssert(pPC->pc_common.pc_owner isnot PACKET_OWNER_LINK);
}
#endif
//
// This function will free the locks
//
nsResult = WanpSendPackets(pAdapter,
pInterface,
pConnEntry,
ppPacketArray,
&leBufferList,
uiNumPackets,
kiIrql);
if(nsResult isnot STATUS_SUCCESS)
{
Trace(SEND,TRACE,
("IpTransmit: SendPackets returned status %x\n",nsResult));
}
DereferenceConnEntry(pConnEntry);
return nsResult;
}
NDIS_STATUS
WanpSendPackets(
PADAPTER pAdapter,
PUMODE_INTERFACE pInterface,
PCONN_ENTRY pConnEntry,
NDIS_PACKET **ppPacketArray,
PLIST_ENTRY pleBufferList,
UINT uiNumPackets,
KIRQL kiIrql
)
/*++
Routine Description:
Main routine to send an array of packets
Locks:
Called with the connection entry (for dial in) or the adapter+interface
(all others) locked
Arguments:
pAdapter The adapter for the connection
pInterface The interface the adapter is mapped to
pConnEntry The connection entry for the send
ppPacketArray The array of packets to send
pBuffHead A list of buffers for the link layer header
uiNumPackets Number of packets (and ll header buffers)
kiIrql Irql at which the adapter or conn entry was locked
Return Value:
NDIS_STATUS_PENDING
--*/
{
NDIS_STATUS nsStatus;
PBYTE pbyHeader;
ULONG i;
#if DBG
Trace(SEND, TRACE,
("SendPackets: %s\n",
pAdapter->asDeviceNameA.Buffer));
#endif
for(i = 0; i < uiNumPackets; i++)
{
PNDIS_BUFFER pnbBuffer, pnbTempBuffer;
PLIST_ENTRY pleNode;
PVOID pvFirstBuffer;
UINT uiFirstBufLen, uiTotalBufLen, uiIpHdrLen;
PIP_HEADER pIpHeader;
PBUFFER_HEAD pBufferHead;
NdisGetFirstBufferFromPacket(ppPacketArray[i],
&pnbTempBuffer,
&pvFirstBuffer,
&uiFirstBufLen,
&uiTotalBufLen);
pIpHeader = (PIP_HEADER)pvFirstBuffer;
RtAssert(pIpHeader);
//
// ToDo: remove till NK fixes the bug in IP transmit
// with header inc
//
// RtAssert(uiFirstBufLen >= sizeof(IP_HEADER));
#if L2TP_DBG
#define L2TP_PORT_NBO 0xA506 // 1701 == 06A5
//
// If this is a l2tp packet, break
//
if(pIpHeader->byProtocol is 17)
{
WORD UNALIGNED *pwPort;
//
// See if we have enough data to get to the UDP header in
// the first buffer
//
uiIpHdrLen = LengthOfIpHeader(pIpHeader);
if(uiFirstBufLen >= uiIpHdrLen + sizeof(ULONG))
{
pwPort = (WORD UNALIGNED *)((ULONG_PTR)pIpHeader + uiIpHdrLen);
}
else
{
PNDIS_BUFFER pNextBuf;
//
// Get the next buffer and look into its
//
pNextBuf = pnbTempBuffer->Next;
pwPort = (WORD UNALIGNED *)(pnbTempBuffer->MappedSystemVa);
}
if((pwPort[0] is L2TP_PORT_NBO) or
(pwPort[1] is L2TP_PORT_NBO))
{
Trace(SEND, ERROR,
("SendPackets: %x buffer %x header %x port %d.%d\n",
pnbTempBuffer, pIpHeader, pwPort,
pwPort[0], pwPort[1]));
RtAssert(FALSE);
}
}
#endif
//
// NOTE: If this is a client send, the server interface is not
// locked. Hence the stats can be inconsistent for the server
// interface
//
if(IsUnicastAddr(pIpHeader->dwDest))
{
pInterface->ulOutUniPkts++;
}
else
{
pInterface->ulOutNonUniPkts++;
}
pleNode = RemoveHeadList(pleBufferList);
#if LIST_DBG
pBufferHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leListLink);
RtAssert(IsListEmpty(&(pBufferHead->leFreeBufferLink)));
RtAssert(pBufferHead->bBusy);
pBufferHead->leListLink.Flink = NULL;
pBufferHead->leListLink.Blink = NULL;
#else
pBufferHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leFreeBufferLink);
#endif
//
// Get a pointer to the data and to the buffer
//
pbyHeader = BUFFER_FROM_HEAD(pBufferHead);
pnbBuffer = pBufferHead->pNdisBuffer;
//
// Copy our prebuilt header into each buffer
//
RtlCopyMemory(pbyHeader,
&(pConnEntry->ehHeader),
sizeof(ETH_HEADER));
//
// Put the ethernet header in the front of the packet
//
NdisChainBufferAtFront(ppPacketArray[i],
pnbBuffer);
//
// Reference the entry once for each packet
//
ReferenceConnEntry(pConnEntry);
#if PKT_DBG
Trace(SEND, ERROR,
("SendPackets: Pkt %x Eth buff %x (%x) Header %x (%x)\n",
ppPacketArray[1],
pnbBuffer,
pbyHeader,
pnbTempBuffer,
pvFirstBuffer));
#endif // PKT_DBG
}
//
// Increment the output queue length. This will be decremented
// in the send complete handler
//
pAdapter->ulQueueLen++;
//
// Let go of the locks
//
if(pConnEntry->duUsage isnot DU_CALLIN)
{
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
}
RtReleaseSpinLock(pConnEntry->prlLock,
kiIrql);
NdisSendPackets(g_nhNdiswanBinding,
ppPacketArray,
uiNumPackets);
//
// Dont dereference the connection entry. We will deref it in
// the send complete handler
//
return NDIS_STATUS_PENDING;
}
VOID
WanNdisSendComplete(
NDIS_HANDLE nhHandle,
PNDIS_PACKET pnpPacket,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Our send complete handler called by NDIS once for each packet that was
pending after a send.
Locks:
Arguments:
Return Value:
--*/
{
PacketContext *pPC;
PNDIS_BUFFER pnbBuffer, pnbEthBuffer;
KIRQL kiIrql;
PADAPTER pAdapter;
PUMODE_INTERFACE pInterface;
PCONN_ENTRY pConnEntry;
PETH_HEADER pEthHeader;
ULONG ulIndex;
PVOID pvFirstBuffer;
UINT uiFirstBufLen, uiTotalLen;
TraceEnter(SEND, "NdisSendComplete");
//
// Get first buffer on packet. This is our ethernet header buffer
//
NdisUnchainBufferAtFront(pnpPacket,
&pnbEthBuffer);
//
// Get the fake ethernet header
//
pEthHeader = NdisBufferVirtualAddress(pnbEthBuffer);
#if DBG
//
// The buffer head should say the same thing
//
RtAssert(pnbEthBuffer is ((HEAD_FROM_BUFFER(pEthHeader))->pNdisBuffer));
#endif
ulIndex = GetConnIndexFromAddr(pEthHeader->rgbySourceAddr);
//
// Done with our buffer
//
FreeBufferToPool(&g_bpHeaderBufferPool,
(PBYTE)pEthHeader);
//
// Get the connection entry
//
RtAcquireSpinLock(&g_rlConnTableLock,
&kiIrql);
pConnEntry = GetConnEntryGivenIndex(ulIndex);
if(pConnEntry is NULL)
{
RtAssert(FALSE);
RtReleaseSpinLock(&g_rlConnTableLock,
kiIrql);
Trace(SEND, ERROR,
("NdisSendComplete: Couldnt find entry for connection %d\n",
ulIndex));
TraceLeave(RCV, "NdisSendComplete");
return;
}
RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
pAdapter = pConnEntry->pAdapter;
#if DBG
Trace(SEND, INFO,
("NdisSendComplete: Extracted adapter %x with name %s\n",
pAdapter,
pAdapter->asDeviceNameA.Buffer));
#endif
pAdapter->ulQueueLen--;
if(pConnEntry->duUsage is DU_CALLIN)
{
pInterface = g_pServerInterface;
RtAssert(pAdapter is g_pServerAdapter);
}
else
{
//
// See if we are still mapped to an interface, if so lock it
//
pInterface = pAdapter->pInterface;
if(pInterface isnot NULL)
{
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
}
}
//
// Right now we have the adapter + interface or the connection entry
// locked.
//
if(nsStatus is NDIS_STATUS_SUCCESS)
{
NdisGetFirstBufferFromPacket(pnpPacket,
&pnbBuffer,
&pvFirstBuffer,
&uiFirstBufLen,
&uiTotalLen);
if(pInterface)
{
pInterface->ulOutOctets += uiTotalLen;
}
#if PKT_DBG
Trace(SEND, ERROR,
("NdisSendComplete: Pkt %x Eth buff %x (%x) Header %x (%x)\n",
pnpPacket,
pnbEthBuffer,
pEthHeader,
pnbBuffer,
pvFirstBuffer));
#endif PKT_DBG
}
else
{
Trace(SEND, INFO,
("NdisSendComplete: Failed %x\n",
nsStatus));
if(pInterface)
{
pInterface->ulOutDiscards++;
}
}
//
// If this is not our packet return it to the protocol
//
pPC = (PacketContext *)pnpPacket->ProtocolReserved;
//
// Unlock
//
if(pConnEntry->duUsage isnot DU_CALLIN)
{
if(pInterface isnot NULL)
{
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
}
}
RtReleaseSpinLock(pConnEntry->prlLock,
kiIrql);
if(pPC->pc_common.pc_owner isnot PACKET_OWNER_LINK)
{
Trace(SEND, TRACE,
("NdisSendComplete: Calling IPSendComplete for %p over %p(%p)\n",
pnpPacket,
pAdapter,
pAdapter->pvIpContext));
g_pfnIpSendComplete(pAdapter->pvIpContext,
pnpPacket,
nsStatus);
}
else
{
//
// Free all buffers from our packet and then the packet itself
//
Trace(SEND, TRACE,
("NdisSendComplete: Not calling IPSendComplete for %p\n",
pnpPacket));
WanpFreePacketAndBuffers(pnpPacket);
}
//
// Deref the conn entry for the send and for the fact that
// GetConnEntry.. put a ref on it
//
DereferenceConnEntry(pConnEntry);
DereferenceConnEntry(pConnEntry);
return;
}
VOID
WanpTransmitQueuedPackets(
IN PADAPTER pAdapter,
IN PUMODE_INTERFACE pInterface,
IN PCONN_ENTRY pConnEntry,
IN KIRQL kiIrql
)
{
ULONG i;
PNDIS_PACKET rgPacketArray[64];
NDIS_PACKET **ppPacketArray;
LIST_ENTRY leBufferList, *pleNode;
//
// This is only called for ROUTER interfaces
//
RtAssert(pConnEntry->duUsage is DU_ROUTER);
RtAssert(pInterface->duUsage is DU_ROUTER);
//
// If there are no packets to transmit, just release the
// locks
//
if(pInterface->ulPacketsPending is 0)
{
RtAssert(IsListEmpty(&(pAdapter->lePendingPktList)));
RtAssert(IsListEmpty(&(pAdapter->lePendingHdrList)));
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
return;
}
if(pInterface->ulPacketsPending <= 64)
{
//
// Just use the stack array
//
ppPacketArray = rgPacketArray;
}
else
{
//
// Allocate a packet array
//
ppPacketArray =
RtAllocate(NonPagedPool,
sizeof(PNDIS_PACKET) * pInterface->ulPacketsPending,
WAN_CONN_TAG);
if(ppPacketArray is NULL)
{
Trace(SEND, ERROR,
("TransmitQueuedPackets: Unable to allocate %d pointers\n",
pInterface->ulPacketsPending));
while(!IsListEmpty(&(pAdapter->lePendingPktList)))
{
PNDIS_PACKET pnpPacket;
pleNode = RemoveHeadList(&(pAdapter->lePendingPktList));
//
// get to the packet structure in which LIST_ENTRY is embedded
//
pnpPacket = CONTAINING_RECORD(pleNode,
NDIS_PACKET,
MacReserved);
WanpFreePacketAndBuffers(pnpPacket);
}
while(!IsListEmpty(&(pAdapter->lePendingHdrList)))
{
PBYTE pbyHeader;
PBUFFER_HEAD pBuffHead;
pleNode = RemoveHeadList(&(pAdapter->lePendingHdrList));
#if LIST_DBG
pBuffHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leListLink);
RtAssert(IsListEmpty(&(pBuffHead->leFreeBufferLink)));
RtAssert(pBuffHead->bBusy);
pBuffHead->leListLink.Flink = NULL;
pBuffHead->leListLink.Blink = NULL;
#else
pBuffHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leFreeBufferLink);
#endif
pbyHeader = BUFFER_FROM_HEAD(pBuffHead);
FreeBufferToPool(&g_bpHeaderBufferPool,
pbyHeader);
}
}
}
for(i = 0, pleNode = pAdapter->lePendingPktList.Flink;
pleNode isnot &(pAdapter->lePendingPktList);
pleNode = pleNode->Flink, i++)
{
PNDIS_PACKET pnpPacket;
pnpPacket = CONTAINING_RECORD(pleNode,
NDIS_PACKET,
MacReserved);
ppPacketArray[i] = pnpPacket;
}
RtAssert(i is pInterface->ulPacketsPending);
#if DBG
for(i = 0, pleNode = pAdapter->lePendingHdrList.Flink;
pleNode isnot &(pAdapter->lePendingHdrList);
pleNode = pleNode->Flink, i++);
RtAssert(i is pInterface->ulPacketsPending);
#endif
//
// copy out the pending hdr list to leBufferList.
//
leBufferList = pAdapter->lePendingHdrList;
pAdapter->lePendingHdrList.Flink->Blink = &leBufferList;
pAdapter->lePendingHdrList.Blink->Flink = &leBufferList;
pInterface->ulPacketsPending = 0;
InitializeListHead(&(pAdapter->lePendingPktList));
InitializeListHead(&(pAdapter->lePendingHdrList));
WanpSendPackets(pAdapter,
pInterface,
pConnEntry,
ppPacketArray,
&leBufferList,
pInterface->ulPacketsPending,
kiIrql);
if(rgPacketArray isnot ppPacketArray)
{
RtFree(ppPacketArray);
}
}
NDIS_STATUS
WanpCopyAndQueuePackets(
PADAPTER pAdapter,
NDIS_PACKET **ppPacketArray,
PLIST_ENTRY pleBufferList,
UINT uiNumPackets
)
/*++
Routine Description:
This routine queues the packet to the adapter
Once this routine is called, the caller can not touch the pleListHead
Locks:
The ADAPTER must be locked and mapped
The interface the adapter is mapped to must also be locked
Arguments:
pAdapter
ppPacketArray
pBuffHead
uiNumPackets
Return Value:
NDIS_STATUS_SUCCESS
STATUS_QUOTA_EXCEEDED
NDIS_STATUS_RESOURCES
--*/
{
PacketContext *pPC;
NDIS_STATUS nsStatus;
PLIST_ENTRY pleNode;
ULONG i;
#if DBG
ULONG ulPended = 0, ulHdrs = 0;
#endif
TraceEnter(SEND, "CopyAndQueuePackets");
if(pAdapter->pInterface->ulPacketsPending >= WANARP_MAX_PENDING_PACKETS)
{
Trace(SEND, WARN,
("CopyAndQueuePackets: Dropping packets since cap exceeded\n"));
return STATUS_QUOTA_EXCEEDED;
}
for(i = 0; i < uiNumPackets; i++)
{
PNDIS_PACKET pnpPacket;
UINT uiTotalLen, uiBytesCopied;
//
// Get size of buffers required
//
NdisQueryPacket(ppPacketArray[i],
NULL,
NULL,
NULL,
&uiTotalLen);
//
// Allocate a packet.
//
pnpPacket = NULL;
NdisAllocatePacket(&nsStatus,
&pnpPacket,
g_nhPacketPool);
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(SEND, ERROR,
("CopyAndQueuePackets: Cant allocate packet. %x\n",
nsStatus));
}
else
{
//
// Allocate buffers for the packet
//
nsStatus = GetBufferChainFromPool(&g_bpDataBufferPool,
pnpPacket,
uiTotalLen,
NULL,
NULL);
}
if(nsStatus is STATUS_SUCCESS)
{
//
// If we got a packet and the buffers, then copy from TCP/IP's
// packet into ours
//
NdisCopyFromPacketToPacket(pnpPacket,
0,
uiTotalLen,
ppPacketArray[i],
0,
&uiBytesCopied);
RtAssert(uiBytesCopied is uiTotalLen);
//
// This is now our packet, so set its context
//
pPC = (PacketContext *)pnpPacket->ProtocolReserved;
pPC->pc_common.pc_owner = PACKET_OWNER_LINK;
//
// Attach Packet to pending packet list
// We use the MacReserved portion as the list entry
//
InsertTailList(&pAdapter->lePendingPktList,
(PLIST_ENTRY)&(pnpPacket->MacReserved));
pAdapter->pInterface->ulPacketsPending++;
#if DBG
ulPended++;
#endif
}
else
{
PBUFFER_HEAD pBufferHead;
PBYTE pbyHeader;
//
// We either have no packet, or couldnt get a buffer.
// Nasty Nasty: Side effect of such a failure is that we free
// one of the header buffers
//
RtAssert(!IsListEmpty(pleBufferList));
pleNode = RemoveHeadList(pleBufferList);
#if LIST_DBG
pBufferHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leListLink);
RtAssert(IsListEmpty(&(pBufferHead->leFreeBufferLink)));
RtAssert(pBufferHead->bBusy);
pBufferHead->leListLink.Flink = NULL;
pBufferHead->leListLink.Blink = NULL;
#else
pBufferHead = CONTAINING_RECORD(pleNode,
BUFFER_HEAD,
leFreeBufferLink);
#endif
//
// Get a pointer to the data and to the buffer
//
pbyHeader = BUFFER_FROM_HEAD(pBufferHead);
FreeBufferToPool(&g_bpHeaderBufferPool,
pbyHeader);
if(pnpPacket)
{
NdisFreePacket(pnpPacket);
}
}
}
//
// we have queued all the packets we could, and for the ones we
// failed, we freed the corresponding ethernet header.
// So the number of headers left on pleBufferList should be the number of
// packets queued
//
if(!IsListEmpty(pleBufferList))
{
#if DBG
for(pleNode = pleBufferList->Flink;
pleNode isnot pleBufferList;
pleNode = pleNode->Flink)
{
ulHdrs++;
}
#endif
//
// Add the headers to the front of the adapter chain
//
pleBufferList->Blink->Flink = pAdapter->lePendingHdrList.Flink;
pleBufferList->Flink->Blink = &(pAdapter->lePendingHdrList);
pAdapter->lePendingHdrList.Flink->Blink = pleBufferList->Blink;
pAdapter->lePendingHdrList.Flink = pleBufferList->Flink;
}
#if DBG
RtAssert(ulPended is ulHdrs);
#endif
return NDIS_STATUS_SUCCESS;
}
VOID
WanpFreePacketAndBuffers(
PNDIS_PACKET pnpPacket
)
{
PNDIS_BUFFER pnbFirstBuffer;
FreeBufferChainToPool(&g_bpDataBufferPool,
pnpPacket);
NdisFreePacket(pnpPacket);
}
VOID
WanIpInvalidateRce(
PVOID pvContext,
RouteCacheEntry *pRce
)
{
return;
}