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.
3764 lines
100 KiB
3764 lines
100 KiB
//
|
|
// Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
|
|
//
|
|
// receive.c
|
|
//
|
|
// IEEE1394 mini-port/call-manager driver
|
|
//
|
|
// Mini-port Receive routines
|
|
//
|
|
// 2/13/1998 ADube Created,
|
|
//
|
|
|
|
#include <precomp.h>
|
|
#define MAX_NUM_SLIST_ENTRY 0x10
|
|
#define FRAGMENT_NUM_INVALID ((UINT)-1)
|
|
//-----------------------------------------------------------------------------
|
|
// Local prototypes (alphabetically)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
nicAllocateAddressRangeCallback(
|
|
IN PNOTIFICATION_INFO NotificationInfo
|
|
);
|
|
|
|
VOID
|
|
nicAllocateAddressRangeDebugSpew(
|
|
IN PIRB pIrb
|
|
);
|
|
|
|
NDIS_STATUS
|
|
nicGetInitializedAddressFifoElement(
|
|
IN UINT BufferLength,
|
|
IN OUT PADDRESS_FIFO *ppElement
|
|
);
|
|
|
|
NDIS_STATUS
|
|
nicGetEmptyAddressFifoElement(
|
|
IN PADDRESS_FIFO *ppElement
|
|
);
|
|
|
|
VOID
|
|
nicReceivePacketWorkItem(
|
|
PNDIS_WORK_ITEM pWorkItem,
|
|
PVOID pContext
|
|
);
|
|
|
|
VOID
|
|
nicAllocateRemainingFifoWorkItem (
|
|
PNDIS_WORK_ITEM pNdisWorkItem,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
nicFifoAllocationScheme (
|
|
PRECVFIFO_VCCB pRecvFIFOVc
|
|
);
|
|
|
|
ULONG ReassemblyAllocated = 0;
|
|
extern ULONG NdisBufferAllocated[NoMoreCodePaths];
|
|
extern ULONG NdisBufferFreed[NoMoreCodePaths];
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// prototype implementation (alphabetically)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
NDIS_STATUS
|
|
nicAllocateAddressRange(
|
|
IN PADAPTERCB pAdapter,
|
|
IN PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function will use the AllocateAddressRange Bus Api
|
|
To do this it must initialize an S-list with structures
|
|
Allocate and Initialize an Irb and an Irp and call the nic
|
|
nicSubmitIrp routine
|
|
This funcion is used by VCs. This routine will complete synchronously
|
|
|
|
|
|
Arguments:
|
|
pAdapter - provides the PDO on which the IRP is sent,
|
|
pRecvFIFOVc - Recv Fifo Vc on which the address range is allocated
|
|
|
|
|
|
Return Value:
|
|
Success - if all allocations and Irp succeeds.
|
|
|
|
--*/
|
|
{
|
|
|
|
PIRB pIrb = NULL;
|
|
PIRP pIrp = NULL;
|
|
PSLIST_HEADER pSlistHead = NULL;
|
|
UINT cnt = 0;
|
|
PDEVICE_OBJECT pPdo = NULL;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
UINT Length;
|
|
ADDRESS_OFFSET AddressOffset;
|
|
UINT MaxNumSlistEntry = MAX_NUM_SLIST_ENTRY;
|
|
BOOLEAN bRefCall = FALSE;
|
|
STORE_CURRENT_IRQL;
|
|
|
|
|
|
ASSERT (pRecvFIFOVc == pAdapter->pRecvFIFOVc);
|
|
|
|
ASSERT (pRecvFIFOVc != NULL);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicAllocateAddressRange, pAdapter 8x, pRecvFIFOVc %x", pAdapter, pRecvFIFOVc ) );
|
|
|
|
|
|
do
|
|
{
|
|
// Increment the Refcount on the VC, so we can gaurantee its presence
|
|
//
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc)
|
|
|
|
//
|
|
// Add a reference to the pdo block.
|
|
// This reference is added to guarantee its presence
|
|
// Removed in Free Address Range or at the end of the function
|
|
//
|
|
|
|
bRefCall = nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicAllocateAddressRange" ) ;
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
if ( bRefCall == FALSE )
|
|
{
|
|
//
|
|
// This will only fail if the Vc is not activated
|
|
//
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate an IRB
|
|
//
|
|
|
|
NdisStatus = nicGetIrb (&pIrb);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT (pIrb != NULL);
|
|
|
|
//
|
|
// Initalize the IrB with the correct values
|
|
// AllocateAddressRange
|
|
//
|
|
|
|
ASSERT (pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.AddressType == NIC1394AddressType_FIFO);
|
|
|
|
AddressOffset.Off_High = pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_High;
|
|
|
|
AddressOffset.Off_Low = pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_Low;
|
|
|
|
ASSERT (pRecvFIFOVc->Hdr.MTU !=0 );
|
|
|
|
Length = pRecvFIFOVc->Hdr.MTU;
|
|
|
|
nicInitAllocateAddressIrb( pIrb,
|
|
pAdapter,
|
|
0,
|
|
Length,
|
|
0,
|
|
ACCESS_FLAGS_TYPE_WRITE|ACCESS_FLAGS_TYPE_BROADCAST,
|
|
NOTIFY_FLAGS_AFTER_WRITE,
|
|
&AddressOffset,
|
|
pRecvFIFOVc);
|
|
|
|
//
|
|
// Allocate an Irp
|
|
//
|
|
|
|
|
|
NdisStatus = nicGetIrp (pAdapter->pNextDeviceObject, &pIrp);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT(pIrp != NULL);
|
|
|
|
NdisStatus = nicSubmitIrp_LocalHostSynch(pAdapter,
|
|
pIrp,
|
|
pIrb );
|
|
|
|
|
|
//
|
|
// Make this a synchronous call as this is during init
|
|
//
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
TRACE( TL_A, TM_Recv, ( "nicAllocateAddressRange SUBMIT IRP FAILED NdisStatus %.8x", NdisStatus ) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see if the IoCallDriver succeeded
|
|
//
|
|
|
|
if(pIrp->IoStatus.Status == STATUS_SUCCESS)
|
|
{
|
|
NdisStatus = nicAllocateAddressRangeSucceeded (pIrb, pRecvFIFOVc);
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT (pIrp->IoStatus.Status != STATUS_MORE_PROCESSING_REQUIRED);
|
|
// else mark status as failure
|
|
//
|
|
//
|
|
//This means dereference will happen in this function
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
//
|
|
// we need to clean up the Irb and the Irp
|
|
//
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Clean up -dereference the Call if things failed
|
|
// If we successfully completed the Irp then all the references made above
|
|
// will be dereferenced when the remote node goes away or the
|
|
// Call is closed
|
|
//
|
|
// Deref the references that were made above.
|
|
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
if (! NT_SUCCESS (NdisStatus))
|
|
{
|
|
if (bRefCall == TRUE)
|
|
{
|
|
nicDereferenceCall ( (PVCCB) pRecvFIFOVc , "nicAllocateAddressRange");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
// We don't care about the status as we are just freeing locally allocated memory
|
|
//
|
|
if (pIrb != NULL)
|
|
{
|
|
nicFreeIrb (pIrb);
|
|
}
|
|
|
|
if (pIrp!= NULL)
|
|
{
|
|
nicFreeIrp (pIrp);
|
|
}
|
|
|
|
|
|
MATCH_IRQL
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicAllocateAddressRange, pVc %.8x, Status %.8x ", pRecvFIFOVc, NdisStatus ) );
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicAllocateAddressRangeCallback(
|
|
IN PNOTIFICATION_INFO pNotificationInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the callback routine for the AllocateAddressRange that was done on a VC.
|
|
We update statistics and then call the common Receive function.
|
|
|
|
Arguments:
|
|
NotificationInfo - This structure contains the VC as context, the source of the packet
|
|
and the length of the payload received by the ohci driver.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PADAPTERCB pAdapter = (PADAPTERCB) pNotificationInfo->Context;
|
|
PRECVFIFO_VCCB pRecvFIFOVc = pAdapter->pRecvFIFOVc;
|
|
PNODE_ADDRESS pSenderNodeAddress = NULL;
|
|
|
|
//
|
|
// Debug spew for debugging
|
|
//
|
|
|
|
TRACE( TL_V, TM_Recv, ( " Mdl is at %.8x",pNotificationInfo->Mdl ) );
|
|
|
|
TRACE( TL_V, TM_Recv, ( " ulLength is %.8x",pNotificationInfo->nLength) );
|
|
|
|
TRACE( TL_V, TM_Recv, ( " pNotificationInfo->RequestPacket %x, ", pNotificationInfo->RequestPacket) );
|
|
|
|
TRACE( TL_V, TM_Recv, ( " tLabel %x, ", ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_tLabel) );
|
|
|
|
pSenderNodeAddress = & (((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_Source_ID);
|
|
|
|
TRACE( TL_V, TM_Recv, ( " Senders' NodeAddress %x, ", pSenderNodeAddress->NA_Node_Number ) );
|
|
|
|
TRACE (TL_V, TM_Reas,("tLabel %x ", ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_tLabel));
|
|
|
|
NdisInterlockedIncrement (&pRecvFIFOVc->NumIndicatedFifos);
|
|
|
|
pNotificationInfo->Fifo->FifoList.Next = NULL;
|
|
pNotificationInfo->Fifo->FifoMdl->Next = NULL;
|
|
|
|
nicFifoAllocationScheme (pRecvFIFOVc);
|
|
|
|
nicStatsRecordNumIndicatedFifos(pRecvFIFOVc->NumIndicatedFifos);
|
|
|
|
nicReceiveCommonCallback (pNotificationInfo,
|
|
(PVCCB)pRecvFIFOVc ,
|
|
AddressRange,
|
|
pNotificationInfo->Mdl );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicAllocateAddressRangeSucceeded (
|
|
IN PIRB pIrb,
|
|
IN OUT PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function updates all the Vc, PdoCb structures once the allocate address range Irb has succeeded
|
|
If the Irp succeeds but the rempte node is going away then it will free the address range before
|
|
returning
|
|
The Irb is used to initialize the fields.
|
|
|
|
|
|
Arguments:
|
|
pIrb : The Irb that was used in the Irp that just succeeded
|
|
pRecvFIFOVc: The RecvFifoVc that started the AllocateAddressRange
|
|
|
|
|
|
Return Value:
|
|
Success: If the address returned is correct.
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
BOOLEAN fPdoBeingRemoved = FALSE;
|
|
NIC1394_FIFO_ADDRESS *pFifoAddress = NULL;
|
|
BOOLEAN fFirstAddressRangeOnVc = FALSE;
|
|
|
|
//
|
|
// These are pointers to the locations that the newly allocated address range needs to be copied to
|
|
//
|
|
|
|
ADDRESS_RANGE *pSrcAddressRange = &pIrb->u.AllocateAddressRange.p1394AddressRange[0];
|
|
ADDRESS_RANGE *pVcAddressRange = &pRecvFIFOVc->VcAddressRange;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicAllocateAddressRangeSucceeded pIrb %.8x, ", pIrb) );
|
|
|
|
|
|
ASSERT (pIrb->u.AllocateAddressRange.AddressesReturned == 1);
|
|
|
|
//
|
|
// we expect this to be populated or
|
|
//
|
|
ASSERT (pRecvFIFOVc != NULL);
|
|
|
|
|
|
//
|
|
// If both high and low are zero, the bus driver is doing something wrong, return Failure
|
|
//
|
|
|
|
if (pSrcAddressRange->AR_Off_Low ==0 && pSrcAddressRange ->AR_Off_High == 0)
|
|
{
|
|
// Some fun with DeMorgan's theorem
|
|
ASSERT (pSrcAddressRange->AR_Off_Low!=0 || pSrcAddressRange ->AR_Off_High!=0);
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
//
|
|
// Copy the Address Ranges returned. For now just copy locally without allocating extra memory
|
|
//
|
|
|
|
pFifoAddress = &pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress;
|
|
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
do
|
|
{
|
|
|
|
|
|
|
|
//
|
|
// check to see if we need to update the Recv Fifo's structures. This needs to be done if the addresses are zeroes
|
|
//
|
|
if (pFifoAddress->Off_Low == 0 && pFifoAddress->Off_High == 0)
|
|
{
|
|
|
|
fFirstAddressRangeOnVc = TRUE;
|
|
|
|
pFifoAddress->Off_Low = pSrcAddressRange->AR_Off_Low;
|
|
pFifoAddress->Off_High = pSrcAddressRange->AR_Off_High;
|
|
|
|
|
|
pVcAddressRange->AR_Off_Low = pSrcAddressRange->AR_Off_Low;
|
|
pVcAddressRange->AR_Off_High = pSrcAddressRange->AR_Off_High;
|
|
pVcAddressRange->AR_Length = pSrcAddressRange->AR_Length;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
ASSERT (pFifoAddress->Off_Low == pSrcAddressRange->AR_Off_Low);
|
|
ASSERT (pFifoAddress->Off_High == pSrcAddressRange->AR_Off_High);
|
|
|
|
}
|
|
|
|
pRecvFIFOVc->AddressesReturned = pIrb->u.AllocateAddressRange.AddressesReturned;
|
|
pRecvFIFOVc->hAddressRange = pIrb->u.AllocateAddressRange.hAddressRange;
|
|
|
|
|
|
//
|
|
// If we reached this far, we have succeeded
|
|
//
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
TRACE( TL_T, TM_Recv, ( " hAddressRange %x, NumReturned %x , Low %x , Hi %x, Length %x",
|
|
pRecvFIFOVc->hAddressRange ,
|
|
pRecvFIFOVc->AddressesReturned,
|
|
pSrcAddressRange->AR_Off_Low,
|
|
pSrcAddressRange->AR_Off_High,
|
|
pSrcAddressRange->AR_Length) );
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicAllocateAddressRangeSucceeded Status %.8x", NdisStatus ) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeAddressFifo(
|
|
IN PADDRESS_FIFO pAddressFifo,
|
|
IN PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Takes a single AddressFifo element, frees it and dereferences the
|
|
VC on which it was allocated.
|
|
|
|
Arguments:
|
|
pAddressFifo - The AddressFifo being freed.
|
|
pRecvFIFOVc - VC on which the Address fifo was allocated.
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PVOID SystemAddress = NIC_GET_SYSTEM_ADDRESS_FOR_MDL (pAddressFifo->FifoMdl);
|
|
UINT Length = MmGetMdlByteCount(pAddressFifo->FifoMdl);
|
|
|
|
ASSERT (SystemAddress!=NULL);
|
|
ASSERT (Length != 0);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFreeAddressFifo") );
|
|
|
|
if (SystemAddress != NULL)
|
|
{
|
|
nicFreeLocalBuffer(Length, SystemAddress);
|
|
}
|
|
|
|
nicFreeMdl (pAddressFifo->FifoMdl);
|
|
|
|
FREE_NONPAGED((PVOID)pAddressFifo);
|
|
|
|
//
|
|
// Dereference the reference added when this AddressFifo was inserted into the list
|
|
//
|
|
|
|
nicDereferenceCall ((PVCCB)pRecvFIFOVc, "nicFreeAddressFifo");
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicFreeAddressFifo") );
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeAllocateAddressRangeSList(
|
|
IN PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function should pop entries from the Slist
|
|
Each entry is an Adress_fifo element containing an MDl
|
|
The function should call nicFreeAddressFifo to free the Address FIFO element
|
|
|
|
|
|
Arguments:
|
|
pRecvFIFOVc - RecvFIfoVc which has the list of Fifo Entries
|
|
which need to be freed.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PADDRESS_FIFO pAddressFifoElement = NULL;
|
|
SLIST_ENTRY *pSingleListEntry = NULL;
|
|
UINT NumFreed = 0;
|
|
|
|
STORE_CURRENT_IRQL;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFreeAllocateAddressRangeSList, Num %.8x",
|
|
ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) ) );
|
|
|
|
while ( ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) != 0)
|
|
{
|
|
pSingleListEntry= ExInterlockedPopEntrySList ( &pRecvFIFOVc->FifoSListHead,
|
|
&pRecvFIFOVc->FifoSListSpinLock );
|
|
|
|
//
|
|
// This will dereference the call
|
|
//
|
|
pAddressFifoElement = CONTAINING_RECORD (pSingleListEntry, ADDRESS_FIFO, FifoList);
|
|
|
|
ASSERT (pAddressFifoElement != NULL);
|
|
|
|
//
|
|
// This will dereference the Vc and free the address fifo
|
|
//
|
|
nicFreeAddressFifo ( pAddressFifoElement,
|
|
pRecvFIFOVc );
|
|
NumFreed ++;
|
|
}
|
|
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
ASSERT ( ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) == 0);
|
|
|
|
pRecvFIFOVc->FifoSListHead.Alignment = 0;
|
|
pRecvFIFOVc->NumOfFifosInSlistInCloseCall = NumFreed;
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
|
|
MATCH_IRQL;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicFreeAllocateAddressRangeSList, NumFreed %x", NumFreed ) );
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicFillAllocateAddressRangeSList(
|
|
PRECVFIFO_VCCB pRecvFIFOVc,
|
|
UINT *Num )
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function inits the Slist that will be sent down with the
|
|
AllocateAddressRange Irb
|
|
|
|
It is the responsibility of the caller to free the Allocated memory
|
|
|
|
|
|
Arguments:
|
|
RecvFifoVc - VC to be linked with the Slist
|
|
Num - Num of AddressFifo Elements that are inserted into the SList
|
|
|
|
Return Value:
|
|
|
|
Num - Contains the number of Fifo elements that were inserted into the Slist
|
|
Status - Success if all allocations succeeded.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
|
|
PADDRESS_FIFO pRecvFifoElement = NULL;
|
|
NDIS_STATUS NdisStatus;
|
|
UINT cnt = 0;
|
|
BOOLEAN bRef = FALSE;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFillAllocateAddressRangeSList" ) );
|
|
|
|
ASSERT (pRecvFIFOVc != NULL);
|
|
|
|
ASSERT (pRecvFIFOVc->Hdr.MTU != 0);
|
|
|
|
|
|
do
|
|
{
|
|
|
|
NdisStatus = nicGetInitializedAddressFifoElement (pRecvFIFOVc->Hdr.MTU,
|
|
&pRecvFifoElement);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT (pRecvFifoElement != NULL);
|
|
|
|
ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
|
|
(PSLIST_ENTRY)&pRecvFifoElement->FifoList,
|
|
&pRecvFIFOVc->FifoSListSpinLock);
|
|
|
|
//
|
|
// Add this once for every Address Fifo element inserted
|
|
// Will be decremented by a call to nicFreeAddressFifo
|
|
//
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
bRef = nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicFillAllocateAddressRangeSList");
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
if (bRef == FALSE)
|
|
{
|
|
NdisStatus = NDIS_STATUS_VC_NOT_ACTIVATED;
|
|
break;
|
|
}
|
|
|
|
TRACE( TL_V, TM_Recv, ( "cnt %.8x, Num %.8x, ",cnt, *Num) );
|
|
|
|
} while (++cnt < *Num);
|
|
|
|
//
|
|
// Need to handle failure cases and also return number allocated
|
|
//
|
|
*Num = cnt;
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
TRACE( TL_V, TM_Recv, ( "nicFillAllocateAddressRangeSList Failed, num allotted %.8x, MTU %,8x ",cnt ,pRecvFIFOVc->Hdr.MTU ) );
|
|
|
|
nicFreeAllocateAddressRangeSList (pRecvFIFOVc);
|
|
|
|
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFillAllocateAddressRangeSList Num %.8x, MTU %.8x",cnt,pRecvFIFOVc->Hdr.MTU ) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetInitializedAddressFifoElement(
|
|
IN UINT BufferLength,
|
|
IN OUT PADDRESS_FIFO *ppElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function return a single AddressFifo element,
|
|
with an MDL pointing to locally owned allocated memory
|
|
The size of the memory needs to be specified at MTU of
|
|
the VC that this belongs to and is the BufferLength.
|
|
|
|
Get locally owned buffer, get address fifo , init MDL with
|
|
local buffer. return the AddressFifo
|
|
|
|
|
|
Arguments:
|
|
BufferLength - The length of the buffer that the Address_fifo contains,
|
|
*ppElement - output variable
|
|
|
|
|
|
Return Value:
|
|
|
|
*ppElement - contains the allocated structure
|
|
Status - On a failure, it contains the appropriate failure code.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
|
|
PVOID pLocalBuffer = NULL;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicGetAddressInitializedFifoElement" ) );
|
|
|
|
ASSERT (BufferLength != 0);
|
|
do
|
|
{
|
|
if (BufferLength == 0)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
TRACE( TL_A, TM_Recv, ( "BufferLength is 0" ) );
|
|
|
|
break;
|
|
}
|
|
//
|
|
// Get Locally owned memory for the data
|
|
//
|
|
NdisStatus = nicGetLocalBuffer (BufferLength, &pLocalBuffer);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
(*ppElement) = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get Empty memory for the Address Fifo element
|
|
//
|
|
NdisStatus = nicGetEmptyAddressFifoElement (ppElement);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
nicFreeLocalBuffer (BufferLength,
|
|
pLocalBuffer);
|
|
|
|
(*ppElement) = NULL;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get an MDL and initialze the MDL with the buffer
|
|
// and initialize the fifo ,with MDL.
|
|
//
|
|
NdisStatus = nicGetMdl ( BufferLength,
|
|
pLocalBuffer,
|
|
&((*ppElement)->FifoMdl));
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS || (*ppElement)->FifoMdl == NULL)
|
|
{
|
|
nicFreeLocalBuffer (BufferLength,
|
|
pLocalBuffer);
|
|
|
|
FREE_NONPAGED (*ppElement);
|
|
|
|
(*ppElement) = NULL;
|
|
|
|
}
|
|
|
|
} while(FALSE);
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicGetInitializedAddressFifoElement, Status %.8x, AddressFifo at %.8x, LocalBuffer at %.8x",
|
|
NdisStatus, *ppElement,MmGetMdlVirtualAddress((*ppElement)->FifoMdl ) ) );
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetEmptyAddressFifoElement(
|
|
IN PADDRESS_FIFO *ppElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and zeroes and empty Address_Fifo structure.
|
|
|
|
Arguments:
|
|
ppElement - Output value
|
|
|
|
Return Value:
|
|
On failure ppElement contains NULL and the appropriate Status
|
|
is returned
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
ULONG Size = 0;
|
|
TRACE( TL_T, TM_Recv, ( "==>nicGetEmptyAddressFifoElement" ) );
|
|
|
|
Size = sizeof (ADDRESS_FIFO );
|
|
|
|
*ppElement = ALLOC_NONPAGED (Size, MTAG_FIFO);
|
|
|
|
if (*ppElement != NULL)
|
|
{
|
|
NdisZeroMemory (*ppElement, Size);
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicGetEmptyAddressFifoElement, Status % .8x, at %.8x",NdisStatus,*ppElement ) );
|
|
|
|
|
|
return NdisStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetNdisBuffer(
|
|
IN UINT Length,
|
|
IN PVOID pLocalBuffer,
|
|
IN OUT PNDIS_BUFFER *ppNdisBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a buffer and Length, this function allocates an NdisBuffer (MDL) to point
|
|
to that buffer
|
|
|
|
Arguments:
|
|
Length - Length of the buffer,
|
|
pLocalBuffer - pointer to the buffer,
|
|
*ppNdisBuffer output variable that contains the MDL
|
|
|
|
|
|
Return Value:
|
|
Status - Appropriate Status code
|
|
ppNDisBuffer - NDisBuffer if allocation succeeds.
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
ASSERT (pLocalBuffer != NULL);
|
|
ASSERT (Length > 0);
|
|
ASSERT (ppNdisBuffer != NULL);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicGetNdisBuffer Local Buffer %.8x, Length %.8x", pLocalBuffer, Length) );
|
|
|
|
if ( Length > 0 &&
|
|
pLocalBuffer != NULL &&
|
|
ppNdisBuffer != NULL)
|
|
{
|
|
NdisAllocateBuffer( &NdisStatus,
|
|
ppNdisBuffer,
|
|
NULL,
|
|
pLocalBuffer,
|
|
Length );
|
|
}
|
|
else
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicGetNdisBuffer Buffer %x, NdisStatus %.8x", *ppNdisBuffer, NdisStatus ) );
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicInitAllocateAddressIrb(
|
|
IN PIRB pIrb,
|
|
IN PVOID pContext,
|
|
IN ULONG fulFlags,
|
|
IN ULONG nLength,
|
|
IN ULONG MaxSegmentSize,
|
|
IN ULONG fulAccessType,
|
|
IN ULONG fulNotificationOptions,
|
|
IN PADDRESS_OFFSET pOffset,
|
|
IN PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the allocate adddress Irb with the
|
|
values passed to the function
|
|
|
|
And adds constants for certain preknown values (e.g. callback, context)
|
|
|
|
Spew as much debug as possible
|
|
|
|
|
|
Arguments:
|
|
Are taken from the AllocateAddress Irb from 1394.h
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
ASSERT (pRecvFIFOVc != NULL);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicInitAllocateAddressIrb" ) );
|
|
|
|
pIrb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
|
|
pIrb->Flags = 0;
|
|
pIrb->u.AllocateAddressRange.Mdl = NULL;
|
|
pIrb->u.AllocateAddressRange.fulFlags = 0;
|
|
pIrb->u.AllocateAddressRange.nLength = nLength;
|
|
pIrb->u.AllocateAddressRange.MaxSegmentSize = 0;
|
|
pIrb->u.AllocateAddressRange.fulAccessType = fulAccessType;
|
|
pIrb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_AFTER_WRITE;
|
|
pIrb->u.AllocateAddressRange.Callback = nicAllocateAddressRangeCallback;
|
|
pIrb->u.AllocateAddressRange.Context = pContext; // should be pAdapter
|
|
|
|
|
|
pIrb->u.AllocateAddressRange.Required1394Offset.Off_High = pOffset->Off_High;
|
|
pIrb->u.AllocateAddressRange.Required1394Offset.Off_Low = pOffset->Off_Low;
|
|
|
|
pIrb->u.AllocateAddressRange.FifoSListHead = &pRecvFIFOVc->FifoSListHead;
|
|
pIrb->u.AllocateAddressRange.FifoSpinLock = &pRecvFIFOVc->FifoSListSpinLock;
|
|
|
|
pIrb->u.AllocateAddressRange.AddressesReturned = 0;
|
|
pIrb->u.AllocateAddressRange.p1394AddressRange = &pRecvFIFOVc->VcAddressRange;
|
|
|
|
|
|
|
|
|
|
|
|
TRACE(TL_V, TM_Recv, ("nLength = 0x%x\n", pIrb->u.AllocateAddressRange.nLength));
|
|
TRACE(TL_V, TM_Recv, ("MaxSegmentSize = 0x%x\n", pIrb->u.AllocateAddressRange.MaxSegmentSize));
|
|
TRACE(TL_V, TM_Recv, ("fulAccessType = 0x%x\n", pIrb->u.AllocateAddressRange.fulAccessType));
|
|
TRACE(TL_V, TM_Recv, ("fulNotificationOptions = 0x%x\n", pIrb->u.AllocateAddressRange.fulNotificationOptions));
|
|
TRACE(TL_V, TM_Recv, ("Callback = 0x%x\n", pIrb->u.AllocateAddressRange.Callback));
|
|
TRACE(TL_V, TM_Recv, ("Context = 0x%x\n", pIrb->u.AllocateAddressRange.Context));
|
|
TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_High = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_High));
|
|
TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_Low = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_Low));
|
|
TRACE(TL_V, TM_Recv, ("FifoSListHeader = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSListHead));
|
|
TRACE(TL_V, TM_Recv, ("FifoSListSpinLock = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSpinLock));
|
|
TRACE(TL_V, TM_Recv, ("AddressesReturned = 0x%x\n", pIrb->u.AllocateAddressRange.AddressesReturned));
|
|
TRACE(TL_V, TM_Recv, ("p1394AddressRange = 0x%x\n", pIrb->u.AllocateAddressRange.p1394AddressRange));
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicInitAllocateAddressIrb" ) );
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicFifoReturnPacket (
|
|
IN PVCCB pVc,
|
|
IN PNDIS_PACKET pMyPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
For FIFO's, this will reinsert the buffer (MDL) into the Fifo SList
|
|
Checks to see if the VC is active and then return it ot the SList .
|
|
Free the FifoElement otherwise
|
|
|
|
Arguments:
|
|
pVc - VC on which the packet is being returned.
|
|
pMyPacket - that contains the packet that contains the Fifo list
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB) pVc;
|
|
PNDIS_BUFFER pMyNdisBuffer;
|
|
PADAPTERCB pAdapter = pRecvFIFOVc->Hdr.pAF->pAdapter;
|
|
BOOLEAN fVcActive = FALSE;
|
|
PADDRESS_FIFO pAddressFifo;
|
|
PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReserved;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFifoReturnPacket pVc %x, pPacket %x, pAdapter %x, ",
|
|
pRecvFIFOVc, pMyPacket, pAdapter) );
|
|
|
|
|
|
//
|
|
// Either the reassembly structure has the indicated Fifo's or if no reassembly was done
|
|
// then the PktContext has it.
|
|
//
|
|
pAddressFifo = pPktContext->AllocateAddressRange.pIndicatedFifo;
|
|
|
|
//
|
|
// Do not push it back in the list if the VC is about to close.
|
|
// However, we push it back in, if the VC has not been activated yet
|
|
//
|
|
|
|
|
|
nicReturnFifoChain ( pAddressFifo , pRecvFIFOVc) ;
|
|
|
|
|
|
//
|
|
// Now we have to free the packet and ndis buffers that we got in the
|
|
// Calback code
|
|
//
|
|
TRACE( TL_V, TM_Recv, ( " AllocateAddress Range - Free Packet and Free Buffer" ) );
|
|
|
|
nicReturnNdisBufferChain (pMyPacket->Private.Head, pVc);
|
|
|
|
nicFreePacket(pMyPacket, &pRecvFIFOVc->PacketPool);
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicFifoReturnPacket " ) );
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
nicReturnNdisBufferChain (
|
|
IN PNDIS_BUFFER pNdisBuffer ,
|
|
IN PVCCB pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions frees a list of NDIS Buffers
|
|
|
|
Arguments:
|
|
|
|
pNdisBuffer - NdisBufferChain
|
|
VC - not used except for statistics.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNext;
|
|
BOOLEAN fIsFifo = (pVc->Hdr.VcType == NIC1394_RecvFIFO);
|
|
|
|
if (pNdisBuffer == NULL)
|
|
{
|
|
ASSERT (pNdisBuffer != NULL);
|
|
return;
|
|
}
|
|
|
|
|
|
while (pNdisBuffer != NULL)
|
|
{
|
|
pNext = pNdisBuffer->Next;
|
|
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
|
|
nicDecRecvBuffer(fIsFifo);
|
|
pNdisBuffer = pNext;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicReturnFifoChain (
|
|
IN PADDRESS_FIFO pAddressFifo,
|
|
IN PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This takes a chain of Address Fifos and returns it to the slist if
|
|
the VC is active or frees the AddressFifo if the VC is not active
|
|
|
|
Arguments:
|
|
pAddressFifo - Address Fifo that needs to be returned,
|
|
pRecvFIFOVc - The VC which owns the AddressFifo
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicReturnFifoChain pAddressFifo %x, pRecvFifoVc %x", pAddressFifo, pRecvFIFOVc) );
|
|
|
|
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
//
|
|
// lets update the value again, before we insert the Address Fifo back in to the Slist
|
|
// If there are any remote nodes present and the VC is active
|
|
// , then we should insert this back into the SList
|
|
//
|
|
|
|
|
|
if ( VC_ACTIVE (pRecvFIFOVc) == TRUE )
|
|
{
|
|
|
|
//
|
|
// Return all the AddressFifo elements to the slist
|
|
// Do this with the lock held so no one can change the
|
|
// VC state from under us
|
|
//
|
|
|
|
|
|
while (pAddressFifo != NULL)
|
|
{
|
|
PADDRESS_FIFO pNextFifo = (PADDRESS_FIFO)(pAddressFifo->FifoList.Next);
|
|
|
|
ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
|
|
(PSLIST_ENTRY)&pAddressFifo ->FifoList,
|
|
&pRecvFIFOVc->FifoSListSpinLock);
|
|
|
|
TRACE( TL_V, TM_Recv, ( " VcActive Address Fifo %x, Next Fifo %x",pAddressFifo , pNextFifo) );
|
|
|
|
pAddressFifo = pNextFifo;
|
|
|
|
NdisInterlockedDecrement (&pRecvFIFOVc->NumIndicatedFifos);
|
|
|
|
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
}
|
|
else //VC_ACTIVE (pRecvFIFOVc) == TRUE
|
|
{
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
//
|
|
// free all the Address Fifo after releasing the lock
|
|
//
|
|
|
|
while (pAddressFifo != NULL)
|
|
{
|
|
PADDRESS_FIFO pNextFifo = (PADDRESS_FIFO)(pAddressFifo->FifoList.Next);
|
|
|
|
//
|
|
// Free the Mdl and Address Fifo structure and decrease the refcount
|
|
// on the call. Do not touch the Vc after this
|
|
//
|
|
|
|
TRACE( TL_V, TM_Recv, ( " Vc NOT Active Address Fifo %x, Next Fifo %x",pAddressFifo , pNextFifo) );
|
|
|
|
nicFreeAddressFifo(pAddressFifo ,
|
|
pRecvFIFOVc);
|
|
|
|
NdisInterlockedDecrement (&pRecvFIFOVc->NumIndicatedFifos);
|
|
|
|
pAddressFifo = pNextFifo;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicReturnFifoChain ") );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicInternalReturnPacket(
|
|
IN PVCCB pVc ,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Finds out what type of Vc is being indicated and calls the appropriate VC return packets handler
|
|
|
|
Arguments:
|
|
MiniportAdapterContext - the pAdapter structure,
|
|
pPacket - pPacket that the protocol returns
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pPacket->MiniportReserved;
|
|
|
|
|
|
switch (pVc->Hdr.VcType)
|
|
{
|
|
case NIC1394_SendRecvChannel:
|
|
case NIC1394_RecvChannel:
|
|
{
|
|
nicChannelReturnPacket (pVc, pPacket );
|
|
break;
|
|
}
|
|
case NIC1394_RecvFIFO:
|
|
{
|
|
|
|
nicFifoReturnPacket ( pVc, pPacket);
|
|
break;
|
|
}
|
|
|
|
|
|
default :
|
|
{
|
|
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
NicReturnPacket(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the return packets handler.
|
|
This functikon handles all the instrumentation to catch outstanding packets and
|
|
then calls the internal return packets function
|
|
|
|
Arguments:
|
|
MiniportAdapterContext - the pAdapter structure,
|
|
pPacket - pPacket that the protocol returns
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PADAPTERCB pAdapter = (PADAPTERCB) MiniportAdapterContext;
|
|
PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pPacket->MiniportReserved;
|
|
PINDICATE_RSVD pIndicateRsvd = NULL;
|
|
PRSVD pRsvd = NULL;
|
|
|
|
//
|
|
// The first parameter of the MiniportReserved will always contain the VC
|
|
//
|
|
|
|
PVCCB pVc = (PVCCB)pPktContext->AllocateAddressRange.pRecvFIFOVc;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> NicReturnPacket pPacket %x ", pPacket) );
|
|
|
|
do
|
|
{
|
|
|
|
//
|
|
// Mark the packet as returned
|
|
//
|
|
pRsvd =(PRSVD)(pPacket->ProtocolReserved);
|
|
pIndicateRsvd = &pRsvd->IndicateRsvd;
|
|
|
|
ASSERT (pIndicateRsvd->Tag == NIC1394_TAG_INDICATED);
|
|
|
|
pIndicateRsvd->Tag = NIC1394_TAG_RETURNED;
|
|
|
|
nicInternalReturnPacket (pVc, pPacket);
|
|
|
|
}while (FALSE);
|
|
|
|
TRACE( TL_T, TM_Recv, ( " <== NicReturnPacket ") );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicFindReassemblyStructure (
|
|
IN PREMOTE_NODE pRemoteNode,
|
|
IN USHORT Dgl,
|
|
IN BUS_OPERATION BusOp,
|
|
IN PVCCB pVc,
|
|
OUT PNDIS1394_REASSEMBLY_STRUCTURE* ppReassembly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walk through all the reassembly operations on this remote node
|
|
and see if one is present
|
|
|
|
If no reassembly is found, it will allocate and initialie a structure.
|
|
All within the context of the reassembly lock
|
|
|
|
Arguments
|
|
Return Value:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
pRemoteNode - Remote Node that is sending the fragments
|
|
dgl - identifier for reassembly packet
|
|
|
|
Together they are unique for each reassembly operation
|
|
|
|
BusOp - Isoch or Fifo
|
|
pVc - on which the fragment has been indicated.
|
|
ppReassembly - Output variable that is filled if the Reassembly is found.
|
|
|
|
|
|
Return Value:
|
|
|
|
ppReassembly - Contains the allocated/found structure
|
|
Status - appropriate failure code on failure.
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pTempReassembly = NULL;
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
|
|
PLIST_ENTRY pReassemblyList = NULL;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicFindReassemblyStructure pRemoteNode %x, dgl %x " , pRemoteNode , Dgl) );
|
|
|
|
//
|
|
// Acquire the reassebly lock . Only let go when either a reassembly structure is found or a new
|
|
// reassembly structure is inserted into the remote node's reassembly list
|
|
//
|
|
REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode);
|
|
REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK (pRemoteNode)
|
|
|
|
pReassemblyList = pRemoteNode->ReassemblyList.Flink;
|
|
|
|
//
|
|
// Find the reassembly with the same dgl
|
|
//
|
|
|
|
while ( pReassemblyList != &pRemoteNode->ReassemblyList)
|
|
{
|
|
pTempReassembly = CONTAINING_RECORD (pReassemblyList ,
|
|
NDIS1394_REASSEMBLY_STRUCTURE,
|
|
ReassemblyListEntry );
|
|
|
|
|
|
TRACE( TL_V, TM_Recv, ( "Current Dgl %x, dgl %x " , pTempReassembly->Dgl , Dgl) );
|
|
|
|
if (pTempReassembly->Dgl == Dgl)
|
|
{
|
|
pReassembly = pTempReassembly;
|
|
break;
|
|
}
|
|
|
|
pReassemblyList = pReassemblyList->Flink;
|
|
}
|
|
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// If we have found a valid reassembly then return
|
|
//
|
|
|
|
if (pReassembly != NULL )
|
|
{
|
|
*ppReassembly = pReassembly ;
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the number of outstanding reassemblies is excessive, do not
|
|
// allocate a new Reassembly strucutre. Drop the packet.
|
|
//
|
|
PADAPTERCB pAdapter = pRemoteNode->pAdapter;
|
|
|
|
if (pAdapter->OutstandingReassemblies > NIC1394_MAX_REASSEMBLY_THRESHOLD)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// We need to allocate and initialize a reassembly structure
|
|
//
|
|
NdisStatus = nicGetReassemblyStructure (&pReassembly);
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
BREAK (TM_Recv, (" nicGetReassemblyStructure nicGetReassemblyStructure FAILED") );
|
|
}
|
|
|
|
NdisStatus = nicInitializeReassemblyStructure (pReassembly,
|
|
Dgl,
|
|
pRemoteNode,
|
|
pVc,
|
|
BusOp);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
pReassembly = NULL;
|
|
BREAK (TM_Recv, (" nicFindReassemblyStructure nicInitializeReassemblyStructure FAILED" ) );
|
|
}
|
|
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Increment the ref count. Ref Count will be freed when the fragment is inserted into
|
|
// the reassembly structure or the packet indicated up
|
|
//
|
|
nicReferenceReassembly ( pReassembly, "nicFindReassemblyStructure " );
|
|
|
|
}
|
|
|
|
REMOTE_NODE_REASSEMBLY_RELEASE_LOCK (pRemoteNode)
|
|
REMOTE_NODE_RELEASE_LOCK (pRemoteNode);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Update output parameters
|
|
//
|
|
*ppReassembly = pReassembly;
|
|
|
|
}
|
|
TRACE( TL_T, TM_Recv, ( "<==nicFindReassemblyStructure NdisStatus %x, *ppReassembly %x" , NdisStatus ,*ppReassembly ) );
|
|
|
|
return NdisStatus ;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetReassemblyStructure (
|
|
IN OUT PNDIS1394_REASSEMBLY_STRUCTURE* ppReassembly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Just allocates a structure and returns
|
|
|
|
Arguments
|
|
|
|
|
|
|
|
Return Value:
|
|
Success - if succeeded
|
|
|
|
Called with the lock held
|
|
|
|
Arguments:
|
|
|
|
ppReassembly - to point to the newly allocated structure
|
|
|
|
Return Value:
|
|
|
|
Success - if succeeded
|
|
|
|
Called with the lock held
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
TRACE( TL_T, TM_Recv, ( "==>nicGetReassemblyStructure ppReassembly %x", ppReassembly ) );
|
|
|
|
*ppReassembly = ALLOC_NONPAGED (sizeof (NDIS1394_REASSEMBLY_STRUCTURE), MTAG_REASSEMBLY);
|
|
|
|
if (*ppReassembly == NULL)
|
|
{
|
|
nicIncrementMallocFailure();
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
else
|
|
{
|
|
NdisZeroMemory (*ppReassembly, sizeof (NDIS1394_REASSEMBLY_STRUCTURE) );
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
(*ppReassembly)->Tag = MTAG_REASSEMBLY;
|
|
ReassemblyAllocated++;
|
|
}
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( " <==nicGetReassemblyStructure NdisStatus %x, pReassembly %x", NdisStatus, *ppReassembly) );
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
nicFreeReassemblyStructure (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Just Frees the structure and returns
|
|
|
|
Arguments:
|
|
ppReassembly - to point to the newly allocated structure
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACE( TL_T, TM_Recv, ( "== nicFreeReassemblyStructure ppReassembly %x", pReassembly ) );
|
|
|
|
pReassembly->Tag = MTAG_FREED;
|
|
|
|
NdisInterlockedDecrement (&ReassemblyAllocated);
|
|
|
|
nicDereferenceReassembly (pReassembly, "nicFreeReassemblyStructure ");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
nicInitializeReassemblyStructure (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
IN USHORT Dgl,
|
|
IN PREMOTE_NODE pRemoteNode,
|
|
IN PVCCB pVc,
|
|
IN BUS_OPERATION ReceiveOp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Goes in and assigns values to all the fields in the structure
|
|
|
|
Arguments:
|
|
pReassembly = pReassembly structure all zeroed out,
|
|
Dgl,- Datagram Label to be used in reassembly
|
|
pRemoteNode - pRemoteNode pointing to the sender
|
|
ReceiveOp - ISoch or Fifo
|
|
Vc - On which the packet came in.
|
|
|
|
|
|
Return Value:
|
|
|
|
Success : - If remote node active and this has been inserted into the remote node's list
|
|
Failure - If remote Node is not active
|
|
Called with the lock held
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN fRemoteNodeActive = FALSE;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicInitializeReassemblyStructure pReassembly %x, ReceiveOp %x", pReassembly, ReceiveOp ) );
|
|
|
|
TRACE( TL_T, TM_Recv, ( " pRemoteNode %x, Dgl %x, pVc %x ", pReassembly, Dgl, pVc ) );
|
|
|
|
//
|
|
// Increment the reassembly count
|
|
//
|
|
nicReassemblyStarted(pAdapter);
|
|
pAdapter->AdaptStats.TempStats.ulMaxOutstandingReassemblies =
|
|
max(pAdapter->AdaptStats.TempStats.ulMaxOutstandingReassemblies,
|
|
pAdapter->AdaptStats.TempStats.ulNumOutstandingReassemblies);
|
|
|
|
|
|
//
|
|
// Dgl - Datagram label. Unique for every reassembly structure gernerated by this local host
|
|
//
|
|
pReassembly->Dgl = Dgl;
|
|
|
|
|
|
//
|
|
// pRemoteNode -> RemoteNode + Dgl are unique for each reassembly structure
|
|
//
|
|
pReassembly->pRemoteNode = pRemoteNode;
|
|
|
|
|
|
//
|
|
// ExpectedFragmentOffset is computed by the Last Fragment's Offset +
|
|
// length of fragment. Does not account for gaps in the reassembled packet.
|
|
//
|
|
pReassembly->ExpectedFragmentOffset = 0;
|
|
|
|
|
|
|
|
//
|
|
// LastNdisBuffer that was appended to the packet
|
|
//
|
|
pReassembly->pTailNdisBuffer = NULL;
|
|
|
|
//
|
|
// Packet that is being reassembled
|
|
//
|
|
pReassembly->pNdisPacket = NULL;
|
|
|
|
|
|
pReassembly->Head.pAddressFifo = NULL;
|
|
pReassembly->Tail.pAddressFifo = NULL;
|
|
pReassembly->ReceiveOp = ReceiveOp;
|
|
pReassembly->pVc = pVc;
|
|
|
|
|
|
//
|
|
// Reference the remote node. This will be derefernced when the packet is returned
|
|
//
|
|
|
|
fRemoteNodeActive = (REMOTE_NODE_ACTIVE (pRemoteNode));
|
|
|
|
TRACE( TL_V, TM_Recv, ( " nicInitializeReassemblyStructure fRemoteNodeActive %x", fRemoteNodeActive) );
|
|
|
|
|
|
if (fRemoteNodeActive == TRUE)
|
|
{
|
|
//
|
|
// REfcount made as the reassembly will happen on the remote node.
|
|
// REfcount released when the last fragment is complete
|
|
//
|
|
nicReferenceRemoteNode (pRemoteNode, InitializeReassemblyStructure);
|
|
|
|
InsertTailList(&pRemoteNode->ReassemblyList, &pReassembly->ReassemblyListEntry);
|
|
|
|
//
|
|
// Reerence REassembly . Ref removed when this is removed from the Remote node list
|
|
//
|
|
nicReferenceReassembly (pReassembly, "nicInitializeReassembly" );
|
|
}
|
|
|
|
|
|
if (fRemoteNodeActive == FALSE)
|
|
{
|
|
//
|
|
// Temporary assert
|
|
//
|
|
|
|
FREE_NONPAGED (pReassembly);
|
|
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// reference the reassembly for its creation. Dereferenced in the Indicate Packet Code path
|
|
//
|
|
nicReferenceReassembly (pReassembly, " nicInitializeReassemblyStructure ");
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicInitializeReassemblyStructure NdisStatus %x, pReassembly%x ", NdisStatus,pReassembly ) );
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
nicAbortReassembly (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This thread can get called in one of two cases. 1) If the Remote node is going away
|
|
and 2) if the Reassembly has timed out. In the former case, we have Remote Node lock and
|
|
that will stop any thread from accessing this list. In the latter case, the Reassembly struct
|
|
has been removed from the Remote Node's Reassembly List while the RemoteNode lock was held.
|
|
This Reassembly structure now cannot be accessed by the Reassembly code or the RemoveRemoteNode code,
|
|
no lock is held in the second case.
|
|
|
|
This function will free all allocated NdisBuffers and return all AddressFifo
|
|
elements to the bus driver (or frees them if the VC is closing down).
|
|
|
|
Arguments
|
|
|
|
pReasssembly - Reassembly structure that needs to be freed
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS_BUFFER pNdisBuffer = NULL;
|
|
PRECVFIFO_VCCB pRecvFIFOVc = NULL;
|
|
PCHANNEL_VCCB pChannelVc = NULL;
|
|
PADAPTERCB pAdapter = pReassembly->pVc->Hdr.pAF->pAdapter;
|
|
STORE_CURRENT_IRQL;
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicAbortReassembly pReassembly %x", pReassembly ) );
|
|
|
|
|
|
//
|
|
// Free all the ndis buffers and so forth
|
|
//
|
|
if (pReassembly != NULL)
|
|
{
|
|
//
|
|
// First Chain the reassembly array into a linked so our return functions can deal with it
|
|
//
|
|
nicChainReassembly (pReassembly);
|
|
|
|
if (pReassembly->pHeadNdisBuffer != NULL)
|
|
{
|
|
nicReturnNdisBufferChain(pReassembly->pHeadNdisBuffer, pReassembly->pVc);
|
|
}
|
|
|
|
switch (pReassembly->ReceiveOp)
|
|
{
|
|
case AddressRange:
|
|
{
|
|
pRecvFIFOVc = (PRECVFIFO_VCCB) pReassembly->pVc;
|
|
|
|
|
|
//
|
|
// Time to return all of our address fifos
|
|
//
|
|
nicReturnFifoChain (pReassembly->Head.pAddressFifo,
|
|
pRecvFIFOVc
|
|
);
|
|
|
|
pReassembly->Head.pAddressFifo = NULL;
|
|
break;
|
|
}
|
|
|
|
case IsochReceive:
|
|
{
|
|
pChannelVc = (PCHANNEL_VCCB)pReassembly->pVc;
|
|
|
|
nicReturnDescriptorChain ( pReassembly->Head.pIsochDescriptor,
|
|
pChannelVc);
|
|
|
|
pReassembly->Head.pIsochDescriptor = NULL;
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
{
|
|
|
|
ASSERT (0);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
ASSERT (0);
|
|
}
|
|
|
|
//
|
|
// Now deref the reassembly and free it.
|
|
//
|
|
nicReassemblyAborted (pAdapter);
|
|
nicFreeReassemblyStructure (pReassembly);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicAbortReassembly pReassembly %x", pReassembly ) );
|
|
MATCH_IRQL;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicDoReassembly (
|
|
IN PNIC_RECV_DATA_INFO pRcvInfo,
|
|
OUT PNDIS1394_REASSEMBLY_STRUCTURE *ppReassembly,
|
|
PBOOLEAN pfReassemblyComplete
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Does the reassembly work .
|
|
Allocates an ndisbuffer pointing to the data .
|
|
Does In order or out of order reassembly
|
|
|
|
Arguments:
|
|
pRcvInfo - pRcv Information
|
|
pReassembly reassmbly structure associated with this fragment
|
|
pfReassemblyComplete - Is the REassembly complete
|
|
Return Value:
|
|
Success - if this fragment was successfully associated with a reassembly structure
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PNDIS_BUFFER pNdisBuffer = NULL;
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
|
|
BOOLEAN fInOrder = FALSE;
|
|
BOOLEAN fNeedToReleaseReassemblyLock = FALSE;
|
|
BOOLEAN fReassemblyComplete = FALSE;
|
|
PADAPTERCB pAdapter = pRcvInfo->pRemoteNode->pAdapter;
|
|
|
|
STORE_CURRENT_IRQL;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicDoReassembly ppReassembly %x pRcvInfo %x",
|
|
ppReassembly, pRcvInfo ) );
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get an NdisBuffer pointing to the data
|
|
//
|
|
NdisStatus = nicGetNdisBufferForReassembly( pRcvInfo, &pNdisBuffer);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// If we break from here, the reassmbly will never get completed and the
|
|
// garbage collector will eventually free this.
|
|
//
|
|
pNdisBuffer = NULL;
|
|
BREAK (TM_Send, ("nicDoReassembly nicGetNdisBufferForReassembly FAILED" ) );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Either there is a reassembly currently going or one will be allocated and initialized
|
|
//
|
|
|
|
NdisStatus = nicFindReassemblyStructure (pRcvInfo->pRemoteNode,
|
|
pRcvInfo->Dgl,
|
|
pRcvInfo->RecvOp,
|
|
(PVCCB)pRcvInfo->pVc,
|
|
&pReassembly);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pReassembly=NULL;
|
|
BREAK (TM_Recv, (" nicDoReassembly nicFindReassemblyStructure FAILED"));
|
|
}
|
|
|
|
|
|
//
|
|
// Now we start doing the actual work . Acquire the
|
|
// reassembly lock so no one else can touch the reassembly
|
|
//
|
|
|
|
|
|
ASSERT (pReassembly != NULL);
|
|
TRACE( TL_V, TM_Recv, ( " ExpectedFragmentOffset %x FragmentHeader Offset %x, ",
|
|
pReassembly->ExpectedFragmentOffset , pRcvInfo->FragmentOffset) );
|
|
|
|
//
|
|
// Code expects that if the reassembly is not Null, then the lock is acquired.
|
|
//
|
|
REASSEMBLY_ACQUIRE_LOCK (pReassembly);
|
|
fNeedToReleaseReassemblyLock = TRUE;
|
|
|
|
|
|
if (REASSEMBLY_ACTIVE (pReassembly) == FALSE)
|
|
{
|
|
//
|
|
// Drop the reassembly, as this structure is about to be freed
|
|
//
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// This is the new reassembly scheme, which uses a table and does out of order and inorder
|
|
// reassembly
|
|
//
|
|
|
|
|
|
NdisStatus = nicInsertFragmentInReassembly (pReassembly,
|
|
pRcvInfo);
|
|
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Do not assert
|
|
//
|
|
TRACE (TL_V, TM_Reas, ("nicDoReassembly nicInsertFragmentInReassembly FAILED") );
|
|
break;
|
|
}
|
|
|
|
|
|
fReassemblyComplete = pReassembly->fReassemblyComplete;
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Release the reassembly lock (if acquired)
|
|
//
|
|
if (fNeedToReleaseReassemblyLock == TRUE)
|
|
{
|
|
REASSEMBLY_RELEASE_LOCK (pReassembly);
|
|
|
|
if (fReassemblyComplete == TRUE)
|
|
{
|
|
//
|
|
// Dereference the remote node as we are removing the reassembly from the remote node
|
|
//
|
|
nicDereferenceReassembly (pReassembly, "nicInsertFragmentInReassembly " );
|
|
//
|
|
// now dereference the remote node. ref was added when the reassembly was
|
|
// inserted into the remote node's list
|
|
//
|
|
nicDereferenceRemoteNode(pReassembly->pRemoteNode, InsertFragmentInReassembly );
|
|
|
|
pReassembly->pRemoteNode = NULL;
|
|
|
|
}
|
|
}
|
|
//
|
|
// Clean up time. First handle the failure case.
|
|
// If reassembly is != NULL, then free the lock
|
|
// and free the reassembly structure
|
|
//
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
*ppReassembly = pReassembly;
|
|
|
|
//
|
|
// Queue a Reassembly timer, if reassembly was not complete
|
|
//
|
|
if (fReassemblyComplete == FALSE)
|
|
{
|
|
nicQueueReassemblyTimer(pAdapter, FALSE);
|
|
}
|
|
}
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// Free any locally allocated structures.
|
|
//
|
|
if (pNdisBuffer)
|
|
{
|
|
NdisFreeBuffer (pNdisBuffer);
|
|
}
|
|
//
|
|
// Return NULL as output. The Reassembly structure is
|
|
// in the remote node's list. The timer routine will pick it up
|
|
//
|
|
|
|
//
|
|
// Deref the ref made the REassembly was found/
|
|
//
|
|
if (pReassembly != NULL)
|
|
{
|
|
nicDereferenceReassembly (pReassembly, "nicDoReassembly - failure" );
|
|
}
|
|
|
|
*ppReassembly = pReassembly = NULL;
|
|
|
|
}
|
|
|
|
*pfReassemblyComplete = fReassemblyComplete;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicDoReassembly NdisStatus %x, , pReassembly %x, Complete %x", NdisStatus, *ppReassembly, *pfReassemblyComplete ) );
|
|
MATCH_IRQL;
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicGetNdisBufferForReassembly(
|
|
IN PNIC_RECV_DATA_INFO pRcvInfo,
|
|
OUT PNDIS_BUFFER *ppNdisBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Function Description:
|
|
This function gets an Ndis Buffer that points to the start of the data
|
|
that the Mdl points to. The Data starts from the point after the
|
|
Fragmentation Header
|
|
|
|
If this is the First fragment, then 32 bytes of the fragment header are also
|
|
copied to make room for the header that the ARP module expects
|
|
|
|
Arguments
|
|
pRcvInfo - Pointer to the Receive Tracking structure
|
|
ppNdisBuffer - Output
|
|
|
|
Return Value:
|
|
Success - if the mem alloc succeeded, appropriate failure code otherwise
|
|
NdisBuffer - Buffer pointing ot the data ,
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PVOID pStartValidData = NULL;
|
|
ULONG ulValidDataLength = 0;
|
|
PNDIS1394_FRAGMENT_HEADER pNonByteSwappedFragmentHeader = NULL;
|
|
USHORT Dgl;
|
|
PNDIS_BUFFER pNdisBuffer = NULL;
|
|
ULONG IsochPrefix = ISOCH_PREFIX_LENGTH;
|
|
PPACKET_FORMAT pIndicatedData = NULL;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicGetNdisBufferForReassembly ") );
|
|
do
|
|
{
|
|
//
|
|
// Get a pointer to the start of the data, ie. it should point past the encapsulation header
|
|
//
|
|
pStartValidData = (PVOID)((ULONG_PTR)pRcvInfo->pEncapHeader + sizeof(NDIS1394_FRAGMENT_HEADER));
|
|
|
|
ulValidDataLength = pRcvInfo->DataLength - sizeof (NDIS1394_FRAGMENT_HEADER);
|
|
//
|
|
// if this is the first fragment, then leave room for the Unfragmented header that will need
|
|
// to be added before sending it up to the IP module
|
|
//
|
|
if (pRcvInfo->fFirstFragment == TRUE)
|
|
{
|
|
ULONG ExtraData = (sizeof(NDIS1394_FRAGMENT_HEADER) - sizeof (NDIS1394_UNFRAGMENTED_HEADER)) ;
|
|
|
|
pStartValidData = (PVOID)((ULONG_PTR)pStartValidData - ExtraData);
|
|
|
|
ulValidDataLength += ExtraData ;
|
|
}
|
|
|
|
|
|
NdisStatus = nicGetNdisBuffer ( ulValidDataLength,
|
|
pStartValidData,
|
|
&pNdisBuffer);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
BREAK (TM_Recv, ( "nicGetNdisBufferForReassembly: nicGetNdisBuffer Failed" ) );
|
|
}
|
|
|
|
nicIncRecvBuffer(pRcvInfo->pVc->Hdr.VcType == NIC1394_RecvFIFO);
|
|
|
|
*ppNdisBuffer = pNdisBuffer;
|
|
pRcvInfo->pNdisBuffer = pNdisBuffer;
|
|
pRcvInfo->pNdisBufferData = pStartValidData;
|
|
|
|
}while (FALSE);
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicGetNdisBufferForReassembly NdisStatus %x, *ppNdisbuffer %x, pStartValidData%x ,ulValidDataLength %x",
|
|
NdisStatus, *ppNdisBuffer, pStartValidData, ulValidDataLength) );
|
|
|
|
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicAddUnfragmentedHeader (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
IN PVOID pEncapHeader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Its purpose is to add the fragment header that arp expects.
|
|
There is room in the Head NdisBuffer to do this
|
|
|
|
We own the buffer, so we can manipulate the data
|
|
|
|
|
|
Arguments:
|
|
pReassembty Structure - contains all the necessary reasembly info
|
|
pEncapHeader - Pointer to where th Unfragmented header will be stored
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
PNDIS1394_UNFRAGMENTED_HEADER pHeader = NULL;
|
|
ASSERT (sizeof(NDIS1394_UNFRAGMENTED_HEADER) == sizeof(ULONG));
|
|
TRACE( TL_T, TM_Recv, ( "==> nicAddUnfragmentedHeader %x, pEncapHeader %x", pReassembly, pEncapHeader) );
|
|
|
|
|
|
pHeader = (PNDIS1394_UNFRAGMENTED_HEADER) pEncapHeader;
|
|
|
|
//
|
|
// Now we add the unfragmented header. first zero it, then add the approriate values
|
|
//
|
|
pHeader->HeaderUlong = 0;
|
|
pHeader->u.FH_lf = lf_Unfragmented;
|
|
pHeader->u.FH_EtherType = pReassembly->EtherType;
|
|
|
|
//
|
|
// Convert the header to network order and indicate it up.
|
|
//
|
|
pHeader->HeaderUlong = SWAPBYTES_ULONG (pHeader->HeaderUlong);
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicAddUnfragmentedHeader pReasembly %x, pHeader %x ", pReassembly, pHeader->HeaderUlong) );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicAbortReassemblyList (
|
|
PLIST_ENTRY pToBeFreedList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Walks the list and calls nicAbortReassembly on each structure
|
|
|
|
Does not do any lock or refcount work as all the Reassembly structures are
|
|
off the Remote node and cannot be accessed by any other thread.
|
|
|
|
|
|
Arguments:
|
|
pToBeFreedList - list of reassembly structures that are going to be freed
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PLIST_ENTRY pReassemblyList = ListNext (pToBeFreedList);
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicAbortReassemblyList pToBeFreedList %x", pToBeFreedList));
|
|
|
|
|
|
while (pReassemblyList != pToBeFreedList)
|
|
{
|
|
pReassembly = CONTAINING_RECORD(pReassemblyList,
|
|
NDIS1394_REASSEMBLY_STRUCTURE,
|
|
ReassemblyListEntry);
|
|
|
|
pReassemblyList = ListNext(pReassemblyList);
|
|
|
|
TRACE( TL_T, TM_Recv, ( " Aborting pReassembly %x", pReassembly));
|
|
|
|
nicAbortReassembly(pReassembly);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFreeAllPendingReassemblyStructures(
|
|
IN PADAPTERCB pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
When we are notified of a reset we need to go and invalidate all
|
|
reassemblies
|
|
|
|
This will always be called from the Reset code path . and will be at dispatch
|
|
It will clear out all the remote node reaassembly and mark them as aborted.
|
|
The Timer routine will then pick them up and free it
|
|
|
|
Does not actually free anything. Just marks them as aborted
|
|
|
|
|
|
Arguments:
|
|
Adapter - Adapter on which the Reset occurred.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pRemoteNodeList = NULL;
|
|
PREMOTE_NODE pRemoteNode = NULL;
|
|
PLIST_ENTRY pReassemblyList = NULL;
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
|
|
ULONG NumMarkedAborted = 0;
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicFreeAllPendingReassemblyStructures "));
|
|
|
|
|
|
pRemoteNodeList = ListNext(&pAdapter->PDOList);
|
|
|
|
ADAPTER_ACQUIRE_LOCK (pAdapter);
|
|
|
|
//
|
|
// Walking through the remote nodes
|
|
//
|
|
while (pRemoteNodeList != &pAdapter->PDOList)
|
|
{
|
|
pRemoteNode = CONTAINING_RECORD(pRemoteNodeList,
|
|
REMOTE_NODE,
|
|
linkPdo);
|
|
|
|
pRemoteNodeList = ListNext (pRemoteNodeList);
|
|
|
|
|
|
//
|
|
// Reference the remote node, so we can guarantee its presence
|
|
//
|
|
if (REMOTE_NODE_ACTIVE (pRemoteNode)== FALSE)
|
|
{
|
|
//
|
|
// The remote node is going away. Skip this remote node
|
|
//
|
|
continue;
|
|
}
|
|
if (nicReferenceRemoteNode (pRemoteNode, FreeAllPendingReassemblyStructures )== FALSE )
|
|
{
|
|
//
|
|
// The remote node is going away. Skip this remote node
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Now walking through all the reassembly structures on that remote node
|
|
//
|
|
REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK(pRemoteNode);
|
|
|
|
pReassemblyList = ListNext (&pRemoteNode->ReassemblyList);
|
|
|
|
while (pReassemblyList != &pRemoteNode->ReassemblyList)
|
|
{
|
|
pReassembly = CONTAINING_RECORD (pReassemblyList,
|
|
NDIS1394_REASSEMBLY_STRUCTURE,
|
|
ReassemblyListEntry);
|
|
|
|
pReassemblyList = ListNext(pReassemblyList);
|
|
|
|
|
|
//
|
|
// If the reassembly has not been touched since the last timer it needs to be freed.
|
|
// Other threads can ask us to free the reassembly by setting the aborted flag
|
|
//
|
|
if (REASSEMBLY_TEST_FLAG (pReassembly, REASSEMBLY_ABORTED) == FALSE);
|
|
{
|
|
|
|
REASSEMBLY_SET_FLAG (pReassembly, REASSEMBLY_ABORTED);
|
|
|
|
NdisInterlockedIncrement (&NumMarkedAborted);
|
|
}
|
|
}
|
|
|
|
|
|
REMOTE_NODE_REASSEMBLY_RELEASE_LOCK(pRemoteNode);
|
|
|
|
nicDereferenceRemoteNode (pRemoteNode, FreeAllPendingReassemblyStructures );
|
|
|
|
}
|
|
|
|
|
|
ADAPTER_RELEASE_LOCK (pAdapter);
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicFreeAllPendingReassemblyStructures NumMarkedAborted %x"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
nicReferenceReassembly (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
PCHAR pString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the return packets handler.
|
|
This functikon handles all the instrumentation to catch outstanding packets and
|
|
then calls the internal return packets function
|
|
|
|
Arguments:
|
|
MiniportAdapterContext - the pAdapter structure,
|
|
pPacket - pPacket that the protocol returns
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG Ref;
|
|
|
|
Ref = NdisInterlockedIncrement (&pReassembly->Ref);
|
|
|
|
TRACE( TL_V, TM_Ref, ( "**nicReferenceReassembly pReassembly %x, to %d, %s ", pReassembly, pReassembly->Ref, pString) );
|
|
|
|
return Ref;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
nicDereferenceReassembly (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
PCHAR pString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Dereference the Reassembly strucure
|
|
|
|
In the case that the ref hits zero, the Reassembly structure is no longer
|
|
in the Remote Node List so no other thread other than the caller has
|
|
access to this strcuture.
|
|
|
|
Arguments:
|
|
pReassembly - pReassembly strucure to be dereferenced,
|
|
PCHAR - Character string for debugging purposes.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG Ref;
|
|
|
|
Ref = NdisInterlockedDecrement (&pReassembly->Ref);
|
|
|
|
TRACE( TL_V, TM_Ref, ( "**nicDereferenceReassembly pReassembly %x, to %d, %s ", pReassembly, pReassembly->Ref, pString) );
|
|
|
|
if ( Ref ==0 )
|
|
{
|
|
|
|
TRACE( TL_V, TM_Ref, ( "**FREEING pReassembly %x, ", pReassembly) );
|
|
FREE_NONPAGED (pReassembly);
|
|
}
|
|
|
|
return Ref;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicIndicateNdisPacketToNdis (
|
|
PNDIS_PACKET pPacket,
|
|
PVCCB pVc,
|
|
PADAPTERCB pAdapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is to be used to indicate packets to NDIS .
|
|
Assumption - There will be only one packet in the array
|
|
|
|
Arguments:
|
|
ppPacket - Packet Array
|
|
pVc -Vc on which the packet came in.
|
|
Adapter - Adapter in which the packet came in
|
|
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
PRSVD pRsvd = NULL;
|
|
PNDIS_MINIPORT_TIMER pRcvTimer= NULL;
|
|
PINDICATE_RSVD pIndicateRsvd = NULL;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicIndicateNdisPacketToNdis pPacket %x, pVc %x, pAdapter %x ",
|
|
pPacket , pVc, pAdapter));
|
|
|
|
TRACE (TL_V, TM_Reas, ("Indicating packet " ));
|
|
|
|
|
|
do
|
|
{
|
|
NdisInterlockedIncrement (&pAdapter->AdaptStats.ulRcvOk);
|
|
|
|
nicDumpPkt (pPacket,"Indicating Rcv ");
|
|
|
|
|
|
ASSERT (pPacket != NULL);
|
|
|
|
//
|
|
// Set up the Context for the indication
|
|
//
|
|
pRsvd =(PRSVD)(pPacket->ProtocolReserved);
|
|
pIndicateRsvd = &pRsvd->IndicateRsvd;
|
|
|
|
|
|
//
|
|
// Update the tag increment counter and indicate rcv
|
|
//
|
|
|
|
pIndicateRsvd->Tag = NIC1394_TAG_INDICATED;
|
|
|
|
ASSERT (pPacket != NULL);
|
|
|
|
nicIncrementRcvVcPktCount(pVc,pPacket);
|
|
|
|
NdisMCoIndicateReceivePacket(pVc->Hdr.NdisVcHandle, &pPacket, 1);
|
|
|
|
ASSERT (pAdapter->MiniportAdapterHandle != NULL);
|
|
NdisMCoReceiveComplete(pAdapter->MiniportAdapterHandle);
|
|
|
|
|
|
}while (FALSE);
|
|
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicIndicateNdisPacketToNdis %x"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicValidateRecvDataIsoch(
|
|
IN PMDL pMdl,
|
|
IN PISOCH_DESCRIPTOR pIsochDescriptor,
|
|
IN PVCCB pVc,
|
|
OUT PNIC_RECV_DATA_INFO pRcvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function ensures that the length of the received packet is within reason.
|
|
In the Isoch case, we do not know the exact number of bytes received, so we check
|
|
against the Mdl Length in the isoch Descriptor
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
do
|
|
{
|
|
NODE_ADDRESS NodeAddress;
|
|
PGASP_HEADER pGaspHeader;
|
|
//
|
|
// Isoch header is already byte swapped
|
|
//
|
|
pRcvInfo->DataLength = pRcvInfo->p1394Data->IsochReceiveFragmented.IsochHeader.IH_Data_Length;
|
|
|
|
if (pRcvInfo->DataLength <= (UINT)FIELD_OFFSET(DATA_FORMAT,IsochReceiveFragmented.Data))
|
|
{
|
|
// Too small. Note that for simplicitly we check for the
|
|
// fragmented case.
|
|
//
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pRcvInfo->fGasp = TRUE;
|
|
|
|
//
|
|
// The total length of the data indicated by the bus driver
|
|
//
|
|
pRcvInfo->Length1394 = pRcvInfo->DataLength + sizeof (ISOCH_HEADER) + sizeof(ULONG); // Account for the prefix and isoch header
|
|
|
|
//
|
|
// Validate the Received length. Isoch Descriptors do not give us the actual length of the received packet, so
|
|
// we rely on the MDL length.
|
|
//
|
|
if ((pRcvInfo->DataLength < sizeof(GASP_HEADER)) || pRcvInfo->DataLength > pIsochDescriptor->ulLength)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The valid data does not include the gasp header
|
|
//
|
|
pRcvInfo->DataLength -= sizeof (GASP_HEADER);
|
|
|
|
|
|
pRcvInfo->NdisPktContext.pIsochContext = pIsochDescriptor;
|
|
|
|
pRcvInfo->pPacketPool = &((PCHANNEL_VCCB) pVc)->PacketPool;
|
|
|
|
//
|
|
// Get the source Info out.
|
|
//
|
|
//
|
|
// pRcvInfo->p1394Data points to the start of the Mdl's VA that was indicated by the bus driver
|
|
//
|
|
pGaspHeader = &pRcvInfo->p1394Data->IsochReceiveFragmented.GaspHeader;
|
|
|
|
//
|
|
// Byte swap the Gasp Header in the actual data. we own the buffer, so we can byte swap it
|
|
//
|
|
pGaspHeader->FirstQuadlet.GaspHeaderHigh = SWAPBYTES_ULONG(pGaspHeader->FirstQuadlet.GaspHeaderHigh);
|
|
pGaspHeader->SecondQuadlet.GaspHeaderLow = SWAPBYTES_ULONG(pGaspHeader->SecondQuadlet.GaspHeaderLow);
|
|
|
|
TRACE (TL_V, TM_Recv, (" Gasp Hi %x, Gasp Lo %x.",
|
|
pGaspHeader->FirstQuadlet.GaspHeaderHigh,
|
|
pGaspHeader->SecondQuadlet.GaspHeaderLow ) );
|
|
|
|
pRcvInfo->pGaspHeader = pGaspHeader;
|
|
|
|
pRcvInfo->SourceID = pGaspHeader->FirstQuadlet.u1.GH_NodeAddress.NA_Node_Number;
|
|
|
|
pRcvInfo->SourceID = pGaspHeader->FirstQuadlet.u1.GH_NodeAddress.NA_Node_Number;
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicValidateRecvDataFifo(
|
|
IN PMDL pMdl,
|
|
IN PNOTIFICATION_INFO pFifoContext,
|
|
IN PVCCB pVc,
|
|
OUT PNIC_RECV_DATA_INFO pRcvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that the length is not too small
|
|
This routine initializes the RecvDataInfo for the default (unfragmented case).
|
|
If the data is unfragmented the main recv routine will then call the Fragmented version of this routine
|
|
|
|
This initializes the length and StartData and fGasp fields of the struct only
|
|
|
|
Arguments:
|
|
pMdl - Mdl that was indicated up by the bus driver
|
|
RecvOp - Is this part of isoch callback, or AddrRange Callback
|
|
pIndicatedStruct - NotificationInfo or IsochDescriptor
|
|
pRcvInfo - Recv Structure that will be updated
|
|
|
|
Return Value:
|
|
Success - if all the operations succeeded
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
do
|
|
{
|
|
pRcvInfo->DataLength = pFifoContext->nLength;
|
|
|
|
if (pRcvInfo->DataLength <= (UINT)FIELD_OFFSET(DATA_FORMAT, AsyncWriteFragmented.Data))
|
|
{
|
|
// Too small. Note that for simplicitly we check for the
|
|
// fragmented case.
|
|
//
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pRcvInfo->fGasp = FALSE;
|
|
|
|
//
|
|
//In Fifo receives the DataLength is equal to the total amount of data indicated by the bus driver
|
|
//
|
|
pRcvInfo->Length1394 = pRcvInfo->DataLength;
|
|
|
|
pRcvInfo->NdisPktContext.pFifoContext = pFifoContext ->Fifo;
|
|
|
|
pRcvInfo->pPacketPool = &((PRECVFIFO_VCCB) pVc)->PacketPool;
|
|
|
|
pRcvInfo->SourceID = ((PASYNC_PACKET)pFifoContext->RequestPacket)->AP_Source_ID.NA_Node_Number;
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
}while (FALSE);
|
|
|
|
return NdisStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
nicValidateRecvData(
|
|
IN PMDL pMdl,
|
|
IN BUS_OPERATION RecvOp,
|
|
IN PVOID pIndicatedStruct,
|
|
IN PVCCB pVc,
|
|
OUT PNIC_RECV_DATA_INFO pRcvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that the length is not too small
|
|
This routine initializes the RecvDataInfo for the default (unfragmented case).
|
|
If the data is unfragmented the main recv routine will then call the Fragmented version of this routine
|
|
|
|
This initializes the length and StartData and fGasp fields of the struct only
|
|
Arguments:
|
|
pMdl - Mdl that was indicated up by the bus driver
|
|
RecvOp - Is this part of isoch callback, or AddrRange Callback
|
|
pIndicatedStruct - NotificationInfo or IsochDescriptor
|
|
pRcvInfo - Recv Structure that will be updated
|
|
|
|
Return Value:
|
|
Success - if all the operations succeeded
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PDATA_FORMAT pData = NULL;
|
|
NDIS1394_UNFRAGMENTED_HEADER EncapHeader;
|
|
PNDIS1394_UNFRAGMENTED_HEADER pEncapHeader = NULL;
|
|
NDIS1394_FRAGMENT_LF lf;
|
|
ULONG UlongLf;
|
|
|
|
|
|
NdisZeroMemory (pRcvInfo , sizeof (NIC_RECV_DATA_INFO) );
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==>nicValidateRecvData pMdl %x, RecvOp %x, pIndicatedStruct %x, pRcvInfo %x",
|
|
pMdl, RecvOp , pIndicatedStruct, pRcvInfo));
|
|
|
|
ASSERT (RecvOp == IsochReceive || RecvOp == AddressRange);
|
|
|
|
pRcvInfo->RecvOp = RecvOp;
|
|
pRcvInfo->pVc = pVc;
|
|
|
|
do
|
|
{
|
|
if (pMdl == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
BREAK (TM_Recv, ("nicValidateRecvData , no Mdl present") );
|
|
}
|
|
|
|
pRcvInfo->p1394Data = (PPACKET_FORMAT)NIC_GET_SYSTEM_ADDRESS_FOR_MDL (pMdl);
|
|
|
|
if (pRcvInfo->p1394Data == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Check minimum valid packet size . Checks whether the data length that was passed to us includes
|
|
// at least the first byte of data
|
|
//
|
|
|
|
if (RecvOp == IsochReceive)
|
|
{
|
|
NdisStatus = nicValidateRecvDataIsoch (pMdl,
|
|
(PISOCH_DESCRIPTOR)pIndicatedStruct,
|
|
pVc,
|
|
pRcvInfo
|
|
);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Validation failed . exit
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get to the Encap header. Should be at the same position for Fragmented and nonfragmented
|
|
//
|
|
pEncapHeader = &pRcvInfo->p1394Data->IsochReceiveNonFragmented.NonFragmentedHeader;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
NdisStatus = nicValidateRecvDataFifo(pMdl,(PNOTIFICATION_INFO)pIndicatedStruct,pVc,pRcvInfo);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
// Failure
|
|
break;
|
|
}
|
|
|
|
pEncapHeader = &pRcvInfo->p1394Data->AsyncWriteNonFragmented.NonFragmentedHeader;
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Byteswap Unfrag Header into a local variable
|
|
//
|
|
//EncapHeader.HeaderUlong = SwapBytesUlong (pEncapHeader->HeaderUlong);
|
|
|
|
EncapHeader.HeaderUlong = SWAPBYTES_ULONG (pEncapHeader->HeaderUlong);
|
|
|
|
EncapHeader.HeaderUlong = pEncapHeader->HeaderUlong & 0x000000C0;
|
|
EncapHeader.HeaderUlong = EncapHeader.HeaderUlong >> 6;
|
|
|
|
pRcvInfo->lf = EncapHeader.HeaderUlong ;
|
|
|
|
//
|
|
// Update the lf
|
|
//
|
|
|
|
pRcvInfo->lf = EncapHeader.HeaderUlong;
|
|
TRACE (TL_V, TM_Reas,("Header %x\n",pRcvInfo->lf ) );
|
|
|
|
ASSERT (EncapHeader.HeaderUlong <= lf_InteriorFragment);
|
|
|
|
|
|
if (pRcvInfo->lf != lf_Unfragmented)
|
|
{
|
|
pRcvInfo->fFragmented = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pRcvInfo->fFragmented = FALSE;
|
|
}
|
|
|
|
if (pRcvInfo->DataLength > pVc->Hdr.MTU)
|
|
{
|
|
//
|
|
// This cannot belong to us
|
|
//
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
pRcvInfo->pEncapHeader = (PVOID)pEncapHeader;
|
|
|
|
//
|
|
// Spew out all the information discovered
|
|
//
|
|
TRACE ( TL_V, TM_Recv, ( "lf %x, p1394Data %x, Length1394 %x, DataLength %x, pEncapHeader %x " ,
|
|
pRcvInfo->lf,
|
|
pRcvInfo->p1394Data,
|
|
pRcvInfo->Length1394,
|
|
pRcvInfo->DataLength,
|
|
pRcvInfo->pEncapHeader ) );
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicValidateRecvData %x", NdisStatus));
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicInitRecvDataFragmented (
|
|
IN PMDL pMdl,
|
|
IN BUS_OPERATION RecvOp,
|
|
IN PVOID pIndicatedStruct,
|
|
OUT PNIC_RECV_DATA_INFO pRcvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The routine will extract from the packet all the information that is required for reassembly
|
|
and store it in the pRcvInfo
|
|
|
|
Arguments:
|
|
pMdl - Indicated Mdl
|
|
RecvOp - IsochReceive ot AddressRange Callback
|
|
pIndicatedStruct - IsochDesc or Address Fifo
|
|
pRcvInfo - output structure
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PNOTIFICATION_INFO pNotificationInfo = NULL;
|
|
PGASP_HEADER pGaspHeader = NULL;
|
|
PNDIS1394_FRAGMENT_HEADER pEncapHeader = NULL;
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicInitRecvDataFragmented pMdl, %x, RecvOp %x, pIndicatedStruct %x, pRcvInfo %x",
|
|
pMdl, RecvOp, pIndicatedStruct, pRcvInfo));
|
|
|
|
do
|
|
{
|
|
pRcvInfo->pMdl = pMdl;
|
|
|
|
|
|
if (RecvOp == IsochReceive)
|
|
{
|
|
|
|
pRcvInfo->NdisPktContext.pIsochContext = (PISOCH_DESCRIPTOR) pIndicatedStruct;
|
|
|
|
}
|
|
else
|
|
{
|
|
pNotificationInfo = (PNOTIFICATION_INFO) pIndicatedStruct;
|
|
|
|
|
|
pRcvInfo->NdisPktContext.pFifoContext = pNotificationInfo->Fifo;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now byte swap the fragment header so it can be correctly interpreted
|
|
//
|
|
pEncapHeader = (PNDIS1394_FRAGMENT_HEADER )pRcvInfo->pEncapHeader;
|
|
|
|
pRcvInfo->FragmentHeader.u.FH_High = SWAPBYTES_ULONG(pEncapHeader->u.FH_High);
|
|
pRcvInfo->FragmentHeader.u1.FH_Low = SWAPBYTES_ULONG(pEncapHeader->u1.FH_Low);
|
|
|
|
//
|
|
// Now get the Dgl
|
|
//
|
|
pRcvInfo->Dgl = (USHORT)pRcvInfo->FragmentHeader.u1.SecondQuadlet.FH_dgl;
|
|
|
|
if (pRcvInfo->lf == lf_FirstFragment)
|
|
{
|
|
pRcvInfo->fFirstFragment = TRUE;
|
|
pRcvInfo->EtherType = pRcvInfo->FragmentHeader.u.FirstQuadlet_FirstFragment.FH_EtherType;
|
|
pRcvInfo->FragmentOffset = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
pRcvInfo->fFirstFragment = FALSE ;
|
|
pRcvInfo->FragmentOffset = pRcvInfo->FragmentHeader.u.FirstQuadlet.FH_fragment_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pRcvInfo->BufferSize = pRcvInfo->FragmentHeader.u.FirstQuadlet.FH_buffersize ;
|
|
|
|
//
|
|
// Spew out all the information that has been found
|
|
//
|
|
TRACE ( TL_V, TM_Recv, (" SourceId %x, FragHead Hi %x, FragHead Lo %x, Dgl %x, fFirstFragment %x",
|
|
pRcvInfo->SourceID,
|
|
pRcvInfo->FragmentHeader.u.FH_High,
|
|
pRcvInfo->FragmentHeader.u1.FH_Low ,
|
|
pRcvInfo->Dgl,
|
|
pRcvInfo->fFirstFragment ) );
|
|
|
|
TRACE ( TL_V, TM_Recv, (" Fragment Offset %x, bufferSize %x", pRcvInfo->FragmentOffset, pRcvInfo->BufferSize));
|
|
ASSERT (pRcvInfo->SourceID < 64);
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<==nicInitRecvDataFragmented " ));
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicInsertFragmentInReassembly (
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
PNIC_RECV_DATA_INFO pRcvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks for over laps and if valid then copies current fragment
|
|
into the table
|
|
|
|
This function does the validation for overlaps
|
|
|
|
Arguments:
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
PNDIS_BUFFER pNdisBuffer,
|
|
PMDL pMdl,
|
|
PVOID pIndicatedStructure,
|
|
ULONG FragOffset,
|
|
ULONG IPLength
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
BOOLEAN fFragPositionFound = FALSE;
|
|
ULONG FragmentNum = 0;
|
|
BOOLEAN Completed = FALSE;
|
|
PNDIS_BUFFER pNdisBuffer = pRcvInfo->pNdisBuffer;
|
|
PMDL pMdl = pRcvInfo->pMdl;
|
|
PVOID pIndicatedStructure = pRcvInfo->NdisPktContext.pCommon;
|
|
ULONG FragOffset = pRcvInfo->FragmentOffset;
|
|
ULONG IPLength = pRcvInfo->DataLength - sizeof (NDIS1394_FRAGMENT_HEADER);
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "==> nicInsertFragmentInReassembly " ));
|
|
|
|
|
|
do
|
|
{
|
|
if (pReassembly->BufferSize != 0 &&
|
|
FragOffset >= pReassembly->BufferSize )
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// First Find the correct entry in the frag table.
|
|
//
|
|
|
|
nicFindInsertionPosition (pReassembly,
|
|
FragOffset,
|
|
IPLength,
|
|
&FragmentNum);
|
|
|
|
if (FragmentNum == FRAGMENT_NUM_INVALID ||
|
|
FragmentNum > (MAX_ALLOWED_FRAGMENTS-1))
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (pReassembly->FragTable[FragmentNum].IPLength != 0)
|
|
{
|
|
//
|
|
// we must copy the current fragments descriptors in the table
|
|
// so as not to overwrite the table
|
|
//
|
|
LONG OffsetIndex =0;
|
|
|
|
//
|
|
// First lets check for overlaps. Do we overlap the last fragment.
|
|
// At this point, FragmentNum contains the record for the
|
|
// next fragment in the reassembly
|
|
//
|
|
if (FragmentNum != 0)
|
|
{
|
|
ULONG PrevFragmentOffset = pReassembly->FragTable[FragmentNum-1].Offset ;
|
|
ULONG PrevFramentLength = pReassembly->FragTable[FragmentNum-1].IPLength ;
|
|
|
|
ULONG EndOfPrevFragment = PrevFramentLength + PrevFragmentOffset ;
|
|
|
|
if (EndOfPrevFragment > FragOffset)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Do we overlap the next fragment
|
|
//
|
|
if (FragmentNum < pReassembly->MaxOffsetTableIndex)
|
|
{
|
|
ULONG EndOfCurrentFragment = FragOffset + IPLength;
|
|
ULONG StartOfNextFragment = pReassembly->FragTable[FragmentNum].Offset ;
|
|
|
|
|
|
if (EndOfCurrentFragment > StartOfNextFragment)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now make room for this fragment
|
|
//
|
|
OffsetIndex = pReassembly->MaxOffsetTableIndex ;
|
|
|
|
if (OffsetIndex >= MAX_ALLOWED_FRAGMENTS)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
ASSERT(OffsetIndex > MAX_ALLOWED_FRAGMENTS) ;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Signed compare and move the records ahead by one
|
|
//
|
|
while (OffsetIndex >= (LONG)FragmentNum)
|
|
{
|
|
pReassembly->FragTable[OffsetIndex+1].Offset = pReassembly->FragTable[OffsetIndex].Offset ;
|
|
pReassembly->FragTable[OffsetIndex+1].IPLength = pReassembly->FragTable[OffsetIndex].IPLength;
|
|
pReassembly->FragTable[OffsetIndex+1].pMdl = pReassembly->FragTable[OffsetIndex].pMdl;
|
|
pReassembly->FragTable[OffsetIndex+1].pNdisBuffer= pReassembly->FragTable[OffsetIndex].pNdisBuffer;
|
|
pReassembly->FragTable[OffsetIndex+1].pNdisBuffer= pReassembly->FragTable[OffsetIndex].pNdisBuffer;
|
|
pReassembly->FragTable[OffsetIndex+1].IndicatedStructure.pCommon = pReassembly->FragTable[OffsetIndex].IndicatedStructure.pCommon ;
|
|
pReassembly->FragTable[OffsetIndex+1].FragHeader = pReassembly->FragTable[OffsetIndex].FragHeader;
|
|
|
|
OffsetIndex --;
|
|
}
|
|
|
|
}
|
|
|
|
pNdisBuffer->Next = NULL;
|
|
pMdl->Next = NULL;
|
|
|
|
//
|
|
// Copy the current fragment into the table
|
|
//
|
|
pReassembly->FragTable[FragmentNum].Offset = FragOffset;
|
|
pReassembly->FragTable[FragmentNum].IPLength = IPLength;
|
|
pReassembly->FragTable[FragmentNum].pNdisBuffer = pNdisBuffer;
|
|
pReassembly->FragTable[FragmentNum].pMdl = pMdl;
|
|
pReassembly->FragTable[FragmentNum].FragHeader = pRcvInfo->FragmentHeader;
|
|
|
|
if (pReassembly->ReceiveOp == IsochReceive)
|
|
{
|
|
pReassembly->FragTable[FragmentNum].IndicatedStructure.pCommon = &((PISOCH_DESCRIPTOR)pIndicatedStructure)->DeviceReserved[IsochNext];
|
|
}
|
|
else
|
|
{
|
|
pReassembly->FragTable[FragmentNum].IndicatedStructure.pFifo = (PADDRESS_FIFO)pIndicatedStructure;
|
|
}
|
|
|
|
pReassembly->BytesRecvSoFar += IPLength;
|
|
//
|
|
// Now increment the Max offset
|
|
//
|
|
|
|
pReassembly->MaxOffsetTableIndex ++;
|
|
|
|
if (pReassembly->BufferSize == 0)
|
|
{
|
|
pReassembly->BufferSize = pRcvInfo->BufferSize;
|
|
}
|
|
|
|
//
|
|
// Add the unfragmented header here as we have to extract the EtherType here
|
|
//
|
|
if (pRcvInfo->fFirstFragment == TRUE)
|
|
{
|
|
|
|
pReassembly->EtherType = (USHORT)pRcvInfo->EtherType;
|
|
|
|
nicAddUnfragmentedHeader (pReassembly, pRcvInfo->pNdisBufferData );
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// According to the RFC, the buffersize of the reassembled packet
|
|
// is 1 less than the number of bytes in the packet
|
|
//
|
|
if (pReassembly->BytesRecvSoFar == pReassembly->BufferSize + 1)
|
|
{
|
|
|
|
nicChainReassembly (pReassembly);
|
|
|
|
pReassembly->fReassemblyComplete = TRUE;
|
|
|
|
RemoveEntryList (&pReassembly->ReassemblyListEntry);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
TRACE( TL_T, TM_Recv, ( "<== nicInsertFragmentInReassembly Status %x, Complete ", NdisStatus , pReassembly->fReassemblyComplete ));
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicFindInsertionPosition (
|
|
PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
|
|
ULONG FragOffset,
|
|
ULONG IPLength,
|
|
PULONG pFragmentNum
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions figures out where should the new fragment be inserted into
|
|
our tracking array. If this is our first fragment, 0 is returned. If the offset
|
|
is greater than the last fragment, the next available position in the array is
|
|
returned.
|
|
|
|
If the new framgent is somewhere in the middle, than the position is based on
|
|
the offset of the newly arrived packet in relation to the already arrived fragment's
|
|
offset
|
|
|
|
Arguments:
|
|
pReassembly, - Our tracking structure
|
|
FragOffset - The Offset of the new fragment
|
|
IPLength, - The length of the new fragment
|
|
pFragmentNum - the output variable
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG FragmentNum = 0;
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// First Do quick checks for Inorder reassembly
|
|
//
|
|
|
|
//
|
|
// Is it the first arrived fragment
|
|
//
|
|
if (pReassembly->MaxOffsetTableIndex == 0 ||
|
|
FragOffset < pReassembly->FragTable[0].Offset +pReassembly->FragTable[0].IPLength )
|
|
{
|
|
FragmentNum = 0;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Do we need to insert it in the last position
|
|
//
|
|
if ((pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1].Offset +
|
|
pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1].IPLength ) <=
|
|
FragOffset)
|
|
{
|
|
|
|
FragmentNum = pReassembly->MaxOffsetTableIndex;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now walk the table and try to find the correct offset
|
|
// We know there is atleast one entry and the current fragment
|
|
// goes is not the last entry
|
|
//
|
|
while ( FragmentNum != pReassembly->MaxOffsetTableIndex)
|
|
{
|
|
if (FragOffset < pReassembly->FragTable[FragmentNum].Offset)
|
|
{
|
|
//
|
|
//We have found the Correct position
|
|
//
|
|
break;
|
|
}
|
|
|
|
FragmentNum++;
|
|
|
|
|
|
|
|
}
|
|
ASSERT (FragmentNum != pReassembly->MaxOffsetTableIndex);
|
|
|
|
FragmentNum = FRAGMENT_NUM_INVALID;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
*pFragmentNum = FragmentNum;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
nicChainReassembly (
|
|
IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Chains the mdl, ndis buffers and indicated structures
|
|
This can be called from abort on the reasssembly complete code path
|
|
|
|
Arguments:
|
|
pReassembly
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG i = 0;
|
|
|
|
|
|
//
|
|
// first chain all fragments save the last one
|
|
//
|
|
while (i< pReassembly->MaxOffsetTableIndex-1)
|
|
{
|
|
PFRAGMENT_DESCRIPTOR pCurr = & pReassembly->FragTable[i];
|
|
PFRAGMENT_DESCRIPTOR pNext = & pReassembly->FragTable[i+1];
|
|
|
|
ASSERT (pNext->IPLength != 0);
|
|
|
|
pCurr->pMdl->Next = pNext->pMdl;
|
|
pCurr->pNdisBuffer->Next = pNext->pNdisBuffer;
|
|
pCurr->IndicatedStructure.pListEntry->Next = pNext->IndicatedStructure.pListEntry;
|
|
|
|
i++;
|
|
}
|
|
|
|
|
|
//
|
|
// Clear the next pointers for the last descriptor
|
|
//
|
|
{
|
|
PFRAGMENT_DESCRIPTOR pLast = & pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1];
|
|
pLast->pMdl->Next = NULL;
|
|
pLast->pNdisBuffer->Next = NULL;
|
|
pLast->IndicatedStructure.pListEntry->Next = NULL;
|
|
|
|
}
|
|
|
|
pReassembly->pHeadNdisBuffer = pReassembly->FragTable[0].pNdisBuffer;
|
|
pReassembly->pHeadMdl = pReassembly->FragTable[0].pMdl;
|
|
|
|
if (pReassembly->ReceiveOp == IsochReceive)
|
|
{
|
|
//
|
|
// The pointer currently has the Next field. But the Head expects that start of an IsochDescriptor
|
|
//
|
|
pReassembly->Head.pCommon = CONTAINING_RECORD (pReassembly->FragTable[0].IndicatedStructure.pCommon,
|
|
ISOCH_DESCRIPTOR,
|
|
DeviceReserved[IsochNext] );
|
|
|
|
}
|
|
else
|
|
{
|
|
pReassembly->Head.pCommon = pReassembly->FragTable[0].IndicatedStructure.pCommon;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicInitSerializedReassemblyStruct(
|
|
PADAPTERCB pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize the Reassembly serialization structure
|
|
|
|
Arguments:
|
|
padapter
|
|
|
|
Return Value:
|
|
Success
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
NdisZeroMemory (&pAdapter->Reassembly, sizeof(pAdapter->Reassembly));
|
|
InitializeListHead(&pAdapter->Reassembly.Queue); // Not be Used
|
|
|
|
NdisInitializeEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
|
|
pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
|
|
|
|
NdisMInitializeTimer (&pAdapter->Reassembly.Timer,
|
|
pAdapter->MiniportAdapterHandle,
|
|
ReassemblyTimerFunction ,
|
|
pAdapter);
|
|
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
nicDeInitSerializedReassmblyStruct(
|
|
PADAPTERCB pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Deinits the Reassembly routine routine
|
|
|
|
if the timer is set, it waits the timer out.
|
|
As all the reassemblies will be marked as aborted in nicFreeAllPendingReassemblies (below)
|
|
it queues a timer one last time to go in and delete all the reassembly structures.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
do
|
|
{
|
|
|
|
BOOLEAN bTimerAlreadySet = FALSE;
|
|
//
|
|
// If this adapter is halting, then mark all reassemblies as aborted
|
|
//
|
|
nicFreeAllPendingReassemblyStructures(pAdapter);
|
|
|
|
|
|
//
|
|
// First wait for any pending timer to fire.
|
|
//
|
|
ADAPTER_ACQUIRE_LOCK (pAdapter);
|
|
bTimerAlreadySet = pAdapter->Reassembly.bTimerAlreadySet ;
|
|
if (bTimerAlreadySet == TRUE)
|
|
{
|
|
//
|
|
// if the (bTimerAlreadySet==TRUE ), it means we can clear/init the event.
|
|
// Because the TimerAlreadySet is cleared and the Event is always set within
|
|
// the same Acquire-Release Spinlock
|
|
//
|
|
NdisResetEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
|
|
pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
|
|
|
|
|
|
}
|
|
ADAPTER_RELEASE_LOCK(pAdapter);
|
|
|
|
|
|
if (bTimerAlreadySet == TRUE)
|
|
{
|
|
NdisWaitEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent,WAIT_INFINITE);
|
|
}
|
|
|
|
//
|
|
// Reset the event , to prepare for the next wait.
|
|
//
|
|
pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
|
|
|
|
NdisResetEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
|
|
|
|
|
|
//
|
|
// Now enqueue the timer one last time to free all pending reassemblies.
|
|
// and Stop any further reassembly timers
|
|
//
|
|
|
|
nicQueueReassemblyTimer (pAdapter,TRUE);
|
|
|
|
|
|
//
|
|
// Wait for the last timer to fire.
|
|
//
|
|
|
|
bTimerAlreadySet = pAdapter->Reassembly.bTimerAlreadySet ;
|
|
|
|
//
|
|
// Only do the wait, if nicQueueReassembly Timer actually queued a reassembly timer
|
|
//
|
|
if (bTimerAlreadySet == TRUE)
|
|
{
|
|
NdisWaitEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent,WAIT_INFINITE);
|
|
}
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
nicQueueReassemblyTimer(
|
|
PADAPTERCB pAdapter,
|
|
BOOLEAN fIsLastTimer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queues a timer to be fired in one second.
|
|
If there is already a timer active it quietly exists
|
|
|
|
Arguments:
|
|
Self explanatory
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
BOOLEAN fSetTimer = FALSE;
|
|
|
|
do
|
|
{
|
|
|
|
|
|
ADAPTER_ACQUIRE_LOCK (pAdapter);
|
|
|
|
|
|
|
|
//
|
|
// If the timer is not set, then this thread must set it
|
|
//
|
|
|
|
|
|
if (pAdapter->Reassembly.bTimerAlreadySet == FALSE && // timer is not set
|
|
pAdapter->Reassembly.PktsInQueue > 0 && // there are packets to be reassembled
|
|
ADAPTER_TEST_FLAG (pAdapter,fADAPTER_NoMoreReassembly) == FALSE ) // the adapter is not halting
|
|
{
|
|
fSetTimer = TRUE;
|
|
pAdapter->Reassembly.bTimerAlreadySet = TRUE;
|
|
}
|
|
|
|
if (fIsLastTimer == TRUE)
|
|
{
|
|
//
|
|
// Stop any further reassembly timers
|
|
//
|
|
|
|
ADAPTER_SET_FLAG (pAdapter, fADAPTER_NoMoreReassembly);
|
|
}
|
|
|
|
|
|
ADAPTER_RELEASE_LOCK (pAdapter);
|
|
|
|
//
|
|
// Now queue the timer
|
|
//
|
|
|
|
if (fSetTimer == TRUE)
|
|
{
|
|
//
|
|
// Set the timer
|
|
//
|
|
|
|
|
|
|
|
TRACE( TL_V, TM_Recv, ( " Set Timer "));
|
|
|
|
NdisMSetTimer ( &pAdapter->Reassembly.Timer, 2000);
|
|
|
|
|
|
}
|
|
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
nicFifoAllocationScheme (
|
|
PRECVFIFO_VCCB pRecvFIFOVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
If there are less than 20 fifo allocated, it starts a workitem to
|
|
allocate a lot more fifos
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN fQueueWorkItemInThisThread = FALSE;
|
|
PNIC_WORK_ITEM pFifoWorkItem = NULL;
|
|
|
|
do
|
|
{
|
|
if (pRecvFIFOVc->NumAllocatedFifos != NUM_RECV_FIFO_FIRST_PHASE)
|
|
{
|
|
break ;
|
|
}
|
|
|
|
if (pRecvFIFOVc->FifoWorkItemInProgress == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pFifoWorkItem = ALLOC_NONPAGED (sizeof(NIC_WORK_ITEM), MTAG_WORKITEM);
|
|
|
|
if (pFifoWorkItem == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
VC_ACQUIRE_LOCK(pRecvFIFOVc);
|
|
|
|
if (VC_ACTIVE (pRecvFIFOVc) &&
|
|
pRecvFIFOVc->FifoWorkItemInProgress == FALSE)
|
|
{
|
|
fQueueWorkItemInThisThread = TRUE;
|
|
|
|
|
|
pRecvFIFOVc->FifoWorkItemInProgress = TRUE;
|
|
|
|
// Add reference to the VC . Derefed in the WorkItem
|
|
//
|
|
nicReferenceCall((VCCB*)pRecvFIFOVc, "Queueing miniport Work Item\n");
|
|
}
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
if (fQueueWorkItemInThisThread == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Queue the workitem
|
|
//
|
|
NdisInitializeWorkItem ( &pFifoWorkItem->NdisWorkItem,
|
|
(NDIS_PROC) nicAllocateRemainingFifoWorkItem,
|
|
(PVOID) pRecvFIFOVc);
|
|
|
|
NdisScheduleWorkItem (&pFifoWorkItem->NdisWorkItem);
|
|
|
|
} while (FALSE);
|
|
|
|
if (fQueueWorkItemInThisThread == FALSE &&
|
|
pFifoWorkItem != NULL)
|
|
{
|
|
FREE_NONPAGED (pFifoWorkItem);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
nicAllocateRemainingFifoWorkItem (
|
|
PNDIS_WORK_ITEM pNdisWorkItem,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This follows a simple algorithm. It simply allocates fifos
|
|
until we reach our expected number of 100
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PRECVFIFO_VCCB pRecvFIFOVc = NULL;
|
|
BOOLEAN fIsVcActive = FALSE;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
|
|
pRecvFIFOVc = (PRECVFIFO_VCCB) (Context);
|
|
|
|
fIsVcActive = VC_ACTIVE(pRecvFIFOVc);
|
|
|
|
do
|
|
{
|
|
PADDRESS_FIFO pRecvFifoElement = NULL;
|
|
|
|
fIsVcActive = VC_ACTIVE(pRecvFIFOVc);
|
|
|
|
if (fIsVcActive == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisStatus = nicGetInitializedAddressFifoElement (pRecvFIFOVc->Hdr.MTU,
|
|
&pRecvFifoElement);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT (pRecvFifoElement != NULL);
|
|
|
|
ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
|
|
(PSLIST_ENTRY)&pRecvFifoElement->FifoList,
|
|
&pRecvFIFOVc->FifoSListSpinLock);
|
|
|
|
//
|
|
// Add this once for every Address Fifo element inserted
|
|
// Will be decremented by a call to nicFreeAddressFifo
|
|
//
|
|
VC_ACQUIRE_LOCK (pRecvFIFOVc);
|
|
|
|
nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicWorkItemFileSList");
|
|
|
|
pRecvFIFOVc->NumAllocatedFifos++;
|
|
|
|
VC_RELEASE_LOCK (pRecvFIFOVc);
|
|
|
|
|
|
} while (pRecvFIFOVc->NumAllocatedFifos < NUM_RECV_FIFO_BUFFERS);
|
|
|
|
pRecvFIFOVc->FifoWorkItemInProgress = FALSE;
|
|
|
|
nicDereferenceCall ((PVCCB)pRecvFIFOVc,"nicAllocateRemainingFifoWorkItem" );
|
|
|
|
FREE_NONPAGED(pNdisWorkItem);
|
|
|
|
}
|
|
|