You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1494 lines
36 KiB
1494 lines
36 KiB
/*++
|
|
|
|
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
|
|
|
|
|
|
PSLIST_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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSLIST_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 */
|
|
|
|
|
|
PSLIST_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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSLIST_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 */
|
|
|