/*++

Copyright (c) 1990-1995  Microsoft Corporation

Module Name:

    Ndiswan.c

Abstract:

    This is the initialization file for the NdisWan driver.  This driver
    is a shim between the protocols, where it conforms to the NDIS 3.1
    Miniport interface spec, and the WAN Miniport drivers, where it exports
    the WAN Extensions for Miniports (it looks like a protocol to the WAN
    Miniport drivers).

Author:

    Tony Bell   (TonyBe) June 06, 1995

Environment:

    Kernel Mode

Revision History:

    TonyBe      06/06/95        Created

--*/

#include "wan.h"

#define __FILE_SIG__    MEMORY_FILESIG

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, NdisWanCreateProtocolInfoTable)
#endif

EXPORT
VOID
NdisTapiDeregisterProvider(
    IN  NDIS_HANDLE
    );

//
// Local function prototypes
//
PVOID
AllocateWanPacket(
    IN  POOL_TYPE   PoolType,
    IN  SIZE_T      NumberOfBytes,
    IN  ULONG       Tag
    );

VOID
FreeWanPacket(
    PVOID   WanPacket
    );

//
// End local function prototypes
//

PMINIPORTCB
NdisWanAllocateMiniportCB(
    IN  PNDIS_STRING    AdapterName
    )
/*++

Routine Name:

    NdisWanAllocateMiniportCB

Routine Description:

    This routine creates and initializes an MiniportCB

Arguments:

Return Values:

--*/
{
    PMINIPORTCB LocalMiniportCB;
    ULONG       ulAllocationSize, i;

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateMiniportCB: Enter"));

    //
    // Allocate and zero out the memory block
    //
    NdisWanAllocateMemory(&LocalMiniportCB, MINIPORTCB_SIZE, MINIPORTCB_TAG);

    if (LocalMiniportCB == NULL) {

        return (NULL);
    }

    NdisZeroMemory(LocalMiniportCB, MINIPORTCB_SIZE);

    //
    // setup the new control block
    //
    NdisAllocateSpinLock(&LocalMiniportCB->Lock);

#ifdef MINIPORT_NAME
    NdisWanAllocateAdapterName(&LocalMiniportCB->AdapterName, AdapterName);
#endif

#if DBG
    InitializeListHead(&LocalMiniportCB->SendPacketList);
    InitializeListHead(&LocalMiniportCB->RecvPacketList);
#endif

    InitializeListHead(&LocalMiniportCB->ProtocolCBList);
    InitializeListHead(&LocalMiniportCB->AfSapCBList);

    NdisWanInitializeSyncEvent(&LocalMiniportCB->HaltEvent);
    NdisWanClearSyncEvent(&LocalMiniportCB->HaltEvent);

    //
    // Add to global list
    //
    InsertTailGlobalList(MiniportCBList, &(LocalMiniportCB->Linkage));

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("%ls MiniportCB: 0x%x, Number: %d",
                         LocalMiniportCB->AdapterName.Buffer, LocalMiniportCB, MiniportCBList.ulCount));

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateMiniportCB: Exit"));

    return (LocalMiniportCB);
}

VOID
NdisWanFreeMiniportCB(
    IN  PMINIPORTCB pMiniportCB
    )
/*++

Routine Name:

    NdisWanFreeMiniportCB

Routine Description:

    This frees a MiniportCB

Arguments:

    pMiniportCB - Pointer to to the MiniportCB that is being destroyed

Return Values:

    None

--*/
{
    PMINIPORTCB mcb;
    BOOLEAN     Found = FALSE;

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanFreeMiniportCB: Enter"));
    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("MiniportCB: 0x%x", pMiniportCB));

#ifdef MINIPORT_NAME
    NdisWanFreeNdisString(&pMiniportCB->AdapterName);
#endif

    NdisFreeSpinLock(&pMiniportCB->Lock);

    NdisAcquireSpinLock(&MiniportCBList.Lock);

    RemoveEntryList(&pMiniportCB->Linkage);

    MiniportCBList.ulCount--;

    //
    // Walk the miniportcb list and see if this is the only
    // instance of this protocol.  If it is we need to notify
    // user-mode that a protocol has been removed.
    //
    mcb = (PMINIPORTCB)MiniportCBList.List.Flink;

    while ((PVOID)mcb != (PVOID)&MiniportCBList.List) {
        if (mcb->ProtocolType == pMiniportCB->ProtocolType) {
            Found = TRUE;
            break;
        }

        mcb = (PMINIPORTCB)mcb->Linkage.Flink;
    }

    NdisReleaseSpinLock(&MiniportCBList.Lock);

    if (Found == FALSE) {
        PROTOCOL_INFO  pinfo;

        NdisZeroMemory(&pinfo, sizeof(pinfo));
        pinfo.ProtocolType = pMiniportCB->ProtocolType;
        pinfo.Flags = PROTOCOL_UNBOUND;
        SetProtocolInfo(&pinfo);
    }

    NdisWanFreeMemory(pMiniportCB);

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanFreeMiniportCB: Exit"));
}

POPENCB
NdisWanAllocateOpenCB(
    IN  PUNICODE_STRING BindName
    )
/*++

Routine Name:

    NdisWanAllocateOpenCB

Routine Description:

    This routine creates and initializes a OpenCB

Arguments:

    BindName - Pointer to an NDIS_STRING that has the name of the WAN Miniport
               that will be used in the NdisOpenAdapter call when we bind to
               the WAN Miniport.

Return Values:

--*/
{
    POPENCB pOpenCB;
    ULONG   ulAllocationSize;
    USHORT  i;

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateOpenCB: Enter"));
    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("BindName: %ls", BindName));

    //
    // Allocate memory for OpenCB
    //
    NdisWanAllocateMemory(&pOpenCB, OPENCB_SIZE, OPENCB_TAG);

    if (pOpenCB == NULL) {
        return (NULL);
    }

    NdisZeroMemory(pOpenCB, OPENCB_SIZE);
    NdisWanInitializeNotificationEvent(&pOpenCB->InitEvent);

    //
    // Parse out the GUID for this miniport
    //


    //
    // Setup new control block
    //
    NdisWanAllocateMemory(&pOpenCB->MiniportName.Buffer, BindName->MaximumLength, NDISSTRING_TAG);
    pOpenCB->MiniportName.MaximumLength = BindName->MaximumLength;
    pOpenCB->MiniportName.Length = BindName->Length;
    NdisWanCopyUnicodeString(&pOpenCB->MiniportName, BindName);

    //
    // Go to the end of the string and work back until we find
    // the first "{".  Now start parsing the string converting
    // and copying from WCHAR to CHAR all digits until we hit
    // the closing "}".
    //
    for (i = pOpenCB->MiniportName.Length/sizeof(WCHAR); i > 0; i--) {
        if (pOpenCB->MiniportName.Buffer[i-1] == (WCHAR)L'{') {
            break;
        }
    }

    if (i != 0) {
        NDIS_STRING Src;

        Src.Length =
            BindName->Length - ((i-1)*sizeof(WCHAR));
        Src.MaximumLength =
            BindName->Length - ((i-1)*sizeof(WCHAR));
        Src.Buffer = &BindName->Buffer[i-1];

        RtlGUIDFromString(&Src, &pOpenCB->Guid);
    }

    NdisAllocateSpinLock(&pOpenCB->Lock);
    InitializeListHead(&pOpenCB->AfSapCBList);
    InitializeListHead(&pOpenCB->AfSapCBClosing);
    InitializeListHead(&pOpenCB->WanRequestList);

#if DBG
    InitializeListHead(&pOpenCB->SendPacketList);
#endif

    //
    // Put OpenCB on global list
    //
    InsertTailGlobalList(OpenCBList, &(pOpenCB->Linkage));

    pOpenCB->RefCount = 1;

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("WanMiniport %ls OpenCB: 0x%x",
                                      pOpenCB->MiniportName.Buffer, pOpenCB));
    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanCreateOpenCB: Exit"));

    return(pOpenCB);
}

VOID
NdisWanFreeOpenCB(
    IN  POPENCB pOpenCB
    )
/*++

Routine Name:

    NdisWanFreeOpenCB

Routine Description:

    This routine frees a OpenCB

Arguments:

    pOpenCB - Pointer to the OpenCB that is being destroyed

Return Values:

    None

--*/
{
    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanFreeOpenCB: Enter - OpenCB: 0x%p", pOpenCB));

    if (pOpenCB->Flags & OPEN_LEGACY &&
        pOpenCB->Flags & SEND_RESOURCES) {
        NdisWanFreeSendResources(pOpenCB);
    }

    //
    // Remove from OpenCB global list
    //
    RemoveEntryGlobalList(OpenCBList, &(pOpenCB->Linkage));

    //
    // Free the memory allocated for the NDIS_STRING
    //
    NdisWanFreeNdisString(&pOpenCB->MiniportName);

    //
    // Free the memory allocated for the control block
    //
    NdisWanFreeMemory(pOpenCB);

    NdisWanDbgOut(DBG_TRACE, DBG_MEMORY, ("NdisWanFreeOpenCB: Exit"));
}

PPROTOCOLCB
NdisWanAllocateProtocolCB(
    IN  PNDISWAN_ROUTE  Route
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    PPROTOCOLCB     LocalProtocolCB;
    PUCHAR          AllocatedMemory;
    PROTOCOL_INFO   ProtocolInfo = {0};

    LocalProtocolCB =
        NdisAllocateFromNPagedLookasideList(&LinkProtoCBList);

    if (LocalProtocolCB == NULL) {
        return(NULL);
    }

    NdisZeroMemory(LocalProtocolCB, PROTOCOLCB_SIZE);

    LocalProtocolCB->Signature = PROTOCB_SIG;

    if (Route->ulBufferLength > 0) {
        NdisWanAllocateMemory(&AllocatedMemory,
                              Route->ulBufferLength,
                              PROTOCOLCB_TAG);
    
        if (AllocatedMemory == NULL) {
            NdisFreeToNPagedLookasideList(&LinkProtoCBList, LocalProtocolCB);
            return (NULL);
        }

        LocalProtocolCB->LineUpInfo = AllocatedMemory;
    }

    //
    // Copy the bindingname
    //
    if (Route->usBindingNameLength != 0) {
        USHORT  usBindingNameLength;
        WCHAR   BindingName[MAX_NAME_LENGTH+1] = {0};

        usBindingNameLength = Route->usBindingNameLength;

        //
        // We will limit the binding name string to 256 wchars
        //
        if (usBindingNameLength > (MAX_NAME_LENGTH * sizeof(WCHAR))) {
            usBindingNameLength = MAX_NAME_LENGTH * sizeof(WCHAR);
        } 

        NdisMoveMemory((PUCHAR)BindingName, 
                       (PUCHAR)Route->BindingName,
                       usBindingNameLength);

        NdisWanStringToNdisString(&LocalProtocolCB->BindingName, BindingName);
    }


    if (Route->usDeviceNameLength != 0) {
        USHORT  usDeviceNameLength;

        usDeviceNameLength = Route->usDeviceNameLength;

        //
        // We will limit the binding name string to 256 wchars
        //
        if (usDeviceNameLength > (MAX_NAME_LENGTH * sizeof(WCHAR))) {
            usDeviceNameLength = (MAX_NAME_LENGTH * sizeof(WCHAR));
        }

        NdisWanAllocateMemory(&(LocalProtocolCB->InDeviceName.Buffer),
                              usDeviceNameLength,
                              NDISSTRING_TAG);

        if (LocalProtocolCB->InDeviceName.Buffer != NULL) {

            LocalProtocolCB->InDeviceName.MaximumLength = usDeviceNameLength;
            LocalProtocolCB->InDeviceName.Length        = usDeviceNameLength;

            RtlCopyMemory((PUCHAR)LocalProtocolCB->InDeviceName.Buffer,
                          (PUCHAR)Route->DeviceName,
                          usDeviceNameLength);
        }

    }

    //
    // Copy over the protocol info
    //
    LocalProtocolCB->ulLineUpInfoLength = Route->ulBufferLength;
    if (Route->ulBufferLength != 0) {
        NdisMoveMemory(LocalProtocolCB->LineUpInfo,
                       Route->Buffer,
                       Route->ulBufferLength);
    }
    
    //
    // Setup the protocol type
    //
    LocalProtocolCB->ProtocolType = Route->usProtocolType;
    
    //
    // Get the PPP protocol value for this protocol type
    //
    ProtocolInfo.ProtocolType = Route->usProtocolType;

    if (GetProtocolInfo(&ProtocolInfo) != TRUE) {

        if (LocalProtocolCB->BindingName.Length != 0) {
            NdisWanFreeNdisString(&LocalProtocolCB->BindingName);
        }

        if (LocalProtocolCB->LineUpInfo != NULL) {
            NdisWanFreeMemory(LocalProtocolCB->LineUpInfo);
        }

        if (LocalProtocolCB->InDeviceName.Length != 0) {
            NdisWanFreeMemory(LocalProtocolCB->InDeviceName.Buffer);
        }

        NdisFreeToNPagedLookasideList(&LinkProtoCBList, LocalProtocolCB);
        return (NULL);
    }

    InitializeListHead(&LocalProtocolCB->VcList);
    NdisWanInitializeSyncEvent(&LocalProtocolCB->UnrouteEvent);

    LocalProtocolCB->PPPProtocolID = ProtocolInfo.PPPId;
    LocalProtocolCB->MTU = ProtocolInfo.MTU;
    LocalProtocolCB->TunnelMTU = ProtocolInfo.TunnelMTU;
    LocalProtocolCB->State = PROTOCOL_ROUTING;
    LocalProtocolCB->RefCount = 1;

    switch (Route->usProtocolType) {
        case PROTOCOL_IP:
            LocalProtocolCB->NonIdleDetectFunc = IpIsDataFrame;
            break;
        case PROTOCOL_IPX:
            LocalProtocolCB->NonIdleDetectFunc = IpxIsDataFrame;
            break;
        case PROTOCOL_NBF:
            LocalProtocolCB->NonIdleDetectFunc = NbfIsDataFrame;
            break;
        default:
            LocalProtocolCB->NonIdleDetectFunc = NULL;
            break;
    }
    
    NdisWanGetSystemTime(&LocalProtocolCB->LastNonIdleData);

    return(LocalProtocolCB);
}

VOID
NdisWanFreeProtocolCB(
    IN  PPROTOCOLCB ProtocolCB
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{

#if DBG
    {
        ULONG i;

        for (i = 0; i < MAX_MCML; i++) {
            ASSERT(ProtocolCB->PacketQueue[i].HeadQueue == NULL);
            ASSERT(ProtocolCB->PacketQueue[i].TailQueue == NULL);
        }

    }
#endif

    if (ProtocolCB->InDeviceName.Length != 0) {
        NdisWanFreeMemory(ProtocolCB->InDeviceName.Buffer);
    }

    if (ProtocolCB->OutDeviceName.Length != 0) {
        NdisWanFreeNdisString(&ProtocolCB->OutDeviceName);
    }

    if (ProtocolCB->BindingName.Length != 0) {
        NdisWanFreeNdisString(&ProtocolCB->BindingName);
    }

    if (ProtocolCB->LineUpInfo != NULL) {
        NdisWanFreeMemory(ProtocolCB->LineUpInfo);
    }

    NdisFreeSpinLock(&ProtocolCB->Lock);

    NdisFreeToNPagedLookasideList(&LinkProtoCBList, ProtocolCB);
}

PLINKCB
NdisWanAllocateLinkCB(
    IN  POPENCB OpenCB,
    IN  ULONG   SendWindow
    )
/*++

Routine Name:

    NdisWanGetLinkCB

Routine Description:

    This function returns a pointer to a LinkCB.  The LinkCB is either retrieved
    from the WanAdapters free list or, if this list is empty, it is allocated.

Arguments:

    OpenCB - Pointer to the WanAdapter control block that this Link is
                   associated with

Return Values:

    None

--*/
{
    PLINKCB LocalLinkCB;

    //
    // Figure out how much we need to allocate
    //

    LocalLinkCB =
        NdisAllocateFromNPagedLookasideList(&LinkProtoCBList);

    if (LocalLinkCB == NULL) {
        
        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for LinkCB"));

        return (NULL);
    }

    NdisZeroMemory(LocalLinkCB, LINKCB_SIZE);

    //
    // Initialize the control block
    //
    NdisWanInitializeSyncEvent(&LocalLinkCB->OutstandingFramesEvent);

    LocalLinkCB->Signature = LINKCB_SIG;
    LocalLinkCB->hLinkContext = NULL;
    LocalLinkCB->State = LINK_UP;
    LocalLinkCB->OpenCB = OpenCB;
    LocalLinkCB->OutstandingFrames = 0;
    LocalLinkCB->SendWindowOpen = TRUE;
    LocalLinkCB->SBandwidth = 100;
    LocalLinkCB->RBandwidth = 100;
    LocalLinkCB->SFlowSpec.MaxSduSize = glMaxMTU;
    LocalLinkCB->RFlowSpec.MaxSduSize = glMRRU;

    LocalLinkCB->LinkInfo.HeaderPadding = OpenCB->WanInfo.HeaderPadding;
    LocalLinkCB->LinkInfo.TailPadding = OpenCB->WanInfo.TailPadding;
    LocalLinkCB->LinkInfo.SendACCM =
    LocalLinkCB->LinkInfo.RecvACCM = OpenCB->WanInfo.DesiredACCM;
    LocalLinkCB->LinkInfo.MaxSendFrameSize = glMaxMTU;
    LocalLinkCB->LinkInfo.MaxRecvFrameSize = glMRU;

    if (OpenCB->Flags & OPEN_LEGACY) {
        LocalLinkCB->SendHandler = SendOnLegacyLink;
    } else {
        LocalLinkCB->SendHandler = SendOnLink;
    }

    if (OpenCB->MediumType == NdisMediumAtm ||

        (OpenCB->MediumType == NdisMediumWan &&
        (OpenCB->MediumSubType == NdisWanMediumAtm ||
         OpenCB->MediumSubType == NdisWanMediumPppoe)) ||

        (OpenCB->MediumType == NdisMediumCoWan &&
        (OpenCB->MediumSubType == NdisWanMediumAtm ||
         OpenCB->MediumSubType == NdisWanMediumPppoe))) {

        LocalLinkCB->RecvHandler = DetectBroadbandFraming;

        LocalLinkCB->LinkInfo.SendFramingBits = 
            PPP_FRAMING | PPP_COMPRESS_ADDRESS_CONTROL;

        LocalLinkCB->LinkInfo.RecvFramingBits = 
            PPP_FRAMING | PPP_COMPRESS_ADDRESS_CONTROL;

    } else {

        LocalLinkCB->RecvHandler = DetectFraming;
    }

    LocalLinkCB->SendWindow =
        (SendWindow == 0 || SendWindow > OpenCB->WanInfo.MaxTransmit) ?
        OpenCB->WanInfo.MaxTransmit : SendWindow;

    if (LocalLinkCB->SendWindow == 0) {
        LocalLinkCB->SendWindow = 1;
    }

    if (OpenCB->Flags & OPEN_LEGACY) {
        LocalLinkCB->SendResources = OpenCB->SendResources;
    } else {
        LocalLinkCB->SendResources = 1000;
    }

    NdisAllocateSpinLock(&LocalLinkCB->Lock);

    LocalLinkCB->RefCount = 1;

    REF_OPENCB(OpenCB);

    InterlockedIncrement(&OpenCB->ActiveLinkCount);

    return (LocalLinkCB);
}


VOID
NdisWanFreeLinkCB(
    PLINKCB LinkCB
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    POPENCB pOpenCB = LinkCB->OpenCB;

    ASSERT(LinkCB->OutstandingFrames == 0);

    LinkCB->State = LINK_DOWN;

    NdisFreeSpinLock(&LocalLinkCB->Lock);

    NdisFreeToNPagedLookasideList(&LinkProtoCBList, LinkCB);

    InterlockedDecrement(&pOpenCB->ActiveLinkCount);

    DEREF_OPENCB(pOpenCB);
}

NDIS_STATUS
NdisWanAllocateSendResources(
    POPENCB OpenCB
    )
/*++

Routine Name:

    NdisWanAllocateSendResources

Routine Description:

    Allocates all resources (SendDescriptors, WanPackets, ...)
    required for sending data.  Should be called at line up time.

Arguments:

    LinkCB - Pointer to the linkcb that the send resources will be attached to.
    SendWindow - Maximum number of sends that this link can handle

Return Values:

    NDIS_STATUS_SUCCESS
    NDIS_STATUS_RESOURCES

--*/
{
    ULONG   SendWindow;
    ULONG   Endpoints;
    ULONG   NumberOfPackets;
    ULONG   BufferSize;
    ULONG   WanPacketSize;
    PNDIS_WAN_PACKET    WanPacket;
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

    do {

        //
        // We have to have atleast of sendwindow+1 of packets for
        // each link on the open.  In the case of MCML we need
        // this amount for each fragment queue and for the
        // single non-fragment queue. So this leaves  us with...
        //
        //
        // SendWindow + 1 + (glMaxMTU/glMinFragSize * MAX_MCML) *
        // number of links on the open
        //
        SendWindow = OpenCB->WanInfo.MaxTransmit;
        Endpoints = OpenCB->WanInfo.Endpoints;

        //
        // Sendwindow
        //
        NumberOfPackets = SendWindow;

        //
        // We keep track of how many fragmenting resources we have
        // available for each link
        //
        NumberOfPackets += ((glMaxMTU/glMinFragSize) * MAX_MCML);
        OpenCB->SendResources = NumberOfPackets;

        //
        // Add one for compression data manipulation
        //
        NumberOfPackets += 1;

        //
        // multiplied by the # of links on this open
        //
        NumberOfPackets *= Endpoints;

        //
        // The size of the buffer that we create is
        //
        BufferSize = OpenCB->WanInfo.MaxFrameSize +
                     OpenCB->WanInfo.HeaderPadding +
                     OpenCB->WanInfo.TailPadding +
                     40 + sizeof(PVOID);

        //
        // We assume compression is always on so we pad out 12%
        // incase the compressor expands.  I don't know where the
        // 12% figure comes from.
        //
        BufferSize += (OpenCB->WanInfo.MaxFrameSize + 7) / 8;

        //
        // Make sure that the buffer is dword aligned.
        //
        BufferSize &= ~((ULONG_PTR)sizeof(PVOID) - 1);

        OpenCB->BufferSize = BufferSize;

        WanPacketSize = 
            sizeof(DATA_DESC) + sizeof(NDIS_WAN_PACKET) + 
            3*sizeof(PVOID) + BufferSize;

        //
        // If this device needs some special memory flags
        // we need to allocate memory for it's WanPackets now.
        // Otherwise we will intialize a lookaside list and
        // retrieve the packets as needed.

        if (OpenCB->WanInfo.MemoryFlags == 0) {


            NdisInitializeNPagedLookasideList(&OpenCB->WanPacketPool,
                                              AllocateWanPacket,
                                              FreeWanPacket,
                                              0,
                                              WanPacketSize,
                                              WANPACKET_TAG,
                                              0);

        } else {
            ULONG   PacketMemorySize;
            PUCHAR  PacketMemory;
            ULONG   n;

            PacketMemorySize = 
                WanPacketSize * NumberOfPackets;

            //
            // Allocate the memory for the wan packet buffer pool
            //
            NdisAllocateMemory(&PacketMemory,
                               PacketMemorySize,
                               OpenCB->WanInfo.MemoryFlags,
                               OpenCB->WanInfo.HighestAcceptableAddress);

            if (PacketMemory == NULL) {
                NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY, ("Error allocating memory for BufferPool, AllocationSize: %d",
                                 PacketMemorySize));

                Status  = NDIS_STATUS_RESOURCES;
                break;
            }

            OpenCB->PacketMemory = PacketMemory;
            OpenCB->PacketMemorySize = PacketMemorySize;
            NdisInitializeSListHead(&OpenCB->WanPacketList);

            for (n = 0; n < NumberOfPackets; n++) {
                PDATA_DESC  DataDesc;

                //
                // Point to the DataDesc
                //
                DataDesc = 
                    (PDATA_DESC)PacketMemory;

                PacketMemory =
                    ((PUCHAR)(DataDesc + 1) + sizeof(PVOID));

                (ULONG_PTR)PacketMemory &= 
                    ~((ULONG_PTR)sizeof(PVOID) - 1);

                // 
                // Point to the WanPacket
                //
                WanPacket = 
                    (PNDIS_WAN_PACKET)PacketMemory;

                PacketMemory = 
                    ((PUCHAR)(WanPacket + 1) + sizeof(PVOID));

                (ULONG_PTR)PacketMemory &= 
                    ~((ULONG_PTR)sizeof(PVOID) - 1);

                //
                // Point to the begining of the data buffer
                //
                WanPacket->StartBuffer = PacketMemory;
                WanPacket->EndBuffer = 
                    PacketMemory + BufferSize - sizeof(PVOID);

                NdisInterlockedPushEntrySList(&OpenCB->WanPacketList,
                                              (PSINGLE_LIST_ENTRY)DataDesc,
                                              &OpenCB->Lock);

                PacketMemory += BufferSize + sizeof(PVOID);
                (ULONG_PTR)PacketMemory &=
                    ~((ULONG_PTR)sizeof(PVOID) - 1);
            }
        }

    } while ( FALSE );

    if (Status == NDIS_STATUS_SUCCESS) {
        OpenCB->Flags |= SEND_RESOURCES;
    }

    return (Status);
}

VOID
NdisWanFreeSendResources(
    POPENCB OpenCB
    )
/*++

Routine Name:

    NdisWanFreeSendResources

Routine Description:

    This routine removes the WanPackets from this opencb's send list
    and free's the memory allocated for these packets.  Should be called
    when we are cleaningup an opencb.

Arguments:

    OpenCB - Pointer to the opencb that the resources are being freed from.

Return Values:

    None

--*/
{
    PUCHAR              PacketMemory;
    ULONG               PacketMemorySize, Flags;

    PacketMemory = OpenCB->PacketMemory;
    PacketMemorySize = OpenCB->PacketMemorySize;
    Flags = OpenCB->WanInfo.MemoryFlags;

    if (OpenCB->WanInfo.MemoryFlags == 0) {
        NdisDeleteNPagedLookasideList(&OpenCB->WanPacketPool);
        return;
    }

    //
    // Remove the packets from the wan packet pool
    //
    for (; ;) {
        PDATA_DESC  DataDesc;

        DataDesc = (PDATA_DESC)
            NdisInterlockedPopEntrySList(&OpenCB->WanPacketList,
                                         &OpenCB->Lock);

        if (DataDesc == NULL) {
            break;
        }
    }

    ASSERT(NdisQueryDepthSList(&OpenCB->WanPacketList) == 0);

    //
    // Free the block of memory allocated for this send
    //
    if (PacketMemory != NULL) {
        NdisFreeMemory(OpenCB->PacketMemory,
                       OpenCB->PacketMemorySize,
                       OpenCB->Flags);
    }
}

PBUNDLECB
NdisWanAllocateBundleCB(
    VOID
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    PBUNDLECB   LocalBundleCB = NULL;
    PWSTR   IOName = L"I/O ProtocolCB";
    PPROTOCOLCB ProtocolCB;
    PSAMPLE_TABLE   SampleTable;
    PBOND_INFO      BonDInfo;
    UINT    Class;
    PUCHAR  pMem;

    //
    // Allocation size is the size of the control block plus the size
    // of a table of pointers to protocolcb's that might be routed to
    // this bundle.
    //
    pMem =
        NdisAllocateFromNPagedLookasideList(&BundleCBList);

    if (pMem == NULL) {
        return (NULL);
    }

    NdisZeroMemory(pMem, BUNDLECB_SIZE);

    LocalBundleCB = (PBUNDLECB)pMem;

    pMem += sizeof(BUNDLECB) + sizeof(PVOID);

    //
    // This is the memory used for the I/O protocolcb
    //
    (PUCHAR)ProtocolCB = pMem;
    (ULONG_PTR)ProtocolCB &= ~((ULONG_PTR)sizeof(PVOID) - 1);

    pMem += sizeof(PROTOCOLCB) + sizeof(PVOID);

    //
    // This is the protocolcb table
    //
    (PUCHAR)LocalBundleCB->ProtocolCBTable = pMem;

    (ULONG_PTR)LocalBundleCB->ProtocolCBTable &=
        ~((ULONG_PTR)sizeof(PVOID) - 1);

    pMem += (MAX_PROTOCOLS * sizeof(PPROTOCOLCB)) + sizeof(PVOID);

    //
    // Initialize the BundleCB
    //
    NdisAllocateSpinLock(&LocalBundleCB->Lock);
    InitializeListHead(&LocalBundleCB->LinkCBList);

    for (Class = 0; Class < MAX_MCML; Class++) {
        PRECV_DESC  RecvDescHole;
        PSEND_FRAG_INFO FragInfo;
        PBUNDLE_RECV_INFO   RecvInfo;

        FragInfo = &LocalBundleCB->SendFragInfo[Class];
        RecvInfo = &LocalBundleCB->RecvInfo[Class];

        InitializeListHead(&FragInfo->FragQueue);
        FragInfo->MinFragSize = glMinFragSize;
        FragInfo->MaxFragSize = glMaxFragSize;

        InitializeListHead(&RecvInfo->AssemblyList);

        //
        // Init the recv hole desc
        //
        RecvDescHole =
            NdisWanAllocateRecvDesc(0);
    
        if (RecvDescHole == NULL) {
            UINT    i;

            for (i = 0; i < MAX_MCML; i++) {
                RecvInfo = &LocalBundleCB->RecvInfo[i];

                if (RecvInfo->RecvDescHole != NULL) {
                    NdisWanFreeRecvDesc(RecvInfo->RecvDescHole);
                    
                }
            }

            NdisFreeToNPagedLookasideList(&BundleCBList, LocalBundleCB);

            return (NULL);
        }
    
        RecvDescHole->Flags = MULTILINK_HOLE_FLAG;

        RecvInfo->RecvDescHole = RecvDescHole;
        InsertHeadList(&RecvInfo->AssemblyList, &RecvDescHole->Linkage);
        RecvInfo->AssemblyCount++;
    }

    InitializeListHead(&LocalBundleCB->ProtocolCBList);
    NdisWanInitializeSyncEvent(&LocalBundleCB->OutstandingFramesEvent);
    LocalBundleCB->State = BUNDLE_UP;
    LocalBundleCB->FramingInfo.MaxRSendFrameSize = glMaxMTU;
    LocalBundleCB->FramingInfo.MaxRRecvFrameSize = glMRRU;
    LocalBundleCB->SFlowSpec.MaxSduSize = glMaxMTU;
    LocalBundleCB->RFlowSpec.MaxSduSize = glMRRU;
    NdisWanGetSystemTime(&LocalBundleCB->LastNonIdleData);
    LocalBundleCB->SendCompInfo.CompType =
    LocalBundleCB->RecvCompInfo.CompType = COMPTYPE_NONE;

    //
    // Add the protocolcb to the bundle's table and list
    //
    ProtocolCB->ProtocolType = PROTOCOL_PRIVATE_IO;
    ProtocolCB->PPPProtocolID = PPP_PROTOCOL_PRIVATE_IO;
    ProtocolCB->BundleCB = LocalBundleCB;
    ProtocolCB->State = PROTOCOL_ROUTED;
    NdisWanStringToNdisString(&ProtocolCB->InDeviceName, IOName);
    LocalBundleCB->IoProtocolCB = ProtocolCB;

    return (LocalBundleCB);
}

VOID
NdisWanFreeBundleCB(
    IN  PBUNDLECB   BundleCB
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    UINT            Class;
    PPROTOCOLCB     IoProtocolCB;
    PPACKET_QUEUE   PacketQueue;

    FlushAssemblyLists(BundleCB);

    if (BundleCB->Flags & BOND_ENABLED) {
        RemoveEntryGlobalList(BonDWorkList, &BundleCB->BonDLinkage);
    }

    //
    // Free the hole place holders
    //
    for (Class = 0; Class < MAX_MCML; Class++) {
        PBUNDLE_RECV_INFO   RecvInfo =
            &BundleCB->RecvInfo[Class];

        ASSERT(RecvInfo->RecvDescHole != NULL);
        
        NdisWanFreeRecvDesc(RecvInfo->RecvDescHole);
        RecvInfo->RecvDescHole = NULL;
    }

#if 0
    KeCancelTimer(&BundleCB->BonDTimer);
#endif

    IoProtocolCB = BundleCB->IoProtocolCB;
    PacketQueue = &IoProtocolCB->PacketQueue[MAX_MCML];

    ASSERT(IsPacketQueueEmpty(PacketQueue));

    //
    // If we have ppp packets queued we need
    // to flush them and free the memory!
    //
    while (!IsPacketQueueEmpty(PacketQueue)) {
        PNDIS_PACKET     Packet;

        Packet =
            RemoveHeadPacketQueue(PacketQueue)

        CompleteNdisPacket(IoProtocolCB->MiniportCB,
                           IoProtocolCB,
                           Packet);
    }

    sl_compress_terminate(&BundleCB->VJCompress);

    if (BundleCB->Flags & SEND_CCP_ALLOCATED) {

        WanDeallocateCCP(BundleCB,
                         &BundleCB->SendCompInfo,
                         TRUE);
        BundleCB->Flags &= ~SEND_CCP_ALLOCATED;
    }

    if (BundleCB->Flags & RECV_CCP_ALLOCATED) {
        WanDeallocateCCP(BundleCB,
                         &BundleCB->RecvCompInfo,
                         FALSE);
        BundleCB->Flags &= ~RECV_CCP_ALLOCATED;
    }

    if (BundleCB->Flags & SEND_ECP_ALLOCATED) {
        WanDeallocateECP(BundleCB,
                         &BundleCB->SendCompInfo,
                         &BundleCB->SendCryptoInfo);
        BundleCB->Flags &= ~SEND_ECP_ALLOCATED;
    }

    if (BundleCB->Flags & RECV_ECP_ALLOCATED) {
        WanDeallocateECP(BundleCB,
                         &BundleCB->RecvCompInfo,
                         &BundleCB->RecvCryptoInfo);
        BundleCB->Flags &= ~RECV_ECP_ALLOCATED;
    }

    if (BundleCB->BonDAllocation != NULL) {
        NdisWanFreeMemory(BundleCB->BonDAllocation);
        BundleCB->BonDAllocation = NULL;
    }

    BundleCB->State = BUNDLE_DOWN;

    NdisFreeSpinLock(&BundleCB->Lock);

    NdisWanFreeNdisString(&BundleCB->IoProtocolCB->InDeviceName);

    NdisFreeToNPagedLookasideList(&BundleCBList, BundleCB);
}


NDIS_STATUS
NdisWanCreateProtocolInfoTable(
    VOID
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
    ULONG       ulAllocationSize = 0;
    PUCHAR      AllocatedMemory;
    PROTOCOL_INFO   ProtocolInfo;

    //
    // Allocate ProtocolLookupTable.  This table is used to match protocol values
    // with their corresponding PPP Protocol values.  The table size is set to
    // MAX_PROTOCOLS.
    //
    ulAllocationSize = sizeof(PROTOCOL_INFO_TABLE) +
                     (sizeof(PROTOCOL_INFO) * MAX_PROTOCOLS);
    

    NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize, PROTOCOLTABLE_TAG);

    if (AllocatedMemory == NULL) {
        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
               ("Failed allocating memory for ProtocolLookupTable! TableSize: %d",
               ulAllocationSize));

        return (NDIS_STATUS_RESOURCES);     
    }

    ProtocolInfoTable = (PPROTOCOL_INFO_TABLE)AllocatedMemory;

    //
    // Save the allocation size
    //
    ProtocolInfoTable->ulAllocationSize = ulAllocationSize;

    //
    // Store the array size.  This should be read from the registry
    //
    ProtocolInfoTable->ulArraySize = MAX_PROTOCOLS;

    NdisAllocateSpinLock(&ProtocolInfoTable->Lock);

    //
    // Setup the pointer to the ProtocolValue array
    //
    AllocatedMemory += sizeof(PROTOCOL_INFO_TABLE);
    ProtocolInfoTable->ProtocolInfo = (PPROTOCOL_INFO)(AllocatedMemory);

    //
    // Insert default values for Netbuei, IP, IPX
    //
    ProtocolInfo.ProtocolType = PROTOCOL_PRIVATE_IO;
    ProtocolInfo.PPPId = PPP_PROTOCOL_PRIVATE_IO;
    ProtocolInfo.MTU = DEFAULT_MTU;
    ProtocolInfo.TunnelMTU = DEFAULT_MTU;
    ProtocolInfo.PacketQueueDepth = DEFAULT_PACKETQUEUE_DEPTH;
    ProtocolInfo.Flags = PROTOCOL_UNBOUND;
    SetProtocolInfo(&ProtocolInfo);

    ProtocolInfo.ProtocolType = PROTOCOL_IP;
    ProtocolInfo.PPPId = PPP_PROTOCOL_IP;
    ProtocolInfo.MTU = DEFAULT_MTU;
    ProtocolInfo.TunnelMTU = DEFAULT_TUNNEL_MTU;
    ProtocolInfo.PacketQueueDepth = DEFAULT_PACKETQUEUE_DEPTH;
    ProtocolInfo.Flags = PROTOCOL_UNBOUND;
    SetProtocolInfo(&ProtocolInfo);

    ProtocolInfo.ProtocolType = PROTOCOL_IPX;
    ProtocolInfo.PPPId = PPP_PROTOCOL_IPX;
    ProtocolInfo.MTU = DEFAULT_MTU;
    ProtocolInfo.TunnelMTU = DEFAULT_MTU;
    ProtocolInfo.PacketQueueDepth = DEFAULT_PACKETQUEUE_DEPTH;
    ProtocolInfo.Flags = PROTOCOL_UNBOUND;
    SetProtocolInfo(&ProtocolInfo);

    ProtocolInfo.ProtocolType = PROTOCOL_NBF;
    ProtocolInfo.PPPId = PPP_PROTOCOL_NBF;
    ProtocolInfo.MTU = DEFAULT_MTU;
    ProtocolInfo.TunnelMTU = DEFAULT_MTU;
    ProtocolInfo.PacketQueueDepth = DEFAULT_PACKETQUEUE_DEPTH;
    ProtocolInfo.Flags = PROTOCOL_UNBOUND;
    SetProtocolInfo(&ProtocolInfo);

    ProtocolInfo.ProtocolType = PROTOCOL_APPLETALK;
    ProtocolInfo.PPPId = PPP_PROTOCOL_APPLETALK;
    ProtocolInfo.MTU = DEFAULT_MTU;
    ProtocolInfo.TunnelMTU = DEFAULT_MTU;
    ProtocolInfo.PacketQueueDepth = DEFAULT_PACKETQUEUE_DEPTH;
    ProtocolInfo.Flags = PROTOCOL_UNBOUND;
    SetProtocolInfo(&ProtocolInfo);

    return (Status);

}

VOID
NdisWanDestroyProtocolInfoTable(
    VOID
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    NdisFreeSpinLock(&ProtocolInfoTable->Lock);

    NdisWanFreeMemory(ProtocolInfoTable);
}

NDIS_STATUS
NdisWanCreateConnectionTable(
    ULONG   TableSize
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    ULONG       ulAllocationSize = 0;
    ULONG       ulArraySize;
    PUCHAR      AllocatedMemory;
    PCONNECTION_TABLE   NewTable;

    //
    // Since we skip the first place in the tables we increase the
    // size by one.
    //
    ulArraySize = TableSize + 1;

    //
    // Allocate the Bundle and Link Arrays based on the number of possible connections
    // that we have in the system.  This should be grown if we get called
    // to reinitialize and gain new ports.
    //
    ulAllocationSize = sizeof(CONNECTION_TABLE) +
                     (sizeof(PBUNDLECB) * ulArraySize) +
                     (sizeof(PLINKCB) * ulArraySize);

    NdisWanAllocateMemory(&AllocatedMemory, ulAllocationSize, CONNECTIONTABLE_TAG);

    if (AllocatedMemory == NULL) {

        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
               ("Failed allocating memory for ConnectionTable! Size: %d, Links: %d",
               ulAllocationSize, TableSize));

        return (NDIS_STATUS_RESOURCES);
    }

    NewTable = (PCONNECTION_TABLE)AllocatedMemory;

    //
    // This is the amount of memory we allocated
    //
    NewTable->ulAllocationSize = ulAllocationSize;
    NewTable->ulArraySize = TableSize;
    NewTable->ulNextLink =
    NewTable->ulNextBundle = 1;
    InitializeListHead(&NewTable->BundleList);
    InitializeListHead(&NewTable->LinkList);

    //
    // Setup pointer to the linkcb array
    //
    AllocatedMemory += sizeof(CONNECTION_TABLE);
    NewTable->LinkArray = (PLINKCB*)(AllocatedMemory);
    
    //
    // Setup the pointer to the bundlecb array
    //
    AllocatedMemory += (sizeof(PLINKCB) * ulArraySize);
    NewTable->BundleArray = (PBUNDLECB*)(AllocatedMemory);

    if (ConnectionTable != NULL) {
        PCONNECTION_TABLE   FreeTable;

        //
        // We must be growing the table.  This will be
        // called with the current connectiontable lock
        // held!
        //
        NewTable->ulNumActiveLinks = ConnectionTable->ulNumActiveLinks;
        NewTable->ulNumActiveBundles = ConnectionTable->ulNumActiveBundles;
        NewTable->ulNextLink = ConnectionTable->ulNextLink;
        NewTable->ulNextBundle = ConnectionTable->ulNextBundle;

        NdisMoveMemory((PUCHAR)NewTable->LinkArray,
                       (PUCHAR)ConnectionTable->LinkArray,
                       ConnectionTable->ulArraySize * sizeof(PLINKCB));

        NdisMoveMemory((PUCHAR)NewTable->BundleArray,
                       (PUCHAR)ConnectionTable->BundleArray,
                       ConnectionTable->ulArraySize * sizeof(PBUNDLECB));

        while (!IsListEmpty(&ConnectionTable->BundleList)) {
            PBUNDLECB   BundleCB;

            BundleCB = (PBUNDLECB)RemoveHeadList(&ConnectionTable->BundleList);
            InsertTailList(&NewTable->BundleList, &BundleCB->Linkage);
        }

        while (!IsListEmpty(&ConnectionTable->LinkList)) {
            PLIST_ENTRY Entry;
            PLINKCB     LinkCB;

            Entry = RemoveHeadList(&ConnectionTable->LinkList);
            LinkCB = 
                (PLINKCB)CONTAINING_RECORD(Entry, LINKCB, ConnTableLinkage);
            InsertTailList(&NewTable->LinkList, &LinkCB->ConnTableLinkage);

        }

        FreeTable = ConnectionTable;
        ConnectionTable = NewTable;

        //
        // Destroy the old table
        //
        NdisWanFreeMemory(FreeTable);


    } else {
        ConnectionTable = NewTable;
    }

    return (NDIS_STATUS_SUCCESS);
}

PNDIS_PACKET
NdisWanAllocateNdisPacket(
    ULONG   MagicNumber
    )
{
    PNDIS_PACKET    ReturnPacket = NULL;
    PPOOL_DESC      PoolDesc;
    NDIS_STATUS     Status = NDIS_STATUS_FAILURE;
    ULONG           i;
    PSINGLE_LIST_ENTRY  p = NULL;
    PNDISWAN_PROTOCOL_RESERVED  pres;

    NdisAcquireSpinLock(&PacketPoolList.Lock);

    //
    // Walk the pool desc list and try to allocate a packet
    //
    PoolDesc = (PPOOL_DESC)PacketPoolList.List.Flink;

    while (PoolDesc != (PPOOL_DESC)&PacketPoolList.List) {

        p = PopEntryList(&PoolDesc->Head);

        if (p != NULL) {
            break;
        }
        
        PoolDesc = (PPOOL_DESC)PoolDesc->Linkage.Flink;
    }

    if (p == NULL) {
        //
        // We have walked the pool list and did not find any
        // free packets on any of the free pools, so allocate
        // a new pool and get a packet from it.
        //
        NdisWanAllocatePriorityMemory(&PoolDesc, 
                                      sizeof(POOL_DESC), 
                                      POOLDESC_TAG,
                                      NormalPoolPriority);

        if (PoolDesc == NULL) {
            NdisReleaseSpinLock(&PacketPoolList.Lock);
            return (NULL);
        }

        NdisAllocatePacketPoolEx(&Status,
                                 &PoolDesc->PoolHandle,
                                 glPacketPoolCount,
                                 0,
                                 sizeof(NDISWAN_PROTOCOL_RESERVED));

        if (Status != NDIS_STATUS_SUCCESS) {
            NdisWanFreeMemory(PoolDesc);
            NdisReleaseSpinLock(&PacketPoolList.Lock);
            return (NULL);
        }

        for (i = 0; i < glPacketPoolCount; i++) {
            PNDIS_PACKET    np;

            NdisAllocatePacket(&Status,
                               &np,
                               PoolDesc->PoolHandle);

            ASSERT(np != NULL);

            pres = PPROTOCOL_RESERVED_FROM_NDIS(np);

            PushEntryList(&PoolDesc->Head, &pres->SLink);

            PoolDesc->FreeCount++;
        }

        InsertTailList(&PacketPoolList.List, &PoolDesc->Linkage);

        PacketPoolList.TotalDescCount++;
        PacketPoolList.FreeCount += PoolDesc->FreeCount;

        if (PacketPoolList.TotalDescCount >
            PacketPoolList.MaxDescCount) {
            
            PacketPoolList.MaxDescCount = PacketPoolList.TotalDescCount;
        }

        p = PopEntryList(&PoolDesc->Head);
    }

    ASSERT(p != NULL);

    pres = CONTAINING_RECORD(p, NDISWAN_PROTOCOL_RESERVED, SLink);
    ReturnPacket = CONTAINING_RECORD(pres, NDIS_PACKET, ProtocolReserved);

    NdisReinitializePacket(ReturnPacket);

    PoolDesc->AllocatedCount++;
    PoolDesc->FreeCount--;
    ASSERT((PoolDesc->AllocatedCount + PoolDesc->FreeCount) == glPacketPoolCount);

    if (PoolDesc->AllocatedCount >
        PoolDesc->MaxAllocatedCount) {

        PoolDesc->MaxAllocatedCount =
            PoolDesc->AllocatedCount;
    }

    PacketPoolList.AllocatedCount++;
    PacketPoolList.FreeCount--;

#if DBG
{
    PPOOL_DESC  pdesc;
    ULONG       FreeCount, AllocatedCount;

    pdesc = (PPOOL_DESC)PacketPoolList.List.Flink;

    FreeCount = AllocatedCount = 0;

    while ((PVOID)pdesc != (PVOID)&PacketPoolList.List) {
        FreeCount += pdesc->FreeCount;
        AllocatedCount += pdesc->AllocatedCount;
        pdesc = (PPOOL_DESC)pdesc->Linkage.Flink;
    }

    if (PacketPoolList.AllocatedCount != AllocatedCount ||
        PacketPoolList.FreeCount != FreeCount){
        DbgPrint("NDISWAN: AllocatePacket - PacketPool counts out of sync!\n");
        DbgBreakPoint();
    }

#if 0
    if (PacketPoolList.AllocatedCount > 200) {
        DbgPrint("NDISWAN: AllocatePacket - Over 200 outstanding packets!\n");
        DbgBreakPoint();
    }
#endif

}
#endif

    if (PacketPoolList.AllocatedCount >
        PacketPoolList.MaxAllocatedCount) {

        PacketPoolList.MaxAllocatedCount =
            PacketPoolList.AllocatedCount;
    }
    
    pres->MagicNumber = MagicNumber;
    pres->PoolDesc = PoolDesc;

    NDIS_SET_PACKET_HEADER_SIZE(ReturnPacket, 
                                MAC_HEADER_LENGTH);

    NDIS_SET_PACKET_STATUS(ReturnPacket, 
                           NDIS_STATUS_SUCCESS);

    NdisReleaseSpinLock(&PacketPoolList.Lock);

    return (ReturnPacket);
}

VOID
NdisWanFreeNdisPacket(
    PNDIS_PACKET    NdisPacket
    )
{
    PNDISWAN_PROTOCOL_RESERVED  pres;
    PPOOL_DESC      PoolDesc;
    PNDIS_BUFFER    NdisBuffer;
    PUCHAR          DataBuffer;

    pres = PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket);

    ASSERT(pres->MagicNumber == MAGIC_INTERNAL_ALLOC ||
           pres->MagicNumber == MAGIC_INTERNAL_IO ||
           pres->MagicNumber == MAGIC_INTERNAL_SEND ||
           pres->MagicNumber == MAGIC_INTERNAL_RECV ||
           pres->MagicNumber == MAGIC_INTERNAL_ALLOC);

    PoolDesc = pres->PoolDesc;

    NdisAcquireSpinLock(&PacketPoolList.Lock);

#if DBG
{
    PPOOL_DESC  pdesc;

    pdesc = (PPOOL_DESC)PacketPoolList.List.Flink;

    while ((PVOID)pdesc != (PVOID)&PacketPoolList.List) {

        if (PoolDesc == pdesc) {
            //
            // We found the correct pool
            //
            break;
        }

        pdesc = (PPOOL_DESC)pdesc->Linkage.Flink;
    }

    if((PVOID)PoolDesc == (PVOID)&PacketPoolList.List){
        DbgPrint("NDISWAN: FreePacket PoolDesc %x not on PacketPoolList!\n",
                 PoolDesc);
        DbgBreakPoint();
    }
}
#endif

    PushEntryList(&PoolDesc->Head, &pres->SLink);

    PoolDesc->AllocatedCount--;
    PoolDesc->FreeCount++;

    ASSERT((PoolDesc->AllocatedCount + PoolDesc->FreeCount) == glPacketPoolCount);

    PacketPoolList.AllocatedCount--;
    PacketPoolList.FreeCount++;

#if DBG
{
    PPOOL_DESC  pdesc;
    ULONG       FreeCount, AllocatedCount;

    pdesc = (PPOOL_DESC)PacketPoolList.List.Flink;

    FreeCount = AllocatedCount = 0;

    while ((PVOID)pdesc != (PVOID)&PacketPoolList.List) {
        FreeCount += pdesc->FreeCount;
        AllocatedCount += pdesc->AllocatedCount;


        pdesc = (PPOOL_DESC)pdesc->Linkage.Flink;
    }

    if (PacketPoolList.AllocatedCount != AllocatedCount ||
        PacketPoolList.FreeCount != FreeCount){
        DbgPrint("NDISWAN: FreePacket - PacketPool counts out of sync!\n");
        DbgBreakPoint();
    }
}
#endif

    //
    // If all of the packets have been returned to this pool desc
    // and this is not the only pool desc then free it!
    //
    if (PoolDesc->AllocatedCount == 0 &&
        PacketPoolList.TotalDescCount > 1 &&
        PacketPoolList.FreeCount > PoolDesc->FreeCount) {
        PSINGLE_LIST_ENTRY  p = NULL;

        RemoveEntryList(&PoolDesc->Linkage);

        PacketPoolList.TotalDescCount--;
        PacketPoolList.FreeCount -= PoolDesc->FreeCount;

        p = PopEntryList(&PoolDesc->Head);

        while (p != NULL) {
            PNDIS_PACKET    ReturnPacket;

            pres = CONTAINING_RECORD(p, NDISWAN_PROTOCOL_RESERVED, SLink);
            ReturnPacket = CONTAINING_RECORD(pres, NDIS_PACKET, ProtocolReserved);

            NdisFreePacket(ReturnPacket);

            p = PopEntryList(&PoolDesc->Head);
        }

        NdisFreePacketPool(PoolDesc->PoolHandle);
        NdisWanFreeMemory(PoolDesc);
    }

    NdisReleaseSpinLock(&PacketPoolList.Lock);
}

PVOID
AllocateDataDesc(
    POOL_TYPE   PoolType,
    SIZE_T      NumberOfBytes,
    ULONG       Tag
    )
/*++

Routine Name:

    AllocateDataDesc

Routine Description:

    This routine is called by the lookasidelist manager if there are not
    any descriptors available.  It will allocated memory for: DATA_DESC,
    NDIS_BUFFER, NDIS_PACKET, and a block of memory of size.
    
Arguments:

Return Values:

--*/
{
    PDATA_DESC      DataDesc;
    PUCHAR          DataBuffer;
    NDIS_STATUS     Status;

    NdisWanAllocatePriorityMemory(&DataDesc, 
                                  NumberOfBytes, 
                                  Tag,
                                  NormalPoolPriority);

    if (DataDesc == NULL) {
        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
                      ("AllocateDataDesc failed! Size %d",
                      NumberOfBytes));
        return (NULL);
    }

    DataBuffer = 
        ((PUCHAR)(DataDesc + 1) + sizeof(PVOID));
    (ULONG_PTR)DataBuffer &= 
        ~((ULONG_PTR)sizeof(PVOID) - 1);

    DataDesc->DataBuffer = DataBuffer;

    DataDesc->DataBufferLength = 
        (ULONG)(((PUCHAR)DataDesc + NumberOfBytes) - DataBuffer);

    // This is not portable to Win95!  I need to allocate a buffer
    // pool and use a valid handle.
    //
    NdisAllocateBuffer(&Status, 
                       &DataDesc->NdisBuffer, 
                       NULL,
                       DataDesc->DataBuffer,
                       DataDesc->DataBufferLength);

    if (Status != NDIS_STATUS_SUCCESS) {

        NdisWanFreeMemory(DataDesc);

        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
                      ("NdisAllocateBuffer failed! DataBufferSize %d",
                      DataDesc->DataBufferLength));
        return (NULL);
    }

    DataDesc->NdisPacket =
        NdisWanAllocateNdisPacket(MAGIC_INTERNAL_ALLOC);

    if (DataDesc->NdisPacket == NULL) {

        NdisFreeBuffer(DataDesc->NdisBuffer);

        NdisWanFreeMemory(DataDesc);

        NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_MEMORY,
                      ("NdisWanAllocateNdisPacket failed! DataBufferSize %d"));

        return (NULL);
    }

    NdisChainBufferAtFront(DataDesc->NdisPacket,
                           DataDesc->NdisBuffer);

    return(DataDesc);
}

VOID
FreeDataDesc(
    PVOID   Buffer
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    PDATA_DESC      DataDesc;

    DataDesc = (PDATA_DESC)Buffer;

    NdisReinitializePacket(DataDesc->NdisPacket);

    NdisWanFreeNdisPacket(DataDesc->NdisPacket);

    NdisFreeBuffer(DataDesc->NdisBuffer);

    NdisWanFreeMemory(Buffer);
}

PRECV_DESC
NdisWanAllocateRecvDesc(
    ULONG   SizeNeeded
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    PDATA_DESC  DataDesc;
    PRECV_DESC  RecvDesc;
    ULONG       Length;
    PNPAGED_LOOKASIDE_LIST  LookasideList;

    if (SizeNeeded > glLargeDataBufferSize) {
        DbgPrint("NDISWAN: Error Allocating RecvDesc Size %d\n",
                 SizeNeeded);
        return (NULL);
    } else if (SizeNeeded > glSmallDataBufferSize) {
        LookasideList = &LargeDataDescList;
    } else {
        LookasideList = &SmallDataDescList;
    }

    DataDesc =
        NdisAllocateFromNPagedLookasideList(LookasideList);

    if (DataDesc == NULL) {
        return (NULL);
    }

    PPROTOCOL_RESERVED_FROM_NDIS(DataDesc->NdisPacket)->MagicNumber =
        MAGIC_INTERNAL_RECV;

    DataDesc->LookasideList = LookasideList;
    RecvDesc = &DataDesc->RecvDesc;

    NdisZeroMemory(RecvDesc, sizeof(RECV_DESC));

    RecvDesc->Signature = RECVDESC_SIG;
    RecvDesc->DataBuffer =
        DataDesc->DataBuffer;
    RecvDesc->NdisBuffer =
        DataDesc->NdisBuffer;
    RecvDesc->NdisPacket =
        DataDesc->NdisPacket;

    NdisQueryBuffer(RecvDesc->NdisBuffer,
                    &RecvDesc->StartBuffer,
                    &Length);

    RecvDesc->CurrentBuffer = 
        RecvDesc->StartBuffer + MAC_HEADER_LENGTH + PROTOCOL_HEADER_LENGTH;

    return (RecvDesc);
}

VOID
NdisWanFreeRecvDesc(
    PRECV_DESC  RecvDesc
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    PDATA_DESC      DataDesc;
    PNDIS_BUFFER    NdisBuffer;
    PNDIS_PACKET    NdisPacket;
    PNPAGED_LOOKASIDE_LIST  LookasideList;

    if (RecvDesc->OriginalPacket != NULL) {

        NdisReturnPackets(&RecvDesc->OriginalPacket, 1);
        RecvDesc->OriginalPacket = NULL;
    }

    DataDesc = 
        CONTAINING_RECORD(RecvDesc, DATA_DESC, RecvDesc);

    NdisBuffer = 
        DataDesc->NdisBuffer;

    NdisPacket =
        DataDesc->NdisPacket;

    LookasideList = 
        DataDesc->LookasideList;

#if DBG
    {
    ULONG           BufferCount;

    NdisQueryPacket(NdisPacket,
                    NULL,
                    &BufferCount,
                    NULL,
                    NULL);

    ASSERT(BufferCount == 1);
    }
#endif

    NdisAdjustBufferLength(NdisBuffer, 
                           DataDesc->DataBufferLength);

    NdisRecalculatePacketCounts(NdisPacket);

    NDIS_SET_PACKET_HEADER_SIZE(NdisPacket, 
                                MAC_HEADER_LENGTH);

    NDIS_SET_PACKET_STATUS(NdisPacket, 
                           NDIS_STATUS_SUCCESS);

    ASSERT(PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber == MAGIC_INTERNAL_RECV);

    NdisFreeToNPagedLookasideList(LookasideList, DataDesc);
}

PSEND_DESC
NdisWanAllocateSendDesc(
    PLINKCB LinkCB,
    ULONG   SizeNeeded
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    POPENCB     OpenCB;
    PSEND_DESC  SendDesc;

    //
    // Need to determine if this link represents a legacy
    // wan miniport or a NDIS 5.0 miniport and get the
    // appropriate buffer descriptor.
    //
    OpenCB = LinkCB->OpenCB;

    if (OpenCB->Flags & OPEN_LEGACY) {
        PDATA_DESC          DataDesc;
        PNDIS_WAN_PACKET    WanPacket;

        //
        // Get a buffer desriptor off of the open block
        //
        if (OpenCB->WanInfo.MemoryFlags == 0) {
            PNPAGED_LOOKASIDE_LIST  LookasideList;

            LookasideList = &OpenCB->WanPacketPool;
    
            DataDesc = 
                NdisAllocateFromNPagedLookasideList(LookasideList);

            if (DataDesc == NULL) {
                return(NULL);
            }

            DataDesc->LookasideList = LookasideList;

            WanPacket = (PNDIS_WAN_PACKET)
                ((PUCHAR)(DataDesc + 1) + sizeof(PVOID));

            (ULONG_PTR)WanPacket &=
                ~((ULONG_PTR)sizeof(PVOID) - 1);

            //
            // Point to the begining of the data.
            //
            WanPacket->StartBuffer = 
                ((PUCHAR)(WanPacket + 1) + sizeof(PVOID));

            (ULONG_PTR)WanPacket->StartBuffer &=
                ~((ULONG_PTR)sizeof(PVOID) - 1);

            WanPacket->EndBuffer = WanPacket->StartBuffer +
                                   OpenCB->BufferSize - sizeof(PVOID);
    
        } else {
            DataDesc = (PDATA_DESC)
                NdisInterlockedPopEntrySList(&OpenCB->WanPacketList,
                                             &OpenCB->Lock);
    
            if (DataDesc == NULL) {
                return (NULL);
            }
        }

        SendDesc = &DataDesc->SendDesc;
        NdisZeroMemory(SendDesc, sizeof(SEND_DESC));

        SendDesc->Signature = SENDESC_SIG;
        SendDesc->LinkCB = LinkCB;
        SendDesc->WanPacket = WanPacket;

        WanPacket->CurrentBuffer =
            WanPacket->StartBuffer + OpenCB->WanInfo.HeaderPadding;

        SendDesc->StartBuffer =
            WanPacket->CurrentBuffer;


    } else {
        PDATA_DESC  DataDesc;
        ULONG       Length;
        PNPAGED_LOOKASIDE_LIST  LookasideList;

        if (SizeNeeded > glLargeDataBufferSize) {
            DbgPrint("NDISWAN: Error Allocating SendDesc Size %d\n",
                     SizeNeeded);
            return (NULL);
        } else if (SizeNeeded > glSmallDataBufferSize) {
            LookasideList = &LargeDataDescList;
        } else {
            LookasideList = &SmallDataDescList;
        }

        DataDesc =
            NdisAllocateFromNPagedLookasideList(LookasideList);

        if (DataDesc == NULL) {
            return (NULL);
        }

        DataDesc->LookasideList = LookasideList;

        PPROTOCOL_RESERVED_FROM_NDIS(DataDesc->NdisPacket)->MagicNumber =
            MAGIC_INTERNAL_SEND;

        SendDesc = &DataDesc->SendDesc;
        NdisZeroMemory(SendDesc, sizeof(SEND_DESC));

        SendDesc->Signature = SENDESC_SIG;
        SendDesc->LinkCB = LinkCB;
        SendDesc->NdisPacket =
            DataDesc->NdisPacket;
        SendDesc->NdisBuffer =
            DataDesc->NdisBuffer;

        NdisQueryBuffer(SendDesc->NdisBuffer,
                        &SendDesc->StartBuffer,
                        &Length);
    }

    LinkCB->SendResources -= 1;
    LinkCB->BundleCB->SendResources -= 1;

    return (SendDesc);
}

VOID
NdisWanFreeSendDesc(
    PSEND_DESC  SendDesc
    )
/*++

Routine Name:

Routine Description:

Arguments:

Return Values:

--*/
{
    POPENCB     OpenCB;
    PDATA_DESC  DataDesc;
    PLINKCB     LinkCB;
    PNPAGED_LOOKASIDE_LIST  LookasideList;

    LinkCB =
        SendDesc->LinkCB;

    OpenCB = LinkCB->OpenCB;

    DataDesc = 
        CONTAINING_RECORD(SendDesc, DATA_DESC, SendDesc);

    LookasideList = DataDesc->LookasideList;

    if (OpenCB->Flags & OPEN_LEGACY) {

        if (OpenCB->WanInfo.MemoryFlags == 0) {

            NdisFreeToNPagedLookasideList(LookasideList, DataDesc);

        } else {

            NdisInterlockedPushEntrySList(&OpenCB->WanPacketList,
                                          (PSINGLE_LIST_ENTRY)DataDesc,
                                          &OpenCB->Lock);
        }

    } else {
        PNDIS_BUFFER    NdisBuffer;
        PNDIS_PACKET    NdisPacket;

        NdisBuffer = 
            DataDesc->NdisBuffer;

        NdisPacket =
            DataDesc->NdisPacket;

#if DBG
        {
        ULONG           BufferCount;

        NdisQueryPacket(NdisPacket,
                        NULL,
                        &BufferCount,
                        NULL,
                        NULL);

        ASSERT(BufferCount == 1);
        }
#endif

        NdisAdjustBufferLength(NdisBuffer,
                               DataDesc->DataBufferLength);

        NdisRecalculatePacketCounts(NdisPacket);

        NDIS_SET_PACKET_HEADER_SIZE(NdisPacket, 
                                    MAC_HEADER_LENGTH);

        NDIS_SET_PACKET_STATUS(NdisPacket, 
                               NDIS_STATUS_SUCCESS);

        ASSERT(PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber == MAGIC_INTERNAL_SEND);

        NdisFreeToNPagedLookasideList(LookasideList, DataDesc);
    }

    LinkCB->SendResources += 1;
    LinkCB->BundleCB->SendResources += 1;
}

PCL_AFSAPCB
NdisWanAllocateClAfSapCB(
    POPENCB             OpenCB,
    PCO_ADDRESS_FAMILY  AddressFamily
    )
{
    PCL_AFSAPCB AfSapCB;

    AfSapCB =
        NdisAllocateFromNPagedLookasideList(&AfSapVcCBList);

    if (AfSapCB == NULL) {
        return (NULL);
    }

    NdisZeroMemory(AfSapCB, sizeof(CL_AFSAPCB));

    AfSapCB->Signature = CLAFSAP_SIG;
    AfSapCB->OpenCB = OpenCB;

    AfSapCB->Af.AddressFamily = AddressFamily->AddressFamily;
    AfSapCB->Af.MajorVersion = AddressFamily->MajorVersion;
    AfSapCB->Af.MinorVersion = AddressFamily->MinorVersion;

    AfSapCB->RefCount = 1;
    AfSapCB->Flags = AF_OPENING;

    return (AfSapCB);
}

VOID
NdisWanFreeClAfSapCB(
    PCL_AFSAPCB AfSapCB
    )
{
    NdisFreeToNPagedLookasideList(&AfSapVcCBList,
                                  AfSapCB);
}

PCM_AFSAPCB
NdisWanAllocateCmAfSapCB(
    PMINIPORTCB MiniportCB
    )
{
    PCM_AFSAPCB AfSapCB;

    AfSapCB =
    NdisAllocateFromNPagedLookasideList(&AfSapVcCBList);

    if (AfSapCB == NULL) {
        return (NULL);
    }

    NdisZeroMemory(AfSapCB, sizeof(CM_AFSAPCB));

    AfSapCB->Signature = CMAFSAP_SIG;
    AfSapCB->MiniportCB = MiniportCB;

    REF_MINIPORTCB(MiniportCB);

    NdisAcquireSpinLock(&MiniportCB->Lock);

    InsertHeadList(&MiniportCB->AfSapCBList,
                   &AfSapCB->Linkage);

    NdisWanInitializeNotificationEvent(&AfSapCB->NotificationEvent);

    NdisWanInterlockedInc(&MiniportCB->AfRefCount);

    NdisReleaseSpinLock(&MiniportCB->Lock);

    return (AfSapCB);
}

VOID
NdisWanFreeCmAfSapCB(
    PCM_AFSAPCB AfSapCB
    )
{
    PMINIPORTCB MiniportCB  = AfSapCB->MiniportCB;

    NdisAcquireSpinLock(&MiniportCB->Lock);

    NdisWanInterlockedDec(&MiniportCB->AfRefCount);

    RemoveEntryList(&AfSapCB->Linkage);

    NdisReleaseSpinLock(&MiniportCB->Lock);

    DEREF_MINIPORTCB(MiniportCB);

    NdisFreeToNPagedLookasideList(&AfSapVcCBList,
                                  AfSapCB);
}

PCM_VCCB
NdisWanAllocateCmVcCB(
    PCM_AFSAPCB AfSapCB,
    NDIS_HANDLE NdisVcHandle
    )
{
    PCM_VCCB    CmVcCB;

    CmVcCB =
        NdisAllocateFromNPagedLookasideList(&AfSapVcCBList);

    if (CmVcCB == NULL) {
        return (NULL);
    }

    NdisZeroMemory(CmVcCB, sizeof(CM_VCCB));

    CmVcCB->AfSapCB = AfSapCB;
    CmVcCB->Signature = CMVC_SIG;
    CmVcCB->NdisVcHandle = NdisVcHandle;

    return (CmVcCB);
}

VOID
NdisWanFreeCmVcCB(
    PCM_VCCB    CmVcCB
    )
{
    NdisFreeToNPagedLookasideList(&AfSapVcCBList, CmVcCB);
}

NDIS_STATUS
AllocateIoNdisPacket(
    ULONG           SizeNeeded,
    PNDIS_PACKET    *NdisPacket,
    PNDIS_BUFFER    *NdisBuffer, 
    PUCHAR          *DataBuffer
    )
/*++

Routine Name:
    
    AllocateIoNdisPacket
    
Routine Description:

    This routine will alocate a packet used to send a PPP control
    packet over a wan endpoint.  The routine is written with the
    assumption that there will only ever be a single NDIS_BUFFER
    attached to the packet.  This buffer is attached immediately
    to the front of the packet.  Before calling a miniport the
    NDIS_BUFFER must have it's length adjusted and the packet must
    recalculate all counts.

Arguments:

Return Values:

--*/
{
    PDATA_DESC  DataDesc;
    ULONG       Length;
    PNPAGED_LOOKASIDE_LIST  LookasideList;

    if (SizeNeeded > glLargeDataBufferSize) {

        DbgPrint("NDISWAN: Error Allocating IoNdisPacket Size %d\n",
                 SizeNeeded);
        return (NDIS_STATUS_FAILURE);
    } else if (SizeNeeded > glSmallDataBufferSize) {
        LookasideList = &LargeDataDescList;
    } else {
        LookasideList = &SmallDataDescList;
    }

    DataDesc =
        NdisAllocateFromNPagedLookasideList(LookasideList);

    if (DataDesc == NULL) {
        return (NDIS_STATUS_RESOURCES);
    }

    DataDesc->LookasideList = LookasideList;

    *NdisPacket =
        DataDesc->NdisPacket;

    PPROTOCOL_RESERVED_FROM_NDIS(DataDesc->NdisPacket)->MagicNumber =
        MAGIC_INTERNAL_IO;

    PPROTOCOL_RESERVED_FROM_NDIS(DataDesc->NdisPacket)->DataDesc =
        DataDesc;

    *NdisBuffer =
        DataDesc->NdisBuffer;

    NdisQueryBuffer(DataDesc->NdisBuffer,
                    &DataDesc->DataBuffer,
                    &Length);
    *DataBuffer =
        DataDesc->DataBuffer;

    return (NDIS_STATUS_SUCCESS);
}

VOID
FreeIoNdisPacket(
    PNDIS_PACKET    NdisPacket
)
/*++

Routine Name:

    FreeIoNdisPacket
    
Routine Description:

    This routine will free a packet used to send a PPP control
    packet over a wan endpoint.  The routine is written with the
    assumption that there will only ever be a single NDIS_BUFFER
    attached to the packet.  This buffer does not have to be
    explicitly removed from the packet here as a pointer to it
    is stored in the DATA_DESC itself and will be freed when
    the DATA_DESC is freed.

Arguments:

Return Values:

--*/
{
    PDATA_DESC      DataDesc;
    PNDIS_BUFFER    NdisBuffer;
    PNPAGED_LOOKASIDE_LIST  LookasideList;

    DataDesc = 
        PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->DataDesc;

    ASSERT(PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->MagicNumber == MAGIC_INTERNAL_IO);

    LookasideList = 
        DataDesc->LookasideList;

    NdisAdjustBufferLength(DataDesc->NdisBuffer,
                           DataDesc->DataBufferLength);

    NdisRecalculatePacketCounts(NdisPacket);

    NDIS_SET_PACKET_HEADER_SIZE(NdisPacket, 
                                MAC_HEADER_LENGTH);

    NDIS_SET_PACKET_STATUS(NdisPacket, 
                           NDIS_STATUS_SUCCESS);

    NdisFreeToNPagedLookasideList(LookasideList, DataDesc);
}

PVOID
AllocateWanPacket(
    IN  POOL_TYPE   PoolType,
    IN  SIZE_T      NumberOfBytes,
    IN  ULONG       Tag
    )
{
    PVOID   pMem;

    NdisWanAllocatePriorityMemory(&pMem,
                                  NumberOfBytes,
                                  Tag,
                                  NormalPoolPriority);

    return(pMem);
}

VOID
FreeWanPacket(
    PVOID   WanPacket
    )
{
    NdisWanFreeMemory(WanPacket);
}