You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3049 lines
68 KiB
3049 lines
68 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arpproc.c - ARP Procedures
|
|
|
|
Abstract:
|
|
|
|
All Client protocol operations related to IP over ATM are here:
|
|
- Registration with an ARP server
|
|
- Resolving an IP address
|
|
- Maintaining the ARP cache
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 07-17-96 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'PPRA'
|
|
|
|
|
|
VOID
|
|
AtmArpStartRegistration(
|
|
IN PATMARP_INTERFACE pInterface LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start registering ourselves with the ARP server, on the specified
|
|
interface. The caller is assume to have a lock for the Interface,
|
|
and we release it here.
|
|
|
|
We first check if all pre-conditions are satisfied, i.e.:
|
|
|
|
1. The Admin State for the interface is UP
|
|
2. The ATM interface is ready
|
|
3. Atleast one IP Address has been configured for the interface
|
|
4. We know the address of atleast one ARP server (SVC environment)
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIP_ADDRESS pIPAddress;
|
|
BOOLEAN WasRunning;
|
|
|
|
pIPAddress = &pInterface->LocalIPAddress.IPAddress;
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
if (pInterface->PVCOnly)
|
|
{
|
|
//
|
|
// PVCs only: no registration required
|
|
//
|
|
pInterface->State = IF_STATUS_UP;
|
|
pInterface->LastChangeTime = GetTimeTicks();
|
|
|
|
AA_SET_FLAG(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERED);
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
#ifdef ATMARP_WMI
|
|
AtmArpWmiSendTCIfIndication(
|
|
pInterface,
|
|
AAGID_QOS_TC_INTERFACE_UP_INDICATION,
|
|
0
|
|
);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We use SVCs; start registering if we know the
|
|
// address of atleast one ARP server, and we have
|
|
// atleast one local IP address to register, and
|
|
// we haven't registered yet, and we are not in
|
|
// the process of registering currently.
|
|
//
|
|
if ((pInterface->AtmInterfaceUp) &&
|
|
(pInterface->ArpServerList.ListSize > 0) &&
|
|
(pInterface->NumOfIPAddresses > 0) &&
|
|
(AA_IS_FLAG_SET(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_NO_CONTACT))
|
|
)
|
|
{
|
|
AADEBUGP(AAD_INFO, ("Starting registration on IF 0x%x\n", pInterface));
|
|
|
|
AA_SET_FLAG(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERING);
|
|
|
|
//
|
|
// Just in case we have left a timer running, stop it.
|
|
//
|
|
WasRunning = AtmArpStopTimer(
|
|
&(pInterface->Timer),
|
|
pInterface
|
|
);
|
|
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pInterface->Timer),
|
|
AtmArpRegistrationTimeout,
|
|
pInterface->ServerRegistrationTimeout,
|
|
(PVOID)pInterface // Context
|
|
);
|
|
|
|
if (!WasRunning)
|
|
{
|
|
AtmArpReferenceInterface(pInterface); // Timer ref
|
|
}
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AtmArpSendARPRequest(
|
|
pInterface,
|
|
pIPAddress, // Source IP is ours
|
|
pIPAddress // Target IP is ours
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't have all necessary preconditions for
|
|
// starting registration.
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The Interface is down
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpRegisterOtherIPAddresses(
|
|
IN PATMARP_INTERFACE pInterface LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Register all unregistered IP addresses with the ARP server. The caller
|
|
is assumed to hold a lock for the Interface structure, which will be
|
|
released here.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ARMARP Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIP_ADDRESS_ENTRY pIPAddressEntry;
|
|
PIP_ADDRESS pIPAddressList; // List of addresses we want to register
|
|
INT AddressCount; // Size of above list
|
|
PIP_ADDRESS pIPAddress; // Temp, to walk thru lists
|
|
|
|
|
|
if (pInterface->NumOfIPAddresses > 1)
|
|
{
|
|
//
|
|
// First make a copy of all addresses we want to register,
|
|
// while we hold a lock to the Interface.
|
|
//
|
|
AA_ALLOC_MEM(
|
|
pIPAddressList,
|
|
IP_ADDRESS,
|
|
(pInterface->NumOfIPAddresses)*sizeof(IP_ADDRESS));
|
|
|
|
|
|
AddressCount = 0;
|
|
if (pIPAddressList != (PIP_ADDRESS)NULL)
|
|
{
|
|
pIPAddress = pIPAddressList;
|
|
|
|
pIPAddressEntry = &(pInterface->LocalIPAddress);
|
|
while (pIPAddressEntry != (PIP_ADDRESS_ENTRY)NULL)
|
|
{
|
|
if (!(pIPAddressEntry->IsRegistered))
|
|
{
|
|
//
|
|
// This one's not registered yet: copy it into our list.
|
|
//
|
|
AA_COPY_MEM(
|
|
(PUCHAR)pIPAddress,
|
|
(PUCHAR)&(pIPAddressEntry->IPAddress),
|
|
sizeof(IP_ADDRESS));
|
|
pIPAddress++;
|
|
AddressCount++;
|
|
}
|
|
pIPAddressEntry = pIPAddressEntry->pNext;
|
|
}
|
|
|
|
}
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
pIPAddress = pIPAddressList;
|
|
while (AddressCount-- > 0)
|
|
{
|
|
AADEBUGP(AAD_INFO, ("Registering Other IP Address on IF 0x%x: %d.%d.%d.%d\n",
|
|
pInterface,
|
|
((PUCHAR)pIPAddress)[0],
|
|
((PUCHAR)pIPAddress)[1],
|
|
((PUCHAR)pIPAddress)[2],
|
|
((PUCHAR)pIPAddress)[3]));
|
|
|
|
AtmArpSendARPRequest(
|
|
pInterface,
|
|
pIPAddress, // Source IP is ours
|
|
pIPAddress // Target IP is ours
|
|
);
|
|
pIPAddress++;
|
|
}
|
|
|
|
if (pIPAddressList != (PIP_ADDRESS)NULL)
|
|
{
|
|
AA_FREE_MEM(pIPAddressList);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No additional addresses to register.
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpRetryServerRegistration(
|
|
IN PATMARP_INTERFACE pInterface LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retry server registration. This is called because of a failure to
|
|
register with the server (connection failure, or no response or
|
|
NAK response or invalid response to our registration ARP Request).
|
|
|
|
If we have tried this server enough times, we move to the next
|
|
ARP server in our list. Wait for a while before retrying.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ARMARP Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
if (pInterface->RetriesLeft > 0)
|
|
{
|
|
//
|
|
// We still have retries on this server.
|
|
//
|
|
pInterface->RetriesLeft--;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Out of retries on this server. Pick up the next timer in the
|
|
// list.
|
|
//
|
|
if (pInterface->pCurrentServer->pNext != (PATMARP_SERVER_ENTRY)NULL)
|
|
{
|
|
pInterface->pCurrentServer = pInterface->pCurrentServer->pNext;
|
|
}
|
|
else
|
|
{
|
|
pInterface->pCurrentServer = pInterface->ArpServerList.pList;
|
|
}
|
|
|
|
pInterface->RetriesLeft = pInterface->MaxRegistrationAttempts - 1;
|
|
}
|
|
|
|
AA_SET_FLAG(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_NO_CONTACT);
|
|
|
|
|
|
//
|
|
// Wait for a while before initiating another
|
|
// connection to the server. When the timer elapses,
|
|
// we will try again.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pInterface->Timer),
|
|
AtmArpServerConnectTimeout,
|
|
pInterface->ServerConnectInterval,
|
|
(PVOID)pInterface
|
|
);
|
|
|
|
AtmArpReferenceInterface(pInterface); // Timer ref
|
|
}
|
|
//
|
|
// else the Interface is going down -- do nothing.
|
|
//
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpHandleServerRegistrationFailure(
|
|
IN PATMARP_INTERFACE pInterface LOCKIN NOLOCKOUT,
|
|
IN PATMARP_VC pVc OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a failure in the Registration process. We close the VC to the
|
|
ARP server, if one exists, and wait for a while before starting the
|
|
registration process again.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP interface
|
|
pVc - (Optional) pointer to VC to ARP Server.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN TimerWasRunning;
|
|
ULONG rc; // Ref Count on Interface.
|
|
|
|
TimerWasRunning = AtmArpStopTimer(&(pInterface->Timer), pInterface);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AtmArpDereferenceInterface(pInterface); // Timer reference
|
|
AA_ASSERT(rc > 0);
|
|
}
|
|
|
|
AtmArpRetryServerRegistration(pInterface);
|
|
//
|
|
// The IF lock is released within the above.
|
|
//
|
|
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
//
|
|
// Tear down this VC (to an ARP server).
|
|
//
|
|
// NOTE: We do this now even though we called RetryServerRegistration
|
|
// above because we have the knowledge that the routine above
|
|
// doesn't really start registration: it only starts a timer
|
|
// on whose expiry we start registration.
|
|
//
|
|
// First unlink this VC from the ATM Entry it's linked to.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
//
|
|
// Now close the call
|
|
//
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// the VC lock is released above
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtmArpIsZeroIPAddress(
|
|
IN UCHAR UNALIGNED * pIPAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the given IP address is all zeros.
|
|
|
|
Arguments:
|
|
|
|
pIPAddress - Pointer to IP address in question
|
|
|
|
Return Value:
|
|
|
|
TRUE if the address is all 0's, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
IP_ADDRESS UNALIGNED * pIPAddrStruct;
|
|
|
|
pIPAddrStruct = (IP_ADDRESS UNALIGNED *)pIPAddress;
|
|
return (BOOLEAN)(*pIPAddrStruct == (IP_ADDRESS)0);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtmArpIsLocalIPAddress(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN UCHAR UNALIGNED * pIPAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the given IP address is one of those assigned to this
|
|
interface.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to Interface structure
|
|
pIPAddress - Pointer to IP address in question
|
|
|
|
Return Value:
|
|
|
|
TRUE if the IP address is one of ours, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PIP_ADDRESS_ENTRY pIPAddrEntry;
|
|
IP_ADDRESS UNALIGNED * pIPAddrStruct;
|
|
BOOLEAN IsLocal;
|
|
|
|
if (pIPAddress != (PUCHAR)NULL)
|
|
{
|
|
pIPAddrStruct = (IP_ADDRESS UNALIGNED *)pIPAddress;
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
pIPAddrEntry = &(pInterface->LocalIPAddress);
|
|
|
|
IsLocal = FALSE;
|
|
do
|
|
{
|
|
if (pIPAddrEntry->IPAddress == *pIPAddrStruct)
|
|
{
|
|
IsLocal = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pIPAddrEntry = pIPAddrEntry->pNext;
|
|
}
|
|
}
|
|
while (pIPAddrEntry != (PIP_ADDRESS_ENTRY)NULL);
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
else
|
|
{
|
|
IsLocal = FALSE;
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("IsLocalIP(%d:%d:%d:%d): returning %d\n",
|
|
(IsLocal? pIPAddress[0] : 0),
|
|
(IsLocal? pIPAddress[1] : 0),
|
|
(IsLocal? pIPAddress[2] : 0),
|
|
(IsLocal? pIPAddress[3] : 0),
|
|
IsLocal));
|
|
return (IsLocal);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtmArpIsLocalAtmAddress(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PUCHAR pAtmAddrString,
|
|
IN UCHAR AtmAddrTypeLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the given ATM address (in "packet" format) is the same as
|
|
our local ATM address.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to Interface structure for which the check
|
|
is being made.
|
|
pAtmAddrString - String of bytes representing an ATM address
|
|
AtmAddrTypeLen - Type and Length (ARP packet format) of ATM address
|
|
|
|
Return Value:
|
|
|
|
TRUE if the given address matches the local ATM address for the
|
|
specified interface, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
ATM_ADDRESSTYPE AddressType;
|
|
ULONG AddressLength;
|
|
|
|
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(AtmAddrTypeLen, &AddressType, &AddressLength);
|
|
|
|
if ((AddressType == pInterface->LocalAtmAddress.AddressType) &&
|
|
(AddressLength == pInterface->LocalAtmAddress.NumberOfDigits) &&
|
|
(AA_MEM_CMP(
|
|
pAtmAddrString,
|
|
pInterface->LocalAtmAddress.Address,
|
|
AddressLength) == 0)
|
|
)
|
|
{
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpSendPacketOnAtmEntry(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN PATMARP_FLOW_SPEC pFlowSpec,
|
|
IN PATMARP_FILTER_SPEC pFilterSpec OPTIONAL,
|
|
IN PATMARP_FLOW_INFO pFlowInfo OPTIONAL,
|
|
IN BOOLEAN IsBroadcast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a packet with the specified Filter-Spec and Flow-Spec to
|
|
the ATM address denoted by the ATM Entry. We look for a VC that
|
|
matches the given Specs, and send/queue this packet on the VC.
|
|
If no such VC exists, we make a call with this Flow-Spec.
|
|
|
|
NOTE: The caller is assumed to hold a lock to the ATM Entry, which
|
|
we will release here.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
pAtmEntry - Pointer to ATM Entry on which this packet
|
|
should be sent
|
|
pNdisPacket - Packet to be sent
|
|
pFlowSpec - Flow-Spec for this packet.
|
|
pFilterSpec - Filter-Spec for this packet.
|
|
pFlowInfo - Flow to which this packet belongs.
|
|
IsBroadcast - Is this to a Class-D or broadcast address?
|
|
|
|
Locks on entry:
|
|
|
|
Locks on exit:
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc; // VC to send this packet on
|
|
PNDIS_BUFFER pHeaderBuffer; // For LLC/SNAP header
|
|
PNDIS_BUFFER pNdisBuffer; // First buffer in the IP packet
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
PUCHAR pHeader;
|
|
AA_HEADER_TYPE HdrType;
|
|
|
|
do
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// TODO -- the atm entry may not be ACTIVE at this time,
|
|
// you may want to check for this and if so fail the call and free
|
|
// the packet (call AtmArpFreeSendPackets) here itself.
|
|
// As it happens we go on and make a call if possible, etc.
|
|
//
|
|
|
|
// Prepend an LLC/SNAP header if required.
|
|
//
|
|
if (pFlowSpec->Encapsulation == ENCAPSULATION_TYPE_LLCSNAP)
|
|
{
|
|
HdrType = (IsBroadcast? AA_HEADER_TYPE_NUNICAST: AA_HEADER_TYPE_UNICAST);
|
|
|
|
#ifdef BACK_FILL
|
|
//
|
|
// We look at the first buffer in the IP packet, to see whether
|
|
// it has space reserved for low-layer headers. If so, we just
|
|
// use it up. Otherwise, we allocate a header buffer of our own.
|
|
//
|
|
NdisQueryPacket(pNdisPacket, NULL, NULL, &pNdisBuffer, NULL);
|
|
AA_ASSERT(pNdisBuffer != NULL);
|
|
if (AtmArpDoBackFill && AA_BACK_FILL_POSSIBLE(pNdisBuffer))
|
|
{
|
|
PUCHAR pArpHeader;
|
|
ULONG ArpHeaderLength;
|
|
|
|
AtmArpBackFillCount++;
|
|
if (HdrType == AA_HEADER_TYPE_UNICAST)
|
|
{
|
|
pArpHeader = (PUCHAR)&AtmArpLlcSnapHeader;
|
|
ArpHeaderLength = sizeof(AtmArpLlcSnapHeader);
|
|
}
|
|
#ifdef IPMCAST
|
|
else
|
|
{
|
|
pArpHeader = (PUCHAR)&AtmArpMcType1ShortHeader;
|
|
ArpHeaderLength = sizeof(AtmArpMcType1ShortHeader);
|
|
}
|
|
#endif // IPMCAST
|
|
(PUCHAR)pNdisBuffer->MappedSystemVa -= ArpHeaderLength;
|
|
pNdisBuffer->ByteOffset -= ArpHeaderLength;
|
|
pNdisBuffer->ByteCount += ArpHeaderLength;
|
|
pHeader = pNdisBuffer->MappedSystemVa;
|
|
AA_COPY_MEM(pHeader,
|
|
pArpHeader,
|
|
ArpHeaderLength);
|
|
}
|
|
else
|
|
{
|
|
pHeaderBuffer = AtmArpAllocateHeader(pInterface, HdrType, &pHeader);
|
|
if (pHeaderBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NdisChainBufferAtFront(pNdisPacket, pHeaderBuffer);
|
|
}
|
|
else
|
|
{
|
|
pHeader = NULL;
|
|
}
|
|
}
|
|
|
|
if (pHeader != NULL)
|
|
{
|
|
#else
|
|
pHeaderBuffer = AtmArpAllocateHeader(pInterface, HdrType, &pHeader);
|
|
if (pHeaderBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NdisChainBufferAtFront(pNdisPacket, pHeaderBuffer);
|
|
#endif // BACK_FILL
|
|
#ifdef IPMCAST
|
|
if (HdrType == AA_HEADER_TYPE_NUNICAST)
|
|
{
|
|
PAA_MC_PKT_TYPE1_SHORT_HEADER pDataHeader;
|
|
|
|
//
|
|
// Fill in our Cluster Member ID
|
|
//
|
|
AAMCDEBUGP(AAD_EXTRA_LOUD+10,
|
|
("(MC)SendPkt: pAtmEntry 0x%x, pHeaderBuffer 0x%x, pHeader 0x%x\n",
|
|
pAtmEntry, pHeaderBuffer, pHeader));
|
|
|
|
pDataHeader = (PAA_MC_PKT_TYPE1_SHORT_HEADER)pHeader;
|
|
pDataHeader->cmi = (USHORT)(pInterface->ClusterMemberId);
|
|
}
|
|
#endif // IPMCAST
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AADEBUGP(AAD_WARNING, ("FAILED TO ALLOCATE HEADER ON IF 0x%x\n",
|
|
pInterface));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Search for a VC that has matching flow/filter specs.
|
|
//
|
|
for (pVc = pAtmEntry->pVcList;
|
|
pVc != NULL_PATMARP_VC;
|
|
pVc = pVc->pNextVc)
|
|
{
|
|
#ifdef GPC
|
|
PVOID VcFlowHandle;
|
|
|
|
VcFlowHandle = pVc->FlowHandle;
|
|
#endif // GPC
|
|
|
|
if ((!AA_IS_VC_GOING_DOWN(pVc)) &&
|
|
(pVc->FlowSpec.SendPeakBandwidth > 0))
|
|
{
|
|
#ifdef GPC
|
|
if (VcFlowHandle == (PVOID)pFlowInfo)
|
|
{
|
|
//
|
|
// This VC was made for this flow.
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (IsBroadcast)
|
|
{
|
|
//
|
|
// We don't support multiple VCs to a multicast IP
|
|
// destination. So, stop at the first available VC.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this VC is associated with a flow already, don't
|
|
// send traffic belonging to another flow (explicit or
|
|
// unclassified best effort) on it.
|
|
//
|
|
if (VcFlowHandle != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
#endif // GPC
|
|
if ((pFilterSpec == (PATMARP_FILTER_SPEC)NULL) ||
|
|
AA_FILTER_SPEC_MATCH(pInterface, pFilterSpec, &(pVc->FilterSpec)))
|
|
{
|
|
if (AA_FLOW_SPEC_MATCH(pInterface, pFlowSpec, &(pVc->FlowSpec)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("pVc %x did not match pkt, Vc has VcHandle %x, SendPeak %d, SendMaxSize %d\n",
|
|
pVc,
|
|
pVc->NdisVcHandle,
|
|
pVc->FlowSpec.SendPeakBandwidth,
|
|
pVc->FlowSpec.SendMaxSize));
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Target FlowSpec %x has SendPeak %d, SendMaxSize %d\n",
|
|
pFlowSpec,
|
|
pFlowSpec->SendPeakBandwidth,
|
|
pFlowSpec->SendMaxSize));
|
|
}
|
|
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
//
|
|
// Found a VC that matches this packet's requirements.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK_DPC(pVc);
|
|
|
|
#ifdef GPC
|
|
//
|
|
// See if the VC and the Flow are unassociated. If so, link
|
|
// together the VC and the Flow, to speed up future packets.
|
|
// Take care not to reassociate a VC that's just been unlinked
|
|
// from a flow.
|
|
//
|
|
if ((pFlowInfo != NULL) &&
|
|
(pVc->FlowHandle == NULL) &&
|
|
(!AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_GPC_MASK,
|
|
AA_VC_GPC_IS_UNLINKED_FROM_FLOW))
|
|
)
|
|
{
|
|
if (NULL == InterlockedCompareExchangePointer(
|
|
&(pFlowInfo->VcContext),
|
|
pVc,
|
|
NULL
|
|
))
|
|
{
|
|
AADEBUGP( AAD_LOUD,
|
|
("SendPktOnAtmEntry: linking VC x%x and FlowInfo x%x\n",
|
|
pVc, pFlowInfo));
|
|
pVc->FlowHandle = (PVOID)pFlowInfo;
|
|
AtmArpReferenceVc(pVc); // GPC FlowInfo ref
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We couldn't associate the vc with the flow, so we need
|
|
// to enable the ageing timer for this vc, because we'll
|
|
// never get notified when the flow is removed/modified.
|
|
//
|
|
if (!AA_IS_TIMER_ACTIVE(&(pVc->Timer)))
|
|
{
|
|
AADEBUGP( AAD_INFO,
|
|
("SendPktOnAtmEntry: Enabling ageing timer on VC x%x "
|
|
"because we could not associate with FlowInfo x%x\n",
|
|
pVc, pFlowInfo));
|
|
AtmArpStartTimer(
|
|
pVc->pInterface,
|
|
&(pVc->Timer),
|
|
AtmArpVcAgingTimeout,
|
|
pInterface->DefaultFlowSpec.AgingTime,
|
|
(PVOID)pVc
|
|
);
|
|
|
|
AtmArpReferenceVc(pVc); // GPC Flow remove decay timer ref
|
|
}
|
|
}
|
|
}
|
|
#endif // GPC
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE))
|
|
{
|
|
#ifdef VC_REFS_ON_SENDS
|
|
AtmArpReferenceVc(pVc); // SendPacketOnAtmEntry
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
pVc->OutstandingSends++; // SendPacketOnAtmEntry
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
AtmArpRefreshTimer(&(pVc->Timer));
|
|
}
|
|
else
|
|
{
|
|
AtmArpQueuePacketOnVc(pVc, pNdisPacket);
|
|
NdisVcHandle = NULL; // to signify we are queueing this packet
|
|
}
|
|
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
if (NdisVcHandle != NULL)
|
|
{
|
|
//
|
|
// A call is active on this VC, so send the packet.
|
|
//
|
|
#if DBG
|
|
if (AaDataDebugLevel & (AAD_DATA_OUT))
|
|
{
|
|
AADEBUGP(AAD_FATAL,
|
|
("Will send Pkt %x on VC %x, Handle %x, sendBW %d, sendMax %d\n",
|
|
pNdisPacket,
|
|
pVc,
|
|
NdisVcHandle,
|
|
pVc->FlowSpec.SendPeakBandwidth,
|
|
pVc->FlowSpec.SendMaxSize));
|
|
}
|
|
#endif
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD+50,
|
|
("SendPktOnAtmEntry: will send Pkt 0x%x on VC 0x%x, VcHandle 0x%x\n",
|
|
pNdisPacket,
|
|
pVc,
|
|
NdisVcHandle));
|
|
|
|
#ifdef PERF
|
|
AadLogSendUpdate(pNdisPacket);
|
|
#endif // PERF
|
|
NDIS_CO_SEND_PACKETS(
|
|
NdisVcHandle,
|
|
&pNdisPacket,
|
|
1
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The packet would have been queued.
|
|
//
|
|
}
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No matching VC exists; create a new one.
|
|
//
|
|
#ifdef IPMCAST
|
|
if (AA_IS_FLAG_SET(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_TYPE_MASK,
|
|
AA_ATM_ENTRY_TYPE_UCAST))
|
|
{
|
|
Status = AtmArpMakeCall(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pFlowSpec,
|
|
pNdisPacket
|
|
);
|
|
//
|
|
// AE lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Multicast ATM Entry: we shouldn't be here, ideally..
|
|
//
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
AAMCDEBUGP(AAD_WARNING,
|
|
("SendPacket: pAtmEntry 0x%x, Flags 0x%x, dropping pkt 0x%x\n",
|
|
pAtmEntry, pAtmEntry->Flags, pNdisPacket));
|
|
|
|
AA_SET_NEXT_PACKET(pNdisPacket, NULL);
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
pNdisPacket,
|
|
TRUE // header present
|
|
);
|
|
}
|
|
#else
|
|
Status = AtmArpMakeCall(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pFlowSpec,
|
|
pNdisPacket
|
|
);
|
|
//
|
|
// The ATM Entry lock is released within the above.
|
|
//
|
|
#endif // IPMCAST
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpQueuePacketOnVc(
|
|
IN PATMARP_VC pVc,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queue a packet on the VC's transmit queue.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC
|
|
pNdisPacket - The packet to be queued.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pPrevPacket;
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("Queueing Pkt 0x%x on VC 0x%x\n",
|
|
pNdisPacket, pVc));
|
|
|
|
if (pVc->PacketList == (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// No packets on this VC.
|
|
//
|
|
pVc->PacketList = pNdisPacket;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Go to the end of the packet list on this VC.
|
|
//
|
|
pPrevPacket = pVc->PacketList;
|
|
while (AA_GET_NEXT_PACKET(pPrevPacket) != (PNDIS_PACKET)NULL)
|
|
{
|
|
pPrevPacket = AA_GET_NEXT_PACKET(pPrevPacket);
|
|
}
|
|
|
|
//
|
|
// Found the last packet in the list. Chain this packet
|
|
// to it.
|
|
//
|
|
AA_SET_NEXT_PACKET(pPrevPacket, pNdisPacket);
|
|
}
|
|
|
|
AA_SET_NEXT_PACKET(pNdisPacket, NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpStartSendsOnVc(
|
|
IN PATMARP_VC pVc LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send all packets queued on a VC. It is assumed that there is
|
|
a call active on the VC, and the Interface state is OK.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC
|
|
|
|
Locks on entry:
|
|
|
|
VC Lock.
|
|
|
|
Locks on exit:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pNdisPacket;
|
|
PNDIS_PACKET pNextNdisPacket;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
ULONG rc; // Ref Count to VC
|
|
|
|
//
|
|
// Remove the entire list of packets queued on the VC.
|
|
//
|
|
pNdisPacket = pVc->PacketList;
|
|
pVc->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
|
|
#ifdef VC_REFS_ON_SENDS
|
|
//
|
|
// Reference the VC for all these packets.
|
|
//
|
|
{
|
|
PNDIS_PACKET pPacket;
|
|
|
|
for (pPacket = pNdisPacket;
|
|
pPacket != NULL;
|
|
pPacket = AA_GET_NEXT_PACKET(pPacket))
|
|
{
|
|
AtmArpReferenceVc(pVc); // StartSendsOnVc
|
|
pVc->OutstandingSends++;// StartSendsOnVc
|
|
}
|
|
}
|
|
#else
|
|
|
|
{
|
|
PNDIS_PACKET pPacket;
|
|
|
|
for (pPacket = pNdisPacket;
|
|
pPacket != NULL;
|
|
pPacket = AA_GET_NEXT_PACKET(pPacket))
|
|
{
|
|
pVc->OutstandingSends++;// StartSendsOnVc (!VC_REFS_ON_SENDS)
|
|
}
|
|
}
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
AtmArpRefreshTimer(&(pVc->Timer));
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
//
|
|
// We have got all that we need from the VC.
|
|
//
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
while (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
pNextNdisPacket = AA_GET_NEXT_PACKET(pNdisPacket);
|
|
AA_SET_NEXT_PACKET(pNdisPacket, NULL);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD+10, ("StartSendsOnVc: pVc 0x%x, Pkt 0x%x\n",
|
|
pVc, pNdisPacket));
|
|
|
|
#ifdef PERF
|
|
AadLogSendUpdate(pNdisPacket);
|
|
#endif // PERF
|
|
NDIS_CO_SEND_PACKETS(
|
|
NdisVcHandle,
|
|
&pNdisPacket,
|
|
1
|
|
);
|
|
|
|
pNdisPacket = pNextNdisPacket;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpSendPacketListOnAtmEntry(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN PNDIS_PACKET pPacketList,
|
|
IN BOOLEAN IsBroadcast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a list of packets towards a destination identified by an
|
|
ATM Entry.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
pAtmEntry - ATM Entry on which the packets are to be sent
|
|
pPacketList - List of packets to be sent.
|
|
IsBroadcast - Are these directed to Class D/broadcast addresses?
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_FLOW_INFO pFlowInfo;
|
|
PATMARP_FLOW_SPEC pFlowSpec;
|
|
PATMARP_FILTER_SPEC pFilterSpec;
|
|
PNDIS_PACKET pNdisPacket;
|
|
PNDIS_PACKET pNextNdisPacket;
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
for (pNdisPacket = pPacketList;
|
|
pNdisPacket != (PNDIS_PACKET)NULL;
|
|
pNdisPacket = pNextNdisPacket)
|
|
{
|
|
pNextNdisPacket = AA_GET_NEXT_PACKET(pNdisPacket);
|
|
AA_SET_NEXT_PACKET(pNdisPacket, NULL);
|
|
|
|
//
|
|
// Get the Filter and Flow specs for this packet
|
|
//
|
|
AA_GET_PACKET_SPECS(pInterface, pNdisPacket, &pFlowInfo, &pFlowSpec, &pFilterSpec);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD+10, ("PktListOnAtmEntry: AtmEntry 0x%x, Pkt 0x%x\n",
|
|
pAtmEntry, pNdisPacket));
|
|
|
|
//
|
|
// Send it off
|
|
//
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
Status = AtmArpSendPacketOnAtmEntry(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pNdisPacket,
|
|
pFlowSpec,
|
|
pFilterSpec,
|
|
pFlowInfo,
|
|
IsBroadcast
|
|
);
|
|
//
|
|
// AE lock is released within the above.
|
|
//
|
|
if ((Status != NDIS_STATUS_PENDING) &&
|
|
(Status != NDIS_STATUS_SUCCESS))
|
|
{
|
|
AADEBUGP(AAD_INFO, ("PktListOnAtmEntry: pIf %x, Pkt %x, Send failure %x\n",
|
|
pInterface, pNdisPacket, Status));
|
|
AtmArpFreeSendPackets(pInterface, pNdisPacket, FALSE);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PATMARP_IP_ENTRY
|
|
AtmArpLearnIPToAtm(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN IP_ADDRESS UNALIGNED * pIPAddress,
|
|
IN UCHAR AtmAddressTypeLength,
|
|
IN UCHAR UNALIGNED * pAtmAddress,
|
|
IN UCHAR AtmSubaddressTypeLength,
|
|
IN UCHAR UNALIGNED * pAtmSubaddress,
|
|
IN BOOLEAN IsStaticEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Learn an IP address to ATM address mapping. This is normally
|
|
called when we receive an ARP reply from the ARP server.
|
|
It may also be called to set up a static mapping.
|
|
|
|
We take care of the case where either the IP address or the
|
|
ATM address (or both) may already exist in the ARP Table: we
|
|
only create the entries that are not present. For example, it
|
|
is possible for multiple IP addresses to map to the same ATM
|
|
address -- in this case, we might find an existing ATM entry
|
|
for a new IP entry.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
pIPAddress - IP address
|
|
AtmAddressTypeLength - Type+Length (ARP packet format) for ATM address
|
|
pAtmAddress - ATM Number
|
|
AtmSubaddressTypeLength - Type+Length (ARP packet format) for ATM subaddress
|
|
pAtmSubaddress - ATM Subaddress
|
|
IsStaticEntry - Is this a static mapping?
|
|
|
|
Return Value:
|
|
|
|
A pointer to the IP Entry that was learned/refreshed.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IP_ENTRY pIpEntry; // Entry for this IP Address
|
|
PATMARP_ATM_ENTRY pAtmEntry; // Entry for this ATM Address
|
|
NDIS_STATUS Status;
|
|
BOOLEAN TimerWasRunning; // Was a timer running on IP Entry?
|
|
ULONG rc; // Ref Count
|
|
PNDIS_PACKET pPacketList;// List of queued packets, if any
|
|
BOOLEAN IsBroadcast;// Is the IP address broadcast/multicast?
|
|
|
|
AADEBUGP(AAD_LOUD, ("LearnIPToAtm: pIf 0x%x, IP Addr: %d:%d:%d:%d, ATM Addr:\n",
|
|
pInterface,
|
|
*((PUCHAR)pIPAddress),
|
|
*((PUCHAR)pIPAddress+1),
|
|
*((PUCHAR)pIPAddress+2),
|
|
*((PUCHAR)pIPAddress+3)));
|
|
|
|
AADEBUGPDUMP(AAD_LOUD, pAtmAddress, (AtmAddressTypeLength & ~AA_PKT_ATM_ADDRESS_BIT));
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
pPacketList = (PNDIS_PACKET)NULL;
|
|
IsBroadcast = FALSE;
|
|
pIpEntry = NULL_PATMARP_IP_ENTRY;
|
|
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
|
|
//
|
|
// Get an ATM Entry. AtmArpSearchForAtmAddress addrefs
|
|
// the entry, so be sure to dereference it if
|
|
// we're not going to be using it.
|
|
//
|
|
pAtmEntry = AtmArpSearchForAtmAddress(
|
|
pInterface,
|
|
AtmAddressTypeLength,
|
|
pAtmAddress,
|
|
AtmSubaddressTypeLength,
|
|
pAtmSubaddress,
|
|
AE_REFTYPE_IE,
|
|
TRUE // Create new entry if not found
|
|
);
|
|
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AADEBUGPMAP(AAD_INFO, "Learnt", pIPAddress, &pAtmEntry->ATMAddress);
|
|
|
|
//
|
|
// Now get an IP Address Entry. AtmArpSeachForIPAddress addrefs
|
|
// the entry, so be sure to deref it if we're not going to be
|
|
// using it.
|
|
//
|
|
pIpEntry = AtmArpSearchForIPAddress(
|
|
pInterface,
|
|
pIPAddress,
|
|
IE_REFTYPE_AE,
|
|
FALSE, // this isn't multicast/broadcast
|
|
TRUE // Create new entry if not found
|
|
);
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
//
|
|
// Got both entries.
|
|
//
|
|
// Check for conflict: if the IP Entry existed before, see if
|
|
// it is linked to a different ATM Entry. If so, we have a new
|
|
// mapping that violates an existing mapping. We discard this
|
|
// new information.
|
|
//
|
|
if (pIpEntry->pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
if (pIpEntry->pAtmEntry != pAtmEntry)
|
|
{
|
|
AADEBUGP(AAD_ERROR,
|
|
("IP Entry 0x%x linked to ATM Entry 0x%x, new ATM Entry 0x%x\n",
|
|
pIpEntry, pIpEntry->pAtmEntry, pAtmEntry));
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// An existing mapping has been reconfirmed.
|
|
//
|
|
AADEBUGP(AAD_INFO,
|
|
("Revalidated IP Entry 0x%x, Addr: %d.%d.%d.%d, PktList 0x%x\n",
|
|
pIpEntry,
|
|
((PUCHAR)pIPAddress)[0],
|
|
((PUCHAR)pIPAddress)[1],
|
|
((PUCHAR)pIPAddress)[2],
|
|
((PUCHAR)pIPAddress)[3],
|
|
pIpEntry->PacketList
|
|
));
|
|
|
|
//
|
|
// Update IP Entry state.
|
|
//
|
|
AA_SET_FLAG(
|
|
pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_RESOLVED);
|
|
|
|
//
|
|
// Remove the list of packets queued on this entry.
|
|
//
|
|
pPacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
|
|
if (pPacketList)
|
|
{
|
|
//
|
|
// We'll be sending out these packets on the
|
|
// atm entry, so better put a tempref on the atm
|
|
// entry now. It is derefed when the packet
|
|
// list is finished being sent on the atm entry.
|
|
//
|
|
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP);// Temp ref: Pkt list.
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
}
|
|
|
|
//
|
|
// We will start the IP Entry aging timer on this
|
|
// entry.
|
|
//
|
|
|
|
//
|
|
// Stop the Address resolution timer running here
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref.
|
|
AA_ASSERT(rc != 0);
|
|
}
|
|
|
|
//
|
|
// Start the Aging timer.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpIPEntryAgingTimeout,
|
|
pInterface->ARPEntryAgingTimeout,
|
|
(PVOID)pIpEntry
|
|
);
|
|
|
|
//
|
|
// Altough we got the initial ref in SearchForIPAddress
|
|
// for IE_REFTYPE_AE, we're actually using it for
|
|
// the timer reference. So we need to switch the reftype
|
|
// here...
|
|
//
|
|
// This reftype stuff is just for tracking purposes.
|
|
//
|
|
AA_SWITCH_IE_REFTYPE(
|
|
pIpEntry,
|
|
IE_REFTYPE_AE,
|
|
IE_REFTYPE_TIMER
|
|
);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This IP Entry wasn't mapped to an ATM Entry previously.
|
|
// Link entries together: first, make the IP entry point
|
|
// to this ATM Entry.
|
|
//
|
|
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
|
|
|
|
//
|
|
// Check if this is still a valid entry....
|
|
//
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING))
|
|
{
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
|
|
pIpEntry->pAtmEntry = pAtmEntry;
|
|
|
|
AA_SET_FLAG(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_ACTIVE);
|
|
|
|
//
|
|
// Add the IP Entry to the ATM Entry's list of IP Entries
|
|
// (multiple IP entries could point to the same ATM Entry).
|
|
//
|
|
pIpEntry->pNextToAtm = pAtmEntry->pIpEntryList;
|
|
pAtmEntry->pIpEntryList = pIpEntry;
|
|
|
|
//
|
|
// Remove the list of packets queued on this IP entry.
|
|
//
|
|
pPacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
if (pPacketList)
|
|
{
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP);// Temp ref: Pkt list.
|
|
}
|
|
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
|
|
|
|
//
|
|
// Update IP Entry state.
|
|
//
|
|
AA_SET_FLAG(
|
|
pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_RESOLVED);
|
|
|
|
TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
if (TimerWasRunning)
|
|
{
|
|
ULONG IeRefCount;
|
|
IeRefCount = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer reference
|
|
AA_ASSERT(IeRefCount > 0);
|
|
}
|
|
|
|
|
|
IsBroadcast = AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_ADDR_TYPE_MASK,
|
|
AA_IP_ENTRY_ADDR_TYPE_NUCAST);
|
|
|
|
if (IsStaticEntry)
|
|
{
|
|
pIpEntry->Flags |= AA_IP_ENTRY_IS_STATIC;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Start the aging timer on this IP Entry.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpIPEntryAgingTimeout,
|
|
pInterface->ARPEntryAgingTimeout,
|
|
(PVOID)pIpEntry
|
|
);
|
|
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer reference
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to locate/allocate IP Entry
|
|
//
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to locate/allocate ATM Entry
|
|
//
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// If we have any queued packets to send, send them now.
|
|
//
|
|
if (pPacketList != (PNDIS_PACKET)NULL)
|
|
{
|
|
AtmArpSendPacketListOnAtmEntry(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pPacketList,
|
|
IsBroadcast
|
|
);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // Send pkt list.
|
|
if (rc>0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pIpEntry)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // LearnIPAtm
|
|
if (rc>0)
|
|
{
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
}
|
|
|
|
if (pAtmEntry)
|
|
{
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_IE); // LearnIPAtm
|
|
if (rc>0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare the return value.
|
|
//
|
|
pIpEntry = NULL_PATMARP_IP_ENTRY;
|
|
}
|
|
|
|
return (pIpEntry);
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpQueuePacketOnIPEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queue a packet on an unresolved IP Entry, unless one of the following
|
|
conditions holds:
|
|
|
|
- We recently got an ARP NAK while trying to resolve this entry. In this
|
|
case, there is no point in queueing up this packet and sending another
|
|
ARP Request, because we might immediately get back another NAK.
|
|
|
|
If we did queue this packet, we check if address resolution is in progress
|
|
on this entry. If not, start it.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - Pointer to ATMARP IP Entry
|
|
pNdisPacket - Packet to be queued
|
|
|
|
Locks on entry:
|
|
|
|
IP Entry
|
|
|
|
Locks on exit:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING if we did queue the packet, NDIS_STATUS_FAILURE
|
|
otherwise.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PNDIS_PACKET pPrevPacket; // For queueing this packet
|
|
NDIS_STATUS Status; // Return value
|
|
IP_ADDRESS SrcIPAddress; // For ARP Request, if required
|
|
IP_ADDRESS DstIPAddress; // For ARP Request, if required
|
|
|
|
|
|
pInterface = pIpEntry->pInterface;
|
|
|
|
//
|
|
// Check if this IP address has experienced an ARP NAK recently.
|
|
// If not, we queue this packet, else we discard it.
|
|
//
|
|
// We also make sure that the ip entry is in ARP table (it had better be,
|
|
// but it's possible that we enter this code path just after the ip
|
|
// entry has been).
|
|
//
|
|
if (!AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_SEEN_NAK)
|
|
&& AA_IE_IS_ALIVE(pIpEntry))
|
|
{
|
|
//
|
|
// Queue the packet.
|
|
//
|
|
if (pIpEntry->PacketList == (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// No packets on this IP Entry.
|
|
//
|
|
pIpEntry->PacketList = pNdisPacket;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Go to the end of the packet list on this IP Entry.
|
|
//
|
|
pPrevPacket = pIpEntry->PacketList;
|
|
while (AA_GET_NEXT_PACKET(pPrevPacket) != (PNDIS_PACKET)NULL)
|
|
{
|
|
pPrevPacket = AA_GET_NEXT_PACKET(pPrevPacket);
|
|
}
|
|
|
|
//
|
|
// Found the last packet in the list. Chain this packet
|
|
// to it.
|
|
//
|
|
AA_SET_NEXT_PACKET(pPrevPacket, pNdisPacket);
|
|
}
|
|
AA_SET_NEXT_PACKET(pNdisPacket, NULL);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
//
|
|
// If needed, start resolving this IP address.
|
|
//
|
|
AtmArpResolveIpEntry(pIpEntry);
|
|
//
|
|
// The IE Lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We have seen an ARP NAK for this IP address recently, or
|
|
// this pIpEntry is not alive.
|
|
// Drop this packet.
|
|
//
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
BOOLEAN
|
|
AtmArpAtmEntryIsReallyClosing(
|
|
PATMARP_ATM_ENTRY pAtmEntry
|
|
)
|
|
{
|
|
BOOLEAN fRet = FALSE;
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING))
|
|
{
|
|
AADEBUGP(AAD_INFO, ("IsReallyClosing -- ENTRY (0x%08lx) is CLOSING\n",
|
|
pAtmEntry));
|
|
|
|
//
|
|
// Decide whether we want to clear the CLOSING state here..
|
|
// We clear the closing state because we saw a case where the
|
|
// entry was permanently in the closing state (a ref count problem).
|
|
// So we will clear this state if it is basically an idle entry,
|
|
// so that it may be reused.
|
|
//
|
|
|
|
if ( pAtmEntry->pIpEntryList == NULL
|
|
&& pAtmEntry->pVcList == NULL
|
|
&& ( pAtmEntry->pMcAtmInfo == NULL
|
|
|| pAtmEntry->pMcAtmInfo->pMcAtmMigrateList == NULL))
|
|
{
|
|
AADEBUGP(AAD_INFO,
|
|
("IsReallyClosing -- ENTRY (0x%08lx) CLEARING CLOSING STATE\n",
|
|
pAtmEntry));
|
|
AA_SET_FLAG(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_ACTIVE);
|
|
}
|
|
else
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
PATMARP_ATM_ENTRY
|
|
AtmArpSearchForAtmAddress(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN UCHAR AtmAddressTypeLength,
|
|
IN UCHAR UNALIGNED * pAtmAddress,
|
|
IN UCHAR AtmSubaddressTypeLength,
|
|
IN UCHAR UNALIGNED * pAtmSubaddress,
|
|
IN AE_REFTYPE RefType,
|
|
IN BOOLEAN CreateNew
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for an ATM Entry that matches the given ATM number+subaddress.
|
|
Optionally, create one if there is no match.
|
|
|
|
The caller is assumed to hold a lock to the IF Table.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
AtmAddressTypeLength - Type+Length (ARP packet format) for the ATM number
|
|
pAtmAddress - ATM Number
|
|
AtmSubaddressTypeLength - Type+Length (ARP packet format) for the ATM subaddress
|
|
pAtmSubaddress - ATM Subaddress
|
|
CreateNew - Do we create a new entry if we don't find one?
|
|
RefType - Type of reference
|
|
|
|
Return Value:
|
|
|
|
Pointer to a matching ATM Entry if found (or created anew).
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
BOOLEAN Found;
|
|
|
|
ATM_ADDRESSTYPE AddressType;
|
|
ULONG AddressLen;
|
|
ATM_ADDRESSTYPE SubaddressType;
|
|
ULONG SubaddressLen;
|
|
|
|
|
|
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(AtmAddressTypeLength, &AddressType, &AddressLen);
|
|
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(AtmSubaddressTypeLength, &SubaddressType, &SubaddressLen);
|
|
|
|
AA_ACQUIRE_IF_ATM_LIST_LOCK(pInterface);
|
|
|
|
|
|
//
|
|
// Go through the list of ATM Entries on this interface, provided the
|
|
// list is "up." The list is not up when shutting down the interface.
|
|
//
|
|
|
|
Found = FALSE;
|
|
|
|
if (pInterface->AtmEntryListUp)
|
|
{
|
|
pAtmEntry = pInterface->pAtmEntryList;
|
|
}
|
|
else
|
|
{
|
|
pAtmEntry = NULL;
|
|
}
|
|
|
|
for (; pAtmEntry != NULL_PATMARP_ATM_ENTRY; pAtmEntry = pAtmEntry->pNext)
|
|
{
|
|
//
|
|
// Compare the ATM Addresses
|
|
//
|
|
if ((AddressType == pAtmEntry->ATMAddress.AddressType) &&
|
|
(AddressLen == pAtmEntry->ATMAddress.NumberOfDigits) &&
|
|
(AA_MEM_CMP(pAtmAddress, pAtmEntry->ATMAddress.Address, AddressLen) == 0))
|
|
{
|
|
//
|
|
// Compare the Subaddress parts
|
|
//
|
|
if ((SubaddressType == pAtmEntry->ATMSubaddress.AddressType) &&
|
|
(SubaddressLen == pAtmEntry->ATMSubaddress.NumberOfDigits) &&
|
|
(AA_MEM_CMP(pAtmSubaddress, pAtmEntry->ATMSubaddress.Address, SubaddressLen) == 0))
|
|
{
|
|
Found = TRUE;
|
|
|
|
//
|
|
// WARNING: AtmArpAtmEntryIsReallyClosing may clear the
|
|
// CLOSING state (if the entry is basically idle) --
|
|
// see comments in that function.
|
|
//
|
|
if (AtmArpAtmEntryIsReallyClosing(pAtmEntry))
|
|
{
|
|
//
|
|
// We don't allow creating a new entry in this case...
|
|
//
|
|
CreateNew = FALSE;
|
|
pAtmEntry = NULL;
|
|
Found = FALSE;
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Found && CreateNew && pInterface->AtmEntryListUp)
|
|
{
|
|
pAtmEntry = AtmArpAllocateAtmEntry(
|
|
pInterface,
|
|
FALSE // Not multicast
|
|
);
|
|
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
//
|
|
// Fill in this new entry.
|
|
//
|
|
pAtmEntry->Flags = AA_ATM_ENTRY_ACTIVE;
|
|
|
|
//
|
|
// The ATM Address.
|
|
//
|
|
pAtmEntry->ATMAddress.AddressType = AddressType;
|
|
pAtmEntry->ATMAddress.NumberOfDigits = AddressLen;
|
|
AA_COPY_MEM(pAtmEntry->ATMAddress.Address,
|
|
pAtmAddress,
|
|
AddressLen);
|
|
|
|
//
|
|
// The ATM Subaddress.
|
|
//
|
|
pAtmEntry->ATMSubaddress.AddressType = SubaddressType;
|
|
pAtmEntry->ATMSubaddress.NumberOfDigits = SubaddressLen;
|
|
AA_COPY_MEM(pAtmEntry->ATMSubaddress.Address,
|
|
pAtmSubaddress,
|
|
SubaddressLen);
|
|
|
|
//
|
|
// Link in this entry to the Interface
|
|
//
|
|
pAtmEntry->pNext = pInterface->pAtmEntryList;
|
|
pInterface->pAtmEntryList = pAtmEntry;
|
|
}
|
|
}
|
|
|
|
if (pAtmEntry)
|
|
{
|
|
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
|
|
AA_REF_AE(pAtmEntry,RefType); // AtmArpSearchForAtmAddress
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
}
|
|
|
|
AA_RELEASE_IF_ATM_LIST_LOCK(pInterface);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("SearchForAtm: returning (%s) ATM Entry 0x%x for addr:\n",
|
|
(Found? "Old": "New"), pAtmEntry));
|
|
AADEBUGPDUMP(AAD_VERY_LOUD, pAtmAddress, AddressLen);
|
|
return (pAtmEntry);
|
|
}
|
|
|
|
|
|
|
|
PATMARP_IP_ENTRY
|
|
AtmArpSearchForIPAddress(
|
|
PATMARP_INTERFACE pInterface,
|
|
IP_ADDRESS UNALIGNED * pIPAddress,
|
|
IE_REFTYPE RefType,
|
|
BOOLEAN IsMulticast,
|
|
BOOLEAN CreateNew
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for an IP Address in the ARP Table. Optionally, create one
|
|
if a match is not found.
|
|
|
|
The caller is assumed to hold a lock to the IF Table.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
pIPAddress - what we are looking for
|
|
IsMulticast - Is this IP address broadcast or multicast?
|
|
RefType - Type of reference to use when we addref the entry.
|
|
CreateNew - Should a new entry be created if no match?
|
|
|
|
Return Value:
|
|
|
|
Pointer to a matching IP Entry if found (or created anew).
|
|
|
|
--*/
|
|
{
|
|
ULONG HashIndex;
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
BOOLEAN Found;
|
|
#ifdef IPMCAST
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
IP_ADDRESS IPAddressValue;
|
|
PATMARP_IP_ENTRY * ppIpEntry;
|
|
#endif // IPMCAST
|
|
|
|
HashIndex = ATMARP_HASH(*pIPAddress);
|
|
Found = FALSE;
|
|
|
|
pIpEntry = pInterface->pArpTable[HashIndex];
|
|
|
|
//
|
|
// Go through the addresses in this hash list.
|
|
//
|
|
while (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
if (IP_ADDR_EQUAL(pIpEntry->IPAddress, *pIPAddress))
|
|
{
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
pIpEntry = pIpEntry->pNextEntry;
|
|
}
|
|
|
|
if (!Found && CreateNew && pInterface->ArpTableUp)
|
|
{
|
|
do
|
|
{
|
|
pIpEntry = AtmArpAllocateIPEntry(pInterface);
|
|
|
|
if (pIpEntry == NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
break;
|
|
}
|
|
#ifdef IPMCAST
|
|
if (IsMulticast)
|
|
{
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("SearchForIpAddr: Creating new MC IP Entry 0x%x for Addr %d.%d.%d.%d\n",
|
|
pIpEntry,
|
|
((PUCHAR)pIPAddress)[0],
|
|
((PUCHAR)pIPAddress)[1],
|
|
((PUCHAR)pIPAddress)[2],
|
|
((PUCHAR)pIPAddress)[3]));
|
|
|
|
pIpEntry->Flags |= AA_IP_ENTRY_ADDR_TYPE_NUCAST;
|
|
|
|
|
|
//
|
|
// Also link this IP Entry into the per-Interface list
|
|
// of multicast addresses. This is sorted in ascending
|
|
// order of "IP Address value", to help processing
|
|
// <Min, Max> pairs of addresses in JOIN/LEAVE messages.
|
|
//
|
|
IPAddressValue = NET_LONG(*pIPAddress);
|
|
|
|
//
|
|
// Find the place to insert this entry at.
|
|
//
|
|
for (ppIpEntry = &(pInterface->pMcSendList);
|
|
*ppIpEntry != NULL_PATMARP_IP_ENTRY;
|
|
ppIpEntry = &((*ppIpEntry)->pNextMcEntry))
|
|
{
|
|
if (NET_LONG((*ppIpEntry)->IPAddress) > IPAddressValue)
|
|
{
|
|
//
|
|
// Found it.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
pIpEntry->pNextMcEntry = *ppIpEntry;
|
|
*ppIpEntry = pIpEntry;
|
|
}
|
|
else
|
|
{
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("SearchForIpAddr: Creating new UNI IP Entry 0x%x for Addr %d.%d.%d.%d\n",
|
|
pIpEntry,
|
|
((PUCHAR)pIPAddress)[0],
|
|
((PUCHAR)pIPAddress)[1],
|
|
((PUCHAR)pIPAddress)[2],
|
|
((PUCHAR)pIPAddress)[3]));
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
//
|
|
// Fill in the rest of the IP entry.
|
|
//
|
|
pIpEntry->IPAddress = *pIPAddress;
|
|
|
|
//
|
|
// This signifies that it is in the arp table.
|
|
//
|
|
AA_SET_FLAG(pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_IDLE2);
|
|
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TABLE); // ARP Table linkage
|
|
|
|
//
|
|
// Link it to the hash table.
|
|
//
|
|
pIpEntry->pNextEntry = pInterface->pArpTable[HashIndex];
|
|
pInterface->pArpTable[HashIndex] = pIpEntry;
|
|
pInterface->NumOfArpEntries++;
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
} // if creating new
|
|
|
|
if (pIpEntry)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
|
AA_REF_IE(pIpEntry, RefType); // AtmArpSearchForIPAddress
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Search for IP Addr: %d.%d.%d.%d, hash ind %d, Found %d, IPEnt 0x%x\n",
|
|
((PUCHAR)pIPAddress)[0],
|
|
((PUCHAR)pIPAddress)[1],
|
|
((PUCHAR)pIPAddress)[2],
|
|
((PUCHAR)pIPAddress)[3],
|
|
HashIndex, Found, pIpEntry));
|
|
|
|
return (pIpEntry);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpAbortIPEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean up and delete an IP entry. This is called when we invalidate
|
|
an ARP mapping.
|
|
|
|
NOTE: The caller is assumed to hold a lock to the IP Entry,
|
|
which will be released here.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - Pointer to IP Entry to be deleted.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_IP_ENTRY * ppNextIpEntry;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
RouteCacheEntry * pRCE;
|
|
PNDIS_PACKET PacketList;
|
|
ULONG rc; // Ref Count on IP Entry.
|
|
BOOLEAN IsMulticastIpEntry;
|
|
BOOLEAN Found;
|
|
BOOLEAN TimerWasRunning;
|
|
BOOLEAN IfTableLockReleased;
|
|
|
|
ULONG HashIndex; // For this IP Entry in ARP Table
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Abort IP entry 0x%x, Flags 0x%x, ATM Entry 0x%x, IP Addr %d:%d:%d:%d\n",
|
|
pIpEntry,
|
|
pIpEntry->Flags,
|
|
pIpEntry->pAtmEntry,
|
|
((PUCHAR)&(pIpEntry->IPAddress))[0],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[1],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[2],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[3]
|
|
));
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
rc = pIpEntry->RefCount;
|
|
pInterface = pIpEntry->pInterface;
|
|
#ifdef IPMCAST
|
|
IsMulticastIpEntry = (AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_ADDR_TYPE_MASK,
|
|
AA_IP_ENTRY_ADDR_TYPE_NUCAST));
|
|
#endif
|
|
IfTableLockReleased = FALSE;
|
|
|
|
//
|
|
// Reacquire the desired locks in the right order.
|
|
//
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
|
|
//
|
|
// Remove any packets queued on this IP Entry.
|
|
//
|
|
PacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
do
|
|
{
|
|
#ifdef IPMCAST
|
|
//
|
|
// If this is a Non-unicast entry, unlink it from the list
|
|
// of Multicast IP Entries on this Interface.
|
|
//
|
|
if (IsMulticastIpEntry)
|
|
{
|
|
for (ppNextIpEntry = &(pInterface->pMcSendList);
|
|
*ppNextIpEntry != NULL_PATMARP_IP_ENTRY;
|
|
ppNextIpEntry = &((*ppNextIpEntry)->pNextMcEntry))
|
|
{
|
|
if (*ppNextIpEntry == pIpEntry)
|
|
{
|
|
//
|
|
// Unlink it.
|
|
//
|
|
*ppNextIpEntry = pIpEntry->pNextMcEntry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
AAMCDEBUGP(AAD_VERY_LOUD,
|
|
("AbortIPEntry (MC): pIpEntry 0x%x: unlinked from MC list\n", pIpEntry));
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// Unlink this IP Entry from all Route Cache Entries
|
|
// that point to it.
|
|
//
|
|
pRCE = pIpEntry->pRCEList;
|
|
while (pRCE != (RouteCacheEntry *)NULL)
|
|
{
|
|
Found = AtmArpUnlinkRCE(pRCE, pIpEntry);
|
|
AA_ASSERT(Found);
|
|
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_RCE); // RCE linkage ref
|
|
if (rc > 0)
|
|
{
|
|
pRCE = pIpEntry->pRCEList;
|
|
}
|
|
else
|
|
{
|
|
pRCE = (RouteCacheEntry *)NULL;
|
|
}
|
|
}
|
|
|
|
if (rc == 0)
|
|
{
|
|
// The IP Entry is gone.
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Stop any timer running on the IP Entry.
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
|
|
if (rc == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Unlink this IP Entry from the ARP Table, if needed.
|
|
//
|
|
Found = FALSE;
|
|
|
|
HashIndex = ATMARP_HASH(pIpEntry->IPAddress);
|
|
ppNextIpEntry = &(pInterface->pArpTable[HashIndex]);
|
|
while (*ppNextIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
if (*ppNextIpEntry == pIpEntry)
|
|
{
|
|
//
|
|
// Make the predecessor point to the next
|
|
// in the list.
|
|
//
|
|
*ppNextIpEntry = pIpEntry->pNextEntry;
|
|
Found = TRUE;
|
|
pInterface->NumOfArpEntries--;
|
|
|
|
//
|
|
// Once it's off the arp table, we set the flag to IDLE.
|
|
//
|
|
AA_SET_FLAG(pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_IDLE);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ppNextIpEntry = &((*ppNextIpEntry)->pNextEntry);
|
|
}
|
|
}
|
|
|
|
if (Found)
|
|
{
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TABLE); // ARP Table ref
|
|
if (rc == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do this last:
|
|
// ------------
|
|
// If this IP Entry is linked to an ATM Entry, unlink it.
|
|
// If this is a multicast ATM entry, shut down the ATM Entry, too.
|
|
//
|
|
pAtmEntry = pIpEntry->pAtmEntry;
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
#ifdef IPMCAST
|
|
BOOLEAN IsMulticastAtmEntry;
|
|
|
|
pIpEntry->pAtmEntry = NULL;
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
IsMulticastAtmEntry = AA_IS_FLAG_SET(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_TYPE_MASK,
|
|
AA_ATM_ENTRY_TYPE_NUCAST);
|
|
if (IsMulticastAtmEntry)
|
|
{
|
|
//
|
|
// We do this because we'll access the ATM
|
|
// Entry below, but only for the PMP case.
|
|
//
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref: Abort IP Entry
|
|
}
|
|
#else
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// Locate the position of this IP Entry in the ATM Entry's list.
|
|
//
|
|
|
|
|
|
ppNextIpEntry = &(pAtmEntry->pIpEntryList);
|
|
|
|
while (*ppNextIpEntry != NULL && *ppNextIpEntry != pIpEntry)
|
|
{
|
|
ppNextIpEntry = &((*ppNextIpEntry)->pNextToAtm);
|
|
}
|
|
|
|
if (*ppNextIpEntry == pIpEntry)
|
|
{
|
|
//
|
|
// Make the predecessor point to the next entry.
|
|
//
|
|
*ppNextIpEntry = pIpEntry->pNextToAtm;
|
|
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_IE); // IP Entry ref
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // ATM Entry linkage ref
|
|
if (rc != 0)
|
|
{
|
|
AA_ASSERT (FALSE); // we expect rc to be 0, but could be a tmp ref.
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We didn't find this IP entry in the atm entry list!
|
|
// Presumably the linkage has been broken by some other
|
|
// path (probably AtmArpInvalidateAtmEntry) while we were
|
|
// in this function.
|
|
//
|
|
// We don't deref here because these two are now not linked.
|
|
//
|
|
//
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
|
|
//
|
|
// IE Lock would have been released above.
|
|
//
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
IfTableLockReleased = TRUE;
|
|
|
|
#ifdef IPMCAST
|
|
//
|
|
// If this was a multicast entry, shut down the ATM Entry
|
|
//
|
|
if (IsMulticastAtmEntry)
|
|
{
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref: Abort IP Entry
|
|
if (rc != 0)
|
|
{
|
|
AtmArpInvalidateAtmEntry(pAtmEntry, FALSE);
|
|
//
|
|
// AE Lock is released within the above.
|
|
//
|
|
}
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No ATM entry linked to this IP entry.
|
|
//
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
if (!IfTableLockReleased)
|
|
{
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
}
|
|
|
|
//
|
|
// Free all packets that were queued on the IP Entry.
|
|
//
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
PacketList,
|
|
FALSE // No LLC/SNAP header on these
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpInvalidateAtmEntry(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN BOOLEAN ShuttingDown
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Invalidate an ATM Entry by unlinking it from IP entries.
|
|
|
|
Typical situation:
|
|
|
|
A non-normal communication problem has been detected on a Vc going to
|
|
this ATM destination. The RFC says that we need to invalidate all IP
|
|
entries for this destination, and let them get re-resolved before sending
|
|
any traffic to them. We implement this by unlinking this ATM entry from
|
|
all IP entries it is linked to. Each such IP entry will get re-resolved
|
|
if+when we try to send a packet to it.
|
|
|
|
The only exceptions are IP Entries that have been statically mapped
|
|
to this ATM Entry: we don't unlink these, unless we are shutting down
|
|
now, as indicated by "ShuttingDown".
|
|
|
|
If we end up with no IP Entries pointing to this ATM Entry, we close all
|
|
SVCs linked to the ATM Entry. If ShuttingDown is TRUE, we close all PVCs
|
|
as well.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - The ATM Entry needing invalidating.
|
|
ShuttingDown - TRUE iff the interface is being shut down.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
PATMARP_IP_ENTRY pNextIpEntry;
|
|
ULONG rc; // Ref Count of ATM Entry
|
|
INT IPEntriesUnlinked;
|
|
PATMARP_IP_ENTRY pStaticIpEntryList; // List of static IP Entries
|
|
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("InvalidateAtmEntry: pAtmEntry 0x%x, Flags 0x%x, ShutDown %d, pIpEntryList 0x%x\n",
|
|
pAtmEntry,
|
|
pAtmEntry->Flags,
|
|
ShuttingDown,
|
|
pAtmEntry->pIpEntryList));
|
|
|
|
#ifndef PROTECT_ATM_ENTRY_IN_CLOSE_CALL
|
|
//
|
|
// Check if we are already closing this ATM Entry. If so,
|
|
// we don't do anything here.
|
|
//
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING))
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Mark this ATM Entry so that we don't use it anymore.
|
|
//
|
|
AA_SET_FLAG(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING);
|
|
|
|
#endif // PROTECT_ATM_ENTRY_IN_CLOSE_CALL
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
pStaticIpEntryList = NULL_PATMARP_IP_ENTRY;
|
|
IPEntriesUnlinked = 0;
|
|
|
|
//
|
|
// Take the IP Entry list out of the ATM Entry.
|
|
//
|
|
pIpEntry = pAtmEntry->pIpEntryList;
|
|
pAtmEntry->pIpEntryList = NULL_PATMARP_IP_ENTRY;
|
|
|
|
#ifdef IPMCAST
|
|
//
|
|
// Delete the Migrate list, if any.
|
|
//
|
|
if (AA_IS_FLAG_SET(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_TYPE_MASK,
|
|
AA_ATM_ENTRY_TYPE_NUCAST))
|
|
{
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_IPMC_ATM_ENTRY pNextMcAtmEntry;
|
|
|
|
for (pMcAtmEntry = pAtmEntry->pMcAtmInfo->pMcAtmMigrateList;
|
|
pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY;
|
|
pMcAtmEntry = pNextMcAtmEntry)
|
|
{
|
|
pNextMcAtmEntry = pMcAtmEntry->pNextMcAtmEntry;
|
|
AA_ASSERT(!AA_IS_TIMER_ACTIVE(&pMcAtmEntry->Timer));
|
|
AA_CHECK_TIMER_IN_ACTIVE_LIST(&pMcAtmEntry->Timer, pAtmEntry->pInterface, pMcAtmEntry, "MC ATM Entry");
|
|
AA_FREE_MEM(pMcAtmEntry);
|
|
}
|
|
|
|
pAtmEntry->pMcAtmInfo->pMcAtmMigrateList = NULL_PATMARP_IPMC_ATM_ENTRY;
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// We let go of the ATM Entry lock here because we'll need
|
|
// to lock each IP Entry in the above list, and we need to make
|
|
// sure that we don't deadlock.
|
|
//
|
|
// However, we make sure that the ATM Entry doesn't go away
|
|
// by adding a reference to it.
|
|
//
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
//
|
|
// Now, unlink all IP entries that are "dynamic", and filter
|
|
// out a list of static mappings.
|
|
//
|
|
while (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
pNextIpEntry = pIpEntry->pNextToAtm;
|
|
|
|
if (ShuttingDown || (!AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_TYPE_MASK,
|
|
AA_IP_ENTRY_IS_STATIC)))
|
|
{
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("InvalidateATMEntry: Unlinking IP entry 0x%x, Flags 0x%x, ATM Entry 0x%x, IP Addr %d:%d:%d:%d; rc=%lu\n",
|
|
pIpEntry,
|
|
pIpEntry->Flags,
|
|
pIpEntry->pAtmEntry,
|
|
((PUCHAR)&(pIpEntry->IPAddress))[0],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[1],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[2],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[3],
|
|
pIpEntry->RefCount
|
|
));
|
|
|
|
//
|
|
// Remove the mapping.
|
|
//
|
|
AA_SET_FLAG(pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_IDLE2);
|
|
|
|
AA_SET_FLAG(pIpEntry->Flags,
|
|
AA_IP_ENTRY_MC_RESOLVE_MASK,
|
|
AA_IP_ENTRY_MC_IDLE);
|
|
pIpEntry->pAtmEntry = NULL_PATMARP_ATM_ENTRY;
|
|
pIpEntry->pNextToAtm = NULL_PATMARP_IP_ENTRY;
|
|
|
|
//
|
|
// Stop any active timer on the IP entry now that we have clobbered
|
|
// its state.
|
|
//
|
|
if (AtmArpStopTimer(&pIpEntry->Timer, pIpEntry->pInterface))
|
|
{
|
|
ULONG IpEntryRc;
|
|
|
|
IpEntryRc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER);
|
|
AA_ASSERT(IpEntryRc != 0);
|
|
}
|
|
|
|
//
|
|
// Remove the ATM Entry linkage reference.
|
|
//
|
|
if (AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE) != 0)
|
|
{
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
//
|
|
// else the IP Entry is gone
|
|
//
|
|
|
|
IPEntriesUnlinked++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Static ARP entry, retain it.
|
|
//
|
|
pIpEntry->pNextToAtm = pStaticIpEntryList;
|
|
pStaticIpEntryList = pIpEntry;
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
pIpEntry = pNextIpEntry;
|
|
}
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
//
|
|
// Put back the static IP entries on the ATM Entry.
|
|
//
|
|
AA_ASSERT(pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY);
|
|
pAtmEntry->pIpEntryList = pStaticIpEntryList;
|
|
|
|
//
|
|
// Now dereference the ATM Entry as many times as we unlinked
|
|
// IP Entries from it.
|
|
//
|
|
rc = pAtmEntry->RefCount;
|
|
while (IPEntriesUnlinked-- > 0)
|
|
{
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_IE); // IP Entry ref
|
|
}
|
|
AA_ASSERT(rc != 0);
|
|
|
|
//
|
|
// Take out the reference we added at the beginning of
|
|
// this routine.
|
|
//
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref
|
|
|
|
//
|
|
// Now, the only IP Entries pointing at this ATM Entry would be
|
|
// static entries. If there are no such IP entries, close all SVCs
|
|
// attached to the ATM Entry. But do all this only if the ATM Entry
|
|
// hasn't been dereferenced away already.
|
|
//
|
|
if (rc != 0)
|
|
{
|
|
//
|
|
// The ATM Entry still exists.
|
|
//
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("InvalidateAtmEntry: nonzero rc on exit.\n"
|
|
"\t pAE=0x%x; rc=%lu; pIpList=0x%x\n",
|
|
pAtmEntry,
|
|
pAtmEntry->RefCount,
|
|
pAtmEntry->pIpEntryList
|
|
));
|
|
|
|
if (pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
//
|
|
// No IP Entries pointing to this ATM Entry.
|
|
//
|
|
AtmArpCloseVCsOnAtmEntry(pAtmEntry, ShuttingDown);
|
|
//
|
|
// The ATM Entry lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_LOUD,
|
|
("InvalidateAtmEnt: AtmEnt %x has nonempty IP list %x, reactivating\n",
|
|
pAtmEntry, pAtmEntry->pIpEntryList));
|
|
|
|
AA_SET_FLAG(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_ACTIVE);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
//
|
|
// else the ATM Entry is gone
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCloseVCsOnAtmEntry(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry LOCKIN NOLOCKOUT,
|
|
IN BOOLEAN ShuttingDown
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Go through the list of VCs chained to an ATM Entry, and close all
|
|
VCs that are SVCs. If the interface is being shut down, close all
|
|
PVCs as well.
|
|
|
|
NOTE: the caller is assumed to hold a lock to the ATM Entry,
|
|
which will be released here.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to ATM Entry on which we want to close SVCs.
|
|
ShuttingDown - TRUE iff the interface is being shut down.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc; // Used to walk the list of VCs on the ATM Entry
|
|
PATMARP_VC pCloseVcList; // List of VCs on the ATM Entry to be closed
|
|
PATMARP_VC *ppNextVc;
|
|
PATMARP_VC pNextVc;
|
|
ULONG rc; // Ref count on ATM Entry
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Reference the ATM Entry so that it cannot go away.
|
|
//
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref: InvalidateAtmEntry
|
|
|
|
#ifdef PROTECT_ATM_ENTRY_IN_CLOSE_CALL
|
|
//
|
|
// Check if we are already closing this ATM Entry. If so,
|
|
// we don't do anything here.
|
|
//
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Mark this ATM Entry so that we don't use it anymore.
|
|
//
|
|
AA_SET_FLAG(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING);
|
|
|
|
#endif // PROTECT_ATM_ENTRY_IN_CLOSE_CALL
|
|
|
|
//
|
|
// Go through the list of VCs on this ATM Entry,
|
|
// close all SVCs, and if we are shutting down,
|
|
// all PVCs, too.
|
|
//
|
|
|
|
if (pAtmEntry->pVcList != NULL_PATMARP_VC)
|
|
{
|
|
pVc = pAtmEntry->pVcList;
|
|
AA_ACQUIRE_VC_LOCK_DPC(pVc);
|
|
AtmArpReferenceVc(pVc); // temp: CloseVCsOnAtmEntry
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
}
|
|
|
|
for (pVc = pAtmEntry->pVcList;
|
|
pVc != NULL_PATMARP_VC;
|
|
pVc = pNextVc)
|
|
{
|
|
pNextVc = pVc->pNextVc;
|
|
|
|
//
|
|
// Make sure we do not follow a stale link after
|
|
// we are done with the current VC.
|
|
//
|
|
if (pNextVc != NULL_PATMARP_VC)
|
|
{
|
|
AA_ACQUIRE_VC_LOCK_DPC(pNextVc);
|
|
AtmArpReferenceVc(pNextVc); // temp: CloseVCsOnAtmEntry
|
|
AA_RELEASE_VC_LOCK_DPC(pNextVc);
|
|
}
|
|
|
|
if (ShuttingDown || (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_TYPE_MASK,
|
|
AA_VC_TYPE_SVC)))
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
if (AtmArpDereferenceVc(pVc) != 0)
|
|
{
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// The VC Lock is released within the above.
|
|
//
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
if (AtmArpDereferenceVc(pVc) != 0)
|
|
{
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
}
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
}
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
//
|
|
// Remove the temp reference
|
|
//
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // Temp ref: InvalidateAtmEntry
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
//
|
|
// else the ATM Entry is gone.
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpResolveIpEntry(
|
|
IN PATMARP_IP_ENTRY pIpEntry LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Trigger off address resolution of an IP entry, unless it's already
|
|
going on. Based on the IP address class, we either go to the ARP
|
|
server or to MARS.
|
|
|
|
NOTE: The caller is assumed to hold a lock to the IP Entry, and it
|
|
will be released here.
|
|
|
|
Arguments:
|
|
|
|
pIpEntry - IP Entry on which we want to start resolution.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
IP_ADDRESS DstIPAddress;
|
|
IP_ADDRESS SrcIPAddress;
|
|
BOOLEAN WasRunning;
|
|
ULONG Flags; // From IP Entry
|
|
|
|
Flags = pIpEntry->Flags;
|
|
|
|
if (!AA_IS_FLAG_SET(
|
|
Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_ARPING) &&
|
|
!AA_IS_FLAG_SET(
|
|
Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_INARPING) &&
|
|
AA_IE_IS_ALIVE(pIpEntry))
|
|
{
|
|
|
|
pInterface = pIpEntry->pInterface;
|
|
|
|
//
|
|
// Get the source and destination IP addresses for
|
|
// the ARP Request.
|
|
//
|
|
DstIPAddress = pIpEntry->IPAddress;
|
|
SrcIPAddress = pInterface->LocalIPAddress.IPAddress;
|
|
|
|
//
|
|
// An aging timer might be running on this IP Entry.
|
|
// [We start one in the NakDelayTimeout routine].
|
|
// Stop it.
|
|
//
|
|
WasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
|
|
//
|
|
// Start an ARP Wait timer.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpAddressResolutionTimeout,
|
|
pInterface->AddressResolutionTimeout,
|
|
(PVOID)pIpEntry
|
|
);
|
|
|
|
|
|
if (!WasRunning)
|
|
{
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref
|
|
}
|
|
|
|
pIpEntry->RetriesLeft = pInterface->MaxResolutionAttempts - 1;
|
|
|
|
//
|
|
// Update the state on this IP Entry.
|
|
//
|
|
AA_SET_FLAG(
|
|
pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_ARPING);
|
|
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
|
|
#ifdef IPMCAST
|
|
if (AA_IS_FLAG_SET(Flags,
|
|
AA_IP_ENTRY_ADDR_TYPE_MASK,
|
|
AA_IP_ENTRY_ADDR_TYPE_UCAST))
|
|
{
|
|
//
|
|
// Unicast address: send out an ARP Request
|
|
//
|
|
AtmArpSendARPRequest(
|
|
pInterface,
|
|
&SrcIPAddress,
|
|
&DstIPAddress
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Multicast/broadcast address: send a MARS Request
|
|
//
|
|
AtmArpMcSendRequest(
|
|
pInterface,
|
|
&DstIPAddress
|
|
);
|
|
}
|
|
#else
|
|
//
|
|
// Now send out the ARP Request
|
|
//
|
|
AtmArpSendARPRequest(
|
|
pInterface,
|
|
&SrcIPAddress,
|
|
&DstIPAddress
|
|
);
|
|
#endif // IPMCAST
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The IP Address is either not alived or being resolved.
|
|
// No more action needed
|
|
// here.
|
|
//
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
EXTERN
|
|
VOID
|
|
AtmArpCleanupArpTable(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Go through the ARP Table, deleting all multicast IP entries that
|
|
are stale (currently defined as having no link to an AtmEntry).
|
|
These IP entries stay around because mulicast entries don't have ageing timers.
|
|
|
|
Arguments:
|
|
|
|
pInterface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN fTableLockWasReleased;
|
|
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
|
|
do
|
|
{
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
|
|
fTableLockWasReleased = FALSE;
|
|
|
|
for (pIpEntry = pInterface->pMcSendList;
|
|
pIpEntry != NULL;
|
|
pIpEntry = pIpEntry->pNextMcEntry)
|
|
{
|
|
//
|
|
// NOTE: by design, we don't claim the ip entry lock when checking
|
|
// whether we should abort the entry or not.
|
|
//
|
|
if ( pIpEntry->pAtmEntry == NULL
|
|
&& !AA_IS_FLAG_SET(
|
|
pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_ARPING))
|
|
{
|
|
//
|
|
// Get locks in the right order.
|
|
//
|
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TMP); // TmpRef
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
|
|
if (AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP)) // TmpRef
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("CleanupArpTable: Aborting stale IP %d:%d:%d:%d\n",
|
|
((PUCHAR)&(pIpEntry->IPAddress))[0],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[1],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[2],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[3]
|
|
));
|
|
AtmArpAbortIPEntry(pIpEntry);
|
|
|
|
//
|
|
// IE Lock is released within the above.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Since we let go of the table lock, we must re-start our search
|
|
// through pMcSendList.
|
|
//
|
|
fTableLockWasReleased = TRUE;
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (fTableLockWasReleased);
|
|
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
}
|