summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/packet.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/st/packet.c597
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 */
+