diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/st/packet.c | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/packet.c b/private/ntos/tdi/st/packet.c new file mode 100644 index 000000000..29e9fe1b8 --- /dev/null +++ b/private/ntos/tdi/st/packet.c @@ -0,0 +1,597 @@ +/*++ + +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 */ + |