/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: packet.c Abstract: This module contains code that implements the SEND_PACKET and RECEIVE_PACKET objects, which describe NDIS packets used by the transport. Environment: Kernel mode Revision History: --*/ #include "precomp.h" #pragma hdrstop // // Local Function Protos // #if defined(_PNP_POWER) #if !defined(DBG) __inline #endif VOID NbiFreeReceiveBufferPool ( IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool ); #endif _PNP_POWER NTSTATUS NbiInitializeSendPacket( IN PDEVICE Device, IN NDIS_HANDLE PoolHandle OPTIONAL, IN PNB_SEND_PACKET Packet, IN PUCHAR Header, IN ULONG HeaderLength ) /*++ Routine Description: This routine initializes a send packet by chaining the buffer for the header on it. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD, AND RETURNS WITH IT HELD. Arguments: Device - The device. PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS Packet - The packet to initialize. Header - Points to storage for the header. HeaderLength - The length of the header. Return Value: None. --*/ { NDIS_STATUS NdisStatus; NTSTATUS Status; PNDIS_BUFFER NdisBuffer; PNDIS_BUFFER NdisNbBuffer; PNB_SEND_RESERVED Reserved; ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded; NbiAllocateSendPacket (Device, PoolHandle, Packet, &Status); if (Status != STATUS_SUCCESS) { // ERROR LOG return Status; } // DbgPrint("NbiInitializeSendPacket: PACKET is (%x)\n", PACKET(Packet)); // // allocate the mac header. // NdisAllocateBuffer( &NdisStatus, &NdisBuffer, Device->NdisBufferPoolHandle, Header, MacHeaderNeeded); if (NdisStatus != NDIS_STATUS_SUCCESS) { NbiFreeSendPacket (Device, Packet); // ERROR LOG return STATUS_INSUFFICIENT_RESOURCES; } NdisChainBufferAtFront (PACKET(Packet), NdisBuffer); // DbgPrint("NbiInitializeSendPacket: MAC header address is (%x)\n", NdisBuffer); // // Allocate the nb header // NdisAllocateBuffer( &NdisStatus, &NdisNbBuffer, Device->NdisBufferPoolHandle, Header + MacHeaderNeeded, HeaderLength - MacHeaderNeeded); if (NdisStatus != NDIS_STATUS_SUCCESS) { NdisBuffer = NULL; NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer); CTEAssert (NdisBuffer); if (NdisBuffer) { NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded); NdisFreeBuffer (NdisBuffer); } NbiFreeSendPacket (Device, Packet); // ERROR LOG return STATUS_INSUFFICIENT_RESOURCES; } // DbgPrint("NbiInitializeSendPacket: IPX header address is (%x)\n", NdisNbBuffer); NdisChainBufferAtBack (PACKET(Packet), NdisNbBuffer); Reserved = SEND_RESERVED(Packet); Reserved->Identifier = IDENTIFIER_NB; Reserved->SendInProgress = FALSE; Reserved->OwnedByConnection = FALSE; Reserved->Header = Header; Reserved->HeaderBuffer = NdisBuffer; Reserved->Reserved[0] = NULL; Reserved->Reserved[1] = NULL; InsertHeadList( &Device->GlobalSendPacketList, &Reserved->GlobalLinkage); return STATUS_SUCCESS; } /* NbiInitializeSendPacket */ NTSTATUS NbiInitializeReceivePacket( IN PDEVICE Device, IN NDIS_HANDLE PoolHandle OPTIONAL, IN PNB_RECEIVE_PACKET Packet ) /*++ Routine Description: This routine initializes a receive packet. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD, AND RETURNS WITH IT HELD. Arguments: Device - The device. PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS Packet - The packet to initialize. Return Value: None. --*/ { NTSTATUS Status; PNB_RECEIVE_RESERVED Reserved; NbiAllocateReceivePacket (Device, PoolHandle, Packet, &Status); if (Status != STATUS_SUCCESS) { // ERROR LOG return Status; } Reserved = RECEIVE_RESERVED(Packet); Reserved->Identifier = IDENTIFIER_NB; Reserved->TransferInProgress = FALSE; InsertHeadList( &Device->GlobalReceivePacketList, &Reserved->GlobalLinkage); return STATUS_SUCCESS; } /* NbiInitializeReceivePacket */ NTSTATUS NbiInitializeReceiveBuffer( IN PDEVICE Device, IN PNB_RECEIVE_BUFFER ReceiveBuffer, IN PUCHAR DataBuffer, IN ULONG DataBufferLength ) /*++ Routine Description: This routine initializes a receive buffer by allocating an NDIS_BUFFER to describe the data buffer. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD, AND RETURNS WITH IT HELD. Arguments: Device - The device. ReceiveBuffer - The receive buffer to initialize. DataBuffer - The data buffer. DataBufferLength - The length of the data buffer. Return Value: None. --*/ { NDIS_STATUS NdisStatus; PNDIS_BUFFER NdisBuffer; NdisAllocateBuffer( &NdisStatus, &NdisBuffer, Device->NdisBufferPoolHandle, DataBuffer, DataBufferLength); if (NdisStatus != NDIS_STATUS_SUCCESS) { // ERROR LOG return STATUS_INSUFFICIENT_RESOURCES; } ReceiveBuffer->NdisBuffer = NdisBuffer; ReceiveBuffer->Data = DataBuffer; ReceiveBuffer->DataLength = 0; InsertHeadList( &Device->GlobalReceiveBufferList, &ReceiveBuffer->GlobalLinkage); return STATUS_SUCCESS; } /* NbiInitializeReceiveBuffer */ VOID NbiDeinitializeSendPacket( IN PDEVICE Device, IN PNB_SEND_PACKET Packet, IN ULONG HeaderLength ) /*++ Routine Description: This routine deinitializes a send packet. Arguments: Device - The device. Packet - The packet to deinitialize. HeaderLength - The length of the first buffer on the packet. Return Value: None. --*/ { PNDIS_BUFFER NdisBuffer = NULL; PNB_SEND_RESERVED Reserved; CTELockHandle LockHandle; ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded; CTEAssert(HeaderLength > MacHeaderNeeded); Reserved = SEND_RESERVED(Packet); NB_GET_LOCK (&Device->Lock, &LockHandle); RemoveEntryList (&Reserved->GlobalLinkage); NB_FREE_LOCK (&Device->Lock, LockHandle); // // Free the mac header // // DbgPrint("NbiDeinitializeSendPacket: PACKET is (%x)\n", PACKET(Packet)); NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer); CTEAssert (NdisBuffer); // DbgPrint("NbiDeinitializeSendPacket: MAC header address is (%x)\n", NdisBuffer); if (NdisBuffer) { NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded); NdisFreeBuffer (NdisBuffer); } // // Free the nb header // NdisBuffer = NULL; NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer); // DbgPrint("NbiDeinitializeSendPacket: IPX header address is (%x)\n", NdisBuffer); CTEAssert (NdisBuffer); if (NdisBuffer) { NdisAdjustBufferLength (NdisBuffer, HeaderLength - MacHeaderNeeded); NdisFreeBuffer (NdisBuffer); } // // free the packet // NbiFreeSendPacket (Device, Packet); } /* NbiDeinitializeSendPacket */ VOID NbiDeinitializeReceivePacket( IN PDEVICE Device, IN PNB_RECEIVE_PACKET Packet ) /*++ Routine Description: This routine initializes a receive packet. Arguments: Device - The device. Packet - The packet to initialize. Return Value: None. --*/ { PNB_RECEIVE_RESERVED Reserved; CTELockHandle LockHandle; Reserved = RECEIVE_RESERVED(Packet); NB_GET_LOCK (&Device->Lock, &LockHandle); RemoveEntryList (&Reserved->GlobalLinkage); NB_FREE_LOCK (&Device->Lock, LockHandle); NbiFreeReceivePacket (Device, Packet); } /* NbiDeinitializeReceivePacket */ VOID NbiDeinitializeReceiveBuffer( IN PDEVICE Device, IN PNB_RECEIVE_BUFFER ReceiveBuffer ) /*++ Routine Description: This routine deinitializes a receive buffer. Arguments: Device - The device. ReceiveBuffer - The receive buffer. Return Value: None. THIS ROUTINE SHOULD BE CALLED WITH THE DEVICE LOCK HELD. If this routine also called from the DestroyDevice routine, it is not necessary to call this with the lock. --*/ { #if defined(_PNP_POWER) RemoveEntryList (&ReceiveBuffer->GlobalLinkage); #else CTELockHandle LockHandle; NB_GET_LOCK (&Device->Lock, &LockHandle); RemoveEntryList (&ReceiveBuffer->GlobalLinkage); NB_FREE_LOCK (&Device->Lock, LockHandle); #endif _PNP_POWER NdisFreeBuffer (ReceiveBuffer->NdisBuffer); } /* NbiDeinitializeReceiveBuffer */ VOID NbiAllocateSendPool( IN PDEVICE Device ) /*++ Routine Description: This routine adds 10 packets to the pool for this device. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS WITH IT HELD. Arguments: Device - The device. Return Value: None. --*/ { PNB_SEND_POOL SendPool; UINT SendPoolSize; UINT PacketNum; PNB_SEND_PACKET Packet; PNB_SEND_RESERVED Reserved; PUCHAR Header; ULONG HeaderLength; NTSTATUS Status; HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS); SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) + (sizeof(NB_SEND_PACKET) * Device->InitPackets) + (HeaderLength * Device->InitPackets); SendPool = (PNB_SEND_POOL)NbiAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool"); if (SendPool == NULL) { NB_DEBUG (PACKET, ("Could not allocate send pool memory\n")); return; } RtlZeroMemory (SendPool, SendPoolSize); #if !defined(NB_OWN_PACKETS) // // Now allocate the ndis packet pool // SendPool->PoolHandle = (NDIS_HANDLE) NDIS_PACKET_POOL_TAG_FOR_NWLNKNB; // Dbg info for Ndis! NdisAllocatePacketPoolEx (&Status, &SendPool->PoolHandle, Device->InitPackets, 0, sizeof(NB_SEND_RESERVED)); if (!NT_SUCCESS(Status)){ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n")); NbiFreeMemory( SendPool, SendPoolSize, MEMORY_PACKET, "Send Pool Freed"); return; } NdisSetPacketPoolProtocolId (SendPool->PoolHandle, NDIS_PROTOCOL_ID_IPX); #endif NB_DEBUG2 (PACKET, ("Initializing send pool %lx, %d packets, header %d\n", SendPool, Device->InitPackets, HeaderLength)); Header = (PUCHAR)(&SendPool->Packets[Device->InitPackets]); for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) { Packet = &SendPool->Packets[PacketNum]; if (NbiInitializeSendPacket ( Device, #ifdef NB_OWN_PACKETS NULL, #else SendPool->PoolHandle, #endif Packet, Header, HeaderLength) != STATUS_SUCCESS) { NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet)); break; } Reserved = SEND_RESERVED(Packet); Reserved->u.SR_NF.Address = NULL; #ifdef NB_TRACK_POOL Reserved->Pool = SendPool; #endif Header += HeaderLength; } SendPool->PacketCount = PacketNum; SendPool->PacketFree = PacketNum; for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) { Packet = &SendPool->Packets[PacketNum]; Reserved = SEND_RESERVED(Packet); ExInterlockedPushEntrySList( &Device->SendPacketList, &Reserved->PoolLinkage, &NbiGlobalPoolInterlock); } InsertTailList (&Device->SendPoolList, &SendPool->Linkage); Device->AllocatedSendPackets += SendPool->PacketCount; } /* NbiAllocateSendPool */ VOID NbiAllocateReceivePool( IN PDEVICE Device ) /*++ Routine Description: This routine adds 5 receive packets to the pool for this device. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS WITH IT HELD. Arguments: Device - The device. Return Value: None. --*/ { PNB_RECEIVE_POOL ReceivePool; UINT ReceivePoolSize; UINT PacketNum; PNB_RECEIVE_PACKET Packet; PNB_RECEIVE_RESERVED Reserved; NTSTATUS Status; ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) + (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets); ReceivePool = (PNB_RECEIVE_POOL)NbiAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool"); if (ReceivePool == NULL) { NB_DEBUG (PACKET, ("Could not allocate receive pool memory\n")); return; } RtlZeroMemory (ReceivePool, ReceivePoolSize); #if !defined(NB_OWN_PACKETS) // // Now allocate the ndis packet pool // ReceivePool->PoolHandle = (NDIS_HANDLE) NDIS_PACKET_POOL_TAG_FOR_NWLNKNB; // Dbg info for Ndis! NdisAllocatePacketPoolEx (&Status, &ReceivePool->PoolHandle, Device->InitPackets, 0, sizeof(NB_RECEIVE_RESERVED)); if (!NT_SUCCESS(Status)){ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n")); NbiFreeMemory( ReceivePool, ReceivePoolSize, MEMORY_PACKET, "Receive Pool Freed"); return; } NdisSetPacketPoolProtocolId (ReceivePool->PoolHandle, NDIS_PROTOCOL_ID_IPX); #endif NB_OWN_PACKETS NB_DEBUG2 (PACKET, ("Initializing receive pool %lx, %d packets\n", ReceivePool, Device->InitPackets)); for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) { Packet = &ReceivePool->Packets[PacketNum]; if (NbiInitializeReceivePacket ( Device, #ifdef NB_OWN_PACKETS NULL, #else ReceivePool->PoolHandle, #endif Packet) != STATUS_SUCCESS) { NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet)); break; } Reserved = RECEIVE_RESERVED(Packet); #ifdef NB_TRACK_POOL Reserved->Pool = ReceivePool; #endif } ReceivePool->PacketCount = PacketNum; ReceivePool->PacketFree = PacketNum; for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) { Packet = &ReceivePool->Packets[PacketNum]; Reserved = RECEIVE_RESERVED(Packet); ExInterlockedPushEntrySList( &Device->ReceivePacketList, &Reserved->PoolLinkage, &NbiGlobalPoolInterlock); // PushEntryList (&Device->ReceivePacketList, &Reserved->PoolLinkage); } InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage); Device->AllocatedReceivePackets += ReceivePool->PacketCount; } /* NbiAllocateReceivePool */ #if defined(_PNP_POWER) VOID NbiAllocateReceiveBufferPool( IN PDEVICE Device, IN UINT DataLength ) /*++ Routine Description: This routine adds receive buffers to the pool for this device. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS WITH IT HELD. Arguments: Device - The device. DataLength - Max length of the data in each buffer. Return Value: None. --*/ { PNB_RECEIVE_BUFFER ReceiveBuffer; UINT ReceiveBufferPoolSize; UINT BufferNum; PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool; PUCHAR Data; ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) + (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) + (DataLength * Device->InitPackets); ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool"); if (ReceiveBufferPool == NULL) { NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n")); return; } RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize); NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n", ReceiveBufferPool, Device->InitPackets, DataLength)); Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]); for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) { ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum]; if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) { NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer)); break; } ReceiveBuffer->Pool = ReceiveBufferPool; Data += DataLength; } ReceiveBufferPool->BufferCount = BufferNum; ReceiveBufferPool->BufferFree = BufferNum; ReceiveBufferPool->BufferDataSize = DataLength; for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) { ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum]; PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage); } InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage); Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount; Device->CurMaxReceiveBufferSize = DataLength; } /* NbiAllocateReceiveBufferPool */ #else VOID NbiAllocateReceiveBufferPool( IN PDEVICE Device ) /*++ Routine Description: This routine adds receive buffers to the pool for this device. NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS WITH IT HELD. Arguments: Device - The device. Return Value: None. --*/ { PNB_RECEIVE_BUFFER ReceiveBuffer; UINT ReceiveBufferPoolSize; UINT BufferNum; PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool; UINT DataLength; PUCHAR Data; DataLength = Device->Bind.LineInfo.MaximumPacketSize; ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) + (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) + (DataLength * Device->InitPackets); ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool"); if (ReceiveBufferPool == NULL) { NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n")); return; } RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize); NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n", ReceiveBufferPool, Device->InitPackets, DataLength)); Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]); for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) { ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum]; if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) { NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer)); break; } #ifdef NB_TRACK_POOL ReceiveBuffer->Pool = ReceiveBufferPool; #endif Data += DataLength; } ReceiveBufferPool->BufferCount = BufferNum; ReceiveBufferPool->BufferFree = BufferNum; for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) { ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum]; PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage); } InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage); Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount; } /* NbiAllocateReceiveBufferPool */ #endif _PNP_POWER #if defined(_PNP_POWER) VOID NbiReAllocateReceiveBufferPool( IN PWORK_QUEUE_ITEM WorkItem ) /*++ Routine Description: This routines destroys all the existing Buffer Pools and creates new one using the larger packet size given to us by IPX because a new card was inserted with a larger packet size. Arguments: WorkItem - The work item that was allocated for this. Return Value: None. --*/ { PDEVICE Device = NbiDevice; CTELockHandle LockHandle; NB_GET_LOCK ( &Device->Lock, &LockHandle ); if ( Device->Bind.LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) { #if DBG DbgPrint("Reallocating new pools due to new maxpacketsize\n"); #endif NbiDestroyReceiveBufferPools( Device ); NbiAllocateReceiveBufferPool( Device, Device->Bind.LineInfo.MaximumPacketSize ); } NB_FREE_LOCK( &Device->Lock, LockHandle ); NbiFreeMemory( WorkItem, sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buff Work Item freed"); } #if !defined(DBG) __inline #endif VOID NbiFreeReceiveBufferPool ( IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool ) /*++ Routine Description: This routine frees the Arguments: Device - Pointer to our device to charge the packet to. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PDEVICE Device = NbiDevice; PNB_RECEIVE_BUFFER ReceiveBuffer; UINT ReceiveBufferPoolSize,i; CTEAssert( ReceiveBufferPool->BufferDataSize ); ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) + (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) + (ReceiveBufferPool->BufferDataSize * Device->InitPackets); // // Check if we can free this pool // CTEAssert(ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ); for (i = 0; i < ReceiveBufferPool->BufferCount; i++) { ReceiveBuffer = &ReceiveBufferPool->Buffers[i]; NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer); } RemoveEntryList( &ReceiveBufferPool->Linkage ); NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool)); NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool"); } VOID NbiDestroyReceiveBufferPools( IN PDEVICE Device ) /*++ Routine Description: This routines walks the ReceiveBufferPoolList and destroys the pool which does not have any buffer in use. Arguments: Return Value: None. THIS ROUTINE COULD BE CALLED WITH THE DEVICE LOCK HELD. If this routine is also called from the DestroyDevice routine, it is not necessary to call this with the lock. --*/ { PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool; PLIST_ENTRY p; PSINGLE_LIST_ENTRY Unused; // // Clean up this list before we call NbiFreeReceiveBufferPool bcoz that will // simply destroy all the buffer which might be queue here on this list. // At the end of this routine we must start with a fresh ReceiveBufferList. // do { Unused = PopEntryList( &Device->ReceiveBufferList ); } while( Unused ); // // Now destroy each individual ReceiveBufferPool. // for ( p = Device->ReceiveBufferPoolList.Flink; p != &Device->ReceiveBufferPoolList; ) { ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage); p = p->Flink; // // This will destroy and unlink this Pool if none of its buffer is // in use currently. // if ( ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ) { NbiFreeReceiveBufferPool( ReceiveBufferPool ); } else { // // When the device is stopping we must succeed in freeing the pool. CTEAssert( Device->State != DEVICE_STATE_STOPPING ); } } } VOID NbiPushReceiveBuffer ( IN PNB_RECEIVE_BUFFER ReceiveBuffer ) /*++ Routine Description: This routine returns the receive buffer back to the free list. It checks the size of this buffer. If it is smaller than the the CurMaxReceiveBufferSize, then it does not return this back to the free list, instead it destroys it and possibly also destroys the pool associated with it. O/w it simply returns this to the free list. Arguments: ReceiveBuffer - Pointer to the buffer to be returned to the free list. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool; PDEVICE Device = NbiDevice; CTELockHandle LockHandle; #if defined(DBG) ULONG BufLen = 0; #endif NB_GET_LOCK( &Device->Lock, &LockHandle ); #if defined(DBG) NdisQueryBufferSafe (ReceiveBuffer->NdisBuffer, NULL, &BufLen, HighPagePriority); CTEAssert( BufLen == ReceiveBufferPool->BufferDataSize ); #endif // // This is an old buffer which was in use when we changed // the CurMaxReceiveBufferSize due to new adapter. We must not // return this buffer back to free list. Infact, if the pool // associated with this buffer does not have any other buffers // in use, we should free the pool also. CTEAssert( ReceiveBufferPool->BufferFree < ReceiveBufferPool->BufferCount ); ReceiveBufferPool->BufferFree++; if ( ReceiveBufferPool->BufferDataSize < Device->CurMaxReceiveBufferSize ) { #if DBG DbgPrint("ReceiveBuffer %lx, not returned to pool %lx( Free %d)\n", ReceiveBuffer, ReceiveBufferPool, ReceiveBufferPool->BufferFree); #endif if ( ReceiveBufferPool->BufferFree == ReceiveBufferPool->BufferCount ) { NbiFreeReceiveBufferPool( ReceiveBufferPool ); } } else { PushEntryList( &Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage ); } NB_FREE_LOCK( &Device->Lock, LockHandle ); } #endif _PNP_POWER PSINGLE_LIST_ENTRY NbiPopSendPacket( IN PDEVICE Device, IN BOOLEAN LockAcquired ) /*++ Routine Description: This routine allocates a packet from the device context's pool. If there are no packets in the pool, it allocates one up to the configured limit. Arguments: Device - Pointer to our device to charge the packet to. LockAcquired - TRUE if Device->Lock is acquired. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PSINGLE_LIST_ENTRY s; CTELockHandle LockHandle; s = ExInterlockedPopEntrySList( &Device->SendPacketList, &NbiGlobalPoolInterlock); if (s != NULL) { return s; } // // No packets in the pool, see if we can allocate more. // if (!LockAcquired) { NB_GET_LOCK (&Device->Lock, &LockHandle); } if (Device->AllocatedSendPackets < Device->MaxPackets) { // // Allocate a pool and try again. // NbiAllocateSendPool (Device); if (!LockAcquired) { NB_FREE_LOCK (&Device->Lock, LockHandle); } s = ExInterlockedPopEntrySList( &Device->SendPacketList, &NbiGlobalPoolInterlock); return s; } else { if (!LockAcquired) { NB_FREE_LOCK (&Device->Lock, LockHandle); } return NULL; } } /* NbiPopSendPacket */ VOID NbiPushSendPacket( IN PNB_SEND_RESERVED Reserved ) /*++ Routine Description: This routine frees a packet back to the device context's pool. If there are connections waiting for packets, it removes one from the list and inserts it on the packetize queue. Arguments: Device - Pointer to our device to charge the packet to. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PDEVICE Device = NbiDevice; PLIST_ENTRY p; PCONNECTION Connection; NB_DEFINE_LOCK_HANDLE (LockHandle) NB_DEFINE_LOCK_HANDLE (LockHandle1) Reserved->CurrentSendIteration = 0; // Re-initialize this field for next Send Request ExInterlockedPushEntrySList( &Device->SendPacketList, &Reserved->PoolLinkage, &NbiGlobalPoolInterlock); if (!IsListEmpty (&Device->WaitPacketConnections)) { NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle); p = RemoveHeadList (&Device->WaitPacketConnections); // // Take a connection off the WaitPacketQueue and put it // on the PacketizeQueue. We don't worry about if the // connection has stopped, that will get checked when // the PacketizeQueue is run down. // // Since this is in send completion, we may not get // a receive complete. We guard against this by calling // NbiReceiveComplete from the long timer timeout. // if (p != &Device->WaitPacketConnections) { Connection = CONTAINING_RECORD (p, CONNECTION, WaitPacketLinkage); CTEAssert (Connection->OnWaitPacketQueue); Connection->OnWaitPacketQueue = FALSE; NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle); NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1); if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) { CTEAssert (!Connection->OnPacketizeQueue); Connection->OnPacketizeQueue = TRUE; NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE); NB_INSERT_TAIL_LIST( &Device->PacketizeConnections, &Connection->PacketizeLinkage, &Device->Lock); Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE; } else { NbiDereferenceConnection (Connection, CREF_W_PACKET); } NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1); } else { NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle); } } } /* NbiPushSendPacket */ VOID NbiCheckForWaitPacket( IN PCONNECTION Connection ) /*++ Routine Description: This routine checks if a connection is on the wait packet queue and if so takes it off and queues it to be packetized. It is meant to be called when the connection's packet has been freed. Arguments: Connection - The connection to check. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PDEVICE Device = NbiDevice; NB_DEFINE_LOCK_HANDLE (LockHandle) NB_DEFINE_LOCK_HANDLE (LockHandle1) NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle); NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1); if (Connection->OnWaitPacketQueue) { Connection->OnWaitPacketQueue = FALSE; RemoveEntryList (&Connection->WaitPacketLinkage); if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) { CTEAssert (!Connection->OnPacketizeQueue); Connection->OnPacketizeQueue = TRUE; NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE); InsertTailList( &Device->PacketizeConnections, &Connection->PacketizeLinkage); Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE; } else { NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1); NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); NbiDereferenceConnection (Connection, CREF_W_PACKET); return; } } NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1); NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle); } /* NbiCheckForWaitPacket */ PSINGLE_LIST_ENTRY NbiPopReceivePacket( IN PDEVICE Device ) /*++ Routine Description: This routine allocates a packet from the device context's pool. If there are no packets in the pool, it allocates one up to the configured limit. Arguments: Device - Pointer to our device to charge the packet to. Return Value: The pointer to the Linkage field in the allocated packet. --*/ { PSINGLE_LIST_ENTRY s; CTELockHandle LockHandle; s = ExInterlockedPopEntrySList( &Device->ReceivePacketList, &NbiGlobalPoolInterlock); if (s != NULL) { return s; } // // No packets in the pool, see if we can allocate more. // if (Device->AllocatedReceivePackets < Device->MaxPackets) { // // Allocate a pool and try again. // NB_GET_LOCK (&Device->Lock, &LockHandle); NbiAllocateReceivePool (Device); NB_FREE_LOCK (&Device->Lock, LockHandle); s = ExInterlockedPopEntrySList( &Device->ReceivePacketList, &NbiGlobalPoolInterlock); return s; } else { return NULL; } } /* NbiPopReceivePacket */ PSINGLE_LIST_ENTRY NbiPopReceiveBuffer( IN PDEVICE Device ) /*++ Routine Description: This routine allocates a receive buffer from the device context's pool. If there are no buffers in the pool, it allocates one up to the configured limit. Arguments: Device - Pointer to our device to charge the buffer to. Return Value: The pointer to the Linkage field in the allocated receive buffer. --*/ { #if defined(_PNP_POWER) PSINGLE_LIST_ENTRY s; PNB_RECEIVE_BUFFER ReceiveBuffer; PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool; CTELockHandle LockHandle; NB_GET_LOCK( &Device->Lock, &LockHandle ); s = PopEntryList( &Device->ReceiveBufferList ); if ( !s ) { // // No buffer in the pool, see if we can allocate more. // if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) { // // Allocate a pool and try again. // NbiAllocateReceiveBufferPool (Device, Device->CurMaxReceiveBufferSize ); s = PopEntryList(&Device->ReceiveBufferList); } } if ( s ) { // // Decrement the BufferFree count on the corresponding ReceiveBufferPool. // so that we know that ReceiveBuffer = CONTAINING_RECORD( s, NB_RECEIVE_BUFFER, PoolLinkage ); ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool; CTEAssert( ReceiveBufferPool->BufferFree && ( ReceiveBufferPool->BufferFree <= ReceiveBufferPool->BufferCount ) ); CTEAssert( ReceiveBufferPool->BufferDataSize == Device->CurMaxReceiveBufferSize ); ReceiveBufferPool->BufferFree--; } NB_FREE_LOCK (&Device->Lock, LockHandle); return s; #else PSINGLE_LIST_ENTRY s; CTELockHandle LockHandle; s = ExInterlockedPopEntryList( &Device->ReceiveBufferList, &Device->Lock.Lock); if (s != NULL) { return s; } // // No buffer in the pool, see if we can allocate more. // if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) { // // Allocate a pool and try again. // NB_GET_LOCK (&Device->Lock, &LockHandle); NbiAllocateReceiveBufferPool (Device); s = PopEntryList(&Device->ReceiveBufferList); NB_FREE_LOCK (&Device->Lock, LockHandle); return s; } else { return NULL; } #endif _PNP_POWER } /* NbiPopReceiveBuffer */