3880 lines
74 KiB
C
3880 lines
74 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 FORE Systems, Inc.
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
Abstract:
|
|
|
|
Utility routines.
|
|
|
|
Author:
|
|
|
|
Larry Cleeton, FORE Systems (v-lcleet@microsoft.com, lrc@fore.com)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
VOID
|
|
AtmLaneInitGlobals(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the global data structures.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(InitGlobals);
|
|
|
|
NdisZeroMemory(pAtmLaneGlobalInfo, sizeof(ATMLANE_GLOBALS));
|
|
|
|
INIT_GLOBAL_LOCK(pAtmLaneGlobalInfo);
|
|
|
|
NdisInitializeListHead(&pAtmLaneGlobalInfo->AdapterList);
|
|
|
|
#if DBG_TRACE
|
|
//
|
|
// Init trace log
|
|
//
|
|
pTraceLogSpace = NULL;
|
|
InitTraceLog(&TraceLog, NULL, 0);
|
|
|
|
// allocate space and init trace log if configured
|
|
|
|
if (DbgLogSize > 0)
|
|
{
|
|
ALLOC_MEM(&pTraceLogSpace, DbgLogSize);
|
|
if (pTraceLogSpace == NULL)
|
|
{
|
|
DBGP((0, "Failed to allocate %d bytes space for trace log\n",
|
|
DbgLogSize));
|
|
}
|
|
else
|
|
{
|
|
InitTraceLog(
|
|
&TraceLog,
|
|
pTraceLogSpace,
|
|
DbgLogSize);
|
|
}
|
|
}
|
|
#endif // DBG_TRACE
|
|
|
|
TRACEOUT(InitGlobals);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PATMLANE_ADAPTER
|
|
AtmLaneAllocAdapter(
|
|
IN PNDIS_STRING pDeviceName,
|
|
IN PVOID SystemSpecific1
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates an Adapter data structure.
|
|
|
|
Arguments:
|
|
|
|
pDeviceName - Points to name of adapter device
|
|
SystemSpecific1 - What we got into our BindAdapter handler.
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated Adapter structure or NULL.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ADAPTER pAdapter;
|
|
NDIS_STATUS Status;
|
|
ULONG TotalLength;
|
|
PNDIS_STRING pConfigString;
|
|
|
|
TRACEIN(AllocAdapter);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pAdapter = NULL_PATMLANE_ADAPTER;
|
|
pConfigString = (PNDIS_STRING)SystemSpecific1;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate everything. Adapter struct size plus two
|
|
// UNICODE string buffers with extra WCHAR each for NULL termination.
|
|
//
|
|
TotalLength = sizeof(ATMLANE_ADAPTER) +
|
|
pDeviceName->MaximumLength + sizeof(WCHAR) +
|
|
pConfigString->MaximumLength + sizeof(WCHAR);
|
|
|
|
ALLOC_MEM(&pAdapter, TotalLength);
|
|
|
|
if (NULL_PATMLANE_ADAPTER == pAdapter)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Zero it.
|
|
//
|
|
NdisZeroMemory(pAdapter, TotalLength);
|
|
|
|
//
|
|
// Debugging info.
|
|
//
|
|
#if DBG
|
|
pAdapter->atmlane_adapter_sig = atmlane_adapter_signature;
|
|
#endif
|
|
|
|
//
|
|
// Init lock.
|
|
//
|
|
INIT_ADAPTER_LOCK(pAdapter);
|
|
|
|
//
|
|
// Init blocking objects.
|
|
//
|
|
INIT_BLOCK_STRUCT(&pAdapter->Block);
|
|
INIT_BLOCK_STRUCT(&pAdapter->UnbindBlock);
|
|
|
|
//
|
|
// Init ElanList
|
|
//
|
|
NdisInitializeListHead(&pAdapter->ElanList);
|
|
|
|
//
|
|
// Copy in the device name
|
|
//
|
|
pAdapter->DeviceName.MaximumLength = pDeviceName->MaximumLength + sizeof(WCHAR);
|
|
pAdapter->DeviceName.Length = pDeviceName->Length;
|
|
pAdapter->DeviceName.Buffer = (PWCHAR)((PUCHAR)pAdapter + sizeof(ATMLANE_ADAPTER));
|
|
NdisMoveMemory(pAdapter->DeviceName.Buffer,
|
|
pDeviceName->Buffer,
|
|
pDeviceName->Length);
|
|
pAdapter->DeviceName.Buffer[pDeviceName->Length/sizeof(WCHAR)] = ((WCHAR)0);
|
|
|
|
|
|
//
|
|
// Copy in the Config string - we will use this to open the
|
|
// registry section for this adapter at a later point.
|
|
//
|
|
pAdapter->ConfigString.MaximumLength = pConfigString->MaximumLength;
|
|
pAdapter->ConfigString.Length = pConfigString->Length;
|
|
pAdapter->ConfigString.Buffer = (PWCHAR)((PUCHAR)pAdapter +
|
|
sizeof(ATMLANE_ADAPTER) +
|
|
pAdapter->DeviceName.MaximumLength);
|
|
|
|
NdisMoveMemory(pAdapter->ConfigString.Buffer,
|
|
pConfigString->Buffer,
|
|
pConfigString->Length);
|
|
pAdapter->ConfigString.Buffer[pConfigString->Length/sizeof(WCHAR)] = ((WCHAR)0);
|
|
|
|
//
|
|
// Link into global Adapter list.
|
|
//
|
|
ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
|
|
InsertTailList(&pAtmLaneGlobalInfo->AdapterList, &pAdapter->Link);
|
|
RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
|
|
|
|
} while (FALSE);
|
|
|
|
TRACEOUT(AllocAdapter);
|
|
|
|
return pAdapter;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneDeallocateAdapter(
|
|
IN PATMLANE_ADAPTER pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an Adapter structure. It is assumed that all
|
|
references to this structure have gone, so it is not necessary
|
|
to acquire a lock to it.
|
|
|
|
Also unlink this from the global Adapter list.
|
|
|
|
Arguments:
|
|
|
|
pAdapter - Pointer to Adapter structure to be deallocated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_NAME pName;
|
|
|
|
|
|
STRUCT_ASSERT(pAdapter, atmlane_adapter);
|
|
|
|
TRACEIN(DeallocateAdapter);
|
|
|
|
ASSERT(pAdapter->RefCount == 0);
|
|
|
|
//
|
|
// Unlink from global Adapter list.
|
|
//
|
|
ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
|
|
RemoveEntryList(&pAdapter->Link);
|
|
RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
|
|
|
|
//
|
|
// Free the lock.
|
|
//
|
|
FREE_ADAPTER_LOCK(pAdapter);
|
|
|
|
#if DBG
|
|
pAdapter->atmlane_adapter_sig++;
|
|
#endif
|
|
|
|
//
|
|
// Free string buffers that may have been allocated
|
|
//
|
|
if (NULL != pAdapter->CfgUpperBindings.Buffer)
|
|
{
|
|
FREE_MEM(pAdapter->CfgUpperBindings.Buffer);
|
|
}
|
|
if (NULL != pAdapter->CfgElanName.Buffer)
|
|
{
|
|
FREE_MEM(pAdapter->CfgElanName.Buffer);
|
|
}
|
|
|
|
|
|
//
|
|
// Free the name lists that may have been allocated.
|
|
//
|
|
while (pAdapter->UpperBindingsList)
|
|
{
|
|
DBGP((1, "DeallocateAdapter: pname 0x%x\n"));
|
|
pName = pAdapter->UpperBindingsList;
|
|
pAdapter->UpperBindingsList = pName->pNext;
|
|
FREE_MEM(pName);
|
|
}
|
|
while (pAdapter->ElanNameList)
|
|
{
|
|
DBGP((1, "DeallocateAdapter: pname 0x%x\n"));
|
|
pName = pAdapter->ElanNameList;
|
|
pAdapter->ElanNameList = pName->pNext;
|
|
FREE_MEM(pName);
|
|
}
|
|
|
|
|
|
//
|
|
// Finally free the Adapter structure.
|
|
//
|
|
FREE_MEM(pAdapter);
|
|
|
|
TRACEOUT(DeallocateAdapter);
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
AtmLaneReferenceAdapter(
|
|
IN PATMLANE_ADAPTER pAdapter,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a references to an Adapter structure.
|
|
NOTE: The caller is assumed to possess the Adapter's lock.
|
|
|
|
Arguments:
|
|
|
|
pAdapter - Pointer to the Adapter structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bReferenced;
|
|
|
|
TRACEIN(ReferenceAdapter);
|
|
|
|
STRUCT_ASSERT(pAdapter, atmlane_adapter);
|
|
|
|
if ((pAdapter->Flags & ADAPTER_FLAGS_DEALLOCATING) == 0)
|
|
{
|
|
pAdapter->RefCount++;
|
|
bReferenced = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bReferenced = FALSE;
|
|
}
|
|
|
|
DBGP((5, "ReferenceAdapter: Adapter %x (%s) new count %d\n",
|
|
pAdapter, String, pAdapter->RefCount));
|
|
|
|
TRACEOUT(ReferenceAdapter);
|
|
|
|
return bReferenced;
|
|
}
|
|
|
|
ULONG
|
|
AtmLaneDereferenceAdapter(
|
|
IN PATMLANE_ADAPTER pAdapter,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from an Adapter structure.
|
|
If the reference count becomes zero, deallocate it.
|
|
NOTE: The caller is assumed to posses the Adapter's lock.
|
|
|
|
Arguments:
|
|
|
|
pAdapter - Pointer to an adapter structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
|
|
TRACEIN(DereferenceAdapter);
|
|
|
|
STRUCT_ASSERT(pAdapter, atmlane_adapter);
|
|
|
|
ASSERT(pAdapter->RefCount > 0);
|
|
|
|
rc = --(pAdapter->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
pAdapter->Flags |= ADAPTER_FLAGS_DEALLOCATING;
|
|
RELEASE_ADAPTER_LOCK(pAdapter);
|
|
AtmLaneDeallocateAdapter(pAdapter);
|
|
}
|
|
|
|
DBGP((5, "DereferenceAdapter: Adapter %x (%s) new count %d\n",
|
|
pAdapter, String, rc));
|
|
|
|
TRACEOUT(DereferenceAdapter);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AtmLaneAllocElan(
|
|
IN PATMLANE_ADAPTER pAdapter,
|
|
IN OUT PATMLANE_ELAN *ppElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates an ELAN data structure.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS or NDIS_STATUS_RESOURCES.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PATMLANE_ELAN pElan;
|
|
PATMLANE_MAC_ENTRY * pMacTable;
|
|
PATMLANE_TIMER_LIST pTimerList;
|
|
USHORT NameBufferSize;
|
|
UINT i;
|
|
ULONG SapSize;
|
|
PCO_SAP pLesSapInfo;
|
|
PCO_SAP pBusSapInfo;
|
|
PCO_SAP pDataSapInfo;
|
|
ULONG ElanNumber;
|
|
|
|
TRACEIN(AllocElan);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
pElan = NULL_PATMLANE_ELAN;
|
|
pMacTable = (PATMLANE_MAC_ENTRY *)NULL;
|
|
|
|
pLesSapInfo = pBusSapInfo = pDataSapInfo = (PCO_SAP)NULL;
|
|
|
|
SapSize = sizeof(CO_SAP)+sizeof(ATM_SAP)+sizeof(ATM_ADDRESS);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate everything.
|
|
//
|
|
ALLOC_MEM(&pElan, sizeof(ATMLANE_ELAN));
|
|
ALLOC_MEM((PVOID *)&pMacTable, ATMLANE_MAC_TABLE_SIZE*sizeof(PATMLANE_MAC_ENTRY));
|
|
ALLOC_MEM(&pLesSapInfo, SapSize);
|
|
ALLOC_MEM(&pBusSapInfo, SapSize);
|
|
ALLOC_MEM(&pDataSapInfo, SapSize);
|
|
|
|
if (NULL_PATMLANE_ELAN != pElan)
|
|
{
|
|
//
|
|
// Zero the Elan structure now so that we clean up properly
|
|
// if any errors occur later on.
|
|
//
|
|
NdisZeroMemory(pElan, sizeof(ATMLANE_ELAN));
|
|
}
|
|
|
|
if ((NULL_PATMLANE_ELAN == pElan) ||
|
|
(NULL == pMacTable) ||
|
|
(NULL == pLesSapInfo) ||
|
|
(NULL == pBusSapInfo) ||
|
|
(NULL == pDataSapInfo))
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate timer structures
|
|
//
|
|
for (i = 0; i < ALT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pElan->TimerList[i]);
|
|
#if DBG
|
|
pTimerList->atmlane_timerlist_sig = atmlane_timerlist_signature;
|
|
#endif
|
|
ALLOC_MEM(&(pTimerList->pTimers),
|
|
sizeof(ATMLANE_TIMER) * AtmLaneTimerListSize[i]);
|
|
if (NULL_PATMLANE_TIMER == pTimerList->pTimers)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Continue initializing the ELAN structure
|
|
//
|
|
#if DBG
|
|
//
|
|
// Signatures, for debugging.
|
|
//
|
|
pElan->atmlane_elan_sig = atmlane_elan_signature;
|
|
pElan->LesSap.atmlane_sap_sig = atmlane_sap_signature;
|
|
pElan->BusSap.atmlane_sap_sig = atmlane_sap_signature;
|
|
pElan->DataSap.atmlane_sap_sig = atmlane_sap_signature;
|
|
#endif
|
|
|
|
//
|
|
// Initialize state fields.
|
|
//
|
|
pElan->AdminState = ELAN_STATE_INIT;
|
|
pElan->State = ELAN_STATE_ALLOCATED;
|
|
NdisInitializeWorkItem(&pElan->EventWorkItem, AtmLaneEventHandler, pElan);
|
|
|
|
//
|
|
// Initialize spinlocks.
|
|
//
|
|
#if SENDLIST
|
|
NdisAllocateSpinLock(&pElan->SendListLock);
|
|
#endif // SENDLIST
|
|
INIT_ELAN_LOCK(pElan);
|
|
INIT_ELAN_MAC_TABLE_LOCK(pElan);
|
|
INIT_ELAN_ATM_LIST_LOCK(pElan);
|
|
INIT_ELAN_TIMER_LOCK(pElan);
|
|
INIT_BLOCK_STRUCT(&pElan->Block);
|
|
INIT_BLOCK_STRUCT(&pElan->InitBlock);
|
|
INIT_BLOCK_STRUCT(&pElan->AfBlock);
|
|
INIT_HEADER_LOCK(pElan);
|
|
|
|
//
|
|
// Init event queue.
|
|
//
|
|
InitializeListHead(&pElan->EventQueue);
|
|
|
|
//
|
|
// Initialize timer wheels.
|
|
//
|
|
for (i = 0; i < ALT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pElan->TimerList[i]);
|
|
NdisZeroMemory(
|
|
pTimerList->pTimers,
|
|
sizeof(ATMLANE_TIMER) * AtmLaneTimerListSize[i]
|
|
);
|
|
pTimerList->MaxTimer = AtmLaneMaxTimerValue[i];
|
|
pTimerList->TimerPeriod = AtmLaneTimerPeriod[i];
|
|
pTimerList->ListContext = (PVOID)pElan;
|
|
pTimerList->TimerListSize = AtmLaneTimerListSize[i];
|
|
|
|
INIT_SYSTEM_TIMER(
|
|
&(pTimerList->NdisTimer),
|
|
AtmLaneTickHandler,
|
|
(PVOID)pTimerList
|
|
);
|
|
}
|
|
|
|
//
|
|
// Initialize all sub-components.
|
|
//
|
|
NdisZeroMemory(pMacTable, ATMLANE_MAC_TABLE_SIZE*sizeof(PATMLANE_MAC_ENTRY));
|
|
NdisZeroMemory(pLesSapInfo, SapSize);
|
|
NdisZeroMemory(pBusSapInfo, SapSize);
|
|
NdisZeroMemory(pDataSapInfo, SapSize);
|
|
|
|
//
|
|
// Link sub-components to the Elan structure.
|
|
//
|
|
pElan->pMacTable = pMacTable;
|
|
|
|
pElan->LesSap.pInfo = pLesSapInfo;
|
|
pElan->BusSap.pInfo = pBusSapInfo;
|
|
pElan->DataSap.pInfo = pDataSapInfo;
|
|
|
|
//
|
|
// Link the Elan to the adapter.
|
|
//
|
|
pElan->pAdapter = pAdapter;
|
|
ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
//
|
|
// Find a free ELAN number.
|
|
//
|
|
for (ElanNumber = 0; ElanNumber <= pAdapter->ElanCount; ElanNumber++)
|
|
{
|
|
PATMLANE_ELAN pThisElan = NULL;
|
|
PLIST_ENTRY p;
|
|
|
|
for (p = pAdapter->ElanList.Flink;
|
|
p != &pAdapter->ElanList;
|
|
p = p->Flink)
|
|
{
|
|
pThisElan = CONTAINING_RECORD(p, ATMLANE_ELAN, Link);
|
|
|
|
if (pThisElan->ElanNumber == ElanNumber)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we made it to the end of the list without hitting
|
|
// the current ElanNumber. If so, use this ElanNumber.
|
|
//
|
|
if (p == &pAdapter->ElanList)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBGP((0, "%d Assign ElanNumber to ELAN %x\n", ElanNumber, pElan));
|
|
(VOID)AtmLaneReferenceAdapter(pAdapter, "elan");
|
|
InsertTailList(&pAdapter->ElanList, &pElan->Link);
|
|
pElan->ElanNumber = ElanNumber;
|
|
pAdapter->ElanCount++;
|
|
RELEASE_ADAPTER_LOCK(pAdapter);
|
|
|
|
//
|
|
// Cache NdisAdapterHandle.
|
|
//
|
|
pElan->NdisAdapterHandle = pAdapter->NdisAdapterHandle;
|
|
|
|
//
|
|
// Generate a MAC Address for the elan
|
|
//
|
|
AtmLaneGenerateMacAddr(pElan);
|
|
|
|
//
|
|
// Set the rest of the LANE Run-time parameters to defaults
|
|
//
|
|
pElan->ControlTimeout = LANE_C7_DEF;
|
|
pElan->MaxUnkFrameCount = LANE_C10_DEF;
|
|
pElan->MaxUnkFrameTime = LANE_C11_DEF;
|
|
pElan->VccTimeout = LANE_C12_DEF;
|
|
pElan->MaxRetryCount = LANE_C13_DEF;
|
|
pElan->AgingTime = LANE_C17_DEF;
|
|
pElan->ForwardDelayTime = LANE_C18_DEF;
|
|
pElan->ArpResponseTime = LANE_C20_DEF;
|
|
pElan->FlushTimeout = LANE_C21_DEF;
|
|
pElan->PathSwitchingDelay = LANE_C22_DEF;
|
|
pElan->ConnComplTimer = LANE_C28_DEF;
|
|
|
|
//
|
|
// Calc the bus rate limiter parameters
|
|
//
|
|
pElan->LimitTime = pElan->MaxUnkFrameTime * 1000;
|
|
pElan->IncrTime = pElan->LimitTime / pElan->MaxUnkFrameCount;
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
if (NDIS_STATUS_SUCCESS != Status)
|
|
{
|
|
//
|
|
// Failure cleanup.
|
|
//
|
|
if (NULL_PATMLANE_ELAN != pElan)
|
|
{
|
|
for (i = 0; i < ALT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pElan->TimerList[i]);
|
|
if (NULL != pTimerList->pTimers)
|
|
{
|
|
FREE_MEM(pTimerList->pTimers);
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pLesSapInfo)
|
|
{
|
|
FREE_MEM(pLesSapInfo);
|
|
}
|
|
if (NULL != pBusSapInfo)
|
|
{
|
|
FREE_MEM(pBusSapInfo);
|
|
}
|
|
if (NULL != pDataSapInfo)
|
|
{
|
|
FREE_MEM(pDataSapInfo);
|
|
}
|
|
if (NULL != pMacTable)
|
|
{
|
|
FREE_MEM(pMacTable);
|
|
}
|
|
if (NULL_PATMLANE_ELAN != pElan)
|
|
{
|
|
FREE_MEM(pElan);
|
|
pElan = NULL_PATMLANE_ELAN;
|
|
}
|
|
}
|
|
//
|
|
// Output pElan
|
|
//
|
|
*ppElan = pElan;
|
|
|
|
TRACEOUT(AllocElan);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneDeallocateElan(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an Elan structure. It is assumed that all
|
|
references to this structure have gone, so it is not necessary
|
|
to acquire a lock to it.
|
|
|
|
Also delink this from the Adapter's Elan list.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to Elan structure to be deallocated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ADAPTER pAdapter;
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
PATMLANE_ATM_ENTRY pNext;
|
|
UINT i;
|
|
|
|
TRACEIN(DeallocateElan);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ASSERT(pElan->RefCount == 0);
|
|
|
|
DBGP((0, "%d Deleting ELAN %p\n", pElan->ElanNumber, pElan));
|
|
|
|
|
|
//
|
|
// Free all subcomponents
|
|
//
|
|
|
|
//
|
|
// MAC Table
|
|
//
|
|
if ((PATMLANE_MAC_ENTRY *)NULL != pElan->pMacTable)
|
|
{
|
|
FREE_MEM(pElan->pMacTable);
|
|
pElan->pMacTable = (PATMLANE_MAC_ENTRY *)NULL;
|
|
}
|
|
|
|
//
|
|
// ATM Entry List
|
|
//
|
|
for (pAtmEntry = pElan->pAtmEntryList;
|
|
pAtmEntry != NULL_PATMLANE_ATM_ENTRY;
|
|
pAtmEntry = (PATMLANE_ATM_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pAtmEntry->pNext;
|
|
FREE_MEM(pAtmEntry);
|
|
}
|
|
pElan->pAtmEntryList = NULL_PATMLANE_ATM_ENTRY;
|
|
|
|
//
|
|
// Timers
|
|
//
|
|
for (i = 0; i < ALT_CLASS_MAX; i++)
|
|
{
|
|
PATMLANE_TIMER_LIST pTimerList = &(pElan->TimerList[i]);
|
|
if (NULL != pTimerList->pTimers)
|
|
{
|
|
FREE_MEM(pTimerList->pTimers);
|
|
}
|
|
pTimerList->pTimers = NULL_PATMLANE_TIMER;
|
|
}
|
|
|
|
//
|
|
// ProtocolPacketPool
|
|
// ProtocolBufferPool
|
|
// ProtocolBufList
|
|
//
|
|
AtmLaneDeallocateProtoBuffers(pElan);
|
|
|
|
//
|
|
// TransmitPacketPool
|
|
//
|
|
if (pElan->TransmitPacketPool != NULL_NDIS_HANDLE)
|
|
{
|
|
NdisFreePacketPool(pElan->TransmitPacketPool);
|
|
pElan->TransmitPacketPool = NULL_NDIS_HANDLE;
|
|
}
|
|
|
|
//
|
|
// ReceivePacketPool
|
|
//
|
|
if (pElan->ReceivePacketPool != NULL_NDIS_HANDLE)
|
|
{
|
|
NdisFreePacketPool(pElan->ReceivePacketPool);
|
|
pElan->ReceivePacketPool = NULL_NDIS_HANDLE;
|
|
}
|
|
|
|
//
|
|
// ReceiveBufferPool
|
|
//
|
|
if (pElan->ReceiveBufferPool != NULL_NDIS_HANDLE)
|
|
{
|
|
NdisFreeBufferPool(pElan->ReceiveBufferPool);
|
|
pElan->ReceiveBufferPool = NULL_NDIS_HANDLE;
|
|
}
|
|
|
|
//
|
|
// HeaderBufList
|
|
// pHeaderTrkList
|
|
//
|
|
AtmLaneDeallocateHeaderBuffers(pElan);
|
|
|
|
//
|
|
// PadBufList
|
|
// pPadTrkList
|
|
//
|
|
AtmLaneDeallocatePadBufs(pElan);
|
|
|
|
//
|
|
// Free the config strings
|
|
//
|
|
if (NULL != pElan->CfgBindName.Buffer)
|
|
{
|
|
FREE_MEM(pElan->CfgBindName.Buffer);
|
|
}
|
|
if (NULL != pElan->CfgDeviceName.Buffer)
|
|
{
|
|
FREE_MEM(pElan->CfgDeviceName.Buffer);
|
|
}
|
|
if (NULL != pElan->CfgElanName.Buffer)
|
|
{
|
|
FREE_MEM(pElan->CfgElanName.Buffer);
|
|
}
|
|
|
|
//
|
|
// Free the Sap info
|
|
//
|
|
|
|
if (NULL != pElan->LesSap.pInfo)
|
|
{
|
|
FREE_MEM(pElan->LesSap.pInfo);
|
|
}
|
|
if (NULL != pElan->BusSap.pInfo)
|
|
{
|
|
FREE_MEM(pElan->BusSap.pInfo);
|
|
}
|
|
if (NULL != pElan->DataSap.pInfo)
|
|
{
|
|
FREE_MEM(pElan->DataSap.pInfo);
|
|
}
|
|
|
|
//
|
|
// Free the locks.
|
|
//
|
|
#if SENDLIST
|
|
NdisFreeSpinLock(&pElan->SendListLock);
|
|
#endif // SENDLIST
|
|
FREE_ELAN_LOCK(pElan);
|
|
FREE_ELAN_MAC_TABLE_LOCK(pElan);
|
|
FREE_ELAN_ATM_LIST_LOCK(pElan);
|
|
FREE_ELAN_TIMER_LOCK(pElan);
|
|
FREE_BLOCK_STRUCT(&pElan->Block);
|
|
FREE_HEADER_LOCK(pElan);
|
|
|
|
AtmLaneUnlinkElanFromAdapter(pElan);
|
|
|
|
#if DBG
|
|
pElan->atmlane_elan_sig++;
|
|
#endif
|
|
//
|
|
// Finally free the Elan structure.
|
|
//
|
|
FREE_MEM(pElan);
|
|
|
|
TRACEOUT(DeallocateElan);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneReferenceElan(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a references to an Elan structure.
|
|
NOTE: The caller is assumed to possess the Elan's lock.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to the Elan structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(ReferenceElan);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
pElan->RefCount++;
|
|
|
|
DBGP((5, "ReferenceElan: Elan %p/%x (%s) new count %d\n",
|
|
pElan, pElan->Flags, String, pElan->RefCount));
|
|
|
|
TRACEOUT(ReferenceElan);
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
AtmLaneDereferenceElan(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from an Elan structure.
|
|
If the reference count becomes zero, deallocate it.
|
|
NOTE: The caller is assumed to posses the Elan's lock.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to an Elan structure.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
#if DBG
|
|
ULONG Flags = pElan->Flags;
|
|
#endif
|
|
|
|
TRACEIN(DereferenceElan);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ASSERT(pElan->RefCount > 0);
|
|
|
|
rc = --(pElan->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
pElan->Flags |= ELAN_DEALLOCATING;
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
AtmLaneDeallocateElan(pElan);
|
|
}
|
|
|
|
DBGP((5, "DereferenceElan: Elan %p/%x (%s) new count %d\n",
|
|
pElan, Flags, String, rc));
|
|
|
|
TRACEOUT(DereferenceElan);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneUnlinkElanFromAdapter(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlinks an ELAN structure from the Adapter structure it is linked to.
|
|
Also continues any pending operation on the Adapter.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to Elan
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ADAPTER pAdapter;
|
|
BOOLEAN CompleteUnbind;
|
|
|
|
DBGP((1, "%d UnlinkElanFromAdapter: pElan %p/%x, Ref %d, pAdapter %p\n",
|
|
pElan->ElanNumber, pElan, pElan->Flags, pElan->RefCount, pElan->pAdapter));
|
|
|
|
pAdapter = pElan->pAdapter;
|
|
|
|
if (pAdapter != NULL_PATMLANE_ADAPTER)
|
|
{
|
|
DBGP((1, "UnlinkElanFromAdapter: pAdapter %x, Flags %x, RefCount %d\n",
|
|
pAdapter,
|
|
pAdapter->Flags, pAdapter->RefCount));
|
|
//
|
|
// Unlink from adapter list.
|
|
//
|
|
ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
pElan->pAdapter = NULL_PATMLANE_ADAPTER;
|
|
RemoveEntryList(&pElan->Link);
|
|
pAdapter->ElanCount--;
|
|
AtmLaneDereferenceAdapter(pAdapter, "elan");
|
|
|
|
if (IsListEmpty(&pAdapter->ElanList) &&
|
|
(pAdapter->Flags & ADAPTER_FLAGS_UNBIND_COMPLETE_PENDING))
|
|
{
|
|
pAdapter->Flags &= ~ADAPTER_FLAGS_UNBIND_COMPLETE_PENDING;
|
|
CompleteUnbind = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CompleteUnbind = FALSE;
|
|
}
|
|
|
|
RELEASE_ADAPTER_LOCK(pAdapter);
|
|
|
|
//
|
|
// If we just freed the last elan structure on this
|
|
// adapter, and an Unbind operation was in progress, complete
|
|
// it now.
|
|
//
|
|
if (CompleteUnbind)
|
|
{
|
|
AtmLaneCompleteUnbindAdapter(pAdapter);
|
|
}
|
|
}
|
|
}
|
|
|
|
PATMLANE_ATM_ENTRY
|
|
AtmLaneAllocateAtmEntry(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATM Entry structure, initialize it, and return it.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to Elan on which the entry is allocated
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated ATM Entry structure if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
|
|
TRACEIN(AllocateAtmEntry);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ALLOC_MEM(&pAtmEntry, sizeof(ATMLANE_ATM_ENTRY));
|
|
if (pAtmEntry != NULL_PATMLANE_ATM_ENTRY)
|
|
{
|
|
NdisZeroMemory(pAtmEntry, sizeof(ATMLANE_ATM_ENTRY));
|
|
#if DBG
|
|
pAtmEntry->atmlane_atm_sig = atmlane_atm_signature;
|
|
#endif
|
|
pAtmEntry->Flags = ATM_ENTRY_IDLE;
|
|
INIT_ATM_ENTRY_LOCK(pAtmEntry);
|
|
pAtmEntry->pElan = pElan;
|
|
|
|
}
|
|
|
|
DBGP((5, "AllocateAtmEntry:ATM Entry: Elan %x, Entry %x\n",
|
|
pElan, pAtmEntry));
|
|
|
|
TRACEOUT(AllocateAtmEntry);
|
|
|
|
return (pAtmEntry);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneDeallocateAtmEntry(
|
|
IN PATMLANE_ATM_ENTRY pAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an ATM Entry structure. It is assumed that all references
|
|
to the structure have gone. We don't need any locks here.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to ATM Entry to be freed.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(DeallocateAtmEntry);
|
|
|
|
|
|
STRUCT_ASSERT(pAtmEntry, atmlane_atm);
|
|
ASSERT(pAtmEntry->RefCount == 0);
|
|
ASSERT(pAtmEntry->pVcList == NULL_PATMLANE_VC);
|
|
|
|
#if DBG
|
|
pAtmEntry->atmlane_atm_sig++;
|
|
#endif
|
|
|
|
FREE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
FREE_MEM(pAtmEntry);
|
|
|
|
DBGP((5, "DeallocateAtmEntry: ATM Entry: %x\n", pAtmEntry));
|
|
|
|
TRACEOUT(DeallocateAtmEntry);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneReferenceAtmEntry(
|
|
IN PATMLANE_ATM_ENTRY pAtmEntry,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to the specified ATM Entry.
|
|
NOTE: The caller is assumed to possess a lock for the Entry.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to the Entry to be referenced
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(ReferenceAtmEntry);
|
|
|
|
STRUCT_ASSERT(pAtmEntry, atmlane_atm);
|
|
|
|
pAtmEntry->RefCount++;
|
|
|
|
DBGP((5, "ReferenceAtmEntry: Entry %x (%s) new count %d\n",
|
|
pAtmEntry, String, pAtmEntry->RefCount));
|
|
|
|
TRACEOUT(ReferenceAtmEntry);
|
|
}
|
|
|
|
|
|
ULONG
|
|
AtmLaneDereferenceAtmEntry(
|
|
IN PATMLANE_ATM_ENTRY pAtmEntry,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from the specified ATM Entry. If the Entry's
|
|
reference count becomes zero, deallocate it.
|
|
|
|
NOTE: The caller is assumed to possess a lock for the Entry.
|
|
SIDE EFFECT: See Return Value below
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to the Entry to be dereferenced.
|
|
|
|
Return Value:
|
|
|
|
Is the new reference count.
|
|
[IMPORTANT] If the Entry's reference count became zero, the Entry will be
|
|
deallocated -- the Entry lock is, obviously, released in this case.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
PATMLANE_ELAN pElan;
|
|
|
|
TRACEIN(DereferenceAtmEntry);
|
|
|
|
STRUCT_ASSERT(pAtmEntry, atmlane_atm);
|
|
|
|
if (pAtmEntry->RefCount == 0)
|
|
{
|
|
rc = 0;
|
|
}
|
|
else
|
|
{
|
|
rc = --(pAtmEntry->RefCount);
|
|
}
|
|
|
|
if (rc == 0)
|
|
{
|
|
PATMLANE_ATM_ENTRY * ppAtmEntry;
|
|
|
|
DBGP((5, "DerefAtmEntry %x, RefCount is 0\n", pAtmEntry));
|
|
|
|
//
|
|
// Unlink this entry from the Elan's list of ATM Entries.
|
|
//
|
|
|
|
//
|
|
// Acquire locks in the right order. However note that in doing so,
|
|
// some other thread might stumble across this ATM entry and reference
|
|
// it (and also dereference it!). To handle this, add a temp ref first.
|
|
//
|
|
pAtmEntry->RefCount++;
|
|
|
|
pElan = pAtmEntry->pElan;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
|
|
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
|
|
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
|
|
//
|
|
// Remove the temp ref above. If the ref count is still at 0,
|
|
// nobody is using this ATM entry and it is safe to remove it
|
|
// from the list.
|
|
//
|
|
rc = --(pAtmEntry->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
//
|
|
// Safe to delete this ATM entry.
|
|
//
|
|
#if DBG
|
|
if (pAtmEntry->pMacEntryList != NULL)
|
|
{
|
|
DBGP((0, "ATMLANE: derefed pAtmEntry %x, but MACEntryList isn't NULL!\n",
|
|
pAtmEntry));
|
|
ASSERT(FALSE);
|
|
}
|
|
#endif // DBG
|
|
|
|
ppAtmEntry = &(pElan->pAtmEntryList);
|
|
while (*ppAtmEntry != pAtmEntry)
|
|
{
|
|
ASSERT(*ppAtmEntry != NULL_PATMLANE_ATM_ENTRY);
|
|
ppAtmEntry = &((*ppAtmEntry)->pNext);
|
|
}
|
|
|
|
*ppAtmEntry = pAtmEntry->pNext;
|
|
|
|
pElan->NumAtmEntries--;
|
|
|
|
//
|
|
// If ATM Entry is for a LANE server
|
|
// then also invalidate elan's cached pointer to it
|
|
//
|
|
switch (pAtmEntry->Type)
|
|
{
|
|
case ATM_ENTRY_TYPE_LECS:
|
|
pElan->pLecsAtmEntry = NULL_PATMLANE_ATM_ENTRY;
|
|
break;
|
|
case ATM_ENTRY_TYPE_LES:
|
|
pElan->pLesAtmEntry = NULL_PATMLANE_ATM_ENTRY;
|
|
break;
|
|
case ATM_ENTRY_TYPE_BUS:
|
|
pElan->pBusAtmEntry = NULL_PATMLANE_ATM_ENTRY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
|
|
|
|
if (rc == 0)
|
|
{
|
|
AtmLaneDeallocateAtmEntry(pAtmEntry);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// As far as this caller is concerned, the ATM entry is gone.
|
|
// Return 0.
|
|
//
|
|
rc = 0;
|
|
}
|
|
}
|
|
|
|
DBGP((5, "DereferenceAtmEntry: Entry %x (%s) new count %d\n",
|
|
pAtmEntry, String, rc));
|
|
|
|
TRACEOUT(DereferenceAtmEntry);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
PATMLANE_VC
|
|
AtmLaneAllocateVc(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATMLANE VC structure, initialize it, and return it.
|
|
|
|
Arguments:
|
|
|
|
pElan - Elan for which this VC is created.
|
|
|
|
Return Value:
|
|
|
|
Pointer to VC if allocated, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_VC pVc;
|
|
|
|
TRACEIN(AllocateVc);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ALLOC_MEM(&pVc, sizeof(ATMLANE_VC));
|
|
|
|
if (pVc != NULL_PATMLANE_VC)
|
|
{
|
|
NdisZeroMemory(pVc, sizeof(ATMLANE_VC));
|
|
#if DBG
|
|
pVc->atmlane_vc_sig = atmlane_vc_signature;
|
|
#endif // DBG
|
|
pVc->pElan = pElan;
|
|
INIT_VC_LOCK(pVc);
|
|
}
|
|
|
|
DBGP((3, "Allocated Vc %x\n", pVc));
|
|
|
|
TRACEOUT(AllocateVc);
|
|
|
|
return (pVc);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneDeallocateVc(
|
|
IN PATMLANE_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an ATMLANE VC structure. It is assumed that all references
|
|
to this VC have gone, so there is no need to acquire a lock to the VC.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to the VC to be deallocated
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(DeallocateVc);
|
|
|
|
STRUCT_ASSERT(pVc, atmlane_vc);
|
|
ASSERT(pVc->RefCount == 0);
|
|
|
|
#if DBG
|
|
pVc->atmlane_vc_sig++;
|
|
#endif
|
|
FREE_VC_LOCK(pVc);
|
|
FREE_MEM(pVc);
|
|
|
|
DBGP((5, "Deallocated Vc %x\n", pVc));
|
|
|
|
TRACEOUT(DeallocateVc);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneReferenceVc(
|
|
IN PATMLANE_VC pVc,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to the specified ATMLANE VC.
|
|
NOTE: The caller is assumed to possess a lock for the VC.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to the VC to be referenced
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(ReferenceVc);
|
|
|
|
STRUCT_ASSERT(pVc, atmlane_vc);
|
|
|
|
pVc->RefCount++;
|
|
|
|
DBGP((5, "ReferenceVc: Vc %x (%s) new count %d\n",
|
|
pVc, String, pVc->RefCount));
|
|
|
|
TRACEOUT(ReferenceVc);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ULONG
|
|
AtmLaneDereferenceVc(
|
|
IN PATMLANE_VC pVc,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from the specified ATMLANE VC. If the VC's
|
|
reference count becomes zero, deallocate it.
|
|
|
|
NOTE: The caller is assumed to possess a lock for the VC.
|
|
SIDE EFFECT: See Return Value below
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to the VC to be dereferenced.
|
|
|
|
Return Value:
|
|
|
|
Is the new reference count.
|
|
[IMPORTANT] If the VC's reference count became zero, the VC will be
|
|
deallocated -- the VC lock is, obviously, released in this case.
|
|
|
|
--*/
|
|
{
|
|
ULONG rv;
|
|
|
|
TRACEIN(DereferenceVc);
|
|
|
|
STRUCT_ASSERT(pVc, atmlane_vc);
|
|
ASSERT(pVc->RefCount > 0);
|
|
|
|
rv = --(pVc->RefCount);
|
|
if (rv == 0)
|
|
{
|
|
RELEASE_VC_LOCK(pVc);
|
|
AtmLaneDeallocateVc(pVc);
|
|
}
|
|
|
|
DBGP((5, "DereferenceVc: Vc %x (%s) new count %d\n",
|
|
pVc, String, rv));
|
|
|
|
TRACEOUT(DereferenceVc);
|
|
|
|
return (rv);
|
|
}
|
|
|
|
PATMLANE_MAC_ENTRY
|
|
AtmLaneAllocateMacEntry(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATMLANE MAC Entry structure, initialize it, and
|
|
return it.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Interface on which this MAC
|
|
Entry is allocated.
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated MAC Entry structure if successful,
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_MAC_ENTRY pMacEntry;
|
|
|
|
TRACEIN(AllocateMacEntry);
|
|
|
|
ALLOC_MEM(&pMacEntry, sizeof(ATMLANE_MAC_ENTRY));
|
|
|
|
if (pMacEntry != NULL_PATMLANE_MAC_ENTRY)
|
|
{
|
|
NdisZeroMemory(pMacEntry, sizeof(ATMLANE_MAC_ENTRY));
|
|
#if DBG
|
|
pMacEntry->atmlane_mac_sig = atmlane_mac_signature;
|
|
#endif // DBG
|
|
pMacEntry->pElan = pElan;
|
|
pMacEntry->Flags = MAC_ENTRY_NEW;
|
|
INIT_MAC_ENTRY_LOCK(pMacEntry);
|
|
|
|
INIT_SYSTEM_TIMER(
|
|
&pMacEntry->BusTimer,
|
|
AtmLaneBusSendTimer,
|
|
pMacEntry);
|
|
|
|
pMacEntry->LimitTime = pElan->LimitTime;
|
|
pMacEntry->IncrTime = pElan->IncrTime;
|
|
}
|
|
|
|
DBGP((5, "AllocateMacEntry: Allocated Entry %x\n", pMacEntry));
|
|
|
|
TRACEOUT(AllocateMacEntry);
|
|
return (pMacEntry);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneDeallocateMacEntry(
|
|
IN PATMLANE_MAC_ENTRY pMacEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an ATMLANE Mac Entry. It is assumed that all references
|
|
to this Mac Entry have gone, so there is no need to acquire its
|
|
lock.
|
|
|
|
Arguments:
|
|
|
|
pMacEntry - Pointer to the Mac Entry to be deallocated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(DeallocateMacEntry);
|
|
|
|
STRUCT_ASSERT(pMacEntry, atmlane_mac);
|
|
ASSERT(pMacEntry->RefCount == 0);
|
|
|
|
#if DBG
|
|
pMacEntry->atmlane_mac_sig++;
|
|
#endif
|
|
|
|
FREE_MAC_ENTRY_LOCK(pMacEntry);
|
|
FREE_MEM(pMacEntry);
|
|
|
|
DBGP((5,"DeallocateMacEntry: Deallocated Entry %x\n", pMacEntry));
|
|
|
|
TRACEOUT(DeallocateMacEntry);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneReferenceMacEntry(
|
|
IN PATMLANE_MAC_ENTRY pMacEntry,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to an ATMLANE Mac Entry.
|
|
NOTE: The caller is assumed to possess a lock for the Mac Entry.
|
|
|
|
Arguments:
|
|
|
|
pMacEntry - Pointer to an ATMLANE Mac Entry.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(ReferenceMacEntry);
|
|
|
|
STRUCT_ASSERT(pMacEntry, atmlane_mac);
|
|
|
|
pMacEntry->RefCount++;
|
|
|
|
DBGP((5, "ReferenceMacEntry: Entry %x (%s) new count %d\n",
|
|
pMacEntry, String, pMacEntry->RefCount));
|
|
|
|
TRACEOUT(ReferenceMacEntry);
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
AtmLaneDereferenceMacEntry(
|
|
IN PATMLANE_MAC_ENTRY pMacEntry,
|
|
IN PUCHAR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from an ATMLANE MAC Entry. If the reference
|
|
count becomes zero, deallocate it.
|
|
NOTE: It is assumed that the caller holds a lock to the MAC Entry.
|
|
See SIDE EFFECT below.
|
|
|
|
Arguments:
|
|
|
|
pMacEntry - Pointer to ATMLANE MAC Entry
|
|
|
|
Return Value:
|
|
|
|
The resulting reference count. If this is zero, then there are two
|
|
SIDE EFFECTS: (1) the MAC Entry lock is released (2) the structure
|
|
is freed.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
|
|
TRACEIN(DereferenceMacEntry);
|
|
|
|
STRUCT_ASSERT(pMacEntry, atmlane_mac);
|
|
|
|
rc = --(pMacEntry->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
PVOID Caller, CallersCaller;
|
|
|
|
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
|
|
|
|
//
|
|
// Save away the caller's address for debugging purposes...
|
|
//
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
pMacEntry->Timer.ContextPtr = Caller;
|
|
|
|
AtmLaneDeallocateMacEntry(pMacEntry);
|
|
}
|
|
|
|
DBGP((5, "DereferenceMacEntry: Entry %x (%s) new count %d\n",
|
|
pMacEntry, String, rc));
|
|
|
|
TRACEOUT(DereferenceMacEntry);
|
|
return (rc);
|
|
}
|
|
|
|
PNDIS_PACKET
|
|
AtmLaneAllocProtoPacket(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS packet for use as a LANE control frame.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE ELAN structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS packet if allocated, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET pNdisPacket;
|
|
|
|
TRACEIN(AllocProtoPacket);
|
|
|
|
NdisAllocatePacket(
|
|
&Status,
|
|
&pNdisPacket,
|
|
pElan->ProtocolPacketPool
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Init ProtocolReserved and mark packet owned by ATMLANE
|
|
//
|
|
ZERO_SEND_RSVD(pNdisPacket);
|
|
#if PROTECT_PACKETS
|
|
INIT_SENDPACKET_LOCK(pNdisPacket);
|
|
#endif // PROTECT_PACKETS
|
|
SET_FLAG(
|
|
PSEND_RSVD(pNdisPacket)->Flags,
|
|
PACKET_RESERVED_OWNER_MASK,
|
|
PACKET_RESERVED_OWNER_ATMLANE
|
|
);
|
|
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedDecrement(&pElan->ProtPktCount);
|
|
if ((pElan->ProtPktCount % 20) == 0)
|
|
{
|
|
DBGP((1, "ProtPktCount %d\n", pElan->ProtPktCount));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
TRACEOUT(AllocProtoPacket);
|
|
|
|
return (pNdisPacket);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneFreeProtoPacket(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS packet used as a LANE control frame.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE ELAN structure
|
|
|
|
pNdisPacket - pointer to NDIS_PACKET to free.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(FreeProtoPacket);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
#if PROTECT_PACKETS
|
|
FREE_SENDPACKET_LOCK(pNdisPacket);
|
|
#endif // PROTECT_PACKETS
|
|
NdisFreePacket(pNdisPacket);
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedIncrement(&pElan->ProtPktCount);
|
|
if ((pElan->ProtPktCount % 20) == 0 &&
|
|
pElan->ProtPktCount != pElan->MaxProtocolBufs)
|
|
{
|
|
DBGP((1, "ProtPktCount %d\n", pElan->ProtPktCount));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
TRACEOUT(FreeProtoPacket);
|
|
return;
|
|
}
|
|
|
|
PNDIS_BUFFER
|
|
AtmLaneGrowHeaders(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a bunch of header buffers on the specified ATMLANE Elan.
|
|
Return one of them.
|
|
|
|
We allocate a new Buffer tracker structure, a new NDIS Buffer pool, and
|
|
finally a chunk of system memory that we break down into header buffers.
|
|
These header buffers are then attached to NDIS Buffers before they are
|
|
inserted into the list of free header buffers for this Interface.
|
|
|
|
Caller is assumed to hold appropriate lock.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated NDIS buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_BUFFER_TRACKER pTracker; // for new set of buffers
|
|
PUCHAR pSpace;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
PNDIS_BUFFER pReturnBuffer;
|
|
PNDIS_BUFFER pBufferList; // allocated list
|
|
INT i; // iteration counter
|
|
NDIS_STATUS Status;
|
|
|
|
TRACEIN(GrowHeaders);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pTracker = NULL_PATMLANE_BUFFER_TRACKER;
|
|
pReturnBuffer = (PNDIS_BUFFER)NULL;
|
|
|
|
do
|
|
{
|
|
if (pElan->CurHeaderBufs >= pElan->MaxHeaderBufs)
|
|
{
|
|
DBGP((2, "GrowHeaders: Elan %x, CurHdrBufs %d > MaxHdrBufs %d\n",
|
|
pElan, pElan->CurHeaderBufs, pElan->MaxHeaderBufs));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize Buffer tracker
|
|
//
|
|
ALLOC_MEM(&pTracker, sizeof(ATMLANE_BUFFER_TRACKER));
|
|
if (pTracker == NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
DBGP((0, "GrowHeaders: Elan %x, alloc failed for tracker\n",
|
|
pElan));
|
|
break;
|
|
}
|
|
|
|
NdisZeroMemory(pTracker, sizeof(ATMLANE_BUFFER_TRACKER));
|
|
|
|
//
|
|
// Get the NDIS Buffer pool
|
|
//
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&(pTracker->NdisHandle),
|
|
DEF_HDRBUF_GROW_SIZE
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0,
|
|
"GrowHeaders: Elan %x, NdisAllocateBufferPool err status %x\n",
|
|
pElan, Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate system space for a bunch of header buffers
|
|
// Note we use RealHeaderBufSize here so that the
|
|
// buffers end up on ULONG boundaries.
|
|
//
|
|
ALLOC_MEM(&(pTracker->pPoolStart),
|
|
pElan->RealHeaderBufSize * DEF_HDRBUF_GROW_SIZE);
|
|
if (pTracker->pPoolStart == (PUCHAR)NULL)
|
|
{
|
|
DBGP((0, "GrowHeaders: Elan %x, could not alloc buf space %d bytes\n",
|
|
pElan, pElan->HeaderBufSize * DEF_HDRBUF_GROW_SIZE));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make NDIS buffers out of the allocated space, and put them
|
|
// into the free header buffer list. Retain one for returning
|
|
// to caller.
|
|
//
|
|
pBufferList = (PNDIS_BUFFER)NULL;
|
|
pSpace = pTracker->pPoolStart;
|
|
for (i = 0; i < DEF_HDRBUF_GROW_SIZE; i++)
|
|
{
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNdisBuffer,
|
|
pTracker->NdisHandle,
|
|
pSpace,
|
|
pElan->HeaderBufSize
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0,
|
|
"GrowHeaders: NdisAllocateBuffer failed: Elan %x, status %x\n",
|
|
pElan, Status));
|
|
break;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
pReturnBuffer = pNdisBuffer;
|
|
}
|
|
else
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = pBufferList;
|
|
pBufferList = pNdisBuffer;
|
|
}
|
|
pSpace += pElan->RealHeaderBufSize;
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
//
|
|
// Successfully allocated at least one more header buffer
|
|
//
|
|
pTracker->pNext = pElan->pHeaderTrkList;
|
|
pElan->pHeaderTrkList = pTracker;
|
|
pElan->CurHeaderBufs += i;
|
|
|
|
pNdisBuffer = pBufferList;
|
|
while (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pBufferList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
AtmLaneFreeHeader(pElan, pNdisBuffer, TRUE);
|
|
pNdisBuffer = pBufferList;
|
|
}
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (pReturnBuffer == (PNDIS_BUFFER)NULL)
|
|
{
|
|
//
|
|
// Failed to allocate. Undo all.
|
|
//
|
|
if (pTracker != NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
FREE_MEM(pTracker->pPoolStart);
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
}
|
|
FREE_MEM(pTracker);
|
|
}
|
|
}
|
|
|
|
DBGP((2, "GrowHeaders: Elan %x, RetBuf %x, New Tracker %x\n",
|
|
pElan, pReturnBuffer, pTracker));
|
|
|
|
TRACEOUT(GrowHeaders);
|
|
|
|
return (pReturnBuffer);
|
|
}
|
|
|
|
PNDIS_BUFFER
|
|
AtmLaneAllocateHeader(
|
|
IN PATMLANE_ELAN pElan,
|
|
OUT PUCHAR * pBufferAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS Buffer to be used for LECID a MAC packet.
|
|
We pick up the buffer at the top of the pre-allocated
|
|
buffer list, if one exists. Otherwise, we try to grow this list and
|
|
allocate.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan
|
|
pBufferAddress - Place to return virtual address of allocated buffer
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
ULONG Length;
|
|
|
|
TRACEIN(AllocateHeader);
|
|
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
|
|
pNdisBuffer = pElan->HeaderBufList;
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pElan->HeaderBufList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)pBufferAddress, &Length);
|
|
}
|
|
else
|
|
{
|
|
pNdisBuffer = AtmLaneGrowHeaders(pElan);
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)pBufferAddress, &Length);
|
|
}
|
|
}
|
|
|
|
DBGP((5, "AllocateHeader: Buffer %x, Elan %x\n",
|
|
pNdisBuffer, pElan));
|
|
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
|
|
TRACEOUT(AllocateHeader);
|
|
return (pNdisBuffer);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneFreeHeader(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN BOOLEAN LockHeld
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate a header buffer.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan from which the buffer came
|
|
pNdisBuffer - Pointer to NDIS buffer being freed
|
|
LockHeld - TRUE if appropriate lock already held
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(FreeHeader);
|
|
|
|
if (!LockHeld)
|
|
{
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
}
|
|
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = pElan->HeaderBufList;
|
|
pElan->HeaderBufList = pNdisBuffer;
|
|
|
|
DBGP((5, "FreeHeader: Buffer %x, Elan %x\n",
|
|
pNdisBuffer, pElan));
|
|
|
|
if (!LockHeld)
|
|
{
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
}
|
|
|
|
TRACEOUT(FreeHeader);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneDeallocateHeaderBuffers(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate everything pertaining to header buffers on an Elan.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
PATMLANE_BUFFER_TRACKER pTracker;
|
|
PATMLANE_BUFFER_TRACKER pNextTracker;
|
|
|
|
TRACEIN(DeallocateHeaderBuffers);
|
|
|
|
//
|
|
// Free all NDIS buffers in the header buffer list.
|
|
//
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
do
|
|
{
|
|
pNdisBuffer = pElan->HeaderBufList;
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pElan->HeaderBufList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No more NDIS buffers.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
while (TRUE);
|
|
|
|
//
|
|
// Now free all the buffer trackers.
|
|
//
|
|
pTracker = pElan->pHeaderTrkList;
|
|
|
|
while (pTracker != NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
pNextTracker = pTracker->pNext;
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
FREE_MEM(pTracker->pPoolStart);
|
|
pTracker->pPoolStart = (PUCHAR)NULL;
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
pTracker->NdisHandle = (NDIS_HANDLE)NULL;
|
|
}
|
|
FREE_MEM(pTracker);
|
|
pTracker = pNextTracker;
|
|
}
|
|
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
|
|
TRACEOUT(DeallocateHeaderBuffers);
|
|
}
|
|
|
|
PNDIS_BUFFER
|
|
AtmLaneGrowPadBufs(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a bunch of packet pad buffers on the specified ATMLANE Elan.
|
|
Return one of them.
|
|
|
|
We allocate a new Buffer tracker structure, a new NDIS Buffer pool, and
|
|
finally a chunk of system memory (if not allocated already, only need one).
|
|
This buffer is then attached to the NDIS Buffers before they are
|
|
inserted into the list of free pad buffers for this Interface.
|
|
|
|
Caller is assumed to hold appropriate lock.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated NDIS buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_BUFFER_TRACKER pTracker; // for new set of buffers
|
|
PUCHAR pSpace;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
PNDIS_BUFFER pReturnBuffer;
|
|
PNDIS_BUFFER pBufferList; // allocated list
|
|
INT i; // iteration counter
|
|
NDIS_STATUS Status;
|
|
|
|
TRACEIN(GrowPadBufs);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pTracker = NULL_PATMLANE_BUFFER_TRACKER;
|
|
pReturnBuffer = (PNDIS_BUFFER)NULL;
|
|
|
|
do
|
|
{
|
|
if (pElan->CurPadBufs >= pElan->MaxPadBufs)
|
|
{
|
|
DBGP((0, "GrowPadBufs: Max Reached! Elan %x, CurPadBufs %d > MaxPadBufs %d\n",
|
|
pElan, pElan->CurPadBufs, pElan->MaxPadBufs));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize Buffer tracker
|
|
//
|
|
ALLOC_MEM(&pTracker, sizeof(ATMLANE_BUFFER_TRACKER));
|
|
if (pTracker == NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
DBGP((0, "GrowPadBufs: Elan %x, alloc failed for tracker\n",
|
|
pElan));
|
|
break;
|
|
}
|
|
|
|
NdisZeroMemory(pTracker, sizeof(ATMLANE_BUFFER_TRACKER));
|
|
|
|
//
|
|
// Get the NDIS Buffer pool
|
|
//
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&(pTracker->NdisHandle),
|
|
DEF_HDRBUF_GROW_SIZE
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0,
|
|
"GrowPadBufs: Elan %x, NdisAllocateBufferPool err status %x\n",
|
|
pElan, Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate system space for a single pad buffer.
|
|
//
|
|
ALLOC_MEM(&(pTracker->pPoolStart), pElan->PadBufSize);
|
|
if (pTracker->pPoolStart == (PUCHAR)NULL)
|
|
{
|
|
DBGP((0, "GrowPadBufs: Elan %x, could not alloc buf space %d bytes\n",
|
|
pElan, pElan->PadBufSize * DEF_HDRBUF_GROW_SIZE));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make NDIS buffers out of the allocated space, and put them
|
|
// into the free pad buffer list. Retain one for returning
|
|
// to caller. NOTE we put same pad buffer in each ndis buffer header
|
|
// since contents is irrelevent.
|
|
//
|
|
pBufferList = (PNDIS_BUFFER)NULL;
|
|
pSpace = pTracker->pPoolStart;
|
|
for (i = 0; i < DEF_HDRBUF_GROW_SIZE; i++)
|
|
{
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNdisBuffer,
|
|
pTracker->NdisHandle,
|
|
pSpace,
|
|
pElan->PadBufSize
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0,
|
|
"GrowPadBufs: NdisAllocateBuffer failed: Elan %x, status %x\n",
|
|
pElan, Status));
|
|
break;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
pReturnBuffer = pNdisBuffer;
|
|
}
|
|
else
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = pBufferList;
|
|
pBufferList = pNdisBuffer;
|
|
}
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
//
|
|
// Successfully allocated at least one more pad buffer
|
|
//
|
|
pTracker->pNext = pElan->pPadTrkList;
|
|
pElan->pPadTrkList = pTracker;
|
|
pElan->CurPadBufs += i;
|
|
|
|
pNdisBuffer = pBufferList;
|
|
while (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pBufferList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
AtmLaneFreePadBuf(pElan, pNdisBuffer, TRUE);
|
|
pNdisBuffer = pBufferList;
|
|
}
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (pReturnBuffer == (PNDIS_BUFFER)NULL)
|
|
{
|
|
//
|
|
// Failed to allocate. Undo all.
|
|
//
|
|
if (pTracker != NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
FREE_MEM(pTracker->pPoolStart);
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
}
|
|
FREE_MEM(pTracker);
|
|
}
|
|
}
|
|
|
|
DBGP((2, "GrowPadBufs: Elan %x, RetBuf %x, New Tracker %x\n",
|
|
pElan, pReturnBuffer, pTracker));
|
|
|
|
TRACEOUT(GrowPadBufs);
|
|
|
|
return (pReturnBuffer);
|
|
}
|
|
|
|
PNDIS_BUFFER
|
|
AtmLaneAllocatePadBuf(
|
|
IN PATMLANE_ELAN pElan,
|
|
OUT PUCHAR * pBufferAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS Buffer to be used to pad a MAC packet to min length.
|
|
We pick up the buffer at the top of the pre-allocated
|
|
buffer list, if one exists. Otherwise, we try to grow this list and
|
|
allocate.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan
|
|
pBufferAddress - Place to return virtual address of allocated buffer
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
ULONG Length;
|
|
|
|
TRACEIN(AtmLaneAllocatePadBuf);
|
|
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
|
|
pNdisBuffer = pElan->PadBufList;
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pElan->PadBufList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)pBufferAddress, &Length);
|
|
}
|
|
else
|
|
{
|
|
pNdisBuffer = AtmLaneGrowPadBufs(pElan);
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)pBufferAddress, &Length);
|
|
}
|
|
}
|
|
|
|
DBGP((5, "AllocatePadBuf: Buffer %x, Elan %x\n",
|
|
pNdisBuffer, pElan));
|
|
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
|
|
TRACEOUT(AllocatePadBuf);
|
|
return (pNdisBuffer);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneFreePadBuf(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN BOOLEAN LockHeld
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate a Pad buffer.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan from which the buffer came
|
|
pNdisBuffer - Pointer to NDIS buffer being freed
|
|
LockHeld - TRUE if appropriate lock already held
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TRACEIN(FreePadBuf);
|
|
|
|
if (!LockHeld)
|
|
{
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
}
|
|
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = pElan->PadBufList;
|
|
pElan->PadBufList = pNdisBuffer;
|
|
|
|
DBGP((5, "FreePadBuf: Buffer %x, Elan %x\n",
|
|
pNdisBuffer, pElan));
|
|
|
|
if (!LockHeld)
|
|
{
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
}
|
|
|
|
TRACEOUT(FreePadBuf);
|
|
}
|
|
|
|
VOID
|
|
AtmLaneDeallocatePadBufs(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate everything pertaining to Pad buffers on an Elan.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
PATMLANE_BUFFER_TRACKER pTracker;
|
|
PATMLANE_BUFFER_TRACKER pNextTracker;
|
|
|
|
TRACEIN(DeallocatePadBufs);
|
|
|
|
//
|
|
// Free all NDIS buffers in the Pad buffer list.
|
|
//
|
|
ACQUIRE_HEADER_LOCK(pElan);
|
|
do
|
|
{
|
|
pNdisBuffer = pElan->PadBufList;
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pElan->PadBufList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No more NDIS buffers.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
while (TRUE);
|
|
|
|
//
|
|
// Now free all the buffer trackers.
|
|
//
|
|
pTracker = pElan->pPadTrkList;
|
|
|
|
while (pTracker != NULL_PATMLANE_BUFFER_TRACKER)
|
|
{
|
|
pNextTracker = pTracker->pNext;
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
FREE_MEM(pTracker->pPoolStart);
|
|
pTracker->pPoolStart = (PUCHAR)NULL;
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
pTracker->NdisHandle = (NDIS_HANDLE)NULL;
|
|
}
|
|
FREE_MEM(pTracker);
|
|
pTracker = pNextTracker;
|
|
}
|
|
|
|
RELEASE_HEADER_LOCK(pElan);
|
|
|
|
TRACEOUT(DeallocatePadBufs);
|
|
}
|
|
|
|
PNDIS_BUFFER
|
|
AtmLaneAllocateProtoBuffer(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN ULONG Length,
|
|
OUT PUCHAR * pBufferAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a buffer to be used for a LANE protocol message. Attach
|
|
it to an NDIS_BUFFER structure and return a pointer to this.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan
|
|
Length - Length, in bytes, of the buffer.
|
|
pBufferAddress - Place to return virtual address of allocated buffer.
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS Buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
|
|
TRACEIN(AllocateProtobuffer);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pNdisBuffer = NULL;
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
|
|
ASSERT(Length <= pElan->ProtocolBufSize);
|
|
|
|
*pBufferAddress = pElan->ProtocolBufList;
|
|
if (*pBufferAddress != (PUCHAR)NULL)
|
|
{
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNdisBuffer,
|
|
pElan->ProtocolBufferPool,
|
|
*pBufferAddress,
|
|
Length
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pElan->ProtocolBufList = *((PUCHAR *)*pBufferAddress);
|
|
}
|
|
}
|
|
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
DBGP((5,
|
|
"AllocateProtoBuffer: ELan %x, pNdisBuffer %x, Length %d, Loc %x\n",
|
|
pElan, pNdisBuffer, Length, *pBufferAddress));
|
|
|
|
TRACEOUT(AllocateProtoBuffer);
|
|
|
|
return (pNdisBuffer);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneFreeProtoBuffer(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_BUFFER pNdisBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an NDIS buffer (and associated memory) used for a protocol
|
|
packet. We return the associated memory to the ProtocolBufList
|
|
in the Elan structure, and the NDIS buffer to NDIS.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE Elan structure
|
|
pNdisBuffer - Pointer to NDIS buffer to be freed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUCHAR * pBufferLinkage;
|
|
ULONG Length;
|
|
|
|
TRACEIN(FreeProtoBuffer);
|
|
|
|
#if 0
|
|
pBufferLinkage = (PUCHAR *)NdisBufferVirtualAddress(pNdisBuffer);
|
|
#else
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)&pBufferLinkage, &Length);
|
|
#endif
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
|
|
*pBufferLinkage = pElan->ProtocolBufList;
|
|
pElan->ProtocolBufList = (PUCHAR)pBufferLinkage;
|
|
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
|
|
DBGP((5, "FreeProtoBuffer: Elan %x, pNdisBuffer %x, Loc %x\n",
|
|
pElan, pNdisBuffer, (ULONG_PTR)pBufferLinkage));
|
|
|
|
TRACEOUT(FreeProtoBuffer);
|
|
return;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmLaneInitProtoBuffers(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the protocol buffer pool for an elan.
|
|
|
|
Allocate a chunk of memory to be used for ATMLANE protocol messages.
|
|
We prepare a linked list of protocol buffers, and attach it to the
|
|
Interface structure.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to Interface on which we need to allocate
|
|
protocol buffers.
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if successful, NDIS_STATUS_RESOURCES if we run
|
|
into a resource failure.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PUCHAR pSpace;
|
|
ULONG i;
|
|
|
|
TRACEIN(InitProtoBuffers);
|
|
|
|
do
|
|
{
|
|
NdisAllocatePacketPool(
|
|
&Status,
|
|
&(pElan->ProtocolPacketPool),
|
|
pElan->MaxProtocolBufs,
|
|
sizeof(SEND_PACKET_RESERVED)
|
|
);
|
|
#if PKT_HDR_COUNTS
|
|
pElan->ProtPktCount = pElan->MaxProtocolBufs;
|
|
DBGP((1, "ProtPktCount %d\n", pElan->ProtPktCount));
|
|
#endif
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&(pElan->ProtocolBufferPool),
|
|
pElan->MaxProtocolBufs
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a big chunk of system memory that we can divide up into
|
|
// protocol buffers.
|
|
//
|
|
ALLOC_MEM(
|
|
&(pElan->ProtocolBufTracker),
|
|
(pElan->ProtocolBufSize * pElan->MaxProtocolBufs)
|
|
);
|
|
|
|
if (pElan->ProtocolBufTracker == (PUCHAR)NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Make all protocol buffers free.
|
|
//
|
|
pSpace = pElan->ProtocolBufTracker;
|
|
{
|
|
PUCHAR LinkPtr;
|
|
|
|
LinkPtr = (PUCHAR)NULL;
|
|
for (i = 0; i < pElan->MaxProtocolBufs; i++)
|
|
{
|
|
*((PUCHAR *)pSpace) = LinkPtr;
|
|
LinkPtr = pSpace;
|
|
pSpace += pElan->ProtocolBufSize;
|
|
}
|
|
pSpace -= pElan->ProtocolBufSize;
|
|
pElan->ProtocolBufList = pSpace;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Undo everything.
|
|
//
|
|
AtmLaneDeallocateProtoBuffers(pElan);
|
|
}
|
|
|
|
TRACEOUT(InitProtoBuffers);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneDeallocateProtoBuffers(
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the protocol buffer pool for an interface.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE elan structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (pElan->ProtocolPacketPool != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreePacketPool(pElan->ProtocolPacketPool);
|
|
pElan->ProtocolPacketPool = NULL;
|
|
}
|
|
|
|
if (pElan->ProtocolBufferPool != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pElan->ProtocolBufferPool);
|
|
pElan->ProtocolBufferPool = NULL;
|
|
}
|
|
|
|
if (pElan->ProtocolBufTracker != (PUCHAR)NULL)
|
|
{
|
|
FREE_MEM(pElan->ProtocolBufTracker);
|
|
pElan->ProtocolBufTracker = (PUCHAR)NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
AtmLaneLinkVcToAtmEntry(
|
|
IN PATMLANE_VC pVc,
|
|
IN PATMLANE_ATM_ENTRY pAtmEntry,
|
|
IN BOOLEAN ServerIncoming
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Link an ATMLANE VC to an ATM Entry. The caller is assumed to
|
|
hold locks to both structures.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMLANE VC structure
|
|
pAtmEntry - Pointer to ATMLANE ATM Entry structure
|
|
ServerIncoming - Incoming call from server
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_VC * ppNext;
|
|
PATMLANE_VC pVcEntry;
|
|
BOOLEAN WasRunning;
|
|
|
|
TRACEIN(LinkVcToAtmEntry);
|
|
|
|
DBGP((2, "LinkVcToAtmEntry: pVc %x to pAtmEntry %x ServerIncoming %s\n",
|
|
pVc, pAtmEntry, ServerIncoming?"TRUE":"FALSE"));
|
|
|
|
//
|
|
// Back pointer from VC to ATM Entry.
|
|
//
|
|
pVc->pAtmEntry = pAtmEntry;
|
|
|
|
//
|
|
// If server incoming connection cache the VC
|
|
// special location in the AtmEntry.
|
|
//
|
|
if (ServerIncoming)
|
|
{
|
|
pAtmEntry->pVcIncoming = pVc;
|
|
pVc->pNextVc = NULL_PATMLANE_VC;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise...
|
|
//
|
|
// Add VC to the list in ascending calling party ATM address order
|
|
//
|
|
ppNext = &pAtmEntry->pVcList;
|
|
while (*ppNext != NULL_PATMLANE_VC)
|
|
{
|
|
if (memcmp(
|
|
&pVc->CallingAtmAddress.Address,
|
|
(*ppNext)->CallingAtmAddress.Address,
|
|
ATM_ADDRESS_LENGTH) < 0)
|
|
{
|
|
//
|
|
// Calling address is less than existing VC.
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Calling address is equal or greater than existing VC.
|
|
// Move on to next.
|
|
//
|
|
ppNext = &((*ppNext)->pNextVc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Found the place we were looking for. Insert the VC here.
|
|
//
|
|
pVc->pNextVc = *ppNext;
|
|
*ppNext = pVc;
|
|
|
|
}
|
|
|
|
//
|
|
// Add the VC reference to the ATM entry.
|
|
//
|
|
AtmLaneReferenceAtmEntry(pAtmEntry, "vc"); // VC reference
|
|
|
|
//
|
|
// Add the ATM Entry reference to the VC.
|
|
//
|
|
AtmLaneReferenceVc(pVc, "atm");
|
|
|
|
//
|
|
// If this VC is not the first in the list, i.e., not the lowest
|
|
// calling party number, then set the timeout to the fast VC
|
|
// timeout value. This will get rid of redundant DataDirect VCs quickly
|
|
// ONLY if they don't get used within the fast timeout period.
|
|
// Otherwise the timeout handler to keep the VC and set
|
|
// the timeout to the normal C12-VccTimeout value.
|
|
//
|
|
if (pVc != pAtmEntry->pVcList)
|
|
{
|
|
pVc->AgingTime = FAST_VC_TIMEOUT;
|
|
}
|
|
|
|
TRACEOUT(LinkVcToAtmEntry);
|
|
}
|
|
|
|
BOOLEAN
|
|
AtmLaneUnlinkVcFromAtmEntry(
|
|
IN PATMLANE_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlink an ATMLANE VC from the ATM Entry it is linked to.
|
|
The caller is assumed to hold a lock for the VC structure.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMLANE VC structure
|
|
|
|
Return Value:
|
|
|
|
TRUE if we found the VC linked to the list on the ATM entry, and unlinked it.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
PATMLANE_MAC_ENTRY pMacEntry, pNextMacEntry;
|
|
ULONG rc;
|
|
PATMLANE_VC * ppVc;
|
|
BOOLEAN Found;
|
|
|
|
DBGP((3, "UnlinkVcFromAtmEntry: pVc %x from pAtmEntry %x\n",
|
|
pVc, pVc->pAtmEntry));
|
|
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
ASSERT(NULL_PATMLANE_ATM_ENTRY != pAtmEntry);
|
|
|
|
pVc->pAtmEntry = NULL_PATMLANE_ATM_ENTRY;
|
|
|
|
//
|
|
// Reacquire locks in the right order.
|
|
//
|
|
AtmLaneReferenceVc(pVc, "temp");
|
|
RELEASE_VC_LOCK(pVc);
|
|
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
ACQUIRE_VC_LOCK(pVc);
|
|
|
|
|
|
//
|
|
// VC is either a server incoming uni-directional connection,
|
|
// where it is linked to the AtmEntry via pVcIncoming, or a
|
|
// bi-directional connection that is in the pVcList.
|
|
//
|
|
if (pAtmEntry->pVcIncoming == pVc)
|
|
{
|
|
//
|
|
// If server incoming VC just remove single entry
|
|
//
|
|
pAtmEntry->pVcIncoming = NULL_PATMLANE_VC;
|
|
Found = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, find this VC in the ATM Entry's VC list
|
|
//
|
|
ppVc = &(pAtmEntry->pVcList);
|
|
while (*ppVc != NULL_PATMLANE_VC && *ppVc != pVc)
|
|
{
|
|
ppVc = &((*ppVc)->pNextVc);
|
|
}
|
|
|
|
//
|
|
// Remove this VC by making it's predecessor in the list
|
|
// point to the next VC in the list.
|
|
//
|
|
if (*ppVc == pVc)
|
|
{
|
|
*ppVc = pVc->pNextVc;
|
|
Found = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Found = FALSE;
|
|
}
|
|
}
|
|
|
|
rc = AtmLaneDereferenceVc(pVc, "temp");
|
|
if (rc > 0)
|
|
{
|
|
RELEASE_VC_LOCK(pVc);
|
|
}
|
|
|
|
//
|
|
// If no more VC's in list mark AtmEntry as NOT connected
|
|
//
|
|
if (pAtmEntry->pVcList == NULL_PATMLANE_VC)
|
|
{
|
|
SET_FLAG(
|
|
pAtmEntry->Flags,
|
|
ATM_ENTRY_STATE_MASK,
|
|
ATM_ENTRY_VALID);
|
|
|
|
DBGP((2, "UnlinkVcFromAtmEntry: Aborting MAC Entries\n"));
|
|
|
|
pMacEntry = pAtmEntry->pMacEntryList;
|
|
|
|
//
|
|
// Take the MAC entry list out so that we can reference
|
|
// entries in this list in peace later on below.
|
|
//
|
|
pAtmEntry->pMacEntryList = NULL_PATMLANE_MAC_ENTRY;
|
|
|
|
//
|
|
// Let go of the ATM entry lock while we abort all
|
|
// the MAC entries in the list above. The ATM entry
|
|
// won't go away because of the VC reference still on it.
|
|
// The MAC entries in the list won't go away since they
|
|
// have the ATM entry reference on them (see UnlinkMacEntry..).
|
|
//
|
|
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
|
|
while (pMacEntry != NULL)
|
|
{
|
|
pNextMacEntry = pMacEntry->pNextToAtm;
|
|
|
|
//
|
|
// Now abort the MAC Entry. Put this MAC entry back
|
|
// on the ATM entry's list so that it gets handled
|
|
// appropriately by AbortMacEntry.
|
|
//
|
|
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
|
|
|
|
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
|
|
pMacEntry->pNextToAtm = pAtmEntry->pMacEntryList;
|
|
pAtmEntry->pMacEntryList = pMacEntry;
|
|
|
|
ASSERT(pMacEntry->pAtmEntry == pAtmEntry);
|
|
|
|
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
|
|
AtmLaneAbortMacEntry(pMacEntry);
|
|
// MacEntry lock released in above
|
|
|
|
pMacEntry = pNextMacEntry;
|
|
}
|
|
|
|
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
|
|
}
|
|
|
|
rc = AtmLaneDereferenceAtmEntry(pAtmEntry, "vc"); // VC reference
|
|
if (rc > 0)
|
|
{
|
|
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
}
|
|
//
|
|
// else the ATM Entry is gone!
|
|
//
|
|
|
|
//
|
|
// Acquire the VC lock again for the caller's sake
|
|
//
|
|
ACQUIRE_VC_LOCK(pVc);
|
|
return (Found);
|
|
}
|
|
|
|
BOOLEAN
|
|
AtmLaneUnlinkMacEntryFromAtmEntry(
|
|
IN PATMLANE_MAC_ENTRY pMacEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlink a Mac Entry from the ATM Entry it is linked to.
|
|
Allow for the MAC entry to be absent in the ATM Entry's list.
|
|
The caller is assumed to hold a lock for the Mac Entry.
|
|
|
|
Arguments:
|
|
|
|
pMacEntry - Pointer to Mac Entry to be unlinked.
|
|
|
|
Return Value:
|
|
|
|
TRUE iff the MAC entry was found and unlinked.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
PATMLANE_MAC_ENTRY * ppNextMacEntry;
|
|
ULONG rc; // Ref Count on ATM Entry
|
|
BOOLEAN bFound = FALSE;
|
|
|
|
pAtmEntry = pMacEntry->pAtmEntry;
|
|
ASSERT(pAtmEntry != NULL_PATMLANE_ATM_ENTRY);
|
|
|
|
DBGP((2, "%d UnlinkMacEntryFromAtmEntry: MacEntry %x AtmEntry %x\n",
|
|
pAtmEntry->pElan->ElanNumber,
|
|
pMacEntry, pMacEntry->pAtmEntry));
|
|
|
|
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
|
|
//
|
|
// Locate the position of this MAC Entry in the ATM Entry's list.
|
|
//
|
|
ppNextMacEntry = &(pAtmEntry->pMacEntryList);
|
|
|
|
while (*ppNextMacEntry != NULL_PATMLANE_MAC_ENTRY)
|
|
{
|
|
if (*ppNextMacEntry == pMacEntry)
|
|
{
|
|
//
|
|
// Found it.
|
|
//
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ppNextMacEntry = &((*ppNextMacEntry)->pNextToAtm);
|
|
}
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
//
|
|
// Make the predecessor point to the next entry.
|
|
//
|
|
*ppNextMacEntry = pMacEntry->pNextToAtm;
|
|
|
|
rc = AtmLaneDereferenceAtmEntry(pAtmEntry, "mac"); // MAC entry reference
|
|
if (rc != 0)
|
|
{
|
|
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
}
|
|
//
|
|
// else the ATM Entry is gone.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The entry wasn't found.
|
|
//
|
|
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneStartTimer(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PATMLANE_TIMER pTimer,
|
|
IN ATMLANE_TIMEOUT_HANDLER TimeoutHandler,
|
|
IN ULONG SecondsToGo,
|
|
IN PVOID ContextPtr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start an ATMLANE timer. Based on the length (SecondsToGo) of the
|
|
timer, we decide on whether to insert it in the short duration
|
|
timer list or in the long duration timer list in the Elan
|
|
structure.
|
|
|
|
NOTE: the caller is assumed to either hold a lock to the structure
|
|
that contains the timer, or ensure that it is safe to access the
|
|
timer structure.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to the ATMLANE Elan
|
|
pTimer - Pointer to ATMLANE Timer structure
|
|
TimeoutHandler - Handler function to be called if this timer expires
|
|
SecondsToGo - When does this timer go off?
|
|
ContextPtr - To be passed to timeout handler if this timer expires
|
|
ContextValue - To be passed to timeout handler if this timer expires
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_TIMER_LIST pTimerList; // List to which this timer goes
|
|
PATMLANE_TIMER pTimerListHead; // Head of above list
|
|
ULONG Index; // Into timer wheel
|
|
ULONG TicksToGo;
|
|
INT i;
|
|
|
|
TRACEIN(StartTimer);
|
|
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
DBGP((5,
|
|
"StartTimer: pElan %x, Secs %d, Handler %x, Ctxtp %x, pTimer %x\n",
|
|
pElan, SecondsToGo, TimeoutHandler, ContextPtr, pTimer));
|
|
|
|
if (IS_TIMER_ACTIVE(pTimer))
|
|
{
|
|
DBGP((5,
|
|
"Start timer: pTimer %x: is active (list %x, hndlr %x), stopping it\n",
|
|
pTimer, pTimer->pTimerList, pTimer->TimeoutHandler));
|
|
AtmLaneStopTimer(pTimer, pElan);
|
|
}
|
|
|
|
ACQUIRE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
ASSERT(!IS_TIMER_ACTIVE(pTimer));
|
|
|
|
//
|
|
// Find the list to which this timer should go, and the
|
|
// offset (TicksToGo)
|
|
//
|
|
Try_Again:
|
|
for (i = 0; i < ALT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pElan->TimerList[i]);
|
|
if (SecondsToGo <= pTimerList->MaxTimer)
|
|
{
|
|
//
|
|
// Found it.
|
|
//
|
|
TicksToGo = SecondsToGo / (pTimerList->TimerPeriod);
|
|
if (TicksToGo >= 1)
|
|
TicksToGo--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ALT_CLASS_MAX)
|
|
{
|
|
//
|
|
// Force this timer down!
|
|
//
|
|
SecondsToGo = pTimerList->MaxTimer;
|
|
goto Try_Again;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the position in the list for this timer
|
|
//
|
|
Index = pTimerList->CurrentTick + TicksToGo;
|
|
if (Index >= pTimerList->TimerListSize)
|
|
{
|
|
Index -= pTimerList->TimerListSize;
|
|
}
|
|
ASSERT(Index < pTimerList->TimerListSize);
|
|
|
|
pTimerListHead = &(pTimerList->pTimers[Index]);
|
|
|
|
//
|
|
// Fill in the timer
|
|
//
|
|
pTimer->pTimerList = pTimerList;
|
|
pTimer->LastRefreshTime = pTimerList->CurrentTick;
|
|
pTimer->Duration = TicksToGo;
|
|
pTimer->TimeoutHandler = TimeoutHandler;
|
|
pTimer->ContextPtr = ContextPtr;
|
|
|
|
//
|
|
// Insert this timer in the "ticking" list
|
|
//
|
|
pTimer->pPrevTimer = pTimerListHead;
|
|
pTimer->pNextTimer = pTimerListHead->pNextTimer;
|
|
if (pTimer->pNextTimer != NULL_PATMLANE_TIMER)
|
|
{
|
|
pTimer->pNextTimer->pPrevTimer = pTimer;
|
|
}
|
|
pTimerListHead->pNextTimer = pTimer;
|
|
|
|
//
|
|
// Start off the system tick timer if necessary.
|
|
//
|
|
pTimerList->TimerCount++;
|
|
if (pTimerList->TimerCount == 1)
|
|
{
|
|
DBGP((5,
|
|
"StartTimer: Starting system timer %x, class %d on Elan %x\n",
|
|
&(pTimerList->NdisTimer), i, pElan));
|
|
|
|
START_SYSTEM_TIMER(&(pTimerList->NdisTimer), pTimerList->TimerPeriod);
|
|
}
|
|
|
|
RELEASE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
//
|
|
// We're done
|
|
//
|
|
DBGP((5,
|
|
"Started timer %x, Elan %x, Secs %d, Index %d, Head %x\n",
|
|
pTimer,
|
|
pElan,
|
|
SecondsToGo,
|
|
Index,
|
|
pTimerListHead));
|
|
|
|
TRACEOUT(StartTimer);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
AtmLaneStopTimer(
|
|
IN PATMLANE_TIMER pTimer,
|
|
IN PATMLANE_ELAN pElan
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop an ATMLANE timer, if it is running. We remove this timer from
|
|
the active timer list and mark it so that we know it's not running.
|
|
|
|
NOTE: the caller is assumed to either hold a lock to the structure
|
|
that contains the timer, or ensure that it is safe to access the
|
|
timer structure.
|
|
|
|
SIDE EFFECT: If we happen to stop the last timer (of this "duration") on
|
|
the Interface, we also stop the appropriate Tick function.
|
|
|
|
Arguments:
|
|
|
|
pTimer - Pointer to ATMLANE Timer structure
|
|
pElan - Pointer to interface to which the timer belongs
|
|
|
|
Return Value:
|
|
|
|
TRUE if the timer was running, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_TIMER_LIST pTimerList; // Timer List to which this timer belongs
|
|
BOOLEAN WasRunning;
|
|
|
|
TRACEIN(StopTimer);
|
|
|
|
DBGP((5,
|
|
"Stopping Timer %x, Elan %x, List %x, Prev %x, Next %x\n",
|
|
pTimer,
|
|
pElan,
|
|
pTimer->pTimerList,
|
|
pTimer->pPrevTimer,
|
|
pTimer->pNextTimer));
|
|
|
|
ACQUIRE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
if (IS_TIMER_ACTIVE(pTimer))
|
|
{
|
|
WasRunning = TRUE;
|
|
|
|
//
|
|
// Unlink timer from the list
|
|
//
|
|
ASSERT(pTimer->pPrevTimer); // the list head always exists
|
|
|
|
pTimer->pPrevTimer->pNextTimer = pTimer->pNextTimer;
|
|
if (pTimer->pNextTimer)
|
|
{
|
|
pTimer->pNextTimer->pPrevTimer = pTimer->pPrevTimer;
|
|
}
|
|
|
|
pTimer->pNextTimer = pTimer->pPrevTimer = NULL_PATMLANE_TIMER;
|
|
|
|
//
|
|
// Update timer count on Interface, for this class of timers
|
|
//
|
|
pTimerList = pTimer->pTimerList;
|
|
pTimerList->TimerCount--;
|
|
|
|
//
|
|
// If all timers of this class are gone, stop the system tick timer
|
|
// for this class
|
|
//
|
|
if (pTimerList->TimerCount == 0)
|
|
{
|
|
DBGP((5,
|
|
"Stopping system timer %x, List %x, Elan %x\n",
|
|
&(pTimerList->NdisTimer),
|
|
pTimerList,
|
|
pElan));
|
|
|
|
pTimerList->CurrentTick = 0;
|
|
STOP_SYSTEM_TIMER(&(pTimerList->NdisTimer));
|
|
}
|
|
|
|
//
|
|
// Mark stopped timer as not active
|
|
//
|
|
pTimer->pTimerList = (PATMLANE_TIMER_LIST)NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
WasRunning = FALSE;
|
|
}
|
|
|
|
RELEASE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
TRACEOUT(StopTimer);
|
|
|
|
return (WasRunning);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmLaneRefreshTimer(
|
|
IN PATMLANE_TIMER pTimer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Refresh a timer that is already running.
|
|
|
|
NOTE: The caller is assumed to possess a lock protecting the
|
|
timer structure (i.e. to the structure containing the timer).
|
|
|
|
NOTE: We don't acquire the IF Timer Lock here, to optimize
|
|
the refresh operation. So, _within_ the confines of this routine,
|
|
the tick handler may fire, and expire this timer. The only care
|
|
that we take here is to make sure that we don't crash if the
|
|
timer expires while we access the Timer list.
|
|
|
|
Arguments:
|
|
|
|
pTimer - Pointer to ATMLANE_TIMER structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_TIMER_LIST pTimerList;
|
|
|
|
TRACEIN(RefreshTimer);
|
|
|
|
if ((pTimerList = pTimer->pTimerList) != (PATMLANE_TIMER_LIST)NULL)
|
|
{
|
|
pTimer->LastRefreshTime = pTimerList->CurrentTick;
|
|
}
|
|
else
|
|
{
|
|
DBGP((5,
|
|
"RefreshTimer: pTimer %x not active: Hnd %x, Ctxtp %x\n",
|
|
pTimer,
|
|
pTimer->TimeoutHandler,
|
|
pTimer->ContextPtr
|
|
));
|
|
}
|
|
|
|
DBGP((5,
|
|
"Refreshed timer %x, List %x, hnd %x, Ctxtp %x, LastRefresh %d\n",
|
|
pTimer,
|
|
pTimer->pTimerList,
|
|
pTimer->TimeoutHandler,
|
|
pTimer->ContextPtr,
|
|
pTimer->LastRefreshTime));
|
|
|
|
TRACEOUT(RefreshTimer);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneTickHandler(
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID Context,
|
|
IN PVOID SystemSpecific2,
|
|
IN PVOID SystemSpecific3
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the handler we register with the system for processing each
|
|
Timer List. This is called every "tick" seconds, where "tick" is
|
|
determined by the granularity of the timer type.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to a Timer List structure
|
|
SystemSpecific[1-3] - Not used
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PATMLANE_ELAN pElan;
|
|
PATMLANE_TIMER_LIST pTimerList;
|
|
|
|
PATMLANE_TIMER pExpiredTimer; // Start of list of expired timers
|
|
PATMLANE_TIMER pNextTimer; // for walking above list
|
|
PATMLANE_TIMER pTimer; // temp, for walking timer list
|
|
PATMLANE_TIMER pPrevExpiredTimer; // for creating expired timer list
|
|
|
|
ULONG Index; // into the timer wheel
|
|
ULONG NewIndex; // for refreshed timers
|
|
|
|
TRACEIN(TickHandler);
|
|
|
|
pTimerList = (PATMLANE_TIMER_LIST)Context;
|
|
STRUCT_ASSERT(pTimerList, atmlane_timerlist);
|
|
|
|
pElan = (PATMLANE_ELAN)pTimerList->ListContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
DBGP((5,
|
|
"Tick: pElan %x, List %x, Count %d\n",
|
|
pElan, pTimerList, pTimerList->TimerCount));
|
|
|
|
pExpiredTimer = NULL_PATMLANE_TIMER;
|
|
|
|
ACQUIRE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
if (ELAN_STATE_OPERATIONAL == pElan->AdminState)
|
|
{
|
|
//
|
|
// Pick up the list of timers scheduled to have expired at the
|
|
// current tick. Some of these might have been refreshed.
|
|
//
|
|
Index = pTimerList->CurrentTick;
|
|
pExpiredTimer = (pTimerList->pTimers[Index]).pNextTimer;
|
|
(pTimerList->pTimers[Index]).pNextTimer = NULL_PATMLANE_TIMER;
|
|
|
|
//
|
|
// Go through the list of timers scheduled to expire at this tick.
|
|
// Prepare a list of expired timers, using the pNextExpiredTimer
|
|
// link to chain them together.
|
|
//
|
|
// Some timers may have been refreshed, in which case we reinsert
|
|
// them in the active timer list.
|
|
//
|
|
pPrevExpiredTimer = NULL_PATMLANE_TIMER;
|
|
|
|
for (pTimer = pExpiredTimer;
|
|
pTimer != NULL_PATMLANE_TIMER;
|
|
pTimer = pNextTimer)
|
|
{
|
|
//
|
|
// Save a pointer to the next timer, for the next iteration.
|
|
//
|
|
pNextTimer = pTimer->pNextTimer;
|
|
|
|
DBGP((5,
|
|
"Tick Handler: pElan %x, looking at timer %x, next %x\n",
|
|
pElan, pTimer, pNextTimer));
|
|
|
|
//
|
|
// Find out when this timer should actually expire.
|
|
//
|
|
NewIndex = pTimer->LastRefreshTime + pTimer->Duration;
|
|
if (NewIndex >= pTimerList->TimerListSize)
|
|
{
|
|
NewIndex -= pTimerList->TimerListSize;
|
|
}
|
|
|
|
//
|
|
// Check if we are currently at the point of expiry.
|
|
//
|
|
if (NewIndex != Index)
|
|
{
|
|
//
|
|
// This timer still has some way to go, so put it back.
|
|
//
|
|
DBGP((5,
|
|
"Tick: Reinserting Timer %x: Hnd %x, Durn %d, Ind %d, NewInd %d\n",
|
|
pTimer, pTimer->TimeoutHandler, pTimer->Duration, Index, NewIndex));
|
|
|
|
//
|
|
// Remove it from the expired timer list. Note that we only
|
|
// need to update the forward (pNextExpiredTimer) links.
|
|
//
|
|
if (pPrevExpiredTimer == NULL_PATMLANE_TIMER)
|
|
{
|
|
pExpiredTimer = pNextTimer;
|
|
}
|
|
else
|
|
{
|
|
pPrevExpiredTimer->pNextExpiredTimer = pNextTimer;
|
|
}
|
|
|
|
//
|
|
// And insert it back into the running timer list.
|
|
//
|
|
pTimer->pNextTimer = (pTimerList->pTimers[NewIndex]).pNextTimer;
|
|
if (pTimer->pNextTimer != NULL_PATMLANE_TIMER)
|
|
{
|
|
pTimer->pNextTimer->pPrevTimer = pTimer;
|
|
}
|
|
pTimer->pPrevTimer = &(pTimerList->pTimers[NewIndex]);
|
|
(pTimerList->pTimers[NewIndex]).pNextTimer = pTimer;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This one has expired. Keep it in the expired timer list.
|
|
//
|
|
pTimer->pNextExpiredTimer = pNextTimer;
|
|
if (pPrevExpiredTimer == NULL_PATMLANE_TIMER)
|
|
{
|
|
pExpiredTimer = pTimer;
|
|
}
|
|
pPrevExpiredTimer = pTimer;
|
|
|
|
//
|
|
// Mark it as inactive.
|
|
//
|
|
ASSERT(pTimer->pTimerList == pTimerList);
|
|
pTimer->pTimerList = (PATMLANE_TIMER_LIST)NULL;
|
|
|
|
//
|
|
// Update the active timer count.
|
|
//
|
|
pTimerList->TimerCount--;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update current tick index in readiness for the next tick.
|
|
//
|
|
if (++Index == pTimerList->TimerListSize)
|
|
{
|
|
pTimerList->CurrentTick = 0;
|
|
}
|
|
else
|
|
{
|
|
pTimerList->CurrentTick = Index;
|
|
}
|
|
|
|
if (pTimerList->TimerCount > 0)
|
|
{
|
|
//
|
|
// Re-arm the tick handler
|
|
//
|
|
DBGP((5,
|
|
"Tick[%d]: Starting system timer %x, on Elan %x\n",
|
|
pTimerList->CurrentTick, &(pTimerList->NdisTimer), pElan));
|
|
|
|
START_SYSTEM_TIMER(&(pTimerList->NdisTimer), pTimerList->TimerPeriod);
|
|
}
|
|
else
|
|
{
|
|
pTimerList->CurrentTick = 0;
|
|
}
|
|
|
|
}
|
|
|
|
RELEASE_ELAN_TIMER_LOCK(pElan);
|
|
|
|
//
|
|
// Now pExpiredTimer is a list of expired timers.
|
|
// Walk through the list and call the timeout handlers
|
|
// for each timer.
|
|
//
|
|
while (pExpiredTimer != NULL_PATMLANE_TIMER)
|
|
{
|
|
pNextTimer = pExpiredTimer->pNextExpiredTimer;
|
|
|
|
DBGP((5,
|
|
"Expired timer %x: handler %x, next %x\n",
|
|
pExpiredTimer, pExpiredTimer->TimeoutHandler, pNextTimer));
|
|
|
|
(*(pExpiredTimer->TimeoutHandler))(
|
|
pExpiredTimer,
|
|
pExpiredTimer->ContextPtr
|
|
);
|
|
|
|
pExpiredTimer = pNextTimer;
|
|
}
|
|
|
|
|
|
TRACEOUT(TickHandler);
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
AtmLaneSystemTimeMs(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine get the current system clock tick value and
|
|
returns this value converted to milliseconds.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
The system clock value in milliseconds.
|
|
|
|
--*/
|
|
{
|
|
#if BINARY_COMPATIBLE
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
NdisGetCurrentSystemTime(&SystemTime);
|
|
|
|
// comes back in 100 nanosecond units, we want milliseconds
|
|
|
|
SystemTime.QuadPart /= 10000;
|
|
|
|
return SystemTime.LowPart;
|
|
#else
|
|
static LARGE_INTEGER Frequency = {0L,0L};
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
SystemTime = KeQueryPerformanceCounter(Frequency.LowPart == 0?&Frequency:NULL);
|
|
|
|
SystemTime.QuadPart = SystemTime.QuadPart * 1000000 / Frequency.QuadPart;
|
|
|
|
return SystemTime.LowPart;
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmLaneBitSwapMacAddr(
|
|
IN OUT PUCHAR ap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine swaps (reverses) the bits in each individual
|
|
byte of a MAC Address. Use for Token Ring MAC addresses.
|
|
|
|
Arguments:
|
|
|
|
ap - Pointer to array of bytes to bitswap in-place.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
unsigned int x;
|
|
|
|
for (i = 0; i != 6; i++)
|
|
{
|
|
x = ap[i];
|
|
x = ((x & 0xaau) >> 1) | ((x & 0x55u) << 1);
|
|
x = ((x & 0xccu) >> 2) | ((x & 0x33u) << 2);
|
|
x = ((x & 0xf0u) >> 4) | ((x & 0x0fu) << 4);
|
|
ap[i] = (UCHAR)x;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
AtmLaneCopyUnicodeString(
|
|
IN OUT PUNICODE_STRING pDestString,
|
|
IN OUT PUNICODE_STRING pSrcString,
|
|
IN BOOLEAN AllocDest,
|
|
IN BOOLEAN ConvertToUpper
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine optionally allocates space in the destination string
|
|
for the source string plus a terminating null. It
|
|
copies the source string to the destination string and
|
|
terminates the destination string with a null.
|
|
|
|
-*/
|
|
BOOLEAN Result = TRUE;
|
|
|
|
TRACEIN(CopyUnicodeString);
|
|
|
|
do
|
|
{
|
|
// Alloc space for the destination string if requested
|
|
|
|
if (AllocDest)
|
|
{
|
|
ALLOC_MEM(&(pDestString->Buffer), pSrcString->Length + sizeof(WCHAR));
|
|
if (NULL == pDestString->Buffer)
|
|
{
|
|
Result = FALSE;
|
|
break;
|
|
}
|
|
|
|
// Init lengths in dest string
|
|
|
|
pDestString->Length = 0;
|
|
pDestString->MaximumLength = pSrcString->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
// Copy the string
|
|
|
|
if (ConvertToUpper)
|
|
{
|
|
#ifndef LANE_WIN98
|
|
(VOID)NdisUpcaseUnicodeString(pDestString, pSrcString);
|
|
#else
|
|
memcpy(pDestString->Buffer, pSrcString->Buffer, pSrcString->Length);
|
|
#endif // LANE_WIN98
|
|
}
|
|
else
|
|
{
|
|
RtlCopyUnicodeString(pDestString, pSrcString);
|
|
}
|
|
|
|
// Null terminate the dest string
|
|
|
|
if (pDestString->Length < pDestString->MaximumLength)
|
|
{
|
|
pDestString->Buffer[pDestString->Length/sizeof(WCHAR)] = ((WCHAR)0);
|
|
}
|
|
else
|
|
{
|
|
pDestString->Buffer[(pDestString->MaximumLength - sizeof(WCHAR))/sizeof(WCHAR)] =
|
|
((WCHAR)0);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
TRACEOUT(CopyUnicodeString);
|
|
return Result;
|
|
}
|
|
|
|
PWSTR
|
|
AtmLaneStrTok(
|
|
IN PWSTR StrToken,
|
|
IN WCHAR ChrDelim,
|
|
OUT PUSHORT pStrLength
|
|
)
|
|
{
|
|
static PWSTR StrSave = NULL;
|
|
USHORT StrLength = 0;
|
|
PWSTR StrOut = NULL;
|
|
|
|
TRACEIN(StrTok);
|
|
do
|
|
{
|
|
// check for bad input
|
|
|
|
if ((StrToken == NULL && StrSave == NULL) ||
|
|
ChrDelim == ((WCHAR)0))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// if starting with new string, reset StrSave
|
|
|
|
if (StrToken != NULL)
|
|
{
|
|
StrSave = StrToken;
|
|
}
|
|
|
|
// token starts at start of current string
|
|
|
|
StrOut = StrSave;
|
|
|
|
// walk string until delimiter or NULL
|
|
|
|
while (*StrSave != ChrDelim && *StrSave != ((WCHAR)0))
|
|
{
|
|
StrSave++;
|
|
StrLength++;
|
|
}
|
|
|
|
// If we found a delimiter then NULL it out and
|
|
// move saved ptr to next token to setup for next
|
|
// call on same string.
|
|
|
|
if (*StrSave == ChrDelim)
|
|
{
|
|
*StrSave = ((WCHAR)0);
|
|
StrSave++;
|
|
}
|
|
|
|
// If pointing at empty string then return null ptr
|
|
|
|
if (*StrOut == ((WCHAR)0))
|
|
{
|
|
StrOut = NULL;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
TRACEOUT(StrTok);
|
|
*pStrLength = StrLength * sizeof(WCHAR);
|
|
return StrOut;
|
|
}
|