windows-nt/Source/XPSP1/NT/net/atm/arp/atmarpc/arpproc.c

3096 lines
66 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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?
#ifdef CUBDD
SINGLE_LIST_ENTRY PendingIrpList;
PATM_ADDRESS pResolvedAddress;
#endif // CUBDD
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;
#ifdef CUBDD
PendingIrpList.Next = (PSINGLE_LIST_ENTRY)NULL;
#endif // CUBDD
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
));
#ifdef CUBDD
//
// Remove the list of IRPs pending on this IP Entry, if any.
//
PendingIrpList = pIpEntry->PendingIrpList;
pIpEntry->PendingIrpList.Next = (PSINGLE_LIST_ENTRY)NULL;
#endif // CUBDD
//
// 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 rc;
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer reference
AA_ASSERT(rc > 0);
}
IsBroadcast = AA_IS_FLAG_SET(pIpEntry->Flags,
AA_IP_ENTRY_ADDR_TYPE_MASK,
AA_IP_ENTRY_ADDR_TYPE_NUCAST);
#ifdef CUBDD
//
// Remove the list of IRPs pending on this IP Entry, if any.
//
PendingIrpList = pIpEntry->PendingIrpList;
pIpEntry->PendingIrpList.Next = (PSINGLE_LIST_ENTRY)NULL;
#endif // CUBDD
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;
}
#if !BINARY_COMPATIBLE
#ifdef CUBDD
if (PendingIrpList.Next != (PSINGLE_LIST_ENTRY)NULL)
{
AA_ALLOC_MEM(pResolvedAddress, ATM_ADDRESS, sizeof(ATM_ADDRESS));
if (pResolvedAddress != (PATM_ADDRESS)NULL)
{
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
AtmAddressTypeLength,
&(pResolvedAddress->AddressType),
&(pResolvedAddress->NumberOfDigits));
AA_COPY_MEM(
pResolvedAddress->Address,
pAtmAddress,
ATM_ADDRESS_LENGTH);
}
AtmArpCompleteArpIrpList(
PendingIrpList,
pResolvedAddress
);
}
#endif // CUBDD
#endif // !BINARY_COMPATIBLE
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);
}