3421 lines
68 KiB
C
3421 lines
68 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c - Utility functions.
|
|
|
|
Abstract:
|
|
|
|
Internal utility functions for ATMARP:
|
|
|
|
- Allocation and deallocation of various structures
|
|
- Timer management
|
|
- Buffer/Packet management
|
|
- Linking/unlinking ATMARP structures
|
|
- Copy support functions
|
|
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 07-15-96 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'LITU'
|
|
|
|
//
|
|
// AtmArpValidateTimerList and AtmArpValidateTimer are used in the checked
|
|
// build to validate the state of a timerlist and timer, respectively.
|
|
// They are not defined and used in the free build.
|
|
//
|
|
|
|
#if DBG
|
|
void
|
|
AtmArpValidateTimerList(
|
|
PATMARP_TIMER_LIST pTimerList
|
|
);
|
|
|
|
void
|
|
AtmArpValidateTimer(
|
|
PATMARP_TIMER_LIST pTimerList,
|
|
PATMARP_TIMER pTimer
|
|
);
|
|
|
|
//
|
|
// AtmArpValidateTimerList is overkill for general use (even default
|
|
// free build) -- because it goes through the entire timer list --
|
|
// so disable it by default
|
|
//
|
|
#if 0
|
|
#define AA_VALIDATE_TIMER_LIST(_ptl) AtmArpValidateTimerList(_ptl)
|
|
#else
|
|
#define AA_VALIDATE_TIMER_LIST(_ptl) ((void) 0)
|
|
#endif
|
|
|
|
#define AA_VALIDATE_TIMER(_ptl,_pt) AtmArpValidateTimer(_ptl,_pt)
|
|
|
|
#else // !DBG
|
|
|
|
#define AA_VALIDATE_TIMER_LIST(_ptl) ((void) 0)
|
|
#define AA_VALIDATE_TIMER(_ptl,_pt) ((void) 0)
|
|
|
|
#endif // !DBG
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpSetMemory(
|
|
IN PUCHAR pStart,
|
|
IN UCHAR Value,
|
|
IN ULONG NumberOfBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set "NumberOfBytes" bytes starting from "pStart" to "Value".
|
|
|
|
Arguments:
|
|
|
|
pStart - where to start filling.
|
|
Value - the value to put everywhere
|
|
NumberOfBytes - how many bytes to fill in
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
while (NumberOfBytes--)
|
|
{
|
|
*pStart++ = Value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
AtmArpMemCmp(
|
|
IN PUCHAR pString1,
|
|
IN PUCHAR pString2,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare two byte strings.
|
|
|
|
Arguments:
|
|
|
|
pString1 - Start of first string
|
|
pString2 - Start of second string
|
|
Length - Length to compare
|
|
|
|
Return Value:
|
|
|
|
0 if both are equal, -1 if string 1 is "smaller", +1 if string 1 is "larger".
|
|
|
|
--*/
|
|
{
|
|
while (Length--)
|
|
{
|
|
if (*pString1 != *pString2)
|
|
{
|
|
return ((*pString1 > *pString2)? (ULONG)1 : (ULONG)-1);
|
|
}
|
|
pString1++;
|
|
pString2++;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
AtmArpRandomNumber(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a positive pseudo-random number; simple linear congruential
|
|
algorithm. ANSI C "rand()" function. Courtesy JameelH.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
a random number.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER Li;
|
|
static LONG seed = 0;
|
|
|
|
if (seed == 0)
|
|
{
|
|
NdisGetCurrentSystemTime(&Li);
|
|
seed = Li.LowPart;
|
|
}
|
|
|
|
seed *= (0x41C64E6D + 0x3039);
|
|
return (seed & 0x7FFFFFFF);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCheckIfTimerIsInActiveList(
|
|
IN PATMARP_TIMER pTimerToCheck,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PVOID pStruct,
|
|
IN PCHAR pStructName
|
|
)
|
|
/*
|
|
Instrumentation to catch a bug that causes the timer list to
|
|
contain a pointer to an element that's been freed.
|
|
*/
|
|
{
|
|
PATMARP_TIMER_LIST pTimerList;
|
|
PATMARP_TIMER pTimer;
|
|
ULONG i, j;
|
|
|
|
do
|
|
{
|
|
if (pInterface == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pTimerToCheck->State == ATMARP_TIMER_STATE_RUNNING ||
|
|
pTimerToCheck->State == ATMARP_TIMER_STATE_EXPIRING)
|
|
{
|
|
DbgPrint("ATMARPC: %s at %x contains timer %x still active on IF %x\n",
|
|
pStructName,
|
|
pStruct,
|
|
pTimerToCheck,
|
|
pInterface);
|
|
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AA_ACQUIRE_IF_TIMER_LOCK(pInterface);
|
|
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &pInterface->TimerList[i];
|
|
|
|
for (j = 0; j < pTimerList->TimerListSize; j++)
|
|
{
|
|
for (pTimer = pTimerList->pTimers[j].pNextTimer;
|
|
pTimer != NULL_PATMARP_TIMER;
|
|
pTimer = pTimer->pNextTimer)
|
|
{
|
|
if (pTimer == pTimerToCheck)
|
|
{
|
|
DbgPrint("ATMARPC: %s at %x contains timer %x still active on IF %x, Head of list %x\n",
|
|
pStructName,
|
|
pStruct,
|
|
pTimerToCheck,
|
|
pInterface,
|
|
&pTimerList->pTimers[j]);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AA_RELEASE_IF_TIMER_LOCK(pInterface);
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
PATMARP_VC
|
|
AtmArpAllocateVc(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATMARP VC structure, initialize it, and return it.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Interface for which this VC is created.
|
|
|
|
Return Value:
|
|
|
|
Pointer to VC if allocated, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AA_ALLOC_MEM(pVc, ATMARP_VC, sizeof(ATMARP_VC));
|
|
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
AA_SET_MEM(pVc, 0, sizeof(ATMARP_VC));
|
|
#if DBG
|
|
pVc->avc_sig = avc_signature;
|
|
#endif // DBG
|
|
pVc->pInterface = pInterface;
|
|
AA_INIT_VC_LOCK(pVc);
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD, ("Allocated Vc 0x%x\n", pVc));
|
|
|
|
return (pVc);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateVc(
|
|
IN PATMARP_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an ATMARP 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
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
AA_ASSERT(pVc->RefCount == 0);
|
|
AA_ASSERT(!AA_IS_TIMER_ACTIVE(&pVc->Timer));
|
|
|
|
AA_CHECK_TIMER_IN_ACTIVE_LIST(&pVc->Timer, pVc->pInterface, pVc, "VC");
|
|
|
|
#if DBG
|
|
pVc->avc_sig++;
|
|
#endif
|
|
AA_FREE_VC_LOCK(pVc);
|
|
AA_FREE_MEM(pVc);
|
|
|
|
AADEBUGP(AAD_LOUD, ("Deallocated Vc 0x%x\n", pVc));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpReferenceVc(
|
|
IN PATMARP_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to the specified ATMARP 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
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
pVc->RefCount++;
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Referencing Vc 0x%x, new count %d\n",
|
|
pVc, pVc->RefCount));
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
AtmArpDereferenceVc(
|
|
IN PATMARP_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from the specified ATMARP 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;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
BOOLEAN bVcOwnerIsAtmArp;
|
|
NDIS_STATUS Status;
|
|
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
AA_ASSERT(pVc->RefCount > 0);
|
|
|
|
rv = --(pVc->RefCount);
|
|
if (rv == 0)
|
|
{
|
|
#ifdef VC_REFS_ON_SENDS
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
bVcOwnerIsAtmArp = AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_OWNER_MASK,
|
|
AA_VC_OWNER_IS_ATMARP);
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
AtmArpDeallocateVc(pVc);
|
|
|
|
#ifdef VC_REFS_ON_SENDS
|
|
if ((NdisVcHandle != NULL) &&
|
|
(bVcOwnerIsAtmArp))
|
|
{
|
|
Status = NdisCoDeleteVc(NdisVcHandle);
|
|
AA_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
AADEBUGP(AAD_LOUD, ("DereferenceVc 0x%x, deleted NdisVcHandle 0x%x\n",
|
|
pVc, NdisVcHandle));
|
|
}
|
|
#endif // VC_REFS_ON_SENDS
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Dereference Vc 0x%x, New RefCount %d\n", pVc, rv));
|
|
|
|
return (rv);
|
|
}
|
|
|
|
|
|
|
|
|
|
PATMARP_ATM_ENTRY
|
|
AtmArpAllocateAtmEntry(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN BOOLEAN IsMulticast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATM Entry structure, initialize it, and return it.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP interface on which the entry is allocated
|
|
IsMulticast - Is this a Multicast entry?
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated ATM Entry structure if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
ULONG Size;
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
Size = sizeof(ATMARP_ATM_ENTRY)
|
|
#ifdef IPMCAST
|
|
+ (IsMulticast? sizeof(ATMARP_IPMC_ATM_INFO): 0);
|
|
#else
|
|
;
|
|
#endif
|
|
|
|
AA_ALLOC_MEM(pAtmEntry, ATMARP_ATM_ENTRY, Size);
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AA_SET_MEM(pAtmEntry, 0, Size);
|
|
#if DBG
|
|
pAtmEntry->aae_sig = aae_signature;
|
|
#endif
|
|
pAtmEntry->Flags = AA_ATM_ENTRY_IDLE;
|
|
#ifdef IPMCAST
|
|
if (IsMulticast)
|
|
{
|
|
pAtmEntry->Flags |= AA_ATM_ENTRY_TYPE_NUCAST;
|
|
pAtmEntry->pMcAtmInfo = (PATMARP_IPMC_ATM_INFO)
|
|
((PUCHAR)pAtmEntry + sizeof(ATMARP_ATM_ENTRY));
|
|
}
|
|
#endif // IPMCAST
|
|
AA_INIT_AE_LOCK(pAtmEntry);
|
|
pAtmEntry->pInterface = pInterface;
|
|
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO, ("Allocated ATM Entry: IF 0x%x, Entry 0x%x\n",
|
|
pInterface, pAtmEntry));
|
|
|
|
return (pAtmEntry);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateAtmEntry(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an ATMARP 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 ATMARP ATM Entry to be freed.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
AA_ASSERT(pAtmEntry->RefCount == 0);
|
|
AA_ASSERT(pAtmEntry->pVcList == NULL_PATMARP_VC);
|
|
AA_ASSERT(!AA_AE_IS_ALIVE(pAtmEntry));
|
|
|
|
|
|
#if DBG
|
|
pAtmEntry->aae_sig++;
|
|
#endif
|
|
|
|
AA_FREE_AE_LOCK(pAtmEntry);
|
|
AA_FREE_MEM(pAtmEntry);
|
|
|
|
AADEBUGP(AAD_INFO, ("Deallocated ATM Entry: 0x%x\n", pAtmEntry));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpReferenceAtmEntry(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to the specified ATMARP 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
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
|
|
pAtmEntry->RefCount++;
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Referencing AtmEntry 0x%x, new count %d\n",
|
|
pAtmEntry, pAtmEntry->RefCount));
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
AtmArpDereferenceAtmEntry(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry
|
|
)
|
|
/*++
|
|
|
|
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;
|
|
PATMARP_INTERFACE pInterface;
|
|
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
AA_ASSERT(pAtmEntry->RefCount > 0);
|
|
|
|
rc = --(pAtmEntry->RefCount);
|
|
if (rc == 0)
|
|
{
|
|
PATMARP_ATM_ENTRY * ppAtmEntry;
|
|
|
|
//
|
|
// We are most likely going to delete this entry...
|
|
//
|
|
// We must observe the protocol of 1st locking the list lock then
|
|
// the pAtmEntry's lock, so this requires us to do the
|
|
// release/lock/lock sequence below.
|
|
//
|
|
// Temporarly addref it again, to make sure that when we
|
|
// release the lock below someone else doesn't get confused.
|
|
//
|
|
pAtmEntry->RefCount++;
|
|
|
|
pInterface = pAtmEntry->pInterface;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
//
|
|
// No locks held at this time!
|
|
//
|
|
|
|
//
|
|
// Acquire locks in the correct order...
|
|
//
|
|
AA_ACQUIRE_IF_ATM_LIST_LOCK(pInterface);
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ASSERT(pAtmEntry->RefCount > 0);
|
|
rc = --(pAtmEntry->RefCount);
|
|
|
|
//
|
|
// We can't assume that the ref count is still zero -- in principle
|
|
// someone may have addrefd this pAtmEntry while both locks
|
|
// were released above...
|
|
//
|
|
if (rc == 0)
|
|
{
|
|
//
|
|
// Unlink this entry from the Interface's list of ATM Entries.
|
|
//
|
|
|
|
ppAtmEntry = &(pInterface->pAtmEntryList);
|
|
while (*ppAtmEntry != pAtmEntry)
|
|
{
|
|
AA_ASSERT(*ppAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
ppAtmEntry = &((*ppAtmEntry)->pNext);
|
|
}
|
|
|
|
*ppAtmEntry = pAtmEntry->pNext;
|
|
|
|
//
|
|
// Set state back to idle -- AtmArpDeallocate checks this...
|
|
//
|
|
AA_SET_FLAG(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_IDLE
|
|
);
|
|
}
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AA_RELEASE_IF_ATM_LIST_LOCK(pInterface);
|
|
|
|
if (rc == 0)
|
|
{
|
|
AtmArpDeallocateAtmEntry(pAtmEntry);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Caller expects to still hold the lock on pAtmEntry!
|
|
// if we return nonzero rc ...
|
|
// We can't simply re-acquire the lock because the caller expects
|
|
// the that lock was never released.
|
|
// So, since the ref count had gone to zero, as far as the caller
|
|
// is concerned this structure has gone away and so we lie
|
|
// and return 0 here...
|
|
//
|
|
rc = 0;
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD,
|
|
("Dereference AtmEntry 0x%x, New RefCount %d\n", pAtmEntry, rc));
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
|
|
PATMARP_IP_ENTRY
|
|
AtmArpAllocateIPEntry(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATMARP IP Entry structure, initialize it, and
|
|
return it.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface on which this IP
|
|
Entry is allocated.
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated IP Entry structure if successful,
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
|
|
AA_ALLOC_MEM(pIpEntry, ATMARP_IP_ENTRY, sizeof(ATMARP_IP_ENTRY));
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AA_SET_MEM(pIpEntry, 0, sizeof(ATMARP_IP_ENTRY));
|
|
#if DBG
|
|
pIpEntry->aip_sig = aip_signature;
|
|
#endif // DBG
|
|
pIpEntry->pInterface = pInterface;
|
|
pIpEntry->Flags = AA_IP_ENTRY_IDLE;
|
|
#ifdef IPMCAST
|
|
pIpEntry->NextMultiSeq = AA_MARS_INITIAL_Y; // Init on allocation
|
|
#endif
|
|
AA_INIT_IE_LOCK(pIpEntry);
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Allocated IP Entry 0x%x\n", pIpEntry));
|
|
return (pIpEntry);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateIPEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an ATMARP IP Entry. It is assumed that all references
|
|
to this IP Entry have gone, so there is no need to acquire its
|
|
lock.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - Pointer to the IP Entry to be deallocated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pIpEntry, aip);
|
|
AA_ASSERT(pIpEntry->RefCount == 0);
|
|
AA_ASSERT(!AA_IE_IS_ALIVE(pIpEntry));
|
|
AA_ASSERT(!AA_IS_TIMER_ACTIVE(&pIpEntry->Timer));
|
|
|
|
AA_CHECK_TIMER_IN_ACTIVE_LIST(&pIpEntry->Timer, pIpEntry->pInterface, pIpEntry, "IP Entry");
|
|
|
|
#if DBG
|
|
pIpEntry->aip_sig = ~(pIpEntry->aip_sig);
|
|
#endif // DBG
|
|
|
|
AA_FREE_IE_LOCK(pIpEntry);
|
|
AA_FREE_MEM(pIpEntry);
|
|
|
|
AADEBUGP(AAD_LOUD, ("Deallocated IP Entry 0x%x\n", pIpEntry));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpReferenceIPEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to an ATMARP IP Entry.
|
|
NOTE: The caller is assumed to possess a lock for the IP Entry.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - Pointer to an ATMARP IP Entry.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pIpEntry, aip);
|
|
|
|
pIpEntry->RefCount++;
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Referenced IP Entry 0x%x, new count %d\n",
|
|
pIpEntry, pIpEntry->RefCount));
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
AtmArpDereferenceIPEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from an ATMARP IP Entry. If the reference
|
|
count becomes zero, deallocate it.
|
|
NOTE: It is assumed that the caller holds a lock to the IP Entry.
|
|
See SIDE EFFECT below.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - Pointer to ATMARP IP Entry
|
|
|
|
Return Value:
|
|
|
|
The resulting reference count. If this is zero, then there are two
|
|
SIDE EFFECTS: (1) the IP Entry lock is released (2) the structure
|
|
is freed.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
|
|
AA_STRUCT_ASSERT(pIpEntry, aip);
|
|
|
|
rc = --(pIpEntry->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
AtmArpDeallocateIPEntry(pIpEntry);
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Dereference IP Entry 0x%x: new count %d\n",
|
|
pIpEntry, rc));
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
PATMARP_INTERFACE
|
|
AtmArpAllocateInterface(
|
|
IN PATMARP_ADAPTER pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an ATMARP interface structure, initialize it, link it to
|
|
the given adapter structure, and return it.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Pointer to ATMARP interface structure, if successful, else NULL.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_IP_ENTRY * pArpTable;
|
|
PATMARP_TIMER_LIST pTimerList;
|
|
NDIS_STATUS Status;
|
|
PCO_SAP pIfSap;
|
|
ULONG SapSize;
|
|
PWSTR pIPConfigBuffer;
|
|
USHORT ConfigBufferSize;
|
|
INT i;
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
pInterface = NULL_PATMARP_INTERFACE;
|
|
pArpTable = (PATMARP_IP_ENTRY *)NULL;
|
|
pIfSap = (PCO_SAP)NULL;
|
|
pIPConfigBuffer = (PWSTR)NULL;
|
|
|
|
SapSize = sizeof(CO_SAP)+sizeof(ATM_SAP)+sizeof(ATM_ADDRESS);
|
|
ConfigBufferSize = MAX_IP_CONFIG_STRING_LEN * sizeof(WCHAR);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate everything.
|
|
//
|
|
AA_ALLOC_MEM(pInterface, ATMARP_INTERFACE, sizeof(ATMARP_INTERFACE));
|
|
AA_ALLOC_MEM(pArpTable, PATMARP_IP_ENTRY, ATMARP_TABLE_SIZE*sizeof(PATMARP_IP_ENTRY));
|
|
AA_ALLOC_MEM(pIfSap, CO_SAP, SapSize);
|
|
|
|
if ((pInterface == NULL_PATMARP_INTERFACE) ||
|
|
(pArpTable == (PATMARP_IP_ENTRY *)NULL) ||
|
|
(pIfSap == (PCO_SAP)NULL))
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Got (almost) everything allocated. Initialize the main IF structure
|
|
// first. IMPORTANT: Keep this SET_MEM right here! Otherwise, we will
|
|
// trash the timer list allocation coming right up.
|
|
//
|
|
AA_SET_MEM(pInterface, 0, sizeof(ATMARP_INTERFACE));
|
|
|
|
//
|
|
// Set up the Buffer pool quadword-aligned slist pointers.
|
|
//
|
|
{
|
|
for (i=0;i<AA_HEADER_TYPE_MAX;i++)
|
|
{
|
|
//
|
|
// Verify that HeaderBufList is 8-byte aligned...
|
|
// (we fully expect it to be because HeaderBufList is of type
|
|
// SLIST_HEADER which has longlong alignment) -- so that
|
|
// if the INTERFACE structure in which it is embedded in is
|
|
// 8-byte aligned, so will HeaderBufList...).
|
|
//
|
|
ASSERT((((ULONG_PTR)&(pInterface->HeaderPool[i].HeaderBufList))
|
|
& 0x7) == 0);
|
|
|
|
//
|
|
// Spec says you gotta init it...
|
|
//
|
|
AA_INIT_SLIST(&(pInterface->HeaderPool[i].HeaderBufList));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate timer structures
|
|
//
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pInterface->TimerList[i]);
|
|
#if DBG
|
|
pTimerList->atl_sig = atl_signature;
|
|
#endif // DBG
|
|
AA_ALLOC_MEM(
|
|
pTimerList->pTimers,
|
|
ATMARP_TIMER,
|
|
sizeof(ATMARP_TIMER) * AtmArpTimerListSize[i]
|
|
);
|
|
if (pTimerList->pTimers == NULL_PATMARP_TIMER)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Continue initializing the IF structure.
|
|
//
|
|
#if DBG
|
|
//
|
|
// Signatures, for debugging.
|
|
//
|
|
pInterface->aai_sig = aai_signature;
|
|
pInterface->aaim_sig = aaim_signature;
|
|
pInterface->aaia_sig = aaia_signature;
|
|
pInterface->aait_sig = aait_signature;
|
|
pInterface->aaio_sig = aaio_signature;
|
|
pInterface->aaic_sig = aaic_signature;
|
|
|
|
pInterface->SapList.aas_sig = aas_signature;
|
|
#if ATMARP_WMI
|
|
pInterface->aaiw_sig = aaiw_signature;
|
|
#endif
|
|
#endif // DBG
|
|
|
|
|
|
//
|
|
// Initialize state fields.
|
|
//
|
|
pInterface->AdminState = IF_STATUS_DOWN;
|
|
pInterface->State = IF_STATUS_DOWN;
|
|
pInterface->LastChangeTime = GetTimeTicks();
|
|
pInterface->ReconfigState = RECONFIG_NOT_IN_PROGRESS;
|
|
|
|
//
|
|
// Initialize IP interface fields.
|
|
//
|
|
pInterface->BroadcastMask = 0;
|
|
pInterface->BroadcastAddress = IP_LOCAL_BCST;
|
|
#ifndef OLD_ENTITY_LIST
|
|
pInterface->ATInstance = INVALID_ENTITY_INSTANCE;
|
|
pInterface->IFInstance = INVALID_ENTITY_INSTANCE;
|
|
#endif // OLD_ENTITY_LIST
|
|
|
|
//
|
|
// Initialize spinlocks.
|
|
//
|
|
AA_INIT_IF_LOCK(pInterface);
|
|
AA_INIT_IF_TABLE_LOCK(pInterface);
|
|
AA_INIT_IF_ATM_LIST_LOCK(pInterface);
|
|
AA_INIT_IF_TIMER_LOCK(pInterface);
|
|
AA_INIT_BLOCK_STRUCT(&(pInterface->Block));
|
|
NdisAllocateSpinLock(&(pInterface->BufferLock));
|
|
|
|
//
|
|
// Initialize list and table status
|
|
//
|
|
pInterface->AtmEntryListUp = TRUE;
|
|
pInterface->ArpTableUp = TRUE;
|
|
|
|
//
|
|
// Initialize timer wheels.
|
|
//
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pInterface->TimerList[i]);
|
|
AA_SET_MEM(
|
|
pTimerList->pTimers,
|
|
0,
|
|
sizeof(ATMARP_TIMER) * AtmArpTimerListSize[i]
|
|
);
|
|
pTimerList->MaxTimer = AtmArpMaxTimerValue[i];
|
|
pTimerList->TimerPeriod = AtmArpTimerPeriod[i];
|
|
pTimerList->ListContext = (PVOID)pInterface;
|
|
pTimerList->TimerListSize = AtmArpTimerListSize[i];
|
|
|
|
AA_INIT_SYSTEM_TIMER(
|
|
&(pTimerList->NdisTimer),
|
|
AtmArpTickHandler,
|
|
(PVOID)pTimerList
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize all sub-components.
|
|
//
|
|
AA_SET_MEM(pArpTable, 0, ATMARP_TABLE_SIZE*sizeof(PATMARP_IP_ENTRY));
|
|
AA_SET_MEM(pIfSap, 0, SapSize);
|
|
|
|
//
|
|
// Link all sub-components to the Interface structure.
|
|
//
|
|
pInterface->pArpTable = pArpTable;
|
|
pInterface->SapList.pInfo = pIfSap;
|
|
|
|
//
|
|
// Link the Interface to the Adapter.
|
|
//
|
|
pInterface->pAdapter = pAdapter;
|
|
pInterface->pNextInterface = pAdapter->pInterfaceList;
|
|
pAdapter->pInterfaceList = pInterface;
|
|
|
|
//
|
|
// Cache the adapter handle.
|
|
//
|
|
pInterface->NdisAdapterHandle = pAdapter->NdisAdapterHandle;
|
|
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Failed to allocate atleast one component. Free the other(s).
|
|
//
|
|
if (pInterface != NULL_PATMARP_INTERFACE)
|
|
{
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pInterface->TimerList[i]);
|
|
|
|
if (pTimerList->pTimers != NULL_PATMARP_TIMER)
|
|
{
|
|
AA_FREE_MEM(pTimerList->pTimers);
|
|
pTimerList->pTimers = NULL_PATMARP_TIMER;
|
|
}
|
|
}
|
|
|
|
AA_FREE_MEM(pInterface);
|
|
pInterface = NULL_PATMARP_INTERFACE; // return value
|
|
}
|
|
|
|
if (pArpTable != (PATMARP_IP_ENTRY *)NULL)
|
|
{
|
|
AA_FREE_MEM(pArpTable);
|
|
}
|
|
|
|
if (pIfSap != (PCO_SAP)NULL)
|
|
{
|
|
AA_FREE_MEM(pIfSap);
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Allocated ATMARP Interface 0x%x\n", pInterface));
|
|
|
|
return (pInterface);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateInterface(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an ATMARP Interface 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 structure it's linked to.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to Interface structure to be deallocated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE * ppInterface;
|
|
PATMARP_ADAPTER pAdapter;
|
|
PATMARP_SAP pAtmArpSap;
|
|
PIP_ADDRESS_ENTRY pIpEntry;
|
|
PATMARP_SERVER_ENTRY pServerEntry;
|
|
PPROXY_ARP_ENTRY pProxyEntry;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_VC pVc;
|
|
INT i;
|
|
|
|
PVOID pNext; // Catch-all for all list traversals
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
AA_ASSERT(pInterface->RefCount == 0);
|
|
|
|
AADEBUGP(AAD_INFO, ("Deallocate Interface 0x%x\n", pInterface));
|
|
|
|
#if DBG
|
|
pInterface->aai_sig = ~(pInterface->aai_sig);
|
|
#endif // DBG
|
|
|
|
//
|
|
// Unlink from Adapter structure
|
|
//
|
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
pAdapter = pInterface->pAdapter;
|
|
if (pAdapter != NULL_PATMARP_ADAPTER)
|
|
{
|
|
ppInterface = &(pAdapter->pInterfaceList);
|
|
while (*ppInterface != NULL_PATMARP_INTERFACE)
|
|
{
|
|
if (*ppInterface == pInterface)
|
|
{
|
|
*ppInterface = pInterface->pNextInterface;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ppInterface = &((*ppInterface)->pNextInterface);
|
|
}
|
|
}
|
|
}
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
|
|
//
|
|
// Free all subcomponents
|
|
//
|
|
|
|
//
|
|
// ARP Table
|
|
//
|
|
if (pInterface->pArpTable != (PATMARP_IP_ENTRY *)NULL)
|
|
{
|
|
AA_FREE_MEM(pInterface->pArpTable);
|
|
pInterface->pArpTable = (PATMARP_IP_ENTRY *)NULL;
|
|
}
|
|
|
|
//
|
|
// Local SAP list
|
|
//
|
|
for (pAtmArpSap = pInterface->SapList.pNextSap;
|
|
pAtmArpSap != NULL_PATMARP_SAP;
|
|
pAtmArpSap = (PATMARP_SAP)pNext)
|
|
{
|
|
pNext = (PVOID)(pAtmArpSap->pNextSap);
|
|
if (pAtmArpSap->pInfo != (PCO_SAP)NULL)
|
|
{
|
|
AA_FREE_MEM(pAtmArpSap->pInfo);
|
|
}
|
|
AA_FREE_MEM(pAtmArpSap);
|
|
}
|
|
if (pInterface->SapList.pInfo != (PCO_SAP)NULL)
|
|
{
|
|
AA_FREE_MEM(pInterface->SapList.pInfo);
|
|
}
|
|
pInterface->SapList.pNextSap = NULL_PATMARP_SAP;
|
|
|
|
|
|
//
|
|
// List of local IP addresses
|
|
//
|
|
for (pIpEntry = pInterface->LocalIPAddress.pNext;
|
|
pIpEntry != (PIP_ADDRESS_ENTRY)NULL;
|
|
pIpEntry = (PIP_ADDRESS_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pIpEntry->pNext;
|
|
AA_FREE_MEM(pIpEntry);
|
|
}
|
|
|
|
|
|
//
|
|
// List of proxy ARP addresses
|
|
//
|
|
for (pProxyEntry = pInterface->pProxyList;
|
|
pProxyEntry != (PPROXY_ARP_ENTRY)NULL;
|
|
pProxyEntry = (PPROXY_ARP_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pProxyEntry->pNext;
|
|
AA_FREE_MEM(pProxyEntry);
|
|
}
|
|
pInterface->pProxyList = (PPROXY_ARP_ENTRY)NULL;
|
|
|
|
//
|
|
// List of ARP Server addresses
|
|
//
|
|
for (pServerEntry = pInterface->ArpServerList.pList;
|
|
pServerEntry != NULL_PATMARP_SERVER_ENTRY;
|
|
pServerEntry = (PATMARP_SERVER_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pServerEntry->pNext;
|
|
AA_FREE_MEM(pServerEntry);
|
|
}
|
|
pInterface->ArpServerList.pList = NULL_PATMARP_SERVER_ENTRY;
|
|
|
|
#ifdef IPMCAST
|
|
//
|
|
// List of MARS Server addresses
|
|
//
|
|
for (pServerEntry = pInterface->MARSList.pList;
|
|
pServerEntry != NULL_PATMARP_SERVER_ENTRY;
|
|
pServerEntry = (PATMARP_SERVER_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pServerEntry->pNext;
|
|
AA_FREE_MEM(pServerEntry);
|
|
}
|
|
pInterface->MARSList.pList = NULL_PATMARP_SERVER_ENTRY;
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// ARP Table
|
|
//
|
|
if (pInterface->pArpTable != (PATMARP_IP_ENTRY *)NULL)
|
|
{
|
|
AA_FREE_MEM(pInterface->pArpTable);
|
|
pInterface->pArpTable = (PATMARP_IP_ENTRY *)NULL;
|
|
}
|
|
|
|
//
|
|
// ATM Entry List
|
|
//
|
|
for (pAtmEntry = pInterface->pAtmEntryList;
|
|
pAtmEntry != NULL_PATMARP_ATM_ENTRY;
|
|
pAtmEntry = (PATMARP_ATM_ENTRY)pNext)
|
|
{
|
|
pNext = (PVOID)pAtmEntry->pNext;
|
|
AA_FREE_MEM(pAtmEntry);
|
|
}
|
|
pInterface->pAtmEntryList = NULL_PATMARP_ATM_ENTRY;
|
|
|
|
//
|
|
// Unresolved VC list
|
|
//
|
|
for (pVc = pInterface->pUnresolvedVcs;
|
|
pVc != NULL_PATMARP_VC;
|
|
pVc = (PATMARP_VC)pNext)
|
|
{
|
|
pNext = (PVOID)pVc->pNextVc;
|
|
AA_FREE_MEM(pVc);
|
|
}
|
|
pInterface->pUnresolvedVcs = (PATMARP_VC)NULL;
|
|
|
|
//
|
|
// Timers
|
|
//
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
PATMARP_TIMER_LIST pTimerList = &(pInterface->TimerList[i]);
|
|
|
|
if (pTimerList->pTimers != NULL_PATMARP_TIMER)
|
|
{
|
|
AA_FREE_MEM(pTimerList->pTimers);
|
|
pTimerList->pTimers = NULL_PATMARP_TIMER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// ProtocolPacketPool
|
|
// ProtocolBufferPool
|
|
// ProtocolBufList
|
|
//
|
|
AtmArpDeallocateProtoBuffers(pInterface);
|
|
|
|
//
|
|
// HeaderBufList
|
|
// pHeaderTrkList
|
|
//
|
|
AtmArpDeallocateHeaderBuffers(pInterface);
|
|
|
|
//
|
|
// Free all Interface locks.
|
|
//
|
|
AA_FREE_IF_LOCK(pInterface);
|
|
AA_FREE_IF_TABLE_LOCK(pInterface);
|
|
AA_FREE_IF_ATM_LIST_LOCK(pInterface);
|
|
AA_FREE_IF_TIMER_LOCK(pInterface);
|
|
AA_FREE_BLOCK_STRUCT(&(pInterface->Block));
|
|
NdisFreeSpinLock(&(pInterface->BufferLock));
|
|
|
|
//
|
|
// Free the Interface structure now
|
|
//
|
|
AA_FREE_MEM(pInterface);
|
|
|
|
//
|
|
// If we just freed the last Interface structure on this
|
|
// adapter, and an Unbind operation was in progress, complete
|
|
// it now.
|
|
//
|
|
if ((pAdapter->pInterfaceList == NULL_PATMARP_INTERFACE) &&
|
|
(pAdapter->Flags & AA_ADAPTER_FLAGS_UNBINDING))
|
|
{
|
|
AtmArpCompleteUnbindAdapter(pAdapter);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpReferenceInterface(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to an Interface structure.
|
|
NOTE: The caller is assumed to possess a lock for the interface
|
|
structure.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to the ATMARP interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
pInterface->RefCount++;
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Reference Interface 0x%x, new count %d\n",
|
|
pInterface, pInterface->RefCount));
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
AtmArpDereferenceInterface(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Subtract a reference from an ATMARP Interface. If the reference
|
|
count becomes zero, deallocate it.
|
|
NOTE: It is assumed that the caller holds a lock to the Interface
|
|
structure. See SIDE EFFECT below.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to the ATMARP interface
|
|
|
|
Return Value:
|
|
|
|
The resulting reference count. If this is zero, then there are two
|
|
SIDE EFFECTS: (1) the Interface lock is released (2) the structure
|
|
is freed.
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
AA_ASSERT(pInterface->RefCount > 0);
|
|
|
|
rc = --(pInterface->RefCount);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Dereference Interface 0x%x, new count %d\n",
|
|
pInterface, rc));
|
|
|
|
if (rc == 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
AtmArpDeallocateInterface(pInterface);
|
|
}
|
|
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpReferenceJoinEntry(
|
|
IN PATMARP_IPMC_JOIN_ENTRY pJoinEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a reference to a Join Entry.
|
|
|
|
Arguments:
|
|
|
|
pJoinEntry - Pointer to Join Entry
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NdisInterlockedIncrement(&pJoinEntry->RefCount);
|
|
}
|
|
|
|
|
|
ULONG
|
|
AtmArpDereferenceJoinEntry(
|
|
IN PATMARP_IPMC_JOIN_ENTRY pJoinEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrements the ref count on a Join Entry. If it goes down to zero,
|
|
deallocates it.
|
|
|
|
Arguments:
|
|
|
|
pJoinEntry - Pointer to the Join Entry
|
|
|
|
Return Value:
|
|
|
|
The final ref count
|
|
|
|
--*/
|
|
{
|
|
ULONG rc;
|
|
|
|
rc = NdisInterlockedDecrement(&pJoinEntry->RefCount);
|
|
|
|
if (rc == 0)
|
|
{
|
|
AA_CHECK_TIMER_IN_ACTIVE_LIST(&pJoinEntry->Timer, pJoinEntry->pInterface, pJoinEntry, "Join Entry");
|
|
AA_FREE_MEM(pJoinEntry);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpStartTimer(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PATMARP_TIMER pTimer,
|
|
IN ATMARP_TIMEOUT_HANDLER TimeoutHandler,
|
|
IN ULONG SecondsToGo,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start an ATMARP 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 Interface
|
|
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:
|
|
|
|
pInterface - Pointer to the ATMARP Interface
|
|
pTimer - Pointer to ATMARP Timer structure
|
|
TimeoutHandler - Handler function to be called if this timer expires
|
|
SecondsToGo - When does this timer go off?
|
|
Context - To be passed to timeout handler if this timer expires
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_TIMER_LIST pTimerList; // List to which this timer goes
|
|
PATMARP_TIMER pTimerListHead; // Head of above list
|
|
ULONG Index; // Into timer wheel
|
|
ULONG TicksToGo;
|
|
INT i;
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD,
|
|
("StartTimer: pIf 0x%x, Secs %d, Handler 0x%x, Ctxt 0x%x, pTimer 0x%x\n",
|
|
pInterface, SecondsToGo, TimeoutHandler, Context, pTimer));
|
|
|
|
|
|
if (AA_IS_TIMER_ACTIVE(pTimer))
|
|
{
|
|
AADEBUGP(AAD_ERROR,
|
|
("Start timer: pTimer 0x%x: is active (list 0x%x, hnd 0x%x), stopping it\n",
|
|
pTimer, pTimer->pTimerList, pTimer->TimeoutHandler));
|
|
|
|
AtmArpStopTimer(pTimer, pInterface);
|
|
}
|
|
|
|
AA_ACQUIRE_IF_TIMER_LOCK(pInterface);
|
|
AA_ASSERT(!AA_IS_TIMER_ACTIVE(pTimer));
|
|
|
|
//
|
|
// Find the list to which this timer should go, and the
|
|
// offset (TicksToGo)
|
|
//
|
|
for (i = 0; i < AAT_CLASS_MAX; i++)
|
|
{
|
|
pTimerList = &(pInterface->TimerList[i]);
|
|
if (SecondsToGo < pTimerList->MaxTimer)
|
|
{
|
|
//
|
|
// Found it.
|
|
//
|
|
TicksToGo = SecondsToGo / (pTimerList->TimerPeriod);
|
|
break;
|
|
}
|
|
}
|
|
|
|
AA_ASSERT(i < AAT_CLASS_MAX);
|
|
|
|
AA_VALIDATE_TIMER_LIST(pTimerList);
|
|
//
|
|
// Find the position in the list for this timer
|
|
//
|
|
Index = pTimerList->CurrentTick + TicksToGo;
|
|
if (Index >= pTimerList->TimerListSize)
|
|
{
|
|
Index -= pTimerList->TimerListSize;
|
|
}
|
|
AA_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->Context = Context;
|
|
pTimer->State = ATMARP_TIMER_STATE_RUNNING;
|
|
|
|
//
|
|
// Insert this timer in the "ticking" list
|
|
//
|
|
pTimer->pPrevTimer = pTimerListHead;
|
|
pTimer->pNextTimer = pTimerListHead->pNextTimer;
|
|
if (pTimer->pNextTimer != NULL_PATMARP_TIMER)
|
|
{
|
|
pTimer->pNextTimer->pPrevTimer = pTimer;
|
|
}
|
|
pTimerListHead->pNextTimer = pTimer;
|
|
|
|
//
|
|
// Start off the system tick timer if necessary.
|
|
//
|
|
pTimerList->TimerCount++;
|
|
if (pTimerList->TimerCount == 1)
|
|
{
|
|
AADEBUGP(AAD_LOUD,
|
|
("StartTimer: Starting system timer 0x%x, class %d on IF 0x%x\n",
|
|
&(pTimerList->NdisTimer), i, pInterface));
|
|
|
|
AA_START_SYSTEM_TIMER(&(pTimerList->NdisTimer), pTimerList->TimerPeriod);
|
|
}
|
|
AA_VALIDATE_TIMER_LIST(pTimerList);
|
|
AA_VALIDATE_TIMER(pTimerList, pTimer);
|
|
|
|
AA_RELEASE_IF_TIMER_LOCK(pInterface);
|
|
|
|
//
|
|
// We're done
|
|
//
|
|
AADEBUGP(AAD_LOUD,
|
|
("Started timer 0x%x, IF 0x%x, Secs %d, Index %d, Head 0x%x\n",
|
|
pTimer,
|
|
pInterface,
|
|
SecondsToGo,
|
|
Index,
|
|
pTimerListHead));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtmArpStopTimer(
|
|
IN PATMARP_TIMER pTimer,
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop an ATMARP 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 ATMARP Timer structure
|
|
pInterface - Pointer to interface to which the timer belongs
|
|
|
|
Return Value:
|
|
|
|
TRUE if the timer was running, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_TIMER_LIST pTimerList; // Timer List to which this timer belongs
|
|
BOOLEAN WasRunning;
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Stopping Timer 0x%x, IF 0x%x, List 0x%x, Prev 0x%x, Next 0x%x\n",
|
|
pTimer,
|
|
pInterface,
|
|
pTimer->pTimerList,
|
|
pTimer->pPrevTimer,
|
|
pTimer->pNextTimer));
|
|
|
|
AA_ACQUIRE_IF_TIMER_LOCK(pInterface);
|
|
|
|
|
|
if (AA_IS_TIMER_ACTIVE(pTimer))
|
|
{
|
|
WasRunning = TRUE;
|
|
|
|
AA_VALIDATE_TIMER_LIST(pTimer->pTimerList);
|
|
AA_VALIDATE_TIMER(NULL, pTimer);
|
|
|
|
//
|
|
// Unlink timer from the list
|
|
//
|
|
AA_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_PATMARP_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)
|
|
{
|
|
AADEBUGP(AAD_LOUD, ("Stopping system timer 0x%x, List 0x%x, IF 0x%x\n",
|
|
&(pTimerList->NdisTimer),
|
|
pTimerList,
|
|
pInterface));
|
|
|
|
pTimerList->CurrentTick = 0;
|
|
AA_STOP_SYSTEM_TIMER(&(pTimerList->NdisTimer));
|
|
}
|
|
|
|
//
|
|
// Mark stopped timer as not active
|
|
//
|
|
pTimer->pTimerList = (PATMARP_TIMER_LIST)NULL;
|
|
|
|
pTimer->State = ATMARP_TIMER_STATE_IDLE;
|
|
|
|
AA_VALIDATE_TIMER_LIST(pTimerList);
|
|
|
|
}
|
|
else
|
|
{
|
|
WasRunning = FALSE;
|
|
}
|
|
|
|
AA_RELEASE_IF_TIMER_LOCK(pInterface);
|
|
|
|
return (WasRunning);
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NO_TIMER_MACRO
|
|
|
|
VOID
|
|
AtmArpRefreshTimer(
|
|
IN PATMARP_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 ATMARP_TIMER structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_TIMER_LIST pTimerList;
|
|
|
|
if ((pTimerList = pTimer->pTimerList) != (PATMARP_TIMER_LIST)NULL)
|
|
{
|
|
pTimer->LastRefreshTime = pTimerList->CurrentTick;
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_VERY_LOUD,
|
|
("RefreshTimer: pTimer 0x%x not active: Hnd 0x%x, Cntxt 0x%x\n",
|
|
pTimer,
|
|
pTimer->TimeoutHandler,
|
|
pTimer->Context
|
|
));
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Refreshed timer 0x%x, List 0x%x, hnd 0x%x, Cntxt 0x%x, LastRefresh %d\n",
|
|
pTimer,
|
|
pTimer->pTimerList,
|
|
pTimer->TimeoutHandler,
|
|
pTimer->Context,
|
|
pTimer->LastRefreshTime));
|
|
}
|
|
|
|
|
|
#endif // NO_TIMER_MACRO
|
|
|
|
|
|
VOID
|
|
AtmArpTickHandler(
|
|
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
|
|
|
|
--*/
|
|
{
|
|
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_TIMER_LIST pTimerList;
|
|
|
|
PATMARP_TIMER pExpiredTimer; // Start of list of expired timers
|
|
PATMARP_TIMER pNextTimer; // for walking above list
|
|
PATMARP_TIMER pTimer; // temp, for walking timer list
|
|
PATMARP_TIMER pPrevExpiredTimer; // for creating expired timer list
|
|
|
|
ULONG Index; // into the timer wheel
|
|
ULONG NewIndex; // for refreshed timers
|
|
|
|
|
|
pTimerList = (PATMARP_TIMER_LIST)Context;
|
|
AA_STRUCT_ASSERT(pTimerList, atl);
|
|
|
|
pInterface = (PATMARP_INTERFACE)pTimerList->ListContext;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Tick: pIf 0x%x, List 0x%x, Count %d\n",
|
|
pInterface, pTimerList, pTimerList->TimerCount));
|
|
|
|
pExpiredTimer = NULL_PATMARP_TIMER;
|
|
|
|
AA_ACQUIRE_IF_TIMER_LOCK(pInterface);
|
|
|
|
AA_VALIDATE_TIMER_LIST(pTimerList);
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
//
|
|
// 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_PATMARP_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_PATMARP_TIMER;
|
|
|
|
for (pTimer = pExpiredTimer;
|
|
pTimer != NULL_PATMARP_TIMER;
|
|
pTimer = pNextTimer)
|
|
{
|
|
//
|
|
// Save a pointer to the next timer, for the next iteration.
|
|
//
|
|
pNextTimer = pTimer->pNextTimer;
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD,
|
|
("Tick Handler: pIf 0x%x, looking at timer 0x%x, next 0x%x\n",
|
|
pInterface, 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.
|
|
//
|
|
AADEBUGP(AAD_LOUD,
|
|
("Tick: Reinserting Timer 0x%x: Hnd 0x%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_PATMARP_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_PATMARP_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_PATMARP_TIMER)
|
|
{
|
|
pExpiredTimer = pTimer;
|
|
}
|
|
pPrevExpiredTimer = pTimer;
|
|
|
|
//
|
|
// Mark it as inactive.
|
|
//
|
|
AA_ASSERT(pTimer->pTimerList == pTimerList);
|
|
pTimer->pTimerList = (PATMARP_TIMER_LIST)NULL;
|
|
|
|
pTimer->State = ATMARP_TIMER_STATE_EXPIRING;
|
|
|
|
//
|
|
// 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
|
|
//
|
|
AADEBUGP(AAD_LOUD, ("Tick[%d]: Starting system timer 0x%x, on IF 0x%x\n",
|
|
pTimerList->CurrentTick, &(pTimerList->NdisTimer), pInterface));
|
|
|
|
AA_START_SYSTEM_TIMER(&(pTimerList->NdisTimer), pTimerList->TimerPeriod);
|
|
}
|
|
else
|
|
{
|
|
pTimerList->CurrentTick = 0;
|
|
}
|
|
|
|
}
|
|
|
|
AA_RELEASE_IF_TIMER_LOCK(pInterface);
|
|
|
|
//
|
|
// Now pExpiredTimer is a list of expired timers.
|
|
// Walk through the list and call the timeout handlers
|
|
// for each timer.
|
|
//
|
|
while (pExpiredTimer != NULL_PATMARP_TIMER)
|
|
{
|
|
pNextTimer = pExpiredTimer->pNextExpiredTimer;
|
|
|
|
AADEBUGP(AAD_LOUD, ("Expired timer 0x%x: handler 0x%x, next 0x%x\n",
|
|
pExpiredTimer, pExpiredTimer->TimeoutHandler, pNextTimer));
|
|
|
|
pExpiredTimer->State = ATMARP_TIMER_STATE_EXPIRED;
|
|
(*(pExpiredTimer->TimeoutHandler))(
|
|
pExpiredTimer,
|
|
pExpiredTimer->Context
|
|
);
|
|
|
|
pExpiredTimer = pNextTimer;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_PACKET
|
|
AtmArpAllocatePacket(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS packet for the specified Interface.
|
|
Currently just a wrapper for the corresponding NDIS function.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface structure
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS packet if allocated, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET pNdisPacket;
|
|
struct PacketContext *PC;
|
|
|
|
NdisAllocatePacket(
|
|
&Status,
|
|
&pNdisPacket,
|
|
pInterface->ProtocolPacketPool
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
PC = (struct PacketContext *)pNdisPacket->ProtocolReserved;
|
|
PC->pc_common.pc_owner = PACKET_OWNER_LINK;
|
|
}
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("Allocate Packet: IF 0x%x, Status 0x%x, Packet 0x%x\n",
|
|
pInterface,
|
|
Status,
|
|
pNdisPacket));
|
|
|
|
return (pNdisPacket);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpFreePacket(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate an NDIS packet on the specified Interface.
|
|
Currently just a wrapper around the corresponding NDIS function.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface structure
|
|
pPacket - Pointer to packet being freed.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NdisFreePacket(pPacket);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("Free Packet: IF 0x%x, Packet 0x%x\n",
|
|
pInterface,
|
|
pPacket));
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_BUFFER
|
|
AtmArpGrowHeaders(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN AA_HEADER_TYPE HdrType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a bunch of header buffers on the specified ATMARP interface.
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface structure
|
|
HdrType - Unicast or Nonunicast
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocated NDIS buffer if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_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;
|
|
|
|
AA_ASSERT(HdrType < AA_HEADER_TYPE_MAX);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pTracker = NULL_PATMARP_BUFFER_TRACKER;
|
|
pReturnBuffer = (PNDIS_BUFFER)NULL;
|
|
|
|
|
|
NdisAcquireSpinLock(&pInterface->BufferLock);
|
|
|
|
do
|
|
{
|
|
if (pInterface->HeaderPool[HdrType].CurHeaderBufs >=
|
|
pInterface->HeaderPool[HdrType].MaxHeaderBufs)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Grow Hdrs: IF 0x%x, Type %d, CurHdrBufs %d > MaxHdrBufs %d\n",
|
|
pInterface,
|
|
HdrType,
|
|
pInterface->HeaderPool[HdrType].CurHeaderBufs,
|
|
pInterface->HeaderPool[HdrType].MaxHeaderBufs));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize Buffer tracker
|
|
//
|
|
AA_ALLOC_MEM(pTracker, ATMARP_BUFFER_TRACKER, sizeof(ATMARP_BUFFER_TRACKER));
|
|
if (pTracker == NULL_PATMARP_BUFFER_TRACKER)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("Grow Hdrs: IF 0x%x, alloc failed for tracker\n",
|
|
pInterface));
|
|
break;
|
|
}
|
|
|
|
AA_SET_MEM(pTracker, 0, sizeof(ATMARP_BUFFER_TRACKER));
|
|
|
|
//
|
|
// Get the NDIS Buffer pool
|
|
//
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&(pTracker->NdisHandle),
|
|
AA_DEF_HDRBUF_GROW_SIZE
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Grow Hdrs: IF 0x%x, NdisAllocateBufferPool err status 0x%x\n",
|
|
pInterface, Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate system space for a bunch of header buffers
|
|
//
|
|
AA_ALLOC_MEM(pTracker->pPoolStart,
|
|
UCHAR,
|
|
pInterface->HeaderPool[HdrType].HeaderBufSize *
|
|
AA_DEF_HDRBUF_GROW_SIZE);
|
|
|
|
if (pTracker->pPoolStart == (PUCHAR)NULL)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Grow Hdrs: IF 0x%x, could not alloc buf space %d bytes\n",
|
|
pInterface,
|
|
pInterface->HeaderPool[HdrType].HeaderBufSize *
|
|
AA_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.
|
|
//
|
|
// We also fill in the contents of the buffers right away, so
|
|
// that we don't have to prepare them afresh for each transmit.
|
|
//
|
|
pBufferList = (PNDIS_BUFFER)NULL;
|
|
pSpace = pTracker->pPoolStart;
|
|
for (i = 0; i < AA_DEF_HDRBUF_GROW_SIZE; i++)
|
|
{
|
|
if (HdrType == AA_HEADER_TYPE_UNICAST)
|
|
{
|
|
//
|
|
// Fill in the (Unicast) LLC/SNAP header
|
|
//
|
|
AA_COPY_MEM(pSpace,
|
|
&AtmArpLlcSnapHeader,
|
|
pInterface->HeaderPool[HdrType].HeaderBufSize);
|
|
}
|
|
else
|
|
{
|
|
AA_ASSERT(HdrType == AA_HEADER_TYPE_NUNICAST);
|
|
//
|
|
// Fill in the (Multicast) Type 1 short form header
|
|
//
|
|
#ifdef IPMCAST
|
|
AA_COPY_MEM(pSpace,
|
|
&AtmArpMcType1ShortHeader,
|
|
pInterface->HeaderPool[HdrType].HeaderBufSize);
|
|
#else
|
|
AA_ASSERT(FALSE);
|
|
#endif // IPMCAST
|
|
}
|
|
|
|
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNdisBuffer,
|
|
pTracker->NdisHandle,
|
|
pSpace,
|
|
pInterface->HeaderPool[HdrType].HeaderBufSize
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Grow Hdrs: NdisAllocateBuffer failed: IF 0x%x, status 0x%x\n",
|
|
pInterface, Status));
|
|
break;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
pReturnBuffer = pNdisBuffer;
|
|
}
|
|
else
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = pBufferList;
|
|
pBufferList = pNdisBuffer;
|
|
}
|
|
pSpace += pInterface->HeaderPool[HdrType].HeaderBufSize;
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
//
|
|
// Successfully allocated atleast one more header buffer
|
|
//
|
|
pTracker->pNext = pInterface->HeaderPool[HdrType].pHeaderTrkList;
|
|
pInterface->HeaderPool[HdrType].pHeaderTrkList = pTracker;
|
|
pInterface->HeaderPool[HdrType].CurHeaderBufs += i;
|
|
|
|
NdisReleaseSpinLock(&pInterface->BufferLock);
|
|
|
|
pNdisBuffer = pBufferList;
|
|
while (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
pBufferList = NDIS_BUFFER_LINKAGE(pNdisBuffer);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
AtmArpFreeHeader(pInterface, pNdisBuffer, HdrType);
|
|
pNdisBuffer = pBufferList;
|
|
}
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (pReturnBuffer == (PNDIS_BUFFER)NULL)
|
|
{
|
|
//
|
|
// Failed to allocate. Undo all.
|
|
//
|
|
NdisReleaseSpinLock(&pInterface->BufferLock);
|
|
|
|
if (pTracker != NULL_PATMARP_BUFFER_TRACKER)
|
|
{
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
AA_FREE_MEM(pTracker->pPoolStart);
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
}
|
|
AA_FREE_MEM(pTracker);
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO, ("Grow ARP Headers: IF 0x%x, RetBuf 0x%x, New Tracker 0x%x\n",
|
|
pInterface, pReturnBuffer, pTracker));
|
|
|
|
return (pReturnBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_BUFFER
|
|
AtmArpAllocateHeader(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN AA_HEADER_TYPE HdrType,
|
|
OUT PUCHAR * pBufferAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate an NDIS Buffer to be used as an LLC/SNAP header prepended
|
|
to an IP 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:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
HdrType - Unicast or Nonunicast
|
|
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;
|
|
PAA_SINGLE_LIST_ENTRY pListEntry;
|
|
|
|
pListEntry = AA_POP_FROM_SLIST(
|
|
&(pInterface->HeaderPool[HdrType].HeaderBufList),
|
|
&(pInterface->BufferLock.SpinLock)
|
|
);
|
|
if (pListEntry != NULL_PAA_SINGLE_LIST_ENTRY)
|
|
{
|
|
pNdisBuffer = STRUCT_OF(NDIS_BUFFER, pListEntry, Next);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
*pBufferAddress = NdisBufferVirtualAddress(pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
pNdisBuffer = AtmArpGrowHeaders(pInterface, HdrType);
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)pBufferAddress, &Length);
|
|
AADEBUGP(AAD_INFO,
|
|
("After growing hdrs: Type %d, returning pNdisBuf 0x%x, Start 0x%x, Len %d\n",
|
|
HdrType, pNdisBuffer, *pBufferAddress, Length));
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Allocated Header Buffer: 0x%x, IF: 0x%x\n",
|
|
pNdisBuffer, pInterface));
|
|
return (pNdisBuffer);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpFreeHeader(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN AA_HEADER_TYPE HdrType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate a header buffer.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP interface from which the buffer came
|
|
pNdisBuffer - Pointer to NDIS buffer being freed
|
|
HdrType - Unicast or Nonunicast
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AA_PUSH_TO_SLIST(
|
|
&(pInterface->HeaderPool[HdrType].HeaderBufList),
|
|
STRUCT_OF(AA_SINGLE_LIST_ENTRY, &(pNdisBuffer->Next), Next),
|
|
&(pInterface->BufferLock.SpinLock)
|
|
);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Freed Header Buffer: 0x%x, IF: 0x%x, HdrType %d\n",
|
|
pNdisBuffer, pInterface, HdrType));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateHeaderBuffers(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deallocate everything pertaining to header buffers on an Interface.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
PAA_SINGLE_LIST_ENTRY pListEntry;
|
|
PATMARP_BUFFER_TRACKER pTracker;
|
|
PATMARP_BUFFER_TRACKER pNextTracker;
|
|
AA_HEADER_TYPE HdrType;
|
|
|
|
for (HdrType = 0; HdrType < AA_HEADER_TYPE_MAX; HdrType++)
|
|
{
|
|
//
|
|
// Free all NDIS buffers in the header buffer list.
|
|
//
|
|
do
|
|
{
|
|
pListEntry = AA_POP_FROM_SLIST(
|
|
&(pInterface->HeaderPool[HdrType].HeaderBufList),
|
|
&(pInterface->BufferLock.SpinLock)
|
|
);
|
|
if (pListEntry != NULL_PAA_SINGLE_LIST_ENTRY)
|
|
{
|
|
pNdisBuffer = STRUCT_OF(NDIS_BUFFER, pListEntry, Next);
|
|
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL;
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No more NDIS buffers.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
while (TRUE);
|
|
|
|
//
|
|
// Now free all the buffer trackers.
|
|
//
|
|
pTracker = pInterface->HeaderPool[HdrType].pHeaderTrkList;
|
|
|
|
while (pTracker != NULL_PATMARP_BUFFER_TRACKER)
|
|
{
|
|
pNextTracker = pTracker->pNext;
|
|
if (pTracker->pPoolStart != (PUCHAR)NULL)
|
|
{
|
|
AA_FREE_MEM(pTracker->pPoolStart);
|
|
pTracker->pPoolStart = (PUCHAR)NULL;
|
|
}
|
|
if (pTracker->NdisHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pTracker->NdisHandle);
|
|
pTracker->NdisHandle = (NDIS_HANDLE)NULL;
|
|
}
|
|
AA_FREE_MEM(pTracker);
|
|
pTracker = pNextTracker;
|
|
}
|
|
|
|
} // for
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_BUFFER
|
|
AtmArpAllocateProtoBuffer(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN ULONG Length,
|
|
OUT PUCHAR * pBufferAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a buffer to be used for an ATM ARP protocol message. Attach
|
|
it to an NDIS_BUFFER structure and return a pointer to this.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
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;
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pNdisBuffer = NULL;
|
|
|
|
AA_ASSERT(Length <= pInterface->ProtocolBufSize);
|
|
|
|
NdisAcquireSpinLock(&pInterface->BufferLock);
|
|
|
|
*pBufferAddress = pInterface->ProtocolBufList;
|
|
if (*pBufferAddress != (PUCHAR)NULL)
|
|
{
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNdisBuffer,
|
|
pInterface->ProtocolBufferPool,
|
|
*pBufferAddress,
|
|
Length
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pInterface->ProtocolBufList = *((PUCHAR *)*pBufferAddress);
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&pInterface->BufferLock);
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Allocated protocol buffer: IF 0x%x, pNdisBuffer 0x%x, Length %d, Loc 0x%x\n",
|
|
pInterface, pNdisBuffer, Length, *pBufferAddress));
|
|
|
|
return (pNdisBuffer);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpFreeProtoBuffer(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
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 interface structure, and the NDIS buffer to NDIS.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP interface structure
|
|
pNdisBuffer - Pointer to NDIS buffer to be freed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUCHAR * pBufferLinkage;
|
|
ULONG Length;
|
|
|
|
NdisQueryBuffer(pNdisBuffer, (PVOID)&pBufferLinkage, &Length);
|
|
|
|
NdisAcquireSpinLock(&pInterface->BufferLock);
|
|
|
|
*pBufferLinkage = pInterface->ProtocolBufList;
|
|
pInterface->ProtocolBufList = (PUCHAR)pBufferLinkage;
|
|
|
|
NdisReleaseSpinLock(&pInterface->BufferLock);
|
|
|
|
NdisFreeBuffer(pNdisBuffer);
|
|
|
|
AADEBUGP(AAD_LOUD, ("Freed Protocol Buf: IF 0x%x, pNdisBuffer 0x%x, Loc 0x%x\n",
|
|
pInterface, pNdisBuffer, pBufferLinkage));
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpInitProtoBuffers(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the protocol buffer pool for an interface.
|
|
|
|
Allocate a chunk of memory to be used for ATMARP protocol messages.
|
|
We prepare a linked list of protocol buffers, and attach it to the
|
|
Interface structure.
|
|
|
|
Arguments:
|
|
|
|
pInterface - 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;
|
|
|
|
do
|
|
{
|
|
NdisAllocatePacketPool(
|
|
&Status,
|
|
&(pInterface->ProtocolPacketPool),
|
|
pInterface->MaxProtocolBufs,
|
|
sizeof(struct PCCommon)
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&(pInterface->ProtocolBufferPool),
|
|
pInterface->MaxProtocolBufs
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a big chunk of system memory that we can divide up into
|
|
// protocol buffers.
|
|
//
|
|
AA_ALLOC_MEM(
|
|
pInterface->ProtocolBufTracker,
|
|
UCHAR,
|
|
(pInterface->ProtocolBufSize * pInterface->MaxProtocolBufs)
|
|
);
|
|
|
|
if (pInterface->ProtocolBufTracker == (PUCHAR)NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Make all protocol buffers free.
|
|
//
|
|
pSpace = pInterface->ProtocolBufTracker;
|
|
{
|
|
PUCHAR LinkPtr;
|
|
|
|
LinkPtr = (PUCHAR)NULL;
|
|
for (i = 0; i < pInterface->MaxProtocolBufs; i++)
|
|
{
|
|
*((PUCHAR *)pSpace) = LinkPtr;
|
|
LinkPtr = pSpace;
|
|
pSpace += pInterface->ProtocolBufSize;
|
|
}
|
|
pSpace -= pInterface->ProtocolBufSize;
|
|
pInterface->ProtocolBufList = pSpace;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Undo everything.
|
|
//
|
|
AtmArpDeallocateProtoBuffers(pInterface);
|
|
}
|
|
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeallocateProtoBuffers(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the protocol buffer pool for an interface.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP interface structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (pInterface->ProtocolPacketPool != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreePacketPool(pInterface->ProtocolPacketPool);
|
|
pInterface->ProtocolPacketPool = NULL;
|
|
}
|
|
|
|
if (pInterface->ProtocolBufferPool != (NDIS_HANDLE)NULL)
|
|
{
|
|
NdisFreeBufferPool(pInterface->ProtocolBufferPool);
|
|
pInterface->ProtocolBufferPool = NULL;
|
|
}
|
|
|
|
if (pInterface->ProtocolBufTracker != (PUCHAR)NULL)
|
|
{
|
|
AA_FREE_MEM(pInterface->ProtocolBufTracker);
|
|
pInterface->ProtocolBufTracker = (PUCHAR)NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpLinkVcToAtmEntry(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_ATM_ENTRY pAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Link an ATMARP VC to an ATM Entry. The caller is assumed to
|
|
hold locks to both structures.
|
|
|
|
If this VC is a "best effort" VC, and there is no "best effort"
|
|
VC linked to the ATM Entry, we make this as the "best effort VC"
|
|
on this ATM Entry.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC structure
|
|
pAtmEntry - Pointer to ATMARP ATM Entry structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC *ppNext;
|
|
ULONG SendBandwidth;
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("Link VC: 0x%x to AtmEntry 0x%x\n",
|
|
pVc, pAtmEntry));
|
|
|
|
//
|
|
// Back pointer from VC to ATM Entry.
|
|
//
|
|
pVc->pAtmEntry = pAtmEntry;
|
|
|
|
//
|
|
// Find the position in which this VC should appear in the ATM Entry's
|
|
// VC list. We maintain this list in descending order of send bandwidth,
|
|
// so that the largest bandwidth VC to a destination appears first.
|
|
//
|
|
SendBandwidth = pVc->FlowSpec.SendPeakBandwidth;
|
|
ppNext = &(pAtmEntry->pVcList);
|
|
while (*ppNext != NULL_PATMARP_VC)
|
|
{
|
|
if (SendBandwidth >= (*ppNext)->FlowSpec.SendPeakBandwidth)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ppNext = &((*ppNext)->pNextVc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Found the place we were looking for. Insert the VC here.
|
|
//
|
|
pVc->pNextVc = *ppNext;
|
|
*ppNext = pVc;
|
|
|
|
if ((pAtmEntry->pBestEffortVc == NULL_PATMARP_VC) &&
|
|
AA_IS_BEST_EFFORT_FLOW(&(pVc->FlowSpec)))
|
|
{
|
|
pAtmEntry->pBestEffortVc = pVc;
|
|
}
|
|
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_VC); // VC reference
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpUnlinkVcFromAtmEntry(
|
|
IN PATMARP_VC pVc,
|
|
IN BOOLEAN bDerefAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlink an ATMARP 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 ATMARP VC structure
|
|
bDerefAtmEntry - Should we deref the ATM entry or not.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_VC * ppVc;
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("Unlink VC: 0x%x from AtmEntry 0x%x\n",
|
|
pVc, pVc->pAtmEntry));
|
|
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
pVc->pAtmEntry = NULL_PATMARP_ATM_ENTRY;
|
|
|
|
//
|
|
// Reacquire locks in the right order.
|
|
//
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AA_ACQUIRE_VC_LOCK_DPC(pVc);
|
|
|
|
//
|
|
// Search for the position of this VC in the ATM Entry's VC list
|
|
//
|
|
ppVc = &(pAtmEntry->pVcList);
|
|
while (*ppVc != pVc)
|
|
{
|
|
AA_ASSERT(*ppVc != NULL_PATMARP_VC);
|
|
ppVc = &((*ppVc)->pNextVc);
|
|
}
|
|
|
|
//
|
|
// Make the predecessor point to the next VC in the list.
|
|
//
|
|
*ppVc = pVc->pNextVc;
|
|
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
|
|
//
|
|
// If this was the Best Effort VC for this ATM Entry, try
|
|
// to find a replacement
|
|
//
|
|
if (pAtmEntry->pBestEffortVc == pVc)
|
|
{
|
|
//
|
|
// Yes, it was. Walk through the list of remaining VCs,
|
|
// if we find another Best Effort VC, make that the
|
|
// BestEffortVc for this ATM Entry
|
|
//
|
|
pAtmEntry->pBestEffortVc = NULL_PATMARP_VC;
|
|
|
|
ppVc = &(pAtmEntry->pVcList);
|
|
while (*ppVc != NULL_PATMARP_VC)
|
|
{
|
|
if (AA_IS_BEST_EFFORT_FLOW(&((*ppVc)->FlowSpec)))
|
|
{
|
|
pAtmEntry->pBestEffortVc = *ppVc;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ppVc = &((*ppVc)->pNextVc);
|
|
}
|
|
}
|
|
AADEBUGP(AAD_LOUD, ("Atm Entry 0x%x, new Best Effort VC: 0x%x\n",
|
|
pAtmEntry, pAtmEntry->pBestEffortVc));
|
|
}
|
|
|
|
if (bDerefAtmEntry)
|
|
{
|
|
if (AA_DEREF_AE(pAtmEntry, AE_REFTYPE_VC) != 0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
//
|
|
// Acquire the VC lock again for the caller's sake
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
}
|
|
|
|
|
|
|
|
PNDIS_BUFFER
|
|
AtmArpCopyToNdisBuffer(
|
|
IN PNDIS_BUFFER pDestBuffer,
|
|
IN PUCHAR pDataSrc,
|
|
IN UINT LenToCopy,
|
|
IN OUT PUINT pOffsetInBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy data into an NDIS buffer chain. Use up as much of the given
|
|
NDIS chain as needed for "LenToCopy" bytes. After copying is over,
|
|
return a pointer to the first NDIS buffer that has space for writing
|
|
into (for the next Copy operation), and the offset within this from
|
|
which to start writing.
|
|
|
|
Arguments:
|
|
|
|
pDestBuffer - First NDIS buffer in a chain of buffers
|
|
pDataSrc - Where to copy data from
|
|
LenToCopy - How much data to copy
|
|
pOffsetInBuffer - Offset in pDestBuffer where we can start copying into.
|
|
|
|
Return Value:
|
|
|
|
The NDIS buffer in the chain where the next Copy can be done. We also
|
|
set *pOffsetInBuffer to the write offset in the returned NDIS buffer.
|
|
|
|
Note: if we are low on memory and run into a failure, we return NULL.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Size and destination for individual (contiguous) copy operations
|
|
//
|
|
UINT CopySize;
|
|
PUCHAR pDataDst;
|
|
|
|
//
|
|
// Start Virtual address for each NDIS buffer in chain.
|
|
//
|
|
PUCHAR VirtualAddress;
|
|
|
|
//
|
|
// Offset within pDestBuffer
|
|
//
|
|
UINT OffsetInBuffer = *pOffsetInBuffer;
|
|
|
|
//
|
|
// Bytes remaining in current buffer
|
|
//
|
|
UINT DestSize;
|
|
|
|
//
|
|
// Total Buffer Length
|
|
//
|
|
UINT BufferLength;
|
|
|
|
|
|
AA_ASSERT(pDestBuffer != (PNDIS_BUFFER)NULL);
|
|
AA_ASSERT(pDataSrc != NULL);
|
|
|
|
#ifdef ATMARP_WIN98
|
|
NdisQueryBuffer(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength
|
|
);
|
|
#else
|
|
NdisQueryBufferSafe(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength,
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (VirtualAddress == NULL)
|
|
{
|
|
return (NULL);
|
|
}
|
|
#endif // ATMARP_WIN98
|
|
|
|
AA_ASSERT(BufferLength >= OffsetInBuffer);
|
|
|
|
pDataDst = VirtualAddress + OffsetInBuffer;
|
|
DestSize = BufferLength - OffsetInBuffer;
|
|
|
|
for (;;)
|
|
{
|
|
CopySize = MIN(LenToCopy, DestSize);
|
|
AA_COPY_MEM(pDataDst, pDataSrc, CopySize);
|
|
|
|
pDataDst += CopySize;
|
|
pDataSrc += CopySize;
|
|
|
|
LenToCopy -= CopySize;
|
|
if (LenToCopy == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DestSize -= CopySize;
|
|
|
|
if (DestSize == 0)
|
|
{
|
|
//
|
|
// Out of space in the current buffer. Move to the next.
|
|
//
|
|
pDestBuffer = NDIS_BUFFER_LINKAGE(pDestBuffer);
|
|
AA_ASSERT(pDestBuffer != (PNDIS_BUFFER)NULL);
|
|
#ifdef ATMARP_WIN98
|
|
NdisQueryBuffer(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength
|
|
);
|
|
#else
|
|
NdisQueryBufferSafe(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength,
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (VirtualAddress == NULL)
|
|
{
|
|
return (NULL);
|
|
}
|
|
#endif // ATMARP_WIN98
|
|
|
|
pDataDst = VirtualAddress;
|
|
DestSize = BufferLength;
|
|
}
|
|
}
|
|
|
|
*pOffsetInBuffer = (UINT) (pDataDst - VirtualAddress);
|
|
|
|
return (pDestBuffer);
|
|
}
|
|
|
|
|
|
PATMARP_INTERFACE
|
|
AtmArpAddInterfaceToAdapter (
|
|
IN PATMARP_ADAPTER pAdapter,
|
|
IN NDIS_HANDLE LISConfigHandle, // Handle to per-LIS config
|
|
IN NDIS_STRING *pIPConfigString
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
struct LLIPBindInfo BindInfo;
|
|
PATMARP_INTERFACE pInterface;
|
|
#ifdef ATMARP_WIN98
|
|
ANSI_STRING AnsiConfigString;
|
|
#endif
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create an ATMARP Interface structure to represent this LIS.
|
|
//
|
|
pInterface = AtmArpAllocateInterface(pAdapter);
|
|
if (pInterface == NULL_PATMARP_INTERFACE)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("NotifyRegAfHandler: could not allocate Interface\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Adapter Binding Reference:
|
|
//
|
|
AtmArpReferenceInterface(pInterface);
|
|
|
|
//
|
|
// Get all configuration information for this LIS.
|
|
//
|
|
Status = AtmArpCfgReadLISConfiguration(
|
|
LISConfigHandle,
|
|
pInterface
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("AddInterfaceToAdapter: bad status (0x%x) reading LIS cfg\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
#ifndef ATMARP_WIN98
|
|
pInterface->IPConfigString = *pIPConfigString; // struct copy.
|
|
#else
|
|
//
|
|
// Win98: Convert IPConfig string from Unicode to ANSI.
|
|
//
|
|
AnsiConfigString.MaximumLength = pIPConfigString->MaximumLength / sizeof(WCHAR) + sizeof(CHAR);
|
|
AA_ALLOC_MEM(AnsiConfigString.Buffer, CHAR, AnsiConfigString.MaximumLength);
|
|
if (AnsiConfigString.Buffer == NULL)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("NotifyRegAfHandler: couldn't alloc Ansi string (%d)\n",
|
|
AnsiConfigString.MaximumLength));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
AnsiConfigString.Length = 0;
|
|
NdisUnicodeStringToAnsiString(&AnsiConfigString, pIPConfigString);
|
|
AnsiConfigString.Buffer[AnsiConfigString.Length] = '\0';
|
|
#endif // !ATMARP_WIN98
|
|
|
|
//
|
|
// Allocate protocol buffers for this LIS.
|
|
//
|
|
Status = AtmArpInitProtoBuffers(pInterface);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("AddInterfaceToAdapter: bad status (0x%x) from InitBufs\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize IP/ATM data structures for this LIS.
|
|
//
|
|
Status = AtmArpInitIpOverAtm(pInterface);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("AddInterfaceToAdapter: bad status (0x%x) from InitIP/ATM\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the Call Manager interface for this LIS.
|
|
//
|
|
Status = AtmArpOpenCallMgr(pInterface);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("AddInterfaceToAdapter: bad status (0x%x) from OpenCallMgr\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Announce this new interface to IP, along with our BindInfo
|
|
// structure.
|
|
//
|
|
AA_SET_MEM(&BindInfo, 0, sizeof(BindInfo));
|
|
|
|
#if ATMOFFLOAD
|
|
//
|
|
// Query and set NIC offload capabilities.
|
|
//
|
|
BindInfo.lip_OffloadFlags = pAdapter->Offload.Flags;
|
|
BindInfo.lip_MaxOffLoadSize = pAdapter->Offload.MaxOffLoadSize;
|
|
BindInfo.lip_MaxSegments = pAdapter->Offload.MinSegmentCount;
|
|
#endif // ATMOFFLOAD
|
|
|
|
BindInfo.lip_context = (PVOID)pInterface;
|
|
#ifdef ATMARP_WIN98
|
|
BindInfo.lip_transmit = AtmArpIfTransmit;
|
|
#else
|
|
BindInfo.lip_transmit = AtmArpIfMultiTransmit;
|
|
#endif
|
|
BindInfo.lip_transfer = AtmArpIfTransfer;
|
|
BindInfo.lip_close = AtmArpIfClose;
|
|
BindInfo.lip_addaddr = AtmArpIfAddAddress;
|
|
BindInfo.lip_deladdr = AtmArpIfDelAddress;
|
|
BindInfo.lip_invalidate = AtmArpIfInvalidate;
|
|
BindInfo.lip_open = AtmArpIfOpen;
|
|
BindInfo.lip_qinfo = AtmArpIfQueryInfo;
|
|
BindInfo.lip_setinfo = AtmArpIfSetInfo;
|
|
BindInfo.lip_getelist = AtmArpIfGetEList;
|
|
BindInfo.lip_mss = pInterface->MTU;
|
|
BindInfo.lip_speed = pInterface->Speed;
|
|
//
|
|
// Set LIP_COPY_FLAG to avoid having TransferData
|
|
// called all the time.
|
|
//
|
|
BindInfo.lip_flags = LIP_COPY_FLAG;
|
|
BindInfo.lip_addrlen = AA_ATM_PHYSADDR_LEN;
|
|
BindInfo.lip_addr = &(pInterface->LocalAtmAddress.Address[AA_ATM_ESI_OFFSET]);
|
|
#ifdef _PNP_POWER_
|
|
BindInfo.lip_pnpcomplete = AtmArpIfPnPComplete;
|
|
#endif // _PNP_POWER_
|
|
|
|
#ifdef PROMIS
|
|
BindInfo.lip_setndisrequest = AtmArpIfSetNdisRequest;
|
|
#endif // PROMIS
|
|
|
|
#ifdef ATMARP_WIN98
|
|
#if DBG
|
|
AADEBUGP(AAD_FATAL, ("Will call AddIF: DeviceName [%ws]\n",
|
|
&(pInterface->pAdapter->DeviceName.Buffer)));
|
|
AADEBUGP(AAD_FATAL, ("And ConfigString: [%s]\n", AnsiConfigString.Buffer));
|
|
#endif
|
|
#endif // ATMARP_WIN98
|
|
|
|
Status = (*(pAtmArpGlobalInfo->pIPAddInterfaceRtn))(
|
|
&(pInterface->pAdapter->DeviceName),
|
|
|
|
#ifndef ATMARP_WIN98
|
|
#if IFCHANGE1
|
|
NULL, // IfName (unused) -- See 10/14/1998 entry
|
|
// in notes.txt
|
|
#endif // IFCHANGE1
|
|
pIPConfigString,
|
|
|
|
#else
|
|
(PNDIS_STRING)&AnsiConfigString,
|
|
#endif
|
|
pAdapter->SystemSpecific2,
|
|
(PVOID)pInterface,
|
|
AtmArpIfDynRegister,
|
|
&BindInfo
|
|
#if IFCHANGE1
|
|
#ifndef ATMARP_WIN98
|
|
,0, // RequestedIndex (unused) -- See 10/14/1998 entry
|
|
// in notes.txt
|
|
|
|
IF_TYPE_IPOVER_ATM,
|
|
IF_ACCESS_BROADCAST,
|
|
IF_CONNECTION_DEDICATED
|
|
#endif
|
|
#endif // IFCHANGE1
|
|
);
|
|
|
|
if (Status == IP_SUCCESS)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_ERROR, ("AddInterface: IPAddInterface ret 0x%x\n",
|
|
Status));
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// There was a failure in processing this LIS.
|
|
//
|
|
if (pInterface != NULL_PATMARP_INTERFACE)
|
|
{
|
|
if (pInterface->NdisAfHandle != NULL)
|
|
{
|
|
(VOID)AtmArpCloseCallMgr(pInterface);
|
|
}
|
|
|
|
pInterface->RefCount = 0;
|
|
AtmArpDeallocateInterface(pInterface);
|
|
|
|
pInterface = NULL_PATMARP_INTERFACE;
|
|
}
|
|
}
|
|
|
|
return pInterface;
|
|
|
|
}
|
|
|
|
#if DBG
|
|
|
|
void
|
|
AtmArpValidateTimerList(
|
|
PATMARP_TIMER_LIST pTimerList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
pTimerList - Timer list
|
|
|
|
Return Value:
|
|
|
|
None -- will assert if timer is not valid.
|
|
|
|
--*/
|
|
|
|
{
|
|
PATMARP_TIMER pTimer;
|
|
UINT u;
|
|
UINT cTimers=0;
|
|
|
|
AA_ASSERT(pTimerList->atl_sig == atl_signature);
|
|
AA_ASSERT(pTimerList->CurrentTick < pTimerList->TimerListSize);
|
|
|
|
for (u=0;u<pTimerList->TimerListSize;u++)
|
|
{
|
|
for ( pTimer = pTimerList->pTimers[u].pNextTimer;
|
|
pTimer;
|
|
pTimer = pTimer->pNextTimer)
|
|
{
|
|
AtmArpValidateTimer(pTimerList, pTimer);
|
|
cTimers++;
|
|
}
|
|
}
|
|
|
|
AA_ASSERT(pTimerList->TimerCount == cTimers);
|
|
|
|
}
|
|
|
|
void
|
|
AtmArpValidateTimer(
|
|
PATMARP_TIMER_LIST pTimerList, // OPTIONAL
|
|
PATMARP_TIMER pTimer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
pTimer - Timer
|
|
|
|
Return Value:
|
|
|
|
None -- will assert if timer is not valid.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pTimerList)
|
|
{
|
|
AA_ASSERT(pTimerList == pTimer->pTimerList);
|
|
}
|
|
|
|
if (pTimer->pPrevTimer)
|
|
{
|
|
AA_ASSERT(pTimer->pPrevTimer->pNextTimer == pTimer);
|
|
}
|
|
|
|
if (pTimer->pNextTimer)
|
|
{
|
|
AA_ASSERT(pTimer->pNextTimer->pPrevTimer == pTimer);
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|