/*++
Copyright (c) 1989-1993  Microsoft Corporation

Module Name:

    packet.c

Abstract:

    This module contains code that implements the SEND_PACKET and
    RECEIVE_PACKET objects, which describe NDIS packets used
    by the transport.

Environment:

    Kernel mode

Revision History:

	Sanjay Anand (SanjayAn) - 22-Sept-1995
	BackFill optimization changes added under #if BACK_FILL

--*/

#include "precomp.h"
#pragma hdrstop


NTSTATUS
IpxInitializeSendPacket(
    IN PDEVICE Device,
    IN PIPX_SEND_PACKET Packet,
    IN PUCHAR Header
    )

/*++

Routine Description:

    This routine initializes a send packet by chaining the
    buffer for the header on it.

Arguments:

    Device - The device.

    Packet - The packet to initialize.

    Header - Points to storage for the header.

Return Value:

    None.

--*/

{

    NDIS_STATUS NdisStatus;
    NTSTATUS Status;
    PNDIS_BUFFER NdisMacBuffer;
    PNDIS_BUFFER NdisIpxBuffer;
    PIPX_SEND_RESERVED Reserved;

    IpxAllocateSendPacket (Device, Packet, &Status);

    if (Status != STATUS_SUCCESS) {
        // ERROR LOG
        return Status;
    }

    NdisAllocateBuffer(
        &NdisStatus,
        &NdisMacBuffer,
        Device->NdisBufferPoolHandle,
        Header,
        MAC_HEADER_SIZE);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        IpxFreeSendPacket (Device, Packet);
        // ERROR LOG
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    NdisAllocateBuffer(
        &NdisStatus,
        &NdisIpxBuffer,
        Device->NdisBufferPoolHandle,
        Header + MAC_HEADER_SIZE,
        IPX_HEADER_SIZE + RIP_PACKET_SIZE);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        IpxFreeSendPacket (Device, Packet);
        // ERROR LOG
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    NdisChainBufferAtFront (PACKET(Packet), NdisMacBuffer);
    NdisChainBufferAtBack (PACKET(Packet), NdisIpxBuffer);

	//
	// This flag optimizes the virtual to physical address X-ln
	// in the MAC drivers on x86
	//
    NdisMacBuffer->MdlFlags|=MDL_NETWORK_HEADER;
    NdisIpxBuffer->MdlFlags|=MDL_NETWORK_HEADER;

    Reserved = SEND_RESERVED(Packet);
    Reserved->Identifier = IDENTIFIER_IPX;
    Reserved->SendInProgress = FALSE;
    Reserved->Header = Header;
    Reserved->HeaderBuffer = NdisMacBuffer;
    Reserved->PaddingBuffer = NULL;
#if BACK_FILL
    Reserved->BackFill = FALSE;
#endif

    ExInterlockedInsertHeadList(
        &Device->GlobalSendPacketList,
        &Reserved->GlobalLinkage,
        &Device->Lock);

    return STATUS_SUCCESS;

}   /* IpxInitializeSendPacket */

#if BACK_FILL
NTSTATUS
IpxInitializeBackFillPacket(
    IN PDEVICE Device,
    IN PIPX_SEND_PACKET Packet,
    IN PUCHAR Header
    )

/*++

Routine Description:

    This routine initializes a send packet by chaining the
    buffer for the header on it.

Arguments:

    Device - The device.

    Packet - The packet to initialize.

    Header - Points to storage for the header.

Return Value:

    None.

--*/

{

    NDIS_STATUS NdisStatus;
    NTSTATUS Status;
    PNDIS_BUFFER NdisMacBuffer;
    PNDIS_BUFFER NdisIpxBuffer;
    PIPX_SEND_RESERVED Reserved;


    IPX_DEBUG (PACKET, ("Initializing backfill packet\n"));
    IpxAllocateSendPacket (Device, Packet, &Status);

    if (Status != STATUS_SUCCESS) {
        // ERROR LOG
        return Status;
    }


    Reserved = SEND_RESERVED(Packet);
    Reserved->Identifier = IDENTIFIER_IPX;
    Reserved->SendInProgress = FALSE;
    Reserved->Header = NULL;
    Reserved->HeaderBuffer = NULL;
    Reserved->PaddingBuffer = NULL;
    Reserved->BackFill = TRUE;

    ExInterlockedInsertHeadList(
        &Device->GlobalBackFillPacketList,
        &Reserved->GlobalLinkage,
        &Device->Lock);

    IPX_DEBUG (PACKET, ("Initializing backfill packet Done\n"));
    return STATUS_SUCCESS;

}   /* IpxInitializeBackFillPacket */
#endif


NTSTATUS
IpxInitializeReceivePacket(
    IN PDEVICE Device,
    IN PIPX_RECEIVE_PACKET Packet
    )

/*++

Routine Description:

    This routine initializes a receive packet.

Arguments:

    Device - The device.

    Packet - The packet to initialize.

Return Value:

    None.

--*/

{

    NTSTATUS Status;
    PIPX_RECEIVE_RESERVED Reserved;

    IpxAllocateReceivePacket (Device, Packet, &Status);

    if (Status != STATUS_SUCCESS) {
        // ERROR LOG
        return Status;
    }

    Reserved = RECEIVE_RESERVED(Packet);
    Reserved->Identifier = IDENTIFIER_IPX;
    Reserved->TransferInProgress = FALSE;
    Reserved->SingleRequest = NULL;
    Reserved->ReceiveBuffer = NULL;
    InitializeListHead (&Reserved->Requests);

    ExInterlockedInsertHeadList(
        &Device->GlobalReceivePacketList,
        &Reserved->GlobalLinkage,
        &Device->Lock);

    return STATUS_SUCCESS;

}   /* IpxInitializeReceivePacket */


NTSTATUS
IpxInitializeReceiveBuffer(
    IN PADAPTER Adapter,
    IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
    IN PUCHAR DataBuffer,
    IN ULONG DataBufferLength
    )

/*++

Routine Description:

    This routine initializes a receive buffer by allocating
    an NDIS_BUFFER to describe the data buffer.

Arguments:

    Adapter - The adapter.

    ReceiveBuffer - The receive buffer to initialize.

    DataBuffer - The data buffer.

    DataBufferLength - The length of the data buffer.

Return Value:

    None.

--*/

{

    NDIS_STATUS NdisStatus;
    PNDIS_BUFFER NdisBuffer;
    PDEVICE Device = Adapter->Device;


    NdisAllocateBuffer(
        &NdisStatus,
        &NdisBuffer,
        Device->NdisBufferPoolHandle,
        DataBuffer,
        DataBufferLength);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        // ERROR LOG
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ReceiveBuffer->NdisBuffer = NdisBuffer;
    ReceiveBuffer->Data = DataBuffer;
    ReceiveBuffer->DataLength = 0;

    ExInterlockedInsertHeadList(
        &Device->GlobalReceiveBufferList,
        &ReceiveBuffer->GlobalLinkage,
        &Device->Lock);

    return STATUS_SUCCESS;

}   /* IpxInitializeReceiveBuffer */


NTSTATUS
IpxInitializePaddingBuffer(
    IN PDEVICE Device,
    IN PIPX_PADDING_BUFFER PaddingBuffer,
    IN ULONG DataBufferLength
    )

/*++

Routine Description:

    This routine initializes a padding buffer by allocating
    an NDIS_BUFFER to describe the data buffer.

Arguments:

    Adapter - The adapter.

    PaddingBuffer - The receive buffer to initialize.

    DataBufferLength - The length of the data buffer.

Return Value:

    None.

--*/

{

    NDIS_STATUS NdisStatus;
    PNDIS_BUFFER NdisBuffer;

    NdisAllocateBuffer(
        &NdisStatus,
        &NdisBuffer,
        Device->NdisBufferPoolHandle,
        PaddingBuffer->Data,
        DataBufferLength);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        // ERROR LOG
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    NDIS_BUFFER_LINKAGE(NdisBuffer) = (PNDIS_BUFFER)NULL;
    PaddingBuffer->NdisBuffer = NdisBuffer;
    PaddingBuffer->DataLength = DataBufferLength;
    RtlZeroMemory (PaddingBuffer->Data, DataBufferLength);

    return STATUS_SUCCESS;

}   /* IpxInitializePaddingBuffer */


VOID
IpxDeinitializeSendPacket(
    IN PDEVICE Device,
    IN PIPX_SEND_PACKET Packet
    )

/*++

Routine Description:

    This routine deinitializes a send packet.

Arguments:

    Device - The device.

    Packet - The packet to deinitialize.

Return Value:

    None.

--*/

{

    PNDIS_BUFFER NdisBuffer;
    PNDIS_BUFFER NdisIpxBuffer;
    PIPX_SEND_RESERVED Reserved;
    CTELockHandle LockHandle;


    Reserved = SEND_RESERVED(Packet);

    CTEGetLock (&Device->Lock, &LockHandle);
    RemoveEntryList (&Reserved->GlobalLinkage);
    CTEFreeLock (&Device->Lock, LockHandle);

    //
    // Free the packet in a slightly unconventional way; this
    // allows us to not have to NULL out HeaderBuffer's linkage
    // field during normal operations when we put it back in
    // the free pool.
    //

    NdisBuffer = Reserved->HeaderBuffer;
    NdisIpxBuffer = NDIS_BUFFER_LINKAGE(NdisBuffer);
    NDIS_BUFFER_LINKAGE (NdisBuffer) = NULL;
    NDIS_BUFFER_LINKAGE (NdisIpxBuffer) = NULL;

#if 0
    NdisAdjustBufferLength (NdisBuffer, PACKET_HEADER_SIZE);
#endif
    NdisAdjustBufferLength (NdisBuffer, MAC_HEADER_SIZE);
    NdisAdjustBufferLength (NdisIpxBuffer, IPX_HEADER_SIZE + RIP_PACKET_SIZE);

    NdisFreeBuffer (NdisBuffer);
    NdisFreeBuffer (NdisIpxBuffer);

    NdisReinitializePacket (PACKET(Packet));
    IpxFreeSendPacket (Device, Packet);

}   /* IpxDeinitializeSendPacket */

#if BACK_FILL
VOID
IpxDeinitializeBackFillPacket(
    IN PDEVICE Device,
    IN PIPX_SEND_PACKET Packet
    )

/*++

Routine Description:

    This routine deinitializes a back fill packet.

Arguments:

    Device - The device.

    Packet - The packet to deinitialize.

Return Value:

    None.

--*/

{

    PNDIS_BUFFER NdisBuffer;
    PNDIS_BUFFER NdisIpxBuffer;
    PIPX_SEND_RESERVED Reserved;
    CTELockHandle LockHandle;

    IPX_DEBUG (PACKET, ("DeInitializing backfill packet\n"));

    Reserved = SEND_RESERVED(Packet);

    CTEGetLock (&Device->Lock, &LockHandle);
    RemoveEntryList (&Reserved->GlobalLinkage);
    CTEFreeLock (&Device->Lock, LockHandle);



    NdisReinitializePacket (PACKET(Packet));
    IpxFreeSendPacket (Device, Packet);
    IPX_DEBUG (PACKET, ("DeInitializing backfill packet Done\n"));


}   /* IpxDeinitializeBackFillPacket */
#endif


VOID
IpxDeinitializeReceivePacket(
    IN PDEVICE Device,
    IN PIPX_RECEIVE_PACKET Packet
    )

/*++

Routine Description:

    This routine initializes a receive packet.

Arguments:

    Device - The device.

    Packet - The packet to initialize.

Return Value:

    None.

--*/

{

    PIPX_RECEIVE_RESERVED Reserved;
    CTELockHandle LockHandle;

    Reserved = RECEIVE_RESERVED(Packet);

    CTEGetLock (&Device->Lock, &LockHandle);
    RemoveEntryList (&Reserved->GlobalLinkage);
    CTEFreeLock (&Device->Lock, LockHandle);

    IpxFreeReceivePacket (Device, Packet);

}   /* IpxDeinitializeReceivePacket */


VOID
IpxDeinitializeReceiveBuffer(
    IN PADAPTER Adapter,
    IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
    IN ULONG DataBufferLength
    )

/*++

Routine Description:

    This routine deinitializes a receive buffer.

Arguments:

    Device - The device.

    ReceiveBuffer - The receive buffer.

    DataBufferLength - The allocated length of the receive buffer.

Return Value:

    None.

--*/

{
    CTELockHandle LockHandle;
    PDEVICE Device = Adapter->Device;

    CTEGetLock (&Device->Lock, &LockHandle);
    RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
    CTEFreeLock (&Device->Lock, LockHandle);

    NdisAdjustBufferLength (ReceiveBuffer->NdisBuffer, DataBufferLength);
    NdisFreeBuffer (ReceiveBuffer->NdisBuffer);

}   /* IpxDeinitializeReceiveBuffer */


VOID
IpxDeinitializePaddingBuffer(
    IN PDEVICE Device,
    IN PIPX_PADDING_BUFFER PaddingBuffer,
    IN ULONG DataBufferLength
    )

/*++

Routine Description:

    This routine deinitializes a padding buffer.

Arguments:

    Device - The device.

    PaddingBuffer - The padding buffer.

    DataBufferLength - The allocated length of the padding buffer.

Return Value:

    None.

--*/

{

    NdisAdjustBufferLength (PaddingBuffer->NdisBuffer, DataBufferLength);
    NdisFreeBuffer (PaddingBuffer->NdisBuffer);

}   /* IpxDeinitializePaddingBuffer */


VOID
IpxAllocateSendPool(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine adds 10 packets to the pool for this device.

Arguments:

    Device - The device.

Return Value:

    None.

--*/

{
    PIPX_SEND_POOL SendPool;
    UINT HeaderSize;
    UINT PacketNum;
    IPX_SEND_PACKET Packet;
    PIPX_SEND_RESERVED Reserved;
    PUCHAR Header;
    NDIS_STATUS Status;

    CTELockHandle LockHandle;

    SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");

    if (SendPool == NULL) {
        IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
        return;
    }

    HeaderSize = PACKET_HEADER_SIZE * Device->InitDatagrams;

    Header = (PUCHAR)IpxAllocateMemory (HeaderSize, MEMORY_PACKET, "SendPool");

    if (Header == NULL) {
        IPX_DEBUG (PACKET, ("Could not allocate header memory\n"));
	//290901
	IpxFreeMemory(SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
        return;
    }

    SendPool->PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKIPX;

    NdisAllocatePacketPoolEx(
                             &Status, 
                             &SendPool->PoolHandle, 
                             Device->InitDatagrams, 
                             0,
                             sizeof(IPX_SEND_RESERVED)
                             );

    if (Status == NDIS_STATUS_RESOURCES) {
        IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
	//290901
        IpxFreeMemory(SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
	IpxFreeMemory(Header, HeaderSize, MEMORY_PACKET, "SendPool");
        return;
    }

    NdisSetPacketPoolProtocolId(SendPool->PoolHandle, NDIS_PROTOCOL_ID_IPX);

    Device->MemoryUsage += Device->InitDatagrams * sizeof(IPX_SEND_RESERVED);

    IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
                             SendPool, Device->InitDatagrams));

    SendPool->Header = Header;

    for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {

        NdisAllocatePacket(&Status, &PACKET(&Packet), SendPool->PoolHandle);

        if (IpxInitializeSendPacket (Device, &Packet, Header) != STATUS_SUCCESS) {
            IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
            break;
        }

        Reserved = SEND_RESERVED(&Packet);
        Reserved->Address = NULL;
        Reserved->OwnedByAddress = FALSE;
#ifdef IPX_TRACK_POOL
        Reserved->Pool = SendPool;
#endif

        IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);

        Header += PACKET_HEADER_SIZE;

    }

    CTEGetLock (&Device->Lock, &LockHandle);

    Device->AllocatedDatagrams += PacketNum;
    InsertTailList (&Device->SendPoolList, &SendPool->Linkage);

    CTEFreeLock (&Device->Lock, LockHandle);
}   /* IpxAllocateSendPool */


#if BACK_FILL

VOID
IpxAllocateBackFillPool(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine adds 10 packets to the pool for this device.

Arguments:

    Device - The device.

Return Value:

    None.

--*/

{
    UINT PacketNum;
    IPX_SEND_PACKET Packet;
    PIPX_SEND_RESERVED Reserved;
    CTELockHandle LockHandle;
    PIPX_SEND_POOL BackFillPool;
    NDIS_STATUS Status;

    IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));

    // Allocate pool for back fillable packets

    BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");

    if (BackFillPool == NULL) {
        IPX_DEBUG (PACKET, ("Could not allocate backfill pool memory\n"));
        return;
    }
    
    BackFillPool->PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKIPX;

    NdisAllocatePacketPoolEx(
                             &Status, 
                             &BackFillPool->PoolHandle, 
                             Device->InitDatagrams, 
                             0,
                             sizeof(IPX_SEND_RESERVED)
                             );

    if (Status == NDIS_STATUS_RESOURCES) {
        IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
        return;
    }
    
    NdisSetPacketPoolProtocolId(BackFillPool->PoolHandle, NDIS_PROTOCOL_ID_IPX);
    
    Device->MemoryUsage += Device->InitDatagrams * sizeof(IPX_SEND_RESERVED);

    for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {

        NdisAllocatePacket(&Status, &PACKET(&Packet), BackFillPool->PoolHandle);

        if (IpxInitializeBackFillPacket (Device, &Packet, NULL) != STATUS_SUCCESS) {
            IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
            break;
        }

        Reserved = SEND_RESERVED(&Packet);
        Reserved->Address = NULL;
        Reserved->OwnedByAddress = FALSE;
#ifdef IPX_TRACK_POOL
        Reserved->Pool = BackFillPool;
#endif

        IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
    }

    CTEGetLock (&Device->Lock, &LockHandle);

    InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);

    CTEFreeLock (&Device->Lock, LockHandle);
}   /* IpxAllocateBackFillPool */

#endif


VOID
IpxAllocateReceivePool(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine adds receive packets to the pool for this device.

Arguments:

    Device - The device.

Return Value:

    None.

--*/

{
    PIPX_RECEIVE_POOL ReceivePool;
    UINT PacketNum;
    IPX_RECEIVE_PACKET Packet;
    PIPX_RECEIVE_RESERVED Reserved;
    CTELockHandle LockHandle;
    NDIS_STATUS Status;

    ReceivePool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");

    if (ReceivePool == NULL) {
        IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
        return;
    }

    ReceivePool->PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKIPX;

    NdisAllocatePacketPoolEx(
                             &Status, 
                             &ReceivePool->PoolHandle, 
                             Device->InitDatagrams, 
                             0,
                             sizeof(IPX_SEND_RESERVED)
                             );

    if (Status == NDIS_STATUS_RESOURCES) {
        IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
        return;
    }
    
    NdisSetPacketPoolProtocolId(ReceivePool->PoolHandle, NDIS_PROTOCOL_ID_IPX);

    IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
                             ReceivePool, Device->InitReceivePackets));

    Device->MemoryUsage += Device->InitDatagrams * sizeof(IPX_SEND_RESERVED);

    for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {

        NdisAllocatePacket(&Status, &PACKET(&Packet), ReceivePool->PoolHandle);

        if (IpxInitializeReceivePacket (Device, &Packet) != STATUS_SUCCESS) {
            IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
            break;
        }

        Reserved = RECEIVE_RESERVED(&Packet);
        Reserved->Address = NULL;
        Reserved->OwnedByAddress = FALSE;
#ifdef IPX_TRACK_POOL
        Reserved->Pool = ReceivePool;
#endif

        IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);

    }

    CTEGetLock (&Device->Lock, &LockHandle);

    Device->AllocatedReceivePackets += PacketNum;

    InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);

    CTEFreeLock (&Device->Lock, LockHandle);
}   /* IpxAllocateReceivePool */

VOID
IpxAllocateReceiveBufferPool(
    IN PADAPTER Adapter
    )

/*++

Routine Description:

    This routine adds receive buffers to the pool for this adapter.

Arguments:

    Adapter - The adapter.

Return Value:

    None.

--*/

{
    PIPX_RECEIVE_BUFFER ReceiveBuffer;
    UINT ReceiveBufferPoolSize;
    UINT BufferNum;
    PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
    PDEVICE Device = Adapter->Device;
    UINT DataLength;
    PUCHAR Data;
    CTELockHandle LockHandle;

    DataLength = Adapter->MaxReceivePacketSize;

    ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
                       (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
                       (DataLength * Device->InitReceiveBuffers);

    ReceiveBufferPool = (PIPX_RECEIVE_BUFFER_POOL)IpxAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
    if (ReceiveBufferPool == NULL) {
        IPX_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
        return;
    }

    IPX_DEBUG (PACKET, ("Init recv buffer pool %lx, %d buffers, data %d\n",
                             ReceiveBufferPool, Device->InitReceiveBuffers, DataLength));

    Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitReceiveBuffers]);


    for (BufferNum = 0; BufferNum < Device->InitReceiveBuffers; BufferNum++) {

        ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];

        if (IpxInitializeReceiveBuffer (Adapter, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
            IPX_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
            break;
        }

#ifdef IPX_TRACK_POOL
        ReceiveBuffer->Pool = ReceiveBufferPool;
#endif

        Data += DataLength;

    }

    ReceiveBufferPool->BufferCount = BufferNum;
    ReceiveBufferPool->BufferFree = BufferNum;

    CTEGetLock (&Device->Lock, &LockHandle);

    for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {

        ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
        IPX_PUSH_ENTRY_LIST (&Adapter->ReceiveBufferList, &ReceiveBuffer->PoolLinkage, &Device->SListsLock);

    }

    InsertTailList (&Adapter->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);

    Adapter->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;

    CTEFreeLock (&Device->Lock, LockHandle);

}   /* IpxAllocateReceiveBufferPool */


PSINGLE_LIST_ENTRY
IpxPopSendPacket(
    PDEVICE Device
    )

/*++

Routine Description:

    This routine allocates a packet from the device context's pool.
    If there are no packets in the pool, it allocates one up to
    the configured limit.

Arguments:

    Device - Pointer to our device to charge the packet to.

Return Value:

    The pointer to the Linkage field in the allocated packet.

--*/

{
    PSINGLE_LIST_ENTRY s;

    s = IPX_POP_ENTRY_LIST(
            &Device->SendPacketList,
            &Device->SListsLock);

    if (s != NULL) {
        return s;
    }

    //
    // No packets in the pool, see if we can allocate more.
    //

    if (Device->AllocatedDatagrams < Device->MaxDatagrams) {

        //
        // Allocate a pool and try again.
        //

        IpxAllocateSendPool (Device);
        s = IPX_POP_ENTRY_LIST(
                &Device->SendPacketList,
                &Device->SListsLock);

        return s;

    } else {

        return NULL;

    }

}   /* IpxPopSendPacket */

#if BACK_FILL

PSINGLE_LIST_ENTRY
IpxPopBackFillPacket(
    PDEVICE Device
    )

/*++

Routine Description:

    This routine allocates a packet from the device context's pool.
    If there are no packets in the pool, it allocates one up to
    the configured limit.

Arguments:

    Device - Pointer to our device to charge the packet to.

Return Value:

    The pointer to the Linkage field in the allocated packet.

--*/

{
    PSINGLE_LIST_ENTRY s;

    IPX_DEBUG (PACKET, ("Popping backfill packet\n"));


    s = IPX_POP_ENTRY_LIST(
            &Device->BackFillPacketList,
            &Device->SListsLock);

    if (s != NULL) {
        return s;
    }

    //
    // No packets in the pool, see if we can allocate more.
    //

    if (Device->AllocatedDatagrams < Device->MaxDatagrams) {

        //
        // Allocate a pool and try again.
        //

        IpxAllocateBackFillPool (Device);
        s = IPX_POP_ENTRY_LIST(
                &Device->BackFillPacketList,
                &Device->SListsLock);


    IPX_DEBUG (PACKET, ("Popping backfill packet done\n"));
        return s;

    } else {

        return NULL;

    }

}   /* IpxPopBackFillPacket */
#endif //BackFill


PSINGLE_LIST_ENTRY
IpxPopReceivePacket(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine allocates a packet from the device context's pool.
    If there are no packets in the pool, it allocates one up to
    the configured limit.

Arguments:

    Device - Pointer to our device to charge the packet to.

Return Value:

    The pointer to the Linkage field in the allocated packet.

--*/

{
    PSINGLE_LIST_ENTRY s;

    s = IPX_POP_ENTRY_LIST(
            &Device->ReceivePacketList,
            &Device->SListsLock);

    if (s != NULL) {
        return s;
    }

    //
    // No packets in the pool, see if we can allocate more.
    //

    if (Device->AllocatedReceivePackets < Device->MaxReceivePackets) {

        //
        // Allocate a pool and try again.
        //

        IpxAllocateReceivePool (Device);
        s = IPX_POP_ENTRY_LIST(
                &Device->ReceivePacketList,
                &Device->SListsLock);

        return s;

    } else {

        return NULL;

    }

}   /* IpxPopReceivePacket */


PSINGLE_LIST_ENTRY
IpxPopReceiveBuffer(
    IN PADAPTER Adapter
    )

/*++

Routine Description:

    This routine allocates a receive buffer from the adapter's pool.
    If there are no buffers in the pool, it allocates one up to
    the configured limit.

Arguments:

    Adapter - Pointer to our adapter to charge the buffer to.

Return Value:

    The pointer to the Linkage field in the allocated receive buffer.

--*/

{
    PSINGLE_LIST_ENTRY s;
    PDEVICE Device = Adapter->Device;

    s = IPX_POP_ENTRY_LIST(
            &Adapter->ReceiveBufferList,
            &Device->SListsLock);

    if (s != NULL) {
        return s;
    }

    //
    // No buffer in the pool, see if we can allocate more.
    //

    if (Adapter->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {

        //
        // Allocate a pool and try again.
        //

        IpxAllocateReceiveBufferPool (Adapter);
        s = IPX_POP_ENTRY_LIST(
                &Adapter->ReceiveBufferList,
                &Device->SListsLock);

        return s;

    } else {

        return NULL;

    }

}   /* IpxPopReceiveBuffer */


PIPX_PADDING_BUFFER
IpxAllocatePaddingBuffer(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine allocates a padding buffer for use by all devices.

Arguments:

    Device - Pointer to our device to charge the packet to.

Return Value:

    The pointer to the allocated padding buffer.

--*/

{
    PIPX_PADDING_BUFFER PaddingBuffer;
    ULONG PaddingBufferSize;

    //
    // We are assuming that we can use 1 global padding buffer for ALL
    // transmits! We must therefore test to make sure that EthernetExtraPadding
    // is not greater than 1. Otherwise, we must assume that the extra padding
    // is being used for something and we therefore cannot share across all
    // transmit requests.
    //

    //
    // We cannot support more than 1 byte padding space, since we allocate only
    // one buffer for all transmit requests.
    //

    if ( Device->EthernetExtraPadding > 1 ) {
        IPX_DEBUG (PACKET, ("Padding buffer cannot be more than 1 byte\n"));
        DbgBreakPoint();
    }

    //
    // Allocate a padding buffer if possible.
    //

    PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;

    PaddingBuffer = IpxAllocateMemory (PaddingBufferSize, MEMORY_PACKET, "PaddingBuffer");

    if (PaddingBuffer != NULL) {

        if (IpxInitializePaddingBuffer (Device, PaddingBuffer, Device->EthernetExtraPadding) !=
                STATUS_SUCCESS) {
            IpxFreeMemory (PaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer");
        } else {
            IPX_DEBUG (PACKET, ("Allocate padding buffer %lx\n", PaddingBuffer));
            return PaddingBuffer;
        }
    }

    return NULL;

}   /* IpxAllocatePaddingBuffer */


VOID
IpxFreePaddingBuffer(
    IN PDEVICE Device
    )

/*++

Routine Description:

    This routine deallocates the padding buffer.

Arguments:

    Device - Pointer to our device to charge the packet to.

Return Value:

    None

--*/

{
    ULONG PaddingBufferSize;

    if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
        return;
    }

    PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
    IpxFreeMemory( IpxPaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer" );
    IpxPaddingBuffer = (PIPX_PADDING_BUFFER)NULL;

}   /* IpxFreePaddingBuffer */