windows-nt/Source/XPSP1/NT/net/atm/arp/atmarpc/marspkt.c
2020-09-26 16:20:57 +08:00

2438 lines
57 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
mars.c
Abstract:
Routines that build and parse MARS packets.
Revision History:
Who When What
-------- -------- ----------------------------------------------
arvindm 12-12-96 Created
Notes:
--*/
#include <precomp.h>
#define _FILENUMBER 'TKPM'
#ifdef IPMCAST
PUCHAR
AtmArpMcMakePacketCopy(
IN PNDIS_PACKET pNdisPacket,
IN PNDIS_BUFFER pNdisBuffer,
IN ULONG TotalLength
)
/*++
Routine Description:
Make a copy of the contents of the given NDIS packet. Allocate
a contiguous piece of memory for this.
Arguments:
pNdisPacket - Pointer to the NDIS packet structure
pNdisBuffer - Pointer to the first NDIS Buffer in the packet
TotalLength - Total Length of the packet
Return Value:
Pointer to the copy, if allocation was successful. Otherwise NULL.
--*/
{
PUCHAR pCopyBuffer;
PUCHAR pCopyDestination;
PUCHAR pNdisData;
ULONG BufferLength;
AA_ALLOC_MEM(pCopyBuffer, UCHAR, TotalLength);
if (pCopyBuffer != (PUCHAR)NULL)
{
pCopyDestination = pCopyBuffer;
while (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
NdisQueryBuffer(
pNdisBuffer,
&pNdisData,
&BufferLength
);
AA_COPY_MEM(pCopyDestination, pNdisData, BufferLength);
pCopyDestination += BufferLength;
pNdisBuffer = NDIS_BUFFER_LINKAGE(pNdisBuffer);
}
}
return (pCopyBuffer);
}
BOOLEAN
AtmArpMcProcessPacket(
IN PATMARP_VC pVc,
IN PNDIS_PACKET pNdisPacket,
IN PNDIS_BUFFER pNdisBuffer,
IN PAA_PKT_LLC_SNAP_HEADER pPktHeader,
IN ULONG TotalLength,
IN ULONG FirstBufferLength
)
/*++
Routine Description:
Process a received packet, which is potentially a MARS control or
multicast data packet. If it is a data packet, pass it up to IP.
Otherwise, process it here.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pNdisPacket - Pointer to the NDIS packet structure
pNdisBuffer - Pointer to the first NDIS Buffer in the packet
pPktHeader - Pointer to the start of the packet contents
TotalLength - Total packet length
FirstBufferLength - Length of first NDIS buffer in packet.
Return Value:
TRUE if we decide to discard this packet, FALSE if it is a valid packet.
--*/
{
PATMARP_INTERFACE pInterface;
ULONG HeaderLength;
PAA_MC_PKT_TYPE1_SHORT_HEADER pType1Header;
PAA_MC_PKT_TYPE2_SHORT_HEADER pType2Header;
PAA_MARS_PKT_FIXED_HEADER pControlHeader;
BOOLEAN IsIPPacket; // Is this an IP packet?
BOOLEAN DiscardThis; // Should we discard this?
BOOLEAN MadeACopy; // Did we make a copy of this?
AA_MARS_TLV_LIST TlvList;
//
// Initialize
//
IsIPPacket = TRUE;
DiscardThis = FALSE;
MadeACopy = FALSE;
pInterface = pVc->pInterface;
AA_SET_MEM(&TlvList, 0, sizeof(TlvList));
do
{
//
// Check if we have a multicast data packet. Since we only
// support IPv4, we only expect to see short form headers.
//
pType1Header = (PAA_MC_PKT_TYPE1_SHORT_HEADER)pPktHeader;
if (AAMC_PKT_IS_TYPE1_DATA(pType1Header))
{
AAMCDEBUGP(AAD_EXTRA_LOUD,
("McProcessPacket: pVc 0x%x, Pkt 0x%x, Type 1, %d bytes, CMI %d\n",
pVc, pNdisPacket, TotalLength, pType1Header->cmi));
AAMCDEBUGPDUMP(AAD_EXTRA_LOUD+500, pPktHeader, MIN(FirstBufferLength, 96));
#if DBG
if (AaDataDebugLevel & AAD_DATA_IN)
{
IP_ADDRESS IPAddress;
if ((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) &&
(pVc->pAtmEntry->pIpEntryList != NULL_PATMARP_IP_ENTRY))
{
IPAddress = pVc->pAtmEntry->pIpEntryList->IPAddress;
}
else
{
IPAddress = 0;
}
AADEBUGP(AAD_WARNING,
("%d <= %d.%d.%d.%d\n",
TotalLength,
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
}
#endif // DBG
#if 0
//
// Bug #138261: Local clients can never receive multicast packets
// sent out by a local application because of this.
//
if (pType1Header->cmi == pInterface->ClusterMemberId)
{
//
// This is a copy of a packet we sent out.
//
DiscardThis = TRUE;
break;
}
#endif // 0
HeaderLength = sizeof(AA_MC_PKT_TYPE1_SHORT_HEADER);
}
else
{
pType2Header = (PAA_MC_PKT_TYPE2_SHORT_HEADER)pPktHeader;
if (AAMC_PKT_IS_TYPE2_DATA(pType2Header))
{
AAMCDEBUGP(AAD_EXTRA_LOUD,
("McProcessPacket: pVc 0x%x, pNdisPacket 0x%x, Type 2 data\n",
pVc, pNdisPacket));
HeaderLength = sizeof(AA_MC_PKT_TYPE2_SHORT_HEADER);
}
else
{
IsIPPacket = FALSE;
}
}
if (IsIPPacket)
{
AA_IF_STAT_INCR(pInterface, InNonUnicastPkts);
//
// Send this up to IP. HeaderLength now contains the number
// of header bytes we need to strip off.
//
(pInterface->IPRcvHandler)(
pInterface->IPContext,
(PVOID)((PUCHAR)pPktHeader+HeaderLength),
FirstBufferLength - HeaderLength,
TotalLength - HeaderLength,
(NDIS_HANDLE)pNdisPacket,
HeaderLength,
(UINT)TRUE // Is NON Unicast
#if P2MP
,NULL
#endif //P2MP
);
break;
}
//
// Check if this is a valid MARS control packet.
//
pControlHeader = (PAA_MARS_PKT_FIXED_HEADER)pPktHeader;
if (AAMC_PKT_IS_CONTROL(pControlHeader))
{
//
// We ignore the checksum (the RFC allows us to do so).
//
AAMCDEBUGP(AAD_EXTRA_LOUD+10,
("McProcessPacket: pControlHeader 0x%x, Op 0x%x, TotalLen %d\n",
pControlHeader, pControlHeader->op, TotalLength));
//
// If the entire MARS packet isn't in the first NDIS buffer,
// we make a copy into a single contiguous chunk of memory,
// to ease parsing.
//
if (FirstBufferLength == TotalLength)
{
MadeACopy = FALSE;
}
else
{
pControlHeader = (PAA_MARS_PKT_FIXED_HEADER)
AtmArpMcMakePacketCopy(
pNdisPacket,
pNdisBuffer,
TotalLength
);
if (pControlHeader == (PAA_MARS_PKT_FIXED_HEADER)NULL)
{
//
// Allocation failed. Discard this packet.
//
DiscardThis = TRUE;
break;
}
else
{
MadeACopy = TRUE;
}
}
if (!AtmArpMcPreprocess(pControlHeader, TotalLength, &TlvList))
{
AAMCDEBUGP(AAD_INFO,
("McProcessPacket: PreProcess failed: pHdr 0x%x, TotalLength %d\n",
pControlHeader, TotalLength));
DiscardThis = TRUE;
break;
}
switch (NET_TO_HOST_SHORT(pControlHeader->op))
{
case AA_MARS_OP_TYPE_MULTI:
AtmArpMcHandleMulti(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
case AA_MARS_OP_TYPE_JOIN:
case AA_MARS_OP_TYPE_LEAVE:
AtmArpMcHandleJoinOrLeave(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
case AA_MARS_OP_TYPE_NAK:
AtmArpMcHandleNak(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
case AA_MARS_OP_TYPE_GROUPLIST_REPLY:
AtmArpMcHandleGroupListReply(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
case AA_MARS_OP_TYPE_REDIRECT_MAP:
AtmArpMcHandleRedirectMap(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
case AA_MARS_OP_TYPE_MIGRATE:
AtmArpMcHandleMigrate(
pVc,
pControlHeader,
TotalLength,
&TlvList
);
break;
default:
AAMCDEBUGP(AAD_WARNING,
("pVc 0x%x, pNdisPacket 0x%x, pHdr 0x%x, bad/unknown op 0x%x\n",
pVc, pNdisPacket, pControlHeader, pControlHeader->op));
AA_ASSERT(FALSE);
break;
} // switch (op)
} // if Control packet
break;
}
while (FALSE);
if (MadeACopy)
{
AA_FREE_MEM(pControlHeader);
}
return (DiscardThis);
}
BOOLEAN
AtmArpMcPreprocess(
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
OUT PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Do preliminary checks on a received MARS control packet.
Go through any TLVs, and make sure we can either handle or
safely ignore them. Be prepared to receive complete garbage in this packet.
Update *pTlvList with information about all valid TLVs that we see.
Arguments:
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
Return Value:
TRUE if the packet passed all checks, FALSE otherwise.
--*/
{
ULONG ExtensionOffset;
PAA_MARS_TLV_HDR pTlv;
ULONG TlvSpaceLeft; // in packet
ULONG TlvLength;
ULONG TlvType;
ULONG TlvAction;
BOOLEAN Passed;
BOOLEAN TlvOk;
Passed = TRUE;
do
{
//
// The USHORT casts below and in obtaining TlvLengths are important
// in order to ensure that these values are less than 2^16.
// Since they are less than 2^16, any sums involving them will not overflow.
//
ExtensionOffset = (USHORT)NET_TO_HOST_SHORT(pControlHeader->extoff);
if (ExtensionOffset != 0)
{
AAMCDEBUGP(AAD_EXTRA_LOUD+20,
("McPreprocess: pControlHdr 0x%x, ExtOff %d, TotalLength %d\n",
pControlHeader, ExtensionOffset, TotalLength));
//
// Is there space for atleast one TLV?
//
if ((ExtensionOffset
+ sizeof(AA_PKT_LLC_SNAP_HEADER) + sizeof(AA_MARS_TLV_HDR))
> TotalLength)
{
Passed = FALSE;
break;
}
pTlv = (PAA_MARS_TLV_HDR)((PUCHAR)pControlHeader +
ExtensionOffset + sizeof(AA_PKT_LLC_SNAP_HEADER));
TlvSpaceLeft = (TotalLength - ExtensionOffset - sizeof(AA_PKT_LLC_SNAP_HEADER));
do
{
TlvType = AAMC_GET_TLV_TYPE(pTlv->Type);
TlvAction = AAMC_GET_TLV_ACTION(pTlv->Type);
//
// Get the rounded-off TLV length
//
TlvLength = (USHORT) NET_TO_HOST_SHORT(pTlv->Length);
TlvLength = AAMC_GET_TLV_TOTAL_LENGTH(TlvLength);
if (TlvLength > TlvSpaceLeft)
{
AAMCDEBUGP(AAD_WARNING,
("McPreprocess: Hdr 0x%x, pTlv 0x%x: TlvLength %d > TlvSpaceLeft %d\n",
pControlHeader, pTlv, TlvLength, TlvSpaceLeft));
Passed = FALSE;
break;
}
TlvOk = FALSE;
switch (TlvType)
{
case AAMC_TLVT_MULTI_IS_MCS:
if (TlvLength == sizeof(AA_MARS_TLV_MULTI_IS_MCS))
{
TlvOk = TRUE;
pTlvList->MultiIsMCSPresent =
pTlvList->MultiIsMCSValue = TRUE;
}
break;
case AAMC_TLVT_NULL:
if (TlvLength == 0)
{
TlvOk = TRUE;
}
break;
default:
break;
}
if (!TlvOk)
{
if (TlvAction == AA_MARS_TLV_TA_STOP_SILENT)
{
Passed = FALSE;
break;
}
if (TlvAction == AA_MARS_TLV_TA_STOP_LOG)
{
AA_LOG_ERROR();
Passed = FALSE;
break;
}
}
pTlv = (PAA_MARS_TLV_HDR)((PUCHAR)pTlv + TlvLength);
TlvSpaceLeft -= TlvLength;
}
while (TlvSpaceLeft >= sizeof(AA_MARS_TLV_HDR));
if (TlvSpaceLeft != 0)
{
//
// Improperly formed TLV at the end of the packet.
//
AAMCDEBUGP(AAD_LOUD,
("McPreprocess: residual space left at end of Pkt 0x%x: %d bytes\n",
pControlHeader, TlvSpaceLeft));
Passed = FALSE;
}
}
break;
}
while (FALSE);
return (Passed);
}
VOID
AtmArpMcHandleMulti(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Process a received MARS_MULTI message. We first look up the IP Entry
for the group address being resolved/revalidated. If we aren't
in "Discard mode" on this entry and the MULTI sequence number is ok,
then we add all ATM endstations returned in this MULTI (that aren't
present already) to the ATM Entry for this multicast group.
If this is the last MULTI for the multicast group, we initiate/update
our point-to-multipoint connection for sending data to the group.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
pTlvList - All TLVs seen in this packet
Return Value:
None
--*/
{
PATMARP_INTERFACE pInterface;
PAA_MARS_MULTI_HEADER pMultiHeader;
PATMARP_IP_ENTRY pIpEntry; // Entry for IP address being resolved
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
ULONG MarsSeqNumber; // MSN received in this packet
ULONG HostSeqNumber; // Our MSN
ULONG SeqDiff; // Difference between MSN and the HSN
USHORT SequenceNoY; // MULTI sequence number
BOOLEAN IsLastMulti; // Is this the final MULTI response?
BOOLEAN bWasRunning; // Was a timer running?
IP_ADDRESS IPAddress; // the address being queried
PNDIS_PACKET pPacketList;
BOOLEAN IsUnicastResolution; // Did we resolve to a single MCS?
//
// Initialize
//
pInterface = pVc->pInterface;
SeqDiff = 0;
pMultiHeader = (PAA_MARS_MULTI_HEADER)pControlHeader;
do
{
ULONG rc;
//
// Get the sequence number of this MARS MULTI.
//
SequenceNoY = NET_TO_HOST_SHORT(pMultiHeader->seqxy);
IsLastMulti = ((SequenceNoY & AA_MARS_X_MASK) != 0);
SequenceNoY = (SequenceNoY & AA_MARS_Y_MASK);
//
// Get the MARS Sequence Number in this message.
//
MarsSeqNumber = NET_TO_HOST_LONG(pMultiHeader->msn);
//
// If this is the last MULTI in reply to our REQUEST,
// calculate the Seq # difference.
//
if (IsLastMulti)
{
AA_ACQUIRE_IF_LOCK(pInterface);
HostSeqNumber = pInterface->HostSeqNumber; // save the old value
pInterface->HostSeqNumber = MarsSeqNumber; // and update
AA_RELEASE_IF_LOCK(pInterface);
SeqDiff = MarsSeqNumber - HostSeqNumber;
}
//
// Get the group address being responded to.
//
IPAddress = *(IP_ADDRESS UNALIGNED *)(
(PUCHAR)pMultiHeader +
sizeof(AA_MARS_MULTI_HEADER) +
(pMultiHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMultiHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMultiHeader->spln)
);
AAMCDEBUGP(AAD_LOUD,
("McHandleMulti: 0x%x, IP %d.%d.%d.%d, MSN %d, HSN %d, Last %d, Y %d, tnum %d\n",
pMultiHeader,
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3],
MarsSeqNumber,
HostSeqNumber,
(ULONG)IsLastMulti,
(ULONG)SequenceNoY,
NET_TO_HOST_SHORT(pMultiHeader->tnum)
));
//
// Get the IP Entry for this address.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
pIpEntry = AtmArpSearchForIPAddress(
pInterface,
&IPAddress,
IE_REFTYPE_AE,
TRUE, // this is a multicast/broadcast address
FALSE // don't create a new entry if the address isn't found
);
AA_RELEASE_IF_TABLE_LOCK(pInterface);
//
// AtmArpSearchForIPAddress addreffs pIpEntry for us ...
//
if (pIpEntry == NULL_PATMARP_IP_ENTRY)
{
AAMCDEBUGP(AAD_INFO, ("McHandleMulti: No IP Entry for %d.%d.%d.%d\n",
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
break;
}
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
//
// A resolution timer may be running here - stop it.
//
bWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
if (bWasRunning)
{
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
AA_ASSERT(rc != 0);
}
IsUnicastResolution = (IsLastMulti &&
(NET_TO_HOST_SHORT(pMultiHeader->tnum) == 1) &&
(pTlvList->MultiIsMCSValue == TRUE));
//
// Check if the multi request is compatible with the existing atm
// entry (if any) associated with the ip entry. If they are not,
// then we must abort the IP entry and get out of here, because
// there was possibly a switch in status of this IP group address from
// being vc-mesh served to mcs served, or vice versa.
//
if (pIpEntry->pAtmEntry)
{
if ( (IsUnicastResolution && pIpEntry->pAtmEntry->pMcAtmInfo != NULL)
|| (!IsUnicastResolution && pIpEntry->pAtmEntry->pMcAtmInfo ==NULL))
{
AAMCDEBUGP(AAD_WARNING,
("HandleMulti: Type Mismatch! %s pIpEntry 0x%x/%x (%d.%d.%d.%d) linked to ATMEntry 0x%x\n",
((IsUnicastResolution) ? "MCS" : "VC-Mesh"),
pIpEntry, pIpEntry->Flags,
((PUCHAR)&(pIpEntry->IPAddress))[0],
((PUCHAR)&(pIpEntry->IPAddress))[1],
((PUCHAR)&(pIpEntry->IPAddress))[2],
((PUCHAR)&(pIpEntry->IPAddress))[3],
pIpEntry->pAtmEntry));
//
// Remove the AE_REF implicitly added by AtmArpMcLookupAtmMember
// above...
//
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // Tmp ref
if (rc!=0)
{
AtmArpAbortIPEntry(pIpEntry);
//
// IE lock is released within the above.
//
}
break;
}
}
//
// Check if we are in discard mode, or this MULTI has a bad
// sequence number. In either case, discard this MULTI, otherwise
// process it.
//
if (!AA_IS_FLAG_SET(
pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_DISCARDING_MULTI
) &&
(SequenceNoY == pIpEntry->NextMultiSeq))
{
PATMARP_ATM_ENTRY pAtmEntry;
//
// Total entries in this MULTI
//
ULONG NumberOfEntries;
//
// All info about one ATM (leaf) entry:
//
PUCHAR pAtmNumber;
ULONG AtmNumberLength;
ATM_ADDRESSTYPE AtmNumberType;
PUCHAR pAtmSubaddress;
ULONG AtmSubaddressLength;
ATM_ADDRESSTYPE AtmSubaddressType;
//
// Process this MARS MULTI.
//
pIpEntry->NextMultiSeq++;
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pMultiHeader->thtl,
&AtmNumberType,
&AtmNumberLength);
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pMultiHeader->tstl,
&AtmSubaddressType,
&AtmSubaddressLength);
pAtmNumber = ((PUCHAR)pMultiHeader +
sizeof(AA_MARS_MULTI_HEADER) +
(pMultiHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMultiHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMultiHeader->spln) +
(pMultiHeader->tpln));
if (IsUnicastResolution)
{
//
// This IP address has resolved to a single ATM address. Search
// for (or allocate a new) ATM Entry for this address.
//
AAMCDEBUGP(AAD_LOUD, ("McHandleMulti: Unicast res for %d.%d.%d.%d\n",
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
AA_RELEASE_IE_LOCK(pIpEntry);
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
pAtmEntry = AtmArpSearchForAtmAddress(
pInterface,
pMultiHeader->thtl,
pAtmNumber,
pMultiHeader->tstl,
(PUCHAR)pAtmNumber + AtmNumberLength,
AE_REFTYPE_IE,
TRUE
);
AA_RELEASE_IF_TABLE_LOCK(pInterface);
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
if ( pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
AAMCDEBUGP(AAD_INFO,
("McHandleMulti: pIpEntry 0x%x, failed to alloc AtmEntry\n",
pIpEntry));
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // Tmp ref
if (rc!=0)
{
AtmArpAbortIPEntry(pIpEntry);
//
// IE lock is released within the above.
//
}
break; // go to end of processing
}
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
//
// AtmArpSearchForAtmAddress addrefs pAtmEntry for us..
//
if (pIpEntry->pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
//
// Link the ATM Entry to this IP Entry.
//
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;
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
}
else
{
//
// There is already a linkage -- deref the
// references implicitly added for us in the
// SearchForXXX calls above...
//
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_IE); // IP
{
if (rc != 0)
{
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
}
}
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // AE
if (rc==0)
{
//
// IpEntry gone away...
//
break;
}
}
//
// At this point we have a lock on pIpEntry, but none
// on pAtmEntry, and we don't have any "extra" refs on
// either.
//
if (pIpEntry->pAtmEntry == pAtmEntry)
{
//
// Either a fresh IP->ATM resolution, or
// reconfirmation of an existing resolution.
//
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD, "MULTI: Unicast Addr: ", &pAtmEntry->ATMAddress);
//
// Update IP Entry state.
//
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_RESOLVED);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_VALIDATE_MASK,
AA_IP_ENTRY_MC_NO_REVALIDATION);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_RESOLVED);
pIpEntry->NextMultiSeq = AA_MARS_INITIAL_Y;
#ifdef AGE_MCAST_IP_ENTRIES
//
// Feb 26, 97: we don't need to age out IP multicast entries:
// VC aging timer is sufficient.
//
//
// Start off IP Aging timeout
//
AtmArpStartTimer(
pInterface,
&(pIpEntry->Timer),
AtmArpIPEntryAgingTimeout,
pInterface->MulticastEntryAgingTimeout,
(PVOID)pIpEntry
);
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref
#endif // AGE_MCAST_IP_ENTRIES
//
// Remove the packet list queued on this IP Entry,
// if any.
//
pPacketList = pIpEntry->PacketList;
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
AA_RELEASE_IE_LOCK(pIpEntry);
if (pPacketList != (PNDIS_PACKET)NULL)
{
//
// The following will trigger off MakeCall.
//
AtmArpSendPacketListOnAtmEntry(
pInterface,
pAtmEntry,
pPacketList,
TRUE
);
}
}
else
{
AAMCDEBUGP(AAD_WARNING,
("HandleMulti: pIpEntry 0x%x/%x (%d.%d.%d.%d) linked to ATMEntry 0x%x, resolves to 0x%x\n",
pIpEntry, pIpEntry->Flags,
((PUCHAR)&(pIpEntry->IPAddress))[0],
((PUCHAR)&(pIpEntry->IPAddress))[1],
((PUCHAR)&(pIpEntry->IPAddress))[2],
((PUCHAR)&(pIpEntry->IPAddress))[3],
pIpEntry->pAtmEntry,
pAtmEntry));
AA_STRUCT_ASSERT(pIpEntry->pAtmEntry, aae);
AtmArpAbortIPEntry(pIpEntry);
//
// IE lock is released within the above.
//
}
break; // go to end of processing
} // Unicast resolution
//
// IP Address resolved to multiple ATM addresses.
//
pAtmEntry = pIpEntry->pAtmEntry;
if (pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
//
// Allocate an ATM Entry and link to this IP Entry.
//
pAtmEntry = AtmArpAllocateAtmEntry(pInterface, TRUE);
if (pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
// Let's deref the implicit addref for pIpEntry...
// Warning -- we should now not release our lock on
// pIpEntry until we're completely done with it
// (unless we first addref it).
//
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // Tmp ref
if (rc!=0)
{
AtmArpAbortIPEntry(pIpEntry);
//
// IE lock is released within the above.
//
}
break; // go to end of processing
}
//
// Link them together.
//
pIpEntry->pAtmEntry = pAtmEntry;
pAtmEntry->pIpEntryList = pIpEntry;
AAMCDEBUGP(AAD_EXTRA_LOUD,
("McHandleMulti: Multicast: linked pIpEntry 0x%x, pAtmEntry 0x%x\n",
pIpEntry, pAtmEntry));
AA_REF_AE(pAtmEntry, AE_REFTYPE_IE); // IP Entry linkage
//
// Link the ATM entry to this Interface
//
AA_RELEASE_IE_LOCK(pIpEntry);
AA_ACQUIRE_IF_ATM_LIST_LOCK(pInterface);
if (pInterface->AtmEntryListUp)
{
pAtmEntry->pNext = pInterface->pAtmEntryList;
pInterface->pAtmEntryList = pAtmEntry;
}
AA_RELEASE_IF_ATM_LIST_LOCK(pInterface);
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
}
else
{
//
// IP already has an atm entry...
//
// Let's deref the implicit addref for pIpEntry...
// Warning -- we should now not release our lock on
// pIpEntry until we're completely done with it
// (unless we first addref it).
//
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_AE); // Tmp ref
if (rc==0)
{
//
// IpEntry gone away...
//
break;
}
}
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
for (NumberOfEntries = NET_TO_HOST_SHORT(pMultiHeader->tnum);
NumberOfEntries != 0;
NumberOfEntries--)
{
pAtmSubaddress = ((PUCHAR)pAtmNumber + AtmNumberLength);
pMcAtmEntry = AtmArpMcLookupAtmMember(
pAtmEntry,
&(pAtmEntry->pMcAtmInfo->pMcAtmEntryList),
pAtmNumber,
AtmNumberLength,
AtmNumberType,
pAtmSubaddress,
AtmSubaddressLength,
TRUE // Create new entry if not found
);
if (pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY)
{
//
// Mark this member "valid".
//
AA_SET_FLAG(
pMcAtmEntry->Flags,
AA_IPMC_AE_GEN_STATE_MASK,
AA_IPMC_AE_VALID);
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD, "MULTI Addr: ", &pMcAtmEntry->ATMAddress);
}
else
{
//
// Resource problems! No point in continuing.
//
break;
}
pAtmNumber = (PUCHAR)pAtmNumber + AtmNumberLength;
} // for
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
if (IsLastMulti)
{
//
// We have successfully resolved this Multicast IP Address.
//
AAMCDEBUGP(AAD_INFO,
("### HandleMulti: pIpEntry 0x%x, resolved %d.%d.%d.%d\n",
pIpEntry,
((PUCHAR)(&IPAddress))[0],
((PUCHAR)(&IPAddress))[1],
((PUCHAR)(&IPAddress))[2],
((PUCHAR)(&IPAddress))[3]));
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_RESOLVED);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_VALIDATE_MASK,
AA_IP_ENTRY_MC_NO_REVALIDATION);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_RESOLVED);
pIpEntry->NextMultiSeq = AA_MARS_INITIAL_Y;
//
// Remove the packet list queued on this IP Entry,
// if any.
//
pPacketList = pIpEntry->PacketList;
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
#ifdef AGE_MCAST_IP_ENTRIES
//
// Start off IP Aging timeout
//
AtmArpStartTimer(
pInterface,
&(pIpEntry->Timer),
AtmArpIPEntryAgingTimeout,
pInterface->MulticastEntryAgingTimeout,
(PVOID)pIpEntry
);
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref
#endif // AGE_MCAST_IP_ENTRIES
AA_RELEASE_IE_LOCK(pIpEntry);
AA_ACQUIRE_AE_LOCK(pAtmEntry);
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP);
AtmArpMcUpdateConnection(pAtmEntry);
//
// AE Lock is released within the above.
//
if (pPacketList != (PNDIS_PACKET)NULL)
{
AtmArpSendPacketListOnAtmEntry(
pInterface,
pAtmEntry,
pPacketList,
TRUE
);
}
AA_ACQUIRE_AE_LOCK(pAtmEntry);
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP);
if (rc != 0)
{
AA_RELEASE_AE_LOCK(pAtmEntry);
}
}
else
{
//
// Restart the address resolution timer on this entry,
// but for a duration equal to the max delay between
// MULTI messages.
//
AtmArpStartTimer(
pInterface,
&(pIpEntry->Timer),
AtmArpAddressResolutionTimeout,
pInterface->MaxDelayBetweenMULTIs,
(PVOID)pIpEntry
);
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Delay b/w MULTI timer ref
AA_RELEASE_IE_LOCK(pIpEntry);
}
}
else
{
AAMCDEBUGP(AAD_WARNING,
("HandleMULTI: fail condition: pIpEntry 0x%x/0x%x, Addr %d.%d.%d.%d, SeqY %d, NextMultiSeq %d, IsLastMulti %d\n",
pIpEntry,
pIpEntry->Flags,
((PUCHAR)&(pIpEntry->IPAddress))[0],
((PUCHAR)&(pIpEntry->IPAddress))[1],
((PUCHAR)&(pIpEntry->IPAddress))[2],
((PUCHAR)&(pIpEntry->IPAddress))[3],
SequenceNoY,
pIpEntry->NextMultiSeq,
IsLastMulti
));
//
// A "failure condition" with this MULTI.
//
if (IsLastMulti)
{
//
// This is the last MULTI of a failed address resolution
// sequence. Start off address resolution afresh.
//
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_IDLE2);
AtmArpResolveIpEntry(pIpEntry);
//
// IE Lock is released within the above.
//
}
else
{
//
// Discard all future MULTIs
//
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_DISCARDING_MULTI);
AA_RELEASE_IE_LOCK(pIpEntry);
}
}
break;
}
while (FALSE);
//
// Finally (according to Section 5.1.4.2 of RFC 2022), check
// if we just had a jump in the MSN.
//
if ((SeqDiff != 1) && (SeqDiff != 0))
{
AAMCDEBUGP(AAD_INFO,
("HandleMulti: IF 0x%x: Bad seq diff %d, MSN 0x%x, HSN 0x%x\n",
pInterface, SeqDiff, MarsSeqNumber, HostSeqNumber));
AtmArpMcRevalidateAll(pInterface);
}
}
VOID
AtmArpMcHandleMigrate(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Arguments:
Return Value:
None
--*/
{
PATMARP_INTERFACE pInterface;
PAA_MARS_MIGRATE_HEADER pMigrateHeader;
PATMARP_IP_ENTRY pIpEntry; // Entry for IP address being resolved
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
PATMARP_ATM_ENTRY pAtmEntry;
ULONG MarsSeqNumber; // MSN received in this packet
ULONG HostSeqNumber; // Our MSN
ULONG SeqDiff; // Difference between MSN and the HSN
BOOLEAN bWasRunning; // Was a timer running?
IP_ADDRESS IPAddress; // the address being queried
//
// Initialize
//
pInterface = pVc->pInterface;
SeqDiff = 0;
pMigrateHeader = (PAA_MARS_MIGRATE_HEADER)pControlHeader;
do
{
//
// Get the MARS Sequence Number in this message.
//
MarsSeqNumber = NET_TO_HOST_LONG(pMigrateHeader->msn);
//
// Calculate the Seq # difference.
//
AA_ACQUIRE_IF_LOCK(pInterface);
HostSeqNumber = pInterface->HostSeqNumber; // save the old value
pInterface->HostSeqNumber = MarsSeqNumber; // and update
AA_RELEASE_IF_LOCK(pInterface);
SeqDiff = MarsSeqNumber - HostSeqNumber;
//
// Get the group address being migrated.
//
IPAddress = *(IP_ADDRESS UNALIGNED *)(
(PUCHAR)pMigrateHeader +
sizeof(AA_MARS_MIGRATE_HEADER) +
(pMigrateHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMigrateHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMigrateHeader->spln)
);
AAMCDEBUGP(AAD_LOUD,
("McHandleMigrate: 0x%x, IP %d.%d.%d.%d, MSN %d, HSN %d\n",
pMigrateHeader,
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3],
MarsSeqNumber,
HostSeqNumber));
//
// Get the IP Entry for this address.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
pIpEntry = AtmArpSearchForIPAddress(
pInterface,
&IPAddress,
IE_REFTYPE_TMP,
TRUE, // this is a multicast/broadcast address
FALSE // don't create a new entry if the address isn't found
);
AA_RELEASE_IF_TABLE_LOCK(pInterface);
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
{
//
// AtmArpSearchForIPAddress addrefs pIpEntry for us ...
//
ULONG rc;
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP);
if (rc == 0)
{
// Oops, IP address has gone away...
pIpEntry = NULL_PATMARP_IP_ENTRY;
}
}
if (pIpEntry == NULL_PATMARP_IP_ENTRY)
{
AAMCDEBUGP(AAD_INFO, ("McHandleMigrate: No IP Entry for %d.%d.%d.%d\n",
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
break;
}
if (pIpEntry->pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
//
// This IP address is being resolved.
//
AA_RELEASE_IE_LOCK(pIpEntry);
break;
}
pAtmEntry = pIpEntry->pAtmEntry;
if (AA_IS_FLAG_SET(
pAtmEntry->Flags,
AA_ATM_ENTRY_TYPE_MASK,
AA_ATM_ENTRY_TYPE_UCAST))
{
AAMCDEBUGP(AAD_INFO,
("McHandleMigrate: IP Addr %d.%d.%d.%d was unicast, aborting pIpEntry 0x%x\n",
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3],
pIpEntry));
AtmArpAbortIPEntry(pIpEntry);
//
// IE Lock is released within the above.
//
break;
}
//
// Check if we are in discard mode.
//
if (!AA_IS_FLAG_SET(
pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_DISCARDING_MULTI))
{
//
// Total entries in this MULTI
//
ULONG NumberOfEntries;
//
// All info about one ATM (leaf) entry:
//
PUCHAR pAtmNumber;
ULONG AtmNumberLength;
ATM_ADDRESSTYPE AtmNumberType;
PUCHAR pAtmSubaddress;
ULONG AtmSubaddressLength;
ATM_ADDRESSTYPE AtmSubaddressType;
//
// Process this MARS MIGRATE fully.
//
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pMigrateHeader->thtl,
&AtmNumberType,
&AtmNumberLength);
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pMigrateHeader->tstl,
&AtmSubaddressType,
&AtmSubaddressLength);
pAtmNumber = ((PUCHAR)pMigrateHeader +
sizeof(AA_MARS_MIGRATE_HEADER) +
(pMigrateHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMigrateHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pMigrateHeader->spln) +
(pMigrateHeader->tpln));
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
for (NumberOfEntries = pMigrateHeader->tnum;
NumberOfEntries != 0;
NumberOfEntries--)
{
pAtmSubaddress = ((PUCHAR)pAtmNumber + AtmNumberLength);
pMcAtmEntry = AtmArpMcLookupAtmMember(
pAtmEntry,
&(pAtmEntry->pMcAtmInfo->pMcAtmMigrateList),
pAtmNumber,
AtmNumberLength,
AtmNumberType,
pAtmSubaddress,
AtmSubaddressLength,
TRUE // Create new entry if not found
);
if (pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY)
{
//
// Mark this member "valid".
//
AA_SET_FLAG(
pMcAtmEntry->Flags,
AA_IPMC_AE_GEN_STATE_MASK,
AA_IPMC_AE_VALID);
}
else
{
//
// Resource problems! No point in continuing.
//
break;
}
pAtmNumber = (PUCHAR)pAtmNumber + AtmNumberLength;
} // for
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_RESOLVED);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_VALIDATE_MASK,
AA_IP_ENTRY_MC_NO_REVALIDATION);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_RESOLVED);
pIpEntry->NextMultiSeq = AA_MARS_INITIAL_Y;
//
// Now close the PMP VC for this group, if one exists.
// If we don't have a VC, start a connection.
//
pVc = pIpEntry->pAtmEntry->pVcList;
AA_RELEASE_IE_LOCK(pIpEntry);
if (pVc != (PATMARP_VC)NULL)
{
AA_ACQUIRE_VC_LOCK(pVc);
//
// When the call is closed, we start a new
// PMP connection, using the migrate list.
//
AtmArpCloseCall(pVc);
}
else
{
AA_ACQUIRE_AE_LOCK(pAtmEntry);
AtmArpMcUpdateConnection(pAtmEntry);
//
// AE Lock is released within the above.
//
}
}
else
{
//
// Discard this MIGRATE
//
AA_RELEASE_IE_LOCK(pIpEntry);
}
break;
}
while (FALSE);
//
// Finally (according to Section 5.1.4.2 of RFC 2022), check
// if we just had a jump in the MSN.
//
if ((SeqDiff != 1) && (SeqDiff != 0))
{
AAMCDEBUGP(AAD_INFO,
("HandleMigrate: IF 0x%x: Bad seq diff %d, MSN 0x%x, HSN 0x%x\n",
pInterface, SeqDiff, MarsSeqNumber, HostSeqNumber));
AtmArpMcRevalidateAll(pInterface);
}
}
VOID
AtmArpMcHandleJoinOrLeave(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Process a received MARS_JOIN/MARS_LEAVE message. If this is a copy of a
message that we had sent, then there are two cases: (1) we are registering with
MARS, in which case we send MARS_JOINs for all pending Joins (2) we were
Joining a multicast group, in which case the Join operation is complete.
If this is not a copy of a MARS_JOIN originated from us, then we check if
the multicast group being joined is one to which we are sending. If so,
and if the station joining is not already a member of that group, we add it.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
pTlvList - All TLVs seen in this packet
Return Value:
None
--*/
{
PAA_MARS_JOIN_LEAVE_HEADER pJoinHeader;
PATMARP_INTERFACE pInterface; // IF on which this packet arrived
ULONG IfState; // State of the interface
IP_ADDRESS IPAddress;
PATMARP_IP_ENTRY pIpEntry; // Our entry for the group being joined
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
PATMARP_ATM_ENTRY pAtmEntry;
ULONG MarsSeqNumber; // MSN received in this packet
ULONG HostSeqNumber; // Our MSN
ULONG SeqDiff; // Difference between MSN and the HSN
USHORT Flags; // From the JOIN packet
BOOLEAN bLayer3Group; // Is a Layer 3 explicitly Joining?
BOOLEAN bCopyBitSet; // Is the COPY bit set?
BOOLEAN bRegister; // Is this a cluster member registering?
BOOLEAN bPunched; // Is the Punched bit set?
PUCHAR pSrcAtmNumber;
PUCHAR pSrcAtmSubaddress;
BOOLEAN bIsAtmNumberOurs; // Is the source ATM Number ours?
ATM_ADDRESSTYPE AtmNumberType;
ULONG AtmNumberLength;
ATM_ADDRESSTYPE AtmSubaddressType;
ULONG AtmSubaddressLength;
IP_ADDRESS UNALIGNED * pMinIPAddress;
IP_ADDRESS UNALIGNED * pMaxIPAddress;
IP_ADDRESS MinIPAddress;
IP_ADDRESS MaxIPAddress;
BOOLEAN IsJoin; // Is this a JOIN?
BOOLEAN ProcessMcSendList = TRUE;
//
// Initialize
//
pInterface = pVc->pInterface;
SeqDiff = 0;
pJoinHeader = (PAA_MARS_JOIN_LEAVE_HEADER)pControlHeader;
IsJoin = (pJoinHeader->op == NET_SHORT(AA_MARS_OP_TYPE_JOIN));
//
// Get the MARS Sequence Number in this message.
//
MarsSeqNumber = NET_TO_HOST_LONG(pJoinHeader->msn);
AA_ACQUIRE_IF_LOCK(pInterface);
HostSeqNumber = pInterface->HostSeqNumber; // save the old value
pInterface->HostSeqNumber = MarsSeqNumber; // and update
IfState = AAMC_IF_STATE(pInterface);
AA_RELEASE_IF_LOCK(pInterface);
SeqDiff = MarsSeqNumber - HostSeqNumber;
//
// Get all "flag" values:
//
Flags = pJoinHeader->flags;
bLayer3Group = ((Flags & AA_MARS_JL_FLAG_LAYER3_GROUP) != 0);
bCopyBitSet = ((Flags & AA_MARS_JL_FLAG_COPY) != 0);
bRegister = ((Flags & AA_MARS_JL_FLAG_REGISTER) != 0);
bPunched = ((Flags & AA_MARS_JL_FLAG_PUNCHED) != 0);
//
// Get at the source ATM number
//
pSrcAtmNumber = ((PUCHAR)pJoinHeader +
sizeof(AA_MARS_JOIN_LEAVE_HEADER));
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pJoinHeader->shtl,
&AtmNumberType,
&AtmNumberLength);
//
// Get at the source ATM subaddress
//
pSrcAtmSubaddress = ((PUCHAR)pSrcAtmNumber + AtmNumberLength);
AA_PKT_TYPE_LEN_TO_ATM_ADDRESS(
pJoinHeader->sstl,
&AtmSubaddressType,
&AtmSubaddressLength);
bIsAtmNumberOurs = ((AtmNumberType == pInterface->LocalAtmAddress.AddressType) &&
(AtmNumberLength == pInterface->LocalAtmAddress.NumberOfDigits) &&
(AA_MEM_CMP(pSrcAtmNumber,
pInterface->LocalAtmAddress.Address,
AtmNumberLength) == 0));
pMinIPAddress = (PIP_ADDRESS)((PUCHAR)pJoinHeader +
sizeof(AA_MARS_JOIN_LEAVE_HEADER)+
AtmNumberLength +
AtmSubaddressLength +
(pJoinHeader->spln & ~AA_PKT_ATM_ADDRESS_BIT));
pMaxIPAddress = (PIP_ADDRESS)((PUCHAR)pMinIPAddress +
(pJoinHeader->tpln & ~AA_PKT_ATM_ADDRESS_BIT));
AAMCDEBUGP(AAD_LOUD,
("Handle %s: Flags 0x%x, OurAtmNum %d, Punch %d, Copy %d, pnum %d, IFState 0x%x\n",
(IsJoin? "JOIN": "LEAVE"),
Flags,
(ULONG)bIsAtmNumberOurs,
(ULONG)bPunched,
(ULONG)bCopyBitSet,
pJoinHeader->pnum,
AAMC_IF_STATE(pInterface)
));
AAMCDEBUGP(AAD_LOUD,
("Handle %s: Min %d.%d.%d.%d, Max %d.%d.%d.%d\n",
(IsJoin? "JOIN": "LEAVE"),
((PUCHAR)pMinIPAddress)[0], ((PUCHAR)pMinIPAddress)[1],
((PUCHAR)pMinIPAddress)[2], ((PUCHAR)pMinIPAddress)[3],
((PUCHAR)pMaxIPAddress)[0], ((PUCHAR)pMaxIPAddress)[1],
((PUCHAR)pMaxIPAddress)[2], ((PUCHAR)pMaxIPAddress)[3]));
if (bIsAtmNumberOurs && (!bPunched) && bCopyBitSet)
{
//
// Potentially sent by us
//
ProcessMcSendList = FALSE; // we may set it back to true -- see below.
if (IfState == AAMC_IF_STATE_REGISTERING)
{
if (IsJoin &&
bRegister &&
(pJoinHeader->pnum == 0))
{
BOOLEAN WasRunning;
//
// Registration complete. Get our Cluster Member ID.
// We store this in network order so that we can
// use it to fill packets directly.
//
AA_ACQUIRE_IF_LOCK(pInterface);
pInterface->ClusterMemberId = pJoinHeader->cmi;
AAMCDEBUGP(AAD_INFO,
("==== HandleJoin: pIf 0x%x, registered with MARS, CMI %d!\n",
pInterface, pInterface->ClusterMemberId));
AAMC_SET_IF_STATE(pInterface, AAMC_IF_STATE_REGISTERED);
//
// Stop the MARS Registration timer.
//
WasRunning = AtmArpStopTimer(&(pInterface->McTimer), pInterface);
AA_ASSERT(WasRunning);
//
// Start MARS wait-for-keepalive timer.
//
AtmArpStartTimer(
pInterface,
&(pInterface->McTimer),
AtmArpMcMARSKeepAliveTimeout,
pInterface->MARSKeepAliveTimeout,
(PVOID)pInterface
);
//
// If we are recovering from a MARS failure,
// then we need to initiate revalidation of all
// groups we send to.
//
if (!AA_IS_FLAG_SET(pInterface->Flags,
AAMC_IF_MARS_FAILURE_MASK,
AAMC_IF_MARS_FAILURE_NONE))
{
AA_SET_FLAG(pInterface->Flags,
AAMC_IF_MARS_FAILURE_MASK,
AAMC_IF_MARS_FAILURE_NONE);
SeqDiff = 2; // a dirty way of triggering the above
}
//
// Send any JOINs we have pended waiting for registration
// to be over.
//
// TBDMC: Section 5.4.1 recommends that if we are doing this
// after a failure recovery, then a random delay should be
// inserted between JOINs...
//
AtmArpMcSendPendingJoins(pInterface);
//
// IF Lock is released within the above.
//
}
//
// else Discard: we aren't interested in this packet
//
}
else
{
//
// Potentially a Join/Leave sent by us for a multicast group
//
if (pJoinHeader->pnum == HOST_TO_NET_SHORT(1))
{
//
// Check if this came on the cluster control vc (or rather, we cheat
// and simply check if this is an incoming vc) -- if
// so we want to also process the McSendList to see if
// we need to add/remove ourselves to any mc ip send entries.
//
if (AA_IS_FLAG_SET(
pVc->Flags,
AA_VC_OWNER_MASK,
AA_VC_OWNER_IS_CALLMGR))
{
ProcessMcSendList = TRUE;
}
//
// Get the IP address range of group being joined/left.
//
IPAddress = *pMinIPAddress;
AtmArpMcHandleJoinOrLeaveCompletion(
pInterface,
IPAddress,
IPAddress ^ *pMaxIPAddress,
IsJoin);
}
//
// else Discard: bad pnum
//
}
}
if (ProcessMcSendList)
{
//
// Not sent by us, or punched, or it was sent by us but it came on the
// cluster control vc. For each <Min, Max> pair in this message,
// check if the pair overlaps any of the MC addresses to which
// we send packets. For each such IP entry, we find the MC ATM
// Entry corresponding to the host that is joining/leaving,
// and if necessary, mark it as needing a connection update.
//
// Then, we go thru the list of MC IP Entries, and start a
// connection update on all marked entries.
//
BOOLEAN bWorkDone;
USHORT MinMaxPairs;
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
MinMaxPairs = NET_TO_HOST_SHORT(pJoinHeader->pnum);
pIpEntry = pInterface->pMcSendList;
while (MinMaxPairs--)
{
MinIPAddress = NET_LONG(*pMinIPAddress);
MaxIPAddress = NET_LONG(*pMaxIPAddress);
while (pIpEntry != NULL_PATMARP_IP_ENTRY)
{
IPAddress = NET_LONG(pIpEntry->IPAddress);
if (IPAddress <= MaxIPAddress)
{
if (IPAddress >= MinIPAddress)
{
//
// This is an IP Entry that might be affected.
//
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
do
{
BOOLEAN bNeedToUpdateConnection;
if (pIpEntry->pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
//
// Skip this because it hasn't been resolved.
//
break;
}
pAtmEntry = pIpEntry->pAtmEntry;
if (AA_IS_FLAG_SET(pAtmEntry->Flags,
AA_ATM_ENTRY_TYPE_MASK,
AA_ATM_ENTRY_TYPE_UCAST))
{
if ((AtmNumberType != pAtmEntry->ATMAddress.AddressType) ||
(AtmNumberLength != pAtmEntry->ATMAddress.NumberOfDigits) ||
(AA_MEM_CMP(pSrcAtmNumber,
pAtmEntry->ATMAddress.Address,
AtmNumberLength) != 0))
{
//
// Addresses don't match; if this is a new JOIN,
// then this IP Entry needs updating.
//
bNeedToUpdateConnection = (IsJoin);
}
else
{
bNeedToUpdateConnection = !(IsJoin);
}
if (bNeedToUpdateConnection)
{
//
// Mark this entry so that we abort it below.
//
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_ABORTING);
}
break; // end of Unicast ATM Entry case
}
//
// Multicast IP Entry.
//
pMcAtmEntry = AtmArpMcLookupAtmMember(
pIpEntry->pAtmEntry,
&(pAtmEntry->pMcAtmInfo->pMcAtmEntryList),
pSrcAtmNumber,
AtmNumberLength,
AtmNumberType,
pSrcAtmSubaddress,
AtmSubaddressLength,
IsJoin
);
if (pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY)
{
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD,
(IsJoin? "Join Addr: ": "Leave Addr"),
&pMcAtmEntry->ATMAddress);
if (!IsJoin)
{
//
// Mark this entry so that it will be dropped from
// our connection to this multicast group.
//
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
AA_IPMC_AE_GEN_STATE_MASK,
AA_IPMC_AE_VALID))
{
AA_SET_FLAG(pMcAtmEntry->Flags,
AA_IPMC_AE_GEN_STATE_MASK,
AA_IPMC_AE_INVALID);
bNeedToUpdateConnection = TRUE;
}
}
else
{
bNeedToUpdateConnection =
(AA_IS_FLAG_SET(pMcAtmEntry->Flags,
AA_IPMC_AE_CONN_STATE_MASK,
AA_IPMC_AE_CONN_DISCONNECTED));
}
if (bNeedToUpdateConnection)
{
//
// Mark this ATM MC entry as wanting a connection
// update.
//
pIpEntry->pAtmEntry->pMcAtmInfo->Flags |=
AA_IPMC_AI_WANT_UPDATE;
}
}
break;
}
while (FALSE);
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
}
pIpEntry = pIpEntry->pNextMcEntry;
}
else
{
//
// This IP Address lies beyond this <Min, Max> pair.
// Go to the next pair.
//
break;
}
}
if (pIpEntry == NULL_PATMARP_IP_ENTRY)
{
break;
}
pMinIPAddress = (PIP_ADDRESS)((PUCHAR)pMaxIPAddress +
(pJoinHeader->tpln & ~AA_PKT_ATM_ADDRESS_BIT));
} // while loop processing all <Min, Max> pairs
AA_RELEASE_IF_TABLE_LOCK(pInterface);
//
// Now, for each ATM MC entry that we marked in the previous
// step, start a connection update.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
//
// We keep running through the McSendList, stopping when no work is done.
// This is because in order to "do work" we must release the table lock,
// in which case the McSendList may be modified by someone else.
//
do
{
bWorkDone = FALSE;
for (pIpEntry = pInterface->pMcSendList;
pIpEntry != NULL_PATMARP_IP_ENTRY;
pIpEntry = pIpEntry->pNextMcEntry)
{
ULONG Flags;
pAtmEntry = pIpEntry->pAtmEntry;
if (pAtmEntry == NULL_PATMARP_ATM_ENTRY)
{
//
// Not yet resolved. Skip this one.
//
continue;
}
if (AA_IS_FLAG_SET(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_ABORTING))
{
//
// Must be a unicast entry that we marked above.
//
AA_RELEASE_IF_TABLE_LOCK(pInterface);
bWorkDone = TRUE;
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
AtmArpAbortIPEntry(pIpEntry);
//
// IE lock is released within the above.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
break;
}
//
// If this is a unicast ATM Entry, there is nothing
// more to be done. If this needed revalidation,
// we would have aborted it above.
//
if (AA_IS_FLAG_SET(pAtmEntry->Flags,
AA_ATM_ENTRY_TYPE_MASK,
AA_ATM_ENTRY_TYPE_UCAST))
{
continue;
}
AA_ASSERT(pAtmEntry->pMcAtmInfo != NULL_PATMARP_IPMC_ATM_INFO);
Flags = pAtmEntry->pMcAtmInfo->Flags;
if (Flags & AA_IPMC_AI_BEING_UPDATED)
{
//
// Nothing to be done on this one.
//
continue;
}
if (Flags & AA_IPMC_AI_WANT_UPDATE)
{
//
// Needs a connection update.
//
AA_RELEASE_IF_TABLE_LOCK(pInterface);
bWorkDone = TRUE;
AA_ACQUIRE_AE_LOCK(pAtmEntry);
AtmArpMcUpdateConnection(pAtmEntry);
//
// AE Lock is released within the above.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
break;
}
}
}
while (bWorkDone);
AA_RELEASE_IF_TABLE_LOCK(pInterface);
} // else (Packet not a copy of ours)
//
// Finally (according to Section 5.1.4.2 of RFC 2022), check
// if we just had a jump in the MSN.
//
if ((SeqDiff != 1) && (SeqDiff != 0))
{
AAMCDEBUGP(AAD_INFO,
("HandleJoin+Leave: IF 0x%x: Bad seq diff %d, MSN 0x%x, HSN 0x%x\n",
pInterface, SeqDiff, MarsSeqNumber, HostSeqNumber));
AtmArpMcRevalidateAll(pInterface);
}
}
VOID
AtmArpMcHandleNak(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Process a received MARS_NAK message. We mark the IP Entry corresponding
to the IP Address being resolved as having seen a NAK. This is so that
we don't send another MARS Request for this IP address too soon. We also
start a timer at the end of which we unmark this IP Entry, so that
we may try to resolve it again.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
IN PAA_MARS_TLV_LIST pTlvList
Return Value:
None
--*/
{
PATMARP_INTERFACE pInterface;
PAA_MARS_REQ_NAK_HEADER pNakHeader;
PATMARP_IP_ENTRY pIpEntry; // Entry for IP address being resolved
PATMARP_ATM_ENTRY pAtmEntry; // Corresponding ATM Entry
IP_ADDRESS IPAddress; // the address being queried
BOOLEAN bWasRunning; // Was a timer running?
PNDIS_PACKET PacketList; // Packets queued for sending
ULONG rc;
//
// Initialize
//
pInterface = pVc->pInterface;
pNakHeader = (PAA_MARS_REQ_NAK_HEADER)pControlHeader;
do
{
//
// Get the group address being responded to.
//
IPAddress = *(IP_ADDRESS UNALIGNED *)(
(PUCHAR)pNakHeader +
sizeof(AA_MARS_REQ_NAK_HEADER) +
(pNakHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pNakHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT) +
(pNakHeader->spln)
);
AAMCDEBUGP(AAD_LOUD,
("McHandleNak: 0x%x, IP %d.%d.%d.%d\n",
pNakHeader,
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
//
// Get the IP Entry for this address.
//
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
pIpEntry = AtmArpSearchForIPAddress(
pInterface,
&IPAddress,
IE_REFTYPE_TMP,
TRUE, // this is a multicast/broadcast address
FALSE // don't create a new entry if the address isn't found
);
AA_RELEASE_IF_TABLE_LOCK(pInterface);
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
{
//
// AtmArpSearchForIPAddress addreffs pIpEntry for us ...
//
ULONG rc;
AA_ACQUIRE_IE_LOCK(pIpEntry);
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP);
if (rc == 0)
{
// Oops, IP address has gone away...
pIpEntry = NULL_PATMARP_IP_ENTRY;
}
}
if (pIpEntry == NULL_PATMARP_IP_ENTRY)
{
AAMCDEBUGP(AAD_INFO, ("McHandleNak: No IP Entry for %d.%d.%d.%d\n",
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
break;
}
bWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
if (bWasRunning)
{
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
AA_ASSERT(rc != 0);
}
else
{
AAMCDEBUGP(AAD_WARNING,
("McHandleNak: 0x%x, IP %d.%d.%d.%d NO TIMER RUNNING\n",
pNakHeader,
((PUCHAR)&IPAddress)[0],
((PUCHAR)&IPAddress)[1],
((PUCHAR)&IPAddress)[2],
((PUCHAR)&IPAddress)[3]));
}
//
// Take out all packets queued on this entry
//
PacketList = pIpEntry->PacketList;
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
//
// Mark this IP Entry as being resolved, but seen NAK.
//
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_RESOLVE_MASK,
AA_IP_ENTRY_MC_RESOLVED);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_MC_VALIDATE_MASK,
AA_IP_ENTRY_MC_NO_REVALIDATION);
AA_SET_FLAG(pIpEntry->Flags,
AA_IP_ENTRY_STATE_MASK,
AA_IP_ENTRY_SEEN_NAK);
AtmArpStartTimer(
pInterface,
&(pIpEntry->Timer),
AtmArpNakDelayTimeout,
pInterface->MinWaitAfterNak,
(PVOID)pIpEntry // Context
);
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
AA_RELEASE_IE_LOCK(pIpEntry);
//
// Free any packets that were queued up.
//
if (PacketList != (PNDIS_PACKET)NULL)
{
AtmArpFreeSendPackets(
pInterface,
PacketList,
FALSE // No headers on these
);
}
break;
}
while (FALSE);
}
VOID
AtmArpMcHandleGroupListReply(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Process a received MARS_GROUPLIST_REPLY message.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
IN PAA_MARS_TLV_LIST pTlvList
Return Value:
None
--*/
{
AAMCDEBUGP(AAD_WARNING, ("GroupListReply unexpected\n"));
AA_ASSERT(FALSE);
}
VOID
AtmArpMcHandleRedirectMap(
IN PATMARP_VC pVc,
IN PAA_MARS_PKT_FIXED_HEADER pControlHeader,
IN ULONG TotalLength,
IN PAA_MARS_TLV_LIST pTlvList
)
/*++
Routine Description:
Process a received MARS_REDIRECT_MAP message. For now, we simply
refresh the MARS Keepalive timer.
TBDMC: Parse fully, and update MARS list, and migrate if necessary.
Arguments:
pVc - Pointer to our VC structure on which the packet
arrived.
pControlHeader - Pointer to the start of the packet contents
TotalLength - Total length of this packet.
IN PAA_MARS_TLV_LIST pTlvList
Return Value:
None
--*/
{
PATMARP_INTERFACE pInterface;
PAA_MARS_REDIRECT_MAP_HEADER pRedirectHeader;
ULONG MarsSeqNumber;
ULONG HostSeqNumber;
ULONG SeqDiff;
//
// Initialize
//
pInterface = pVc->pInterface;
SeqDiff = 0;
AAMCDEBUGP(AAD_VERY_LOUD, ("### REDIRECT MAP 0x%x on VC 0x%x, IF 0x%x/0x%x\n",
pControlHeader, pVc, pInterface, pInterface->Flags));
pRedirectHeader = (PAA_MARS_REDIRECT_MAP_HEADER)pControlHeader;
AA_ACQUIRE_IF_LOCK(pInterface);
if ((AAMC_IF_STATE(pInterface) == AAMC_IF_STATE_REGISTERED) &&
(AA_IS_FLAG_SET(pInterface->Flags,
AAMC_IF_MARS_FAILURE_MASK,
AAMC_IF_MARS_FAILURE_NONE)))
{
//
// Get the MARS Sequence Number in this message.
//
MarsSeqNumber = NET_TO_HOST_LONG(pRedirectHeader->msn);
HostSeqNumber = pInterface->HostSeqNumber; // save the old value
pInterface->HostSeqNumber = MarsSeqNumber; // and update
SeqDiff = MarsSeqNumber - HostSeqNumber;
//
// The MC Timer running on the IF must be MARS Keepalive
//
AA_ASSERT(pInterface->McTimer.TimeoutHandler == AtmArpMcMARSKeepAliveTimeout);
AAMCDEBUGP(AAD_EXTRA_LOUD,
("Redirect MAP: refreshing keepalive on IF 0x%x, new HSN %d\n",
pInterface, pInterface->HostSeqNumber));
AtmArpRefreshTimer(&(pInterface->McTimer));
}
AA_RELEASE_IF_LOCK(pInterface);
//
// Finally (according to Section 5.1.4.2 of RFC 2022), check
// if we just had a jump in the MSN.
//
if ((SeqDiff != 1) && (SeqDiff != 0))
{
AAMCDEBUGP(AAD_INFO,
("HandleRedirectMap: IF 0x%x: Bad seq diff %d, MSN 0x%x, HSN 0x%x\n",
pInterface, SeqDiff, MarsSeqNumber, HostSeqNumber));
AtmArpMcRevalidateAll(pInterface);
}
return;
}
#endif // IPMCAST