|
|
/*++
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; }
|