File:  [WindowsNT SDKs] / ntddk / src / network / tdi / packet.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1989-1993  Microsoft Corporation

Module Name:

    packet.c

Abstract:

    This module contains code that implements the TP_PACKET object, which
    describes an NDIS packet.

Environment:

    Kernel mode

Revision History:

--*/

#include "st.h"

//
// This is temporary; this is the quota that we charge for a receive
// packet for now, until we fix the problem with token-ring needing
// big packets and using all the memory. The number is the actual
// value for Ethernet.
//

#if 1
#define RECEIVE_BUFFER_QUOTA(_DeviceContext)   1533
#else
#define RECEIVE_BUFFER_QUOTA(_DeviceContext)   (_DeviceContext)->ReceiveBufferLength
#endif




VOID
StAllocateSendPacket(
    IN PDEVICE_CONTEXT DeviceContext,
    OUT PTP_PACKET *TransportSendPacket
    )

/*++

Routine Description:

    This routine allocates storage for a send packet. Some initialization
    is done here.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportSendPacket - Returns a pointer to the packet, or NULL if no
        storage can be allocated.

Return Value:

    None.

--*/

{

    PTP_PACKET Packet;
    NDIS_STATUS NdisStatus;
    PNDIS_PACKET NdisPacket;
    PSEND_PACKET_TAG SendTag;
    PNDIS_BUFFER NdisBuffer;

    if ((DeviceContext->MemoryLimit != 0) &&
            ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
                DeviceContext->MemoryLimit)) {
        PANIC("ST: Could not allocate send packet: limit\n");
        StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 107);
        *TransportSendPacket = NULL;
        return;
    }

    Packet = (PTP_PACKET)ExAllocatePool (NonPagedPool, DeviceContext->PacketLength);
    if (Packet == NULL) {
        PANIC("ST: Could not allocate send packet: no pool\n");
        StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 207);
        *TransportSendPacket = NULL;
        return;
    }
    RtlZeroMemory (Packet, DeviceContext->PacketLength);

    DeviceContext->MemoryUsage += DeviceContext->PacketLength;

    NdisAllocatePacket (
        &NdisStatus,
        &NdisPacket,
        DeviceContext->SendPacketPoolHandle);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        ExFreePool (Packet);
        StWriteResourceErrorLog (DeviceContext, 0, 307);
        *TransportSendPacket = NULL;
        return;
    }

    NdisAllocateBuffer(
        &NdisStatus,
        &NdisBuffer,
        DeviceContext->NdisBufferPoolHandle,
        Packet->Header,
        DeviceContext->PacketHeaderLength);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        NdisFreePacket (NdisPacket);
        ExFreePool (Packet);
        *TransportSendPacket = NULL;
        return;
    }

    NdisChainBufferAtFront (NdisPacket, NdisBuffer);

    Packet->NdisPacket = NdisPacket;
    SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
    SendTag->Type = TYPE_I_FRAME;
    SendTag->Packet = Packet;
    SendTag->Owner = NULL;

    Packet->Type = ST_PACKET_SIGNATURE;
    Packet->Size = sizeof (TP_PACKET);
    Packet->Provider = DeviceContext;

    ++DeviceContext->PacketAllocated;

    *TransportSendPacket = Packet;

}   /* StAllocateSendPacket */


VOID
StDeallocateSendPacket(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PTP_PACKET TransportSendPacket
    )

/*++

Routine Description:

    This routine frees storage for a send packet.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportSendPacket - A pointer to the send packet.

Return Value:

    None.

--*/

{
    PNDIS_PACKET NdisPacket = TransportSendPacket->NdisPacket;
    PNDIS_BUFFER NdisBuffer;

    NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
    if (NdisBuffer != NULL) {
        NdisFreeBuffer (NdisBuffer);
    }

    NdisFreePacket (NdisPacket);
    ExFreePool (TransportSendPacket);

    --DeviceContext->PacketAllocated;
    DeviceContext->MemoryUsage -= DeviceContext->PacketLength;

}   /* StDeallocateSendPacket */


VOID
StAllocateReceivePacket(
    IN PDEVICE_CONTEXT DeviceContext,
    OUT PNDIS_PACKET *TransportReceivePacket
    )

/*++

Routine Description:

    This routine allocates storage for a receive packet. Some initialization
    is done here.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportReceivePacket - Returns a pointer to the packet, or NULL if no
        storage can be allocated.

Return Value:

    None.

--*/

{
    NDIS_STATUS NdisStatus;
    PNDIS_PACKET NdisPacket;
    PRECEIVE_PACKET_TAG ReceiveTag;

    //
    // This does not count in DeviceContext->MemoryUsage because
    // the storage is allocated when we allocate the packet pool.
    //

    NdisAllocatePacket (
        &NdisStatus,
        &NdisPacket,
        DeviceContext->ReceivePacketPoolHandle);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        StWriteResourceErrorLog (DeviceContext, 0, 309);
        *TransportReceivePacket = NULL;
        return;
    }

    ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
    ReceiveTag->PacketType = TYPE_AT_INDICATE;

    ++DeviceContext->ReceivePacketAllocated;

    *TransportReceivePacket = NdisPacket;

}   /* StAllocateReceivePacket */


VOID
StDeallocateReceivePacket(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PNDIS_PACKET TransportReceivePacket
    )

/*++

Routine Description:

    This routine frees storage for a receive packet.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportReceivePacket - A pointer to the packet.

Return Value:

    None.

--*/

{

    NdisFreePacket (TransportReceivePacket);

    --DeviceContext->ReceivePacketAllocated;

}   /* StDeallocateReceivePacket */


VOID
StAllocateReceiveBuffer(
    IN PDEVICE_CONTEXT DeviceContext,
    OUT PBUFFER_TAG *TransportReceiveBuffer
    )

/*++

Routine Description:

    This routine allocates storage for a receive buffer. Some initialization
    is done here.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportReceiveBuffer - Returns a pointer to the buffer, or NULL if no
        storage can be allocated.

Return Value:

    None.

--*/

{
    PBUFFER_TAG BufferTag;
    NDIS_STATUS NdisStatus;
    PNDIS_BUFFER NdisBuffer;


    if ((DeviceContext->MemoryLimit != 0) &&
            ((DeviceContext->MemoryUsage + RECEIVE_BUFFER_QUOTA(DeviceContext)) >
                DeviceContext->MemoryLimit)) {
        PANIC("ST: Could not allocate receive buffer: limit\n");
        StWriteResourceErrorLog (DeviceContext, RECEIVE_BUFFER_QUOTA(DeviceContext), 108);
        *TransportReceiveBuffer = NULL;
        return;
    }

    BufferTag = (PBUFFER_TAG)ExAllocatePool (
                    NonPagedPoolCacheAligned,
                    DeviceContext->ReceiveBufferLength);

    if (BufferTag == NULL) {
        PANIC("ST: Could not allocate receive buffer: no pool\n");
        StWriteResourceErrorLog (DeviceContext, DeviceContext->ReceiveBufferLength, 208);
        *TransportReceiveBuffer = NULL;
        return;
    }

    DeviceContext->MemoryUsage += RECEIVE_BUFFER_QUOTA(DeviceContext);

    //
    // point to the buffer for NDIS
    //

    NdisAllocateBuffer(
        &NdisStatus,
        &NdisBuffer,
        DeviceContext->NdisBufferPoolHandle,
        BufferTag->Buffer,
        DeviceContext->MaxReceivePacketSize);

    if (NdisStatus != NDIS_STATUS_SUCCESS) {
        ExFreePool (BufferTag);
        *TransportReceiveBuffer = NULL;
        return;
    }

    BufferTag->Length = DeviceContext->MaxReceivePacketSize;
    BufferTag->NdisBuffer = NdisBuffer;

    ++DeviceContext->ReceiveBufferAllocated;

    *TransportReceiveBuffer = BufferTag;

}   /* StAllocateReceiveBuffer */


VOID
StDeallocateReceiveBuffer(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PBUFFER_TAG TransportReceiveBuffer
    )

/*++

Routine Description:

    This routine frees storage for a receive buffer.

    NOTE: This routine is called with the device context spinlock
    held, or at such a time as synchronization is unnecessary.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    TransportReceiveBuffer - A pointer to the buffer.

Return Value:

    None.

--*/

{

    NdisFreeBuffer (TransportReceiveBuffer->NdisBuffer);
    ExFreePool (TransportReceiveBuffer);

    --DeviceContext->ReceiveBufferAllocated;
    DeviceContext->MemoryUsage -= RECEIVE_BUFFER_QUOTA(DeviceContext);

}   /* StDeallocateReceiveBuffer */


NTSTATUS
StCreatePacket(
    PDEVICE_CONTEXT DeviceContext,
    PTP_PACKET *Packet
    )

/*++

Routine Description:

    This routine allocates a packet from the device context's pool,
    and prepares the MAC and DLC headers for use by the connection.

Arguments:

    DeviceContext - Pointer to our device context to charge the packet to.

    Packet - Pointer to a place where we will return a pointer to the
        allocated packet.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    KIRQL oldirql;
    PSINGLE_LIST_ENTRY s;
    PTP_PACKET ThePacket;

    s = ExInterlockedPopEntryList (
            &DeviceContext->PacketPool,
            &DeviceContext->Interlock);

    if (s == NULL) {
        ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
        ++DeviceContext->PacketExhausted;
        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);

    ThePacket->Provider = DeviceContext;   // who owns this packet
    ThePacket->PacketSent = FALSE;
    ThePacket->PacketNoNdisBuffer = FALSE;

    *Packet = ThePacket;                // return pointer to the packet.
    return STATUS_SUCCESS;
} /* StCreatePacket */


VOID
StDestroyPacket(
    PTP_PACKET Packet
    )

/*++

Routine Description:

    This routine destroys a packet, thereby returning it to the pool.  If
    it is determined that there is at least one connection waiting for a
    packet to become available (and it just has), then the connection is
    removed from the device context's list and AdvanceSend is called to
    prep the connection further.

Arguments:

    Packet - Pointer to a packet to be returned to the pool.

Return Value:

    none.

--*/

{
    KIRQL oldirql1;
    PDEVICE_CONTEXT DeviceContext;
    PTP_CONNECTION Connection;
    PLIST_ENTRY p;
    PNDIS_BUFFER HeaderBuffer;
    PNDIS_BUFFER NdisBuffer;


    //
    // Strip off and unmap the buffers describing data and header.
    //

    NdisUnchainBufferAtFront (Packet->NdisPacket, &HeaderBuffer);

    // data buffers get thrown away

    if (Packet->PacketNoNdisBuffer) {

        //
        // If the NDIS_BUFFER chain is not ours, then we can't
        // start unchaining since that would mess up the queue;
        // instead we just drop the rest of the chain.
        //

        NdisReinitializePacket (Packet->NdisPacket);

    } else {

        //
        // Return all the NDIS_BUFFERs to the system.
        //

        NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
        while (NdisBuffer != NULL) {
            NdisFreeBuffer (NdisBuffer);
            NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
        }

    }

    ASSERT (HeaderBuffer != NULL);
    NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;

    NdisChainBufferAtFront (Packet->NdisPacket, HeaderBuffer);


    //
    // Put the packet back for use again.
    //

    DeviceContext = Packet->Provider;

    ExInterlockedPushEntryList (
            &DeviceContext->PacketPool,
            (PSINGLE_LIST_ENTRY)&Packet->Linkage,
            &DeviceContext->Interlock);

    //
    // If there is a connection waiting to ship out more packets, then
    // wake it up and start packetizing again.
    //
    // We do a quick check without the lock; there is a small
    // window where we may not take someone off, but this
    // window exists anyway and we assume that more packets
    // will be freed in the future.
    //

    if (IsListEmpty (&DeviceContext->PacketWaitQueue)) {
        return;
    }

    p = ExInterlockedRemoveHeadList(
        &DeviceContext->PacketWaitQueue,
        &DeviceContext->SpinLock);

    if (p != NULL) {

        //
        // Remove a connection from the "packet starved" queue.
        //

        Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketWaitLinkage);
        ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
        Connection->Flags &= ~CONNECTION_FLAGS_SUSPENDED;

        //
        // Place the connection on the packetize queue and start
        // packetizing the next connection to be serviced.  If he
        // is already on the packetize queue for some reason, then
        // don't do this.
        //

        Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;

        if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING) &&
            !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {

            Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;

            StReferenceConnection ("Packet available", Connection);

            ExInterlockedInsertTailList(
                &DeviceContext->PacketizeQueue,
                &Connection->PacketizeLinkage,
                &DeviceContext->SpinLock);
        }

        RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
        PacketizeConnections (DeviceContext);

    }

} /* StDestroyPacket */


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.