2243 lines
51 KiB
C
2243 lines
51 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arppkt.c - ATMARP Packet Routines.
|
|
|
|
Abstract:
|
|
|
|
Routines that build and parse ARP packets.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 07-29-96 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'TKPA'
|
|
|
|
|
|
VOID
|
|
AtmArpSendPacketOnVc(
|
|
IN PATMARP_VC pVc LOCKIN NOLOCKOUT,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a packet on the specified VC. Apart from calling NDIS to do
|
|
the job, we refresh the aging timer on this VC.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC
|
|
pNdisPacket - Pointer to packet to be sent.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_HANDLE NdisVcHandle;
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE) &&
|
|
!AA_IS_VC_GOING_DOWN(pVc))
|
|
{
|
|
//
|
|
// A call is active on this VC, so send the packet.
|
|
//
|
|
AtmArpRefreshTimer(&(pVc->Timer));
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
#ifdef VC_REFS_ON_SENDS
|
|
AtmArpReferenceVc(pVc); // SendPacketOnVc
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
pVc->OutstandingSends++; // SendPacketOnVc
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD+50,
|
|
("SendPacketOnVc: pVc 0x%x, Pkt 0x%x, VcHandle 0x%x\n",
|
|
pVc, pNdisPacket, NdisVcHandle));
|
|
|
|
#ifdef PERF
|
|
AadLogSendUpdate(pNdisPacket);
|
|
#endif // PERF
|
|
NDIS_CO_SEND_PACKETS(
|
|
NdisVcHandle,
|
|
&pNdisPacket,
|
|
1
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (!AA_IS_VC_GOING_DOWN(pVc))
|
|
{
|
|
//
|
|
// Call must be in progress. Queue this packet; it will
|
|
// be sent as soon as the call is fully set up.
|
|
//
|
|
AtmArpQueuePacketOnVc(pVc, pNdisPacket);
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This VC is going down. Complete the send with a failure.
|
|
//
|
|
#ifdef VC_REFS_ON_SENDS
|
|
AtmArpReferenceVc(pVc); // SendPacketOnVc2
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
pVc->OutstandingSends++; // SendPacketOnVc - failure completion
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
#if DBG
|
|
#if DBG_CO_SEND
|
|
{
|
|
PULONG pContext;
|
|
pContext = (PULONG)&(pNdisPacket->WrapperReserved[0]);;
|
|
*pContext = 'AaAa';
|
|
}
|
|
#endif
|
|
#endif
|
|
AtmArpCoSendCompleteHandler(
|
|
NDIS_STATUS_FAILURE,
|
|
(NDIS_HANDLE)pVc,
|
|
pNdisPacket
|
|
);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_PACKET
|
|
AtmArpBuildARPPacket(
|
|
IN USHORT OperationType,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PUCHAR * ppArpPacket,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a generic ARP packet with the given attributes.
|
|
|
|
Arguments:
|
|
|
|
OperationType - Op type (e.g. ARP Request, ARP Reply)
|
|
pInterface - Pointer to ATMARP Interface
|
|
ppArpPacket - Pointer to place to return start of packet
|
|
pArpContents - Pointer to structure describing contents
|
|
|
|
Return Value:
|
|
|
|
Pointer to NDIS packet if successful, NULL otherwise. If successful,
|
|
we also set *ppArpPacket to point to the first byte in the constructed
|
|
ARP packet.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pNdisPacket;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
ULONG BufferLength; // Length of ARP packet
|
|
ULONG Length; // Temp length
|
|
PUCHAR pPkt; // Start of allocated packet
|
|
PUCHAR pBuf; // Used to walk the packet
|
|
PAA_ARP_PKT_HEADER pArpHeader; // ARP packet header
|
|
|
|
//
|
|
// Calculate the length of what we're about to build
|
|
//
|
|
BufferLength = AA_ARP_PKT_HEADER_LENGTH +
|
|
(pArpContents->SrcAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) +
|
|
(pArpContents->SrcAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) +
|
|
(pArpContents->DstAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) +
|
|
(pArpContents->DstAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT) +
|
|
0;
|
|
|
|
if (pArpContents->pSrcIPAddress != (PUCHAR)NULL)
|
|
{
|
|
BufferLength += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
if (pArpContents->pDstIPAddress != (PUCHAR)NULL)
|
|
{
|
|
BufferLength += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
pNdisPacket = AtmArpAllocatePacket(pInterface);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
pNdisBuffer = AtmArpAllocateProtoBuffer(
|
|
pInterface,
|
|
BufferLength,
|
|
&(pPkt)
|
|
);
|
|
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
//
|
|
// Return value:
|
|
//
|
|
*ppArpPacket = pPkt;
|
|
|
|
//
|
|
// Initialize packet with all 0's
|
|
//
|
|
AA_SET_MEM(pPkt, 0, BufferLength);
|
|
|
|
pArpHeader = (PAA_ARP_PKT_HEADER)pPkt;
|
|
|
|
//
|
|
// Fixed-location fields:
|
|
//
|
|
pArpHeader->LLCSNAPHeader = AtmArpLlcSnapHeader;
|
|
pArpHeader->LLCSNAPHeader.EtherType = NET_SHORT(AA_PKT_ETHERTYPE_ARP);
|
|
pArpHeader->hrd = NET_SHORT(AA_PKT_ATM_FORUM_AF);
|
|
pArpHeader->pro = NET_SHORT(AA_PKT_PRO_IP);
|
|
pArpHeader->op = NET_SHORT(OperationType);
|
|
|
|
//
|
|
// Now fill in the variable length fields
|
|
//
|
|
pBuf = pArpHeader->Variable;
|
|
|
|
//
|
|
// Source ATM Number
|
|
//
|
|
Length = (pArpContents->SrcAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
if (Length > 0)
|
|
{
|
|
pArpHeader->shtl = pArpContents->SrcAtmNumberTypeLen;
|
|
AA_COPY_MEM(pBuf, pArpContents->pSrcAtmNumber, Length);
|
|
pBuf += Length;
|
|
}
|
|
|
|
//
|
|
// Source ATM subaddress
|
|
//
|
|
Length = (pArpContents->SrcAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
if (Length > 0)
|
|
{
|
|
pArpHeader->shtl = pArpContents->SrcAtmSubaddrTypeLen;
|
|
AA_COPY_MEM(pBuf, pArpContents->pSrcAtmSubaddress, Length);
|
|
pBuf += Length;
|
|
}
|
|
|
|
//
|
|
// Source Protocol (IP) address
|
|
//
|
|
if (pArpContents->pSrcIPAddress != (PUCHAR)NULL)
|
|
{
|
|
pArpHeader->spln = AA_IPV4_ADDRESS_LENGTH;
|
|
AA_COPY_MEM(pBuf, pArpContents->pSrcIPAddress, AA_IPV4_ADDRESS_LENGTH);
|
|
|
|
pBuf += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
//
|
|
// Target ATM Number
|
|
//
|
|
Length = (pArpContents->DstAtmNumberTypeLen & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
if (Length > 0)
|
|
{
|
|
pArpHeader->thtl = pArpContents->DstAtmNumberTypeLen;
|
|
AA_COPY_MEM(pBuf, pArpContents->pDstAtmNumber, Length);
|
|
pBuf += Length;
|
|
}
|
|
|
|
//
|
|
// Target ATM subaddress
|
|
//
|
|
Length = (pArpContents->DstAtmSubaddrTypeLen & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
if (Length > 0)
|
|
{
|
|
pArpHeader->thtl = pArpContents->DstAtmSubaddrTypeLen;
|
|
AA_COPY_MEM(pBuf, pArpContents->pDstAtmSubaddress, Length);
|
|
pBuf += Length;
|
|
}
|
|
|
|
//
|
|
// Target Protocol (IP) address
|
|
//
|
|
if (pArpContents->pDstIPAddress != (PUCHAR)NULL)
|
|
{
|
|
pArpHeader->tpln = AA_IPV4_ADDRESS_LENGTH;
|
|
AA_COPY_MEM(pBuf, pArpContents->pDstIPAddress, AA_IPV4_ADDRESS_LENGTH);
|
|
|
|
pBuf += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
AtmArpFreePacket(pInterface, pNdisPacket);
|
|
pNdisPacket = (PNDIS_PACKET)NULL;
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD, ("BldArpPkt: pIf 0x%x, Op %d, NdisPkt 0x%x, NdisBuf 0x%x\n",
|
|
pInterface, OperationType, pNdisPacket, pNdisBuffer));
|
|
|
|
return (pNdisPacket);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpSendARPRequest(
|
|
PATMARP_INTERFACE pInterface,
|
|
IP_ADDRESS UNALIGNED * pSrcIPAddress,
|
|
IP_ADDRESS UNALIGNED * pDstIPAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send an ARP Request to the server, for the given interface.
|
|
|
|
Preconditions: the ATM interface is UP, and the AdminState
|
|
for the interface is IF_STATUS_UP.
|
|
|
|
We first build an ARP Request with the given parameters. Then,
|
|
if a Best Effort VC to the server's ATM address exists, the packet
|
|
is sent on this. Other possibilities:
|
|
- the Best Effort VC to the server is being set up: queue it
|
|
on the VC
|
|
- No Best Effort VC to the server exists: Create a new VC on this
|
|
ATM Entry, make a call with Best Effort flow specs, and queue
|
|
the request on this VC.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface structure
|
|
pSrcIPAddress - Pointer to Source IP Address
|
|
pDstIPAddress - Pointer to Destination IP Address (to be
|
|
resolved)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ATM_ENTRY pAtmEntry; // Entry for the server's ATM address
|
|
PATMARP_VC pVc; // VC to the server
|
|
PNDIS_PACKET pNdisPacket;
|
|
PATMARP_FLOW_SPEC pFlowSpec;
|
|
PUCHAR pArpPacket; // Pointer to ARP packet being constructed
|
|
|
|
AA_ARP_PKT_CONTENTS ArpContents;// Describes the packet we want to build
|
|
|
|
NDIS_STATUS Status;
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Sending ARP Request on IF 0x%x for IP Addr: %d.%d.%d.%d\n",
|
|
pInterface,
|
|
((PUCHAR)pDstIPAddress)[0],
|
|
((PUCHAR)pDstIPAddress)[1],
|
|
((PUCHAR)pDstIPAddress)[2],
|
|
((PUCHAR)pDstIPAddress)[3]
|
|
));
|
|
|
|
AA_ASSERT(pInterface->pCurrentServer != NULL_PATMARP_SERVER_ENTRY);
|
|
AA_ASSERT(pInterface->pCurrentServer->pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
|
|
//
|
|
// Prepare the ARP packet contents structure
|
|
//
|
|
AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS));
|
|
|
|
//
|
|
// Source ATM Number
|
|
//
|
|
ArpContents.pSrcAtmNumber = pInterface->LocalAtmAddress.Address;
|
|
ArpContents.SrcAtmNumberTypeLen =
|
|
AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress));
|
|
|
|
//
|
|
// Source IP Address
|
|
//
|
|
ArpContents.pSrcIPAddress = (PUCHAR)pSrcIPAddress;
|
|
|
|
//
|
|
// Target IP Address
|
|
//
|
|
ArpContents.pDstIPAddress = (PUCHAR)pDstIPAddress;
|
|
|
|
//
|
|
// Build the ARP Request
|
|
//
|
|
pNdisPacket = AtmArpBuildARPPacket(
|
|
AA_PKT_OP_TYPE_ARP_REQUEST,
|
|
pInterface,
|
|
&pArpPacket,
|
|
&ArpContents
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Find the ATM Entry for the in-use ATMARP Server:
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
pAtmEntry = pInterface->pCurrentServer->pAtmEntry;
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
//
|
|
// Get at the Best Effort VC going to this ATM address:
|
|
//
|
|
pVc = pAtmEntry->pBestEffortVc;
|
|
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
ULONG rc;
|
|
|
|
AA_ACQUIRE_VC_LOCK_DPC(pVc);
|
|
AtmArpReferenceVc(pVc); // temp ref
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry); // Not needed anymore
|
|
|
|
//
|
|
// A VC to the server exists; send this packet on the VC
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
rc = AtmArpDereferenceVc(pVc); // temp ref
|
|
|
|
if (rc != 0)
|
|
{
|
|
AtmArpSendPacketOnVc(pVc, pNdisPacket);
|
|
//
|
|
// The VC lock is released in SendPacketOnVc
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The VC has been deref'ed away! Set up pVc for the
|
|
// check coming up.
|
|
//
|
|
pVc = NULL_PATMARP_VC;
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
}
|
|
|
|
if (pVc == NULL_PATMARP_VC)
|
|
{
|
|
//
|
|
// We don't have an appropriate VC to the server, so create
|
|
// one, and queue this packet for transmission as soon as
|
|
// the call is made.
|
|
//
|
|
// AtmArpMakeCall needs the caller to hold the ATM Entry lock.
|
|
//
|
|
AA_GET_CONTROL_PACKET_SPECS(pInterface, &pFlowSpec);
|
|
Status = AtmArpMakeCall(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pFlowSpec,
|
|
pNdisPacket
|
|
);
|
|
//
|
|
// The AE lock is released within the above.
|
|
//
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpSendInARPRequest(
|
|
IN PATMARP_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send an InATMARP Request on a VC.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC on which we send the request
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PNDIS_PACKET pNdisPacket;
|
|
PUCHAR pArpPacket; // Pointer to ARP packet being constructed
|
|
|
|
AA_ARP_PKT_CONTENTS ArpContents;// Describes the packet we want to build
|
|
|
|
//
|
|
// Prepare the ARP packet contents structure
|
|
//
|
|
AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS));
|
|
|
|
pInterface = pVc->pInterface;
|
|
|
|
//
|
|
// Source IP Address
|
|
//
|
|
ArpContents.pSrcIPAddress = (PUCHAR)&(pInterface->LocalIPAddress.IPAddress);
|
|
|
|
//
|
|
// Source ATM number
|
|
//
|
|
ArpContents.pSrcAtmNumber = pInterface->LocalAtmAddress.Address;
|
|
ArpContents.SrcAtmNumberTypeLen =
|
|
AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress));
|
|
|
|
//
|
|
// Build the InATMARP Request packet
|
|
//
|
|
pNdisPacket = AtmArpBuildARPPacket(
|
|
AA_PKT_OP_TYPE_INARP_REQUEST,
|
|
pInterface,
|
|
&pArpPacket,
|
|
&ArpContents
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
#ifndef VC_REFS_ON_SENDS
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
#endif // VC_REFS_ON_SENDS
|
|
|
|
AtmArpSendPacketOnVc(pVc, pNdisPacket);
|
|
//
|
|
// The VC lock is released by SendPacketOnVc
|
|
//
|
|
}
|
|
else
|
|
{
|
|
#ifdef VC_REFS_ON_SENDS
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
#endif // VC_REFS_ON_SENDS
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UINT
|
|
AtmArpCoReceivePacketHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is routine is called when a packet is received on a VC owned
|
|
by the ATMARP module. If it is an ARP packet, we consume it ourselves.
|
|
Otherwise, we pass it up to IP.
|
|
|
|
In any case, we refresh the VC aging timer on this VC.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - Actually a pointer to our Adapter structure
|
|
ProtocolVcContext - Actually a pointer to our VC structure
|
|
pNdisPacket - NDIS packet being received.
|
|
|
|
Return Value:
|
|
|
|
0 always, because we don't hold on to ARP packets, and we assume
|
|
IP doesn't either.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_VC pVc;
|
|
UINT TotalLength; // Total bytes in packet
|
|
PNDIS_BUFFER pNdisBuffer; // Pointer to first buffer
|
|
UINT BufferLength;
|
|
UINT IsNonUnicast; // Is this to a non-unicast destn MAC addr?
|
|
BOOLEAN Discarded; // Are we discarding this packet?
|
|
|
|
PAA_PKT_LLC_SNAP_HEADER pPktHeader; // LLC/SNAP header
|
|
UINT ReturnCount = 0;
|
|
|
|
#if DBG
|
|
pPktHeader = NULL;
|
|
#endif
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
pInterface = pVc->pInterface;
|
|
|
|
Discarded = FALSE;
|
|
IsNonUnicast = (UINT)FALSE;
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
//
|
|
// Refresh VC aging on this VC
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
AtmArpRefreshTimer(&(pVc->Timer));
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
NdisQueryPacket(
|
|
pNdisPacket,
|
|
NULL,
|
|
NULL,
|
|
&pNdisBuffer,
|
|
&TotalLength
|
|
);
|
|
|
|
//
|
|
// We expect atleast the LLC/SNAP header to be present
|
|
// Note: this precludes Null encapsulation.
|
|
//
|
|
if (TotalLength >= AA_PKT_LLC_SNAP_HEADER_LENGTH)
|
|
{
|
|
AA_IF_STAT_ADD(pInterface, InOctets, TotalLength);
|
|
|
|
NdisQueryBuffer(
|
|
pNdisBuffer,
|
|
(PVOID *)&pPktHeader,
|
|
&BufferLength
|
|
);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD,
|
|
("Rcv: VC 0x%x, NDISpkt 0x%x, NDISbuf 0x%x, Buflen %d, Totlen %d, Pkthdr 0x%x\n",
|
|
pVc,
|
|
pNdisPacket,
|
|
pNdisBuffer,
|
|
BufferLength,
|
|
TotalLength,
|
|
pPktHeader));
|
|
|
|
AADEBUGPDUMP(AAD_EXTRA_LOUD+20, pPktHeader, BufferLength);
|
|
|
|
AA_ASSERT(BufferLength >= AA_PKT_LLC_SNAP_HEADER_LENGTH);
|
|
|
|
if (AA_PKT_LLC_SNAP_HEADER_OK(pPktHeader))
|
|
{
|
|
//
|
|
// If the EtherType is IP, pass up this packet to
|
|
// the IP layer
|
|
//
|
|
if (pPktHeader->EtherType == NET_SHORT(AA_PKT_ETHERTYPE_IP))
|
|
{
|
|
AADEBUGP(AAD_EXTRA_LOUD,
|
|
("Rcv: VC 0x%x, NDISpkt 0x%x: EtherType is IP, passing up\n"));
|
|
|
|
#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 (IsNonUnicast)
|
|
{
|
|
AA_IF_STAT_INCR(pInterface, InNonUnicastPkts);
|
|
}
|
|
else
|
|
{
|
|
AA_IF_STAT_INCR(pInterface, InUnicastPkts);
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
if (NDIS_GET_PACKET_STATUS(pNdisPacket) != NDIS_STATUS_RESOURCES)
|
|
{
|
|
UINT HeaderSize;
|
|
UINT DataSize;
|
|
#define ATMARP_MIN_1ST_RECV_BUFSIZE 512
|
|
|
|
HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(pNdisPacket);
|
|
|
|
//
|
|
// 2/8/1998 JosephJ
|
|
// We set DataSize to the total payload size,
|
|
// unless the first buffer is too small to
|
|
// hold the IP header. In the latter case,
|
|
// we set DataSize to be the size of the 1st buffer
|
|
// (minus the LLS/SNAP header size).
|
|
//
|
|
// This is to work around a bug in tcpip.
|
|
//
|
|
// 2/25/1998 JosephJ
|
|
// Unfortunately we have to back out YET AGAIN
|
|
// because large pings (eg ping -l 4000) doesn't
|
|
// work -- bug#297784
|
|
// Hence the "0" in "0 && DataSize" below.
|
|
// Take out the "0" to put back the per fix.
|
|
//
|
|
DataSize = BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER);
|
|
if (0 && DataSize >= ATMARP_MIN_1ST_RECV_BUFSIZE)
|
|
{
|
|
DataSize = TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER);
|
|
}
|
|
|
|
(pInterface->IPRcvPktHandler)(
|
|
pInterface->IPContext,
|
|
(PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)),
|
|
DataSize,
|
|
TotalLength,
|
|
(NDIS_HANDLE)pNdisPacket,
|
|
sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
IsNonUnicast,
|
|
0,
|
|
pNdisBuffer,
|
|
&ReturnCount
|
|
#if P2MP
|
|
,NULL
|
|
#endif //P2MP
|
|
);
|
|
}
|
|
else
|
|
{
|
|
(pInterface->IPRcvHandler)(
|
|
pInterface->IPContext,
|
|
(PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)),
|
|
BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
(NDIS_HANDLE)pNdisPacket,
|
|
sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
IsNonUnicast
|
|
#if P2MP
|
|
,NULL
|
|
#endif //P2MP
|
|
);
|
|
}
|
|
#else
|
|
// For Win98:
|
|
(pInterface->IPRcvHandler)(
|
|
pInterface->IPContext,
|
|
(PVOID)((PUCHAR)pPktHeader+sizeof(AA_PKT_LLC_SNAP_HEADER)),
|
|
BufferLength - sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
TotalLength - sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
(NDIS_HANDLE)pNdisPacket,
|
|
sizeof(AA_PKT_LLC_SNAP_HEADER),
|
|
IsNonUnicast
|
|
#if P2MP
|
|
,NULL
|
|
#endif //P2MP
|
|
);
|
|
|
|
#endif // _PNP_POWER_
|
|
}
|
|
else if (pPktHeader->EtherType == NET_SHORT(AA_PKT_ETHERTYPE_ARP))
|
|
{
|
|
//
|
|
// An ARP packet: we handle it ourselves
|
|
//
|
|
AA_ASSERT(BufferLength == TotalLength);
|
|
AA_IF_STAT_INCR(pInterface, InUnicastPkts);
|
|
AtmArpHandleARPPacket(
|
|
pVc,
|
|
pPktHeader,
|
|
BufferLength
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Discard packet -- bad EtherType
|
|
//
|
|
AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, bad EtherType 0x%x\n",
|
|
pVc, pPktHeader, (ULONG)pPktHeader->EtherType));
|
|
Discarded = TRUE;
|
|
AA_IF_STAT_INCR(pInterface, UnknownProtos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef IPMCAST
|
|
Discarded = AtmArpMcProcessPacket(
|
|
pVc,
|
|
pNdisPacket,
|
|
pNdisBuffer,
|
|
pPktHeader,
|
|
TotalLength,
|
|
BufferLength
|
|
);
|
|
#else
|
|
//
|
|
// Discard packet -- bad LLC/SNAP
|
|
//
|
|
AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, bad LLC/SNAP\n",
|
|
pVc, pPktHeader));
|
|
Discarded = TRUE;
|
|
#endif // IPMCAST
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Discard packet -- too short
|
|
//
|
|
AADEBUGP(AAD_WARNING, ("VC: 0x%x, Pkt hdr 0x%x, too short: %d\n",
|
|
pVc, pPktHeader, TotalLength));
|
|
Discarded = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Discard packet -- IF down
|
|
//
|
|
AADEBUGP(AAD_WARNING, ("pInterface: 0x%x is down, discarding NDIS pkt 0x%x\n",
|
|
pInterface, pNdisPacket));
|
|
Discarded = TRUE;
|
|
}
|
|
|
|
if (Discarded)
|
|
{
|
|
AA_IF_STAT_INCR(pInterface, InDiscards);
|
|
}
|
|
|
|
return (ReturnCount);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleARPPacket(
|
|
IN PATMARP_VC pVc,
|
|
IN PAA_PKT_LLC_SNAP_HEADER pPktHeader,
|
|
IN ULONG PacketLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a received ARP packet. We complete most of the packet checks
|
|
here, and then branch off to do different things based on the Op type
|
|
in the packet.
|
|
|
|
We do not hang on to the packet, i.e. when we return from here,
|
|
the packet is free.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC on which packet arrived
|
|
pPktHeader - Pointer to start of packet (including LLC/SNAP)
|
|
PacketLength - Length including LLC/SNAP header
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PAA_ARP_PKT_HEADER pArpHeader;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// For walking down the packet
|
|
//
|
|
UCHAR UNALIGNED * pPacket;
|
|
|
|
//
|
|
// For storing pointers to the packet contents. We'll need this
|
|
// if we have to send a reply packet.
|
|
//
|
|
AA_ARP_PKT_CONTENTS ArpContents;
|
|
|
|
BOOLEAN SrcAtmBelongsToUs;
|
|
BOOLEAN SrcIPBelongsToUs;
|
|
|
|
//
|
|
// Initialize (Important: don't remove the zeroing of ArpContents)
|
|
//
|
|
AA_SET_MEM((PUCHAR)&ArpContents, 0, sizeof(AA_ARP_PKT_CONTENTS));
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
pInterface = pVc->pInterface;
|
|
|
|
pArpHeader = STRUCT_OF(AA_ARP_PKT_HEADER, pPktHeader, LLCSNAPHeader);
|
|
|
|
AADEBUGP(AAD_EXTRA_LOUD+10,
|
|
("HandleARPPkt: VC 0x%x, IF 0x%x, pPktHdr 0x%x, Len %d\n",
|
|
pVc,
|
|
pInterface,
|
|
pPktHeader,
|
|
PacketLength));
|
|
|
|
do
|
|
{
|
|
if (PacketLength < AA_ARP_PKT_HEADER_LENGTH)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("HandleARPPkt: IF 0x%x, PacketLength %d < HdrLen %d\n",
|
|
pInterface, PacketLength, AA_ARP_PKT_HEADER_LENGTH));
|
|
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
break;
|
|
}
|
|
|
|
if ((pArpHeader->hrd != NET_SHORT(AA_PKT_HRD)) ||
|
|
(pArpHeader->pro != NET_SHORT(AA_PKT_PRO)))
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleARPPkt: IF 0x%x, Bad hdr (%d != %d) or pro (%d != %d)\n",
|
|
pInterface,
|
|
pArpHeader->hrd,
|
|
AA_PKT_HRD,
|
|
pArpHeader->pro,
|
|
AA_PKT_PRO));
|
|
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get at the variable part of the packet, and get pointers
|
|
// to all addresses.
|
|
//
|
|
// TBD: add more checks on ATM address lengths and combinations
|
|
// Note: we check for packet length later.
|
|
//
|
|
pPacket = pArpHeader->Variable;
|
|
|
|
//
|
|
// Source ATM Number
|
|
//
|
|
if (pArpHeader->shtl != 0)
|
|
{
|
|
ArpContents.SrcAtmNumberTypeLen = pArpHeader->shtl;
|
|
ArpContents.pSrcAtmNumber = pPacket;
|
|
pPacket += (pArpHeader->shtl & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
}
|
|
|
|
//
|
|
// Source ATM Subaddress
|
|
//
|
|
if (pArpHeader->sstl != 0)
|
|
{
|
|
ArpContents.SrcAtmSubaddrTypeLen = pArpHeader->sstl;
|
|
ArpContents.pSrcAtmSubaddress = pPacket;
|
|
pPacket += (pArpHeader->sstl & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
}
|
|
|
|
//
|
|
// Source IP Address. Older 1577 implementations may send an
|
|
// IP address field filled with all 0's to denote an unspecified
|
|
// IP address.
|
|
//
|
|
if (pArpHeader->spln != 0)
|
|
{
|
|
if (pArpHeader->spln != AA_IPV4_ADDRESS_LENGTH)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleARPPkt: IF 0x%x, bad spln %d != %d\n",
|
|
pInterface,
|
|
pArpHeader->spln,
|
|
AA_IPV4_ADDRESS_LENGTH));
|
|
|
|
Status = NDIS_STATUS_INVALID_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
if (!AtmArpIsZeroIPAddress(pPacket))
|
|
{
|
|
ArpContents.pSrcIPAddress = pPacket;
|
|
}
|
|
pPacket += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
//
|
|
// Target ATM Number
|
|
//
|
|
if (pArpHeader->thtl != 0)
|
|
{
|
|
ArpContents.DstAtmNumberTypeLen = pArpHeader->thtl;
|
|
ArpContents.pDstAtmNumber = pPacket;
|
|
pPacket += (pArpHeader->thtl & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
}
|
|
|
|
//
|
|
// Target ATM Subaddress
|
|
//
|
|
if (pArpHeader->tstl != 0)
|
|
{
|
|
ArpContents.DstAtmSubaddrTypeLen = pArpHeader->tstl;
|
|
ArpContents.pDstAtmSubaddress = pPacket;
|
|
pPacket += (pArpHeader->tstl & ~AA_PKT_ATM_ADDRESS_BIT);
|
|
}
|
|
|
|
//
|
|
// Target IP Address [see comments for Source IP Address]
|
|
//
|
|
if (pArpHeader->tpln != 0)
|
|
{
|
|
if (pArpHeader->tpln != AA_IPV4_ADDRESS_LENGTH)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleARPPkt: IF 0x%x, bad tpln %d != %d\n",
|
|
pInterface,
|
|
pArpHeader->tpln,
|
|
AA_IPV4_ADDRESS_LENGTH));
|
|
|
|
Status = NDIS_STATUS_INVALID_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
if (!AtmArpIsZeroIPAddress(pPacket))
|
|
{
|
|
ArpContents.pDstIPAddress = pPacket;
|
|
}
|
|
pPacket += AA_IPV4_ADDRESS_LENGTH;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
if ((ULONG)(pPacket - (PUCHAR)pArpHeader) > PacketLength)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleARPPkt: IF 0x%x, pPktHdr 0x%x. Length %d TOO SMALL (want %d)\n",
|
|
pInterface,
|
|
pArpHeader,
|
|
PacketLength,
|
|
(pPacket - (PUCHAR)pArpHeader)));
|
|
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this is an ARP NAK packet, swap Source and Target
|
|
// addresses, in preparation for what follows. This is
|
|
// because, unlike any other Reply packet where the Source
|
|
// and Target addresses get swapped, the ARP NAK
|
|
// packet is a copy of the ARP Request, with only the
|
|
// Op code changed.
|
|
//
|
|
if (NET_SHORT(pArpHeader->op) == AA_PKT_OP_TYPE_ARP_NAK)
|
|
{
|
|
UCHAR TypeLen;
|
|
UCHAR UNALIGNED * pAddress;
|
|
|
|
//
|
|
// IP Addresses:
|
|
//
|
|
pAddress = ArpContents.pSrcIPAddress;
|
|
ArpContents.pSrcIPAddress = ArpContents.pDstIPAddress;
|
|
ArpContents.pDstIPAddress = pAddress;
|
|
|
|
//
|
|
// ATM Number:
|
|
//
|
|
TypeLen = ArpContents.SrcAtmNumberTypeLen;
|
|
ArpContents.SrcAtmNumberTypeLen = ArpContents.DstAtmNumberTypeLen;
|
|
ArpContents.DstAtmNumberTypeLen = TypeLen;
|
|
pAddress = ArpContents.pSrcAtmNumber;
|
|
ArpContents.pSrcAtmNumber = ArpContents.pDstAtmNumber;
|
|
ArpContents.pDstAtmNumber = pAddress;
|
|
|
|
//
|
|
// ATM Subaddress:
|
|
//
|
|
TypeLen = ArpContents.SrcAtmSubaddrTypeLen;
|
|
ArpContents.SrcAtmSubaddrTypeLen = ArpContents.DstAtmSubaddrTypeLen;
|
|
ArpContents.DstAtmSubaddrTypeLen = TypeLen;
|
|
pAddress = ArpContents.pSrcAtmSubaddress;
|
|
ArpContents.pSrcAtmSubaddress = ArpContents.pDstAtmSubaddress;
|
|
ArpContents.pDstAtmSubaddress = pAddress;
|
|
}
|
|
|
|
|
|
SrcIPBelongsToUs = AtmArpIsLocalIPAddress(
|
|
pInterface,
|
|
ArpContents.pSrcIPAddress
|
|
);
|
|
|
|
SrcAtmBelongsToUs = AtmArpIsLocalAtmAddress(
|
|
pInterface,
|
|
ArpContents.pSrcAtmNumber,
|
|
ArpContents.SrcAtmNumberTypeLen
|
|
);
|
|
|
|
//
|
|
// Check if someone else is claiming to be the owner
|
|
// of "our" IP address:
|
|
//
|
|
if (SrcIPBelongsToUs && !SrcAtmBelongsToUs)
|
|
{
|
|
AADEBUGP(AAD_ERROR,
|
|
("Pkt 0x%x: src IP is ours, src ATM is bad!\n", pPktHeader));
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
pInterface->State = IF_STATUS_DOWN;
|
|
pInterface->LastChangeTime = GetTimeTicks();
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AtmArpStartRegistration(pInterface);
|
|
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if this is directed to someone else: if so, drop it.
|
|
//
|
|
|
|
//
|
|
// Check if the Target IP address is ours. A null IP address is
|
|
// acceptable (e.g. [In]ARP Request).
|
|
//
|
|
if ((ArpContents.pDstIPAddress != (PUCHAR)NULL) &&
|
|
!AtmArpIsLocalIPAddress(pInterface, ArpContents.pDstIPAddress))
|
|
{
|
|
//
|
|
// A target IP address is present, and it is not ours
|
|
//
|
|
AADEBUGP(AAD_WARNING,
|
|
("ArpPkt 0x%x has unknown target IP addr (%d.%d.%d.%d)\n",
|
|
pPktHeader,
|
|
ArpContents.pDstIPAddress[0],
|
|
ArpContents.pDstIPAddress[1],
|
|
ArpContents.pDstIPAddress[2],
|
|
ArpContents.pDstIPAddress[3]));
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If there is a Target ATM Number, check to see if it is ours.
|
|
//
|
|
if ((ArpContents.pDstAtmNumber != (PUCHAR)NULL) &&
|
|
(!AtmArpIsLocalAtmAddress(
|
|
pInterface,
|
|
ArpContents.pDstAtmNumber,
|
|
ArpContents.DstAtmNumberTypeLen))
|
|
)
|
|
{
|
|
//
|
|
// A target ATM number is present, and it is not ours
|
|
//
|
|
AADEBUGP(AAD_WARNING,
|
|
("ArpPkt 0x%x has unknown target ATM addr (0x%x, 0x%x)\n",
|
|
pPktHeader,
|
|
ArpContents.DstAtmNumberTypeLen,
|
|
ArpContents.pDstAtmNumber));
|
|
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Handle the various Op types
|
|
//
|
|
switch (NET_SHORT(pArpHeader->op))
|
|
{
|
|
case AA_PKT_OP_TYPE_ARP_REQUEST:
|
|
AtmArpHandleARPRequest(
|
|
pVc,
|
|
pInterface,
|
|
pArpHeader,
|
|
&ArpContents
|
|
);
|
|
break;
|
|
|
|
case AA_PKT_OP_TYPE_ARP_REPLY:
|
|
AtmArpHandleARPReply(
|
|
pVc,
|
|
pInterface,
|
|
pArpHeader,
|
|
&ArpContents,
|
|
SrcIPBelongsToUs,
|
|
SrcAtmBelongsToUs
|
|
);
|
|
break;
|
|
|
|
case AA_PKT_OP_TYPE_ARP_NAK:
|
|
AtmArpHandleARPNAK(
|
|
pVc,
|
|
pInterface,
|
|
pArpHeader,
|
|
&ArpContents
|
|
);
|
|
break;
|
|
|
|
case AA_PKT_OP_TYPE_INARP_REQUEST:
|
|
AtmArpHandleInARPRequest(
|
|
pVc,
|
|
pInterface,
|
|
pArpHeader,
|
|
&ArpContents
|
|
);
|
|
break;
|
|
|
|
case AA_PKT_OP_TYPE_INARP_REPLY:
|
|
AtmArpHandleInARPReply(
|
|
pVc,
|
|
pInterface,
|
|
pArpHeader,
|
|
&ArpContents
|
|
);
|
|
break;
|
|
|
|
default:
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleARPPkt: IF 0x%x, pArpHdr 0x%x, Op %d not known\n",
|
|
pInterface, pArpHeader, NET_SHORT(pArpHeader->op)));
|
|
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleARPRequest(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PAA_ARP_PKT_HEADER pArpHeader,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a received ATMARP Request. All we need to do is send
|
|
an ATMARP Reply, since the calling routine has already verified
|
|
that the Target IP address is ours.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to VC on which the request arrived
|
|
pInterface - Pointer to ATMARP Interface containing this VC
|
|
pArpHeader - Pointer to ARP Header for this packet
|
|
pArpContents - Parsed contents of received ARP Request packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Temp locations used for swapping fields
|
|
//
|
|
UCHAR UNALIGNED * pAddress;
|
|
UCHAR Length;
|
|
//
|
|
// ARP Reply packet
|
|
//
|
|
PNDIS_PACKET pNdisPacket;
|
|
PUCHAR pArpPacket;
|
|
|
|
//
|
|
// Swap source and target addresses, and fill in our ATM info
|
|
// in the source ATM addresses fields.
|
|
//
|
|
|
|
//
|
|
// IP Addresses
|
|
//
|
|
pAddress = pArpContents->pSrcIPAddress;
|
|
pArpContents->pSrcIPAddress = pArpContents->pDstIPAddress;
|
|
pArpContents->pDstIPAddress = pAddress;
|
|
|
|
//
|
|
// ATM Numbers: set the target ATM number to the source ATM
|
|
// number, but set the source ATM number to the local ATM
|
|
// address.
|
|
//
|
|
pArpContents->pDstAtmNumber = pArpContents->pSrcAtmNumber;
|
|
pArpContents->DstAtmNumberTypeLen = pArpContents->SrcAtmNumberTypeLen;
|
|
pArpContents->pSrcAtmNumber = (pInterface->LocalAtmAddress.Address);
|
|
pArpContents->SrcAtmNumberTypeLen =
|
|
AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress));
|
|
|
|
//
|
|
// ATM Subaddresses
|
|
//
|
|
pArpContents->pDstAtmSubaddress = pArpContents->pSrcAtmSubaddress;
|
|
pArpContents->DstAtmSubaddrTypeLen = pArpContents->SrcAtmSubaddrTypeLen;
|
|
pArpContents->pSrcAtmSubaddress = NULL;
|
|
pArpContents->SrcAtmSubaddrTypeLen = 0;
|
|
|
|
//
|
|
// Build the ARP Reply packet
|
|
//
|
|
pNdisPacket = AtmArpBuildARPPacket(
|
|
AA_PKT_OP_TYPE_ARP_REPLY,
|
|
pInterface,
|
|
&pArpPacket,
|
|
pArpContents
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// And send it off. Since we are in the context of a receive
|
|
// indication on this VC, we can safely access the VC now.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
AtmArpSendPacketOnVc(pVc, pNdisPacket);
|
|
//
|
|
// The VC lock is released by SendPacketOnVc
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleARPReply(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PAA_ARP_PKT_HEADER pArpHeader,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents,
|
|
IN BOOLEAN SrcIPAddressIsOurs,
|
|
IN BOOLEAN SrcAtmAddressIsOurs
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a received ATMARP Reply packet. There are two major
|
|
cases here:
|
|
(1) We were trying to register one of our IP addresses with
|
|
the server.
|
|
(2) We were trying to resolve a remote IP address.
|
|
|
|
In case (1), if we just registered the first of possibly many
|
|
IP addresses assigned to this interface, we register all the other
|
|
IP addresses.
|
|
|
|
In case (2), we set up an IP to ATM mapping and initiate a connection
|
|
if necessary.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to VC on which the reply arrived
|
|
pInterface - Pointer to ATMARP Interface containing this VC
|
|
pArpHeader - Pointer to ARP Header for this packet
|
|
pArpContents - Parsed contents of received ARP Request packet
|
|
SrcIPAddressIsOurs - The source IP address is one of ours
|
|
SrcAtmAddressIsOurs - The source ATM info is ours.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN TimerWasRunning;
|
|
BOOLEAN IsFirstRegistration;
|
|
PIP_ADDRESS_ENTRY pIPAddressEntry;
|
|
ULONG rc; // Ref Count
|
|
|
|
AADEBUGP(AAD_LOUD,
|
|
("Handle ARP Reply: pVc 0x%x, pIf 0x%x, IF Flags 0x%x, OurIP %d, OurATM %d\n",
|
|
pVc, pInterface, pInterface->Flags, SrcIPAddressIsOurs, SrcAtmAddressIsOurs));
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERING))
|
|
{
|
|
//
|
|
// We just completed registering with the server. Since we don't
|
|
// send ARP requests to resolve any other addresses while we
|
|
// are registering, the Source IP address must be ours.
|
|
//
|
|
|
|
//
|
|
// Stop the Registration timer
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pInterface->Timer), pInterface);
|
|
AA_ASSERT(TimerWasRunning == TRUE);
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AtmArpDereferenceInterface(pInterface); // Timer reference
|
|
AA_ASSERT(rc > 0);
|
|
}
|
|
//
|
|
// We have already verified that the Target addresses are ours.
|
|
// Check that the source addresses are ours, too.
|
|
//
|
|
if (!SrcIPAddressIsOurs || !SrcAtmAddressIsOurs)
|
|
{
|
|
//
|
|
// Registration failure. Start recovery.
|
|
//
|
|
AtmArpHandleServerRegistrationFailure(pInterface, pVc);
|
|
//
|
|
// IF lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We registered an IP address successfully!
|
|
//
|
|
// Find the entry for the IP Address that we have registered,
|
|
// and mark it as registered.
|
|
//
|
|
pIPAddressEntry = &(pInterface->LocalIPAddress);
|
|
while (*((IP_ADDRESS UNALIGNED *)(pArpContents->pSrcIPAddress))
|
|
!= pIPAddressEntry->IPAddress)
|
|
{
|
|
AA_ASSERT(pIPAddressEntry->pNext != (PIP_ADDRESS_ENTRY)NULL);
|
|
pIPAddressEntry = pIPAddressEntry->pNext;
|
|
}
|
|
pIPAddressEntry->IsRegistered = TRUE;
|
|
|
|
IsFirstRegistration = pIPAddressEntry->IsFirstRegistration;
|
|
pIPAddressEntry->IsFirstRegistration = FALSE;
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("**** Registered IP Addr: %d.%d.%d.%d on IF 0x%x\n",
|
|
((PUCHAR)&(pIPAddressEntry->IPAddress))[0],
|
|
((PUCHAR)&(pIPAddressEntry->IPAddress))[1],
|
|
((PUCHAR)&(pIPAddressEntry->IPAddress))[2],
|
|
((PUCHAR)&(pIPAddressEntry->IPAddress))[3],
|
|
pInterface));
|
|
|
|
AA_SET_FLAG(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERED);
|
|
|
|
pInterface->State = IF_STATUS_UP;
|
|
pInterface->LastChangeTime = GetTimeTicks();
|
|
|
|
//
|
|
// Start the Server refresh timer so that we send our ARP info
|
|
// to the server every so often (default = 15 minutes).
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pInterface->Timer),
|
|
AtmArpServerRefreshTimeout,
|
|
pInterface->ServerRefreshTimeout,
|
|
(PVOID)pInterface // Context
|
|
);
|
|
|
|
AtmArpReferenceInterface(pInterface); // Timer reference
|
|
|
|
//
|
|
// If we have any more addresses to register, do so now.
|
|
//
|
|
AtmArpRegisterOtherIPAddresses(pInterface);
|
|
//
|
|
// IF Lock is freed in the above
|
|
//
|
|
#ifdef ATMARP_WMI
|
|
if (IsFirstRegistration)
|
|
{
|
|
//
|
|
// Send a WMI event, which carries the list of IP Addresses
|
|
// registered on this IF. We do this only if this is a new
|
|
// IP address.
|
|
//
|
|
AtmArpWmiSendTCIfIndication(
|
|
pInterface,
|
|
AAGID_QOS_TC_INTERFACE_UP_INDICATION,
|
|
0
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Resolved an IP to ATM address
|
|
//
|
|
AADEBUGP(AAD_INFO,
|
|
("ARP Reply: Resolved IP Addr: %d.%d.%d.%d\n",
|
|
((PUCHAR)(pArpContents->pSrcIPAddress))[0],
|
|
((PUCHAR)(pArpContents->pSrcIPAddress))[1],
|
|
((PUCHAR)(pArpContents->pSrcIPAddress))[2],
|
|
((PUCHAR)(pArpContents->pSrcIPAddress))[3]
|
|
));
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
(VOID)AtmArpLearnIPToAtm(
|
|
pInterface,
|
|
(IP_ADDRESS *)pArpContents->pSrcIPAddress,
|
|
pArpContents->SrcAtmNumberTypeLen,
|
|
pArpContents->pSrcAtmNumber,
|
|
pArpContents->SrcAtmSubaddrTypeLen,
|
|
pArpContents->pSrcAtmSubaddress,
|
|
FALSE // Not a static entry
|
|
);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleARPNAK(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PAA_ARP_PKT_HEADER pArpHeader,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a received ARP-NAK packet. If this is in response to
|
|
an ARP Request we had sent to register ourselves, then we close
|
|
the VC to this ARP server, and try the next server in our list of
|
|
servers, after waiting for a while.
|
|
|
|
If we were trying to resolve a remote IP address, then we mark
|
|
the ARP IP entry corresponding to this IP address as having
|
|
received a NAK, and free any packets queued on this. We also make
|
|
a timestamp on the Entry so that we don't send another ARP Request
|
|
for the same IP address very soon.
|
|
|
|
Arguments:
|
|
pVc - Pointer to VC on which the NAK arrived
|
|
pInterface - Pointer to ATMARP Interface containing this VC
|
|
pArpHeader - Pointer to ARP Header for this packet
|
|
pArpContents - Parsed contents of received ARP Request packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN TimerWasRunning;
|
|
ULONG rc; // Ref Count
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
PNDIS_PACKET PacketList; // Packets queued for sending
|
|
#if !BINARY_COMPATIBLE
|
|
#ifdef CUBDD
|
|
SINGLE_LIST_ENTRY PendingIrpList;
|
|
#endif // CUBDD
|
|
#endif // !BINARY_COMPATIBLE
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERING))
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Rcvd ARP NAK while registering: pIf 0x%x\n", pInterface));
|
|
|
|
//
|
|
// Registration was in progress, and it failed. Start recovery.
|
|
//
|
|
AtmArpHandleServerRegistrationFailure(pInterface, pVc);
|
|
//
|
|
// IF lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We were trying to resolve an IP address. Get the Address
|
|
// IP Entry corresponding to this IP address.
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
pIpEntry = AtmArpSearchForIPAddress(
|
|
pInterface,
|
|
(IP_ADDRESS *)pArpContents->pSrcIPAddress,
|
|
IE_REFTYPE_TMP,
|
|
FALSE, // this isn't multicast/broadcast
|
|
FALSE // Don't create a new one
|
|
);
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AADEBUGP(AAD_INFO,
|
|
("Rcvd ARP NAK: pIf 0x%x, IP addr %d:%d:%d:%d\n",
|
|
pInterface,
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[0],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[1],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[2],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[3]));
|
|
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
//
|
|
// AtmArpSerchForIPAddress addrefd pIpEntry for us -- we deref it
|
|
// here now that we've locked it.
|
|
//
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP);
|
|
|
|
if (rc > 0)
|
|
{
|
|
#if !BINARY_COMPATIBLE
|
|
#ifdef CUBDD
|
|
//
|
|
// Take out the list of pending IRPs on this IP Entry.
|
|
//
|
|
PendingIrpList = pIpEntry->PendingIrpList;
|
|
pIpEntry->PendingIrpList.Next = (PSINGLE_LIST_ENTRY)NULL;
|
|
#endif // CUBDD
|
|
#endif // !BINARY_COMPATIBLE
|
|
|
|
//
|
|
// Take out all packets queued on this entry
|
|
//
|
|
PacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
//
|
|
// The Address resolution timer must be running on this Entry;
|
|
// stop it.
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer reference
|
|
}
|
|
else
|
|
{
|
|
rc = pIpEntry->RefCount;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Continue only if the IP Entry hasn't gone away
|
|
//
|
|
if (rc > 0)
|
|
{
|
|
//
|
|
// Set the IP entry's state so that we don't send any
|
|
// address resolution traffic for this IP address for
|
|
// some time.
|
|
//
|
|
AA_SET_FLAG(pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_SEEN_NAK);
|
|
|
|
//
|
|
// Start a NAK Delay timer: until this expires, we won't
|
|
// send any ARP requests for this IP address. This makes
|
|
// sure that we don't keep pounding on the server with
|
|
// an unresolvable IP address.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpNakDelayTimeout,
|
|
pInterface->MinWaitAfterNak,
|
|
(PVOID)pIpEntry // Context
|
|
);
|
|
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
|
|
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
// else the IP Entry lock would have been released.
|
|
|
|
|
|
//
|
|
// Free any packets that were queued up.
|
|
//
|
|
if (PacketList != (PNDIS_PACKET)NULL)
|
|
{
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
PacketList,
|
|
FALSE // No headers on these
|
|
);
|
|
}
|
|
#if !BINARY_COMPATIBLE
|
|
#ifdef CUBDD
|
|
AtmArpCompleteArpIrpList(
|
|
PendingIrpList,
|
|
(PATM_ADDRESS)NULL
|
|
);
|
|
#endif // CUBDD
|
|
#endif // !BINARY_COMPATIBLE
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No IP Address Entry matching the IP address being
|
|
// ARP'ed for. Nothing to be done in this case.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleInARPRequest(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PAA_ARP_PKT_HEADER pArpHeader,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an InARP Request. We send back an InARP Reply packet
|
|
with our address information.
|
|
|
|
In case this is a PVC we were trying to resolve, it is possible
|
|
that we are waiting for an InARP Reply ourselves, and the remote
|
|
station came up only now. To speed up the resolution process,
|
|
we restart the InARP Wait timeout so that it expires soon, causing
|
|
another InARP Request to be sent.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to VC on which the request arrived
|
|
pInterface - Pointer to ATMARP Interface containing this VC
|
|
pArpHeader - Pointer to ARP Header for this packet
|
|
pArpContents - Parsed contents of received ARP Request packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Temp locations used for swapping fields
|
|
//
|
|
UCHAR UNALIGNED * pAddress;
|
|
UCHAR Length;
|
|
//
|
|
// ARP Reply packet
|
|
//
|
|
PNDIS_PACKET pNdisPacket;
|
|
PUCHAR pArpPacket;
|
|
|
|
//
|
|
// Copy the Source address (IP+ATM) info into the Target address
|
|
// fields, and fill in the Source info fields with our IP+ATM info.
|
|
//
|
|
|
|
//
|
|
// IP Addresses:
|
|
//
|
|
pArpContents->pDstIPAddress = pArpContents->pSrcIPAddress;
|
|
pArpContents->pSrcIPAddress = (PUCHAR)&(pInterface->LocalIPAddress.IPAddress);
|
|
|
|
//
|
|
// ATM Numbers: set the target ATM number to the source ATM
|
|
// number, but set the source ATM number to the local ATM
|
|
// address.
|
|
//
|
|
pArpContents->pDstAtmNumber = pArpContents->pSrcAtmNumber;
|
|
pArpContents->DstAtmNumberTypeLen = pArpContents->SrcAtmNumberTypeLen;
|
|
pArpContents->pSrcAtmNumber = (pInterface->LocalAtmAddress.Address);
|
|
pArpContents->SrcAtmNumberTypeLen =
|
|
AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(&(pInterface->LocalAtmAddress));
|
|
|
|
//
|
|
// ATM Subaddresses
|
|
//
|
|
pArpContents->pDstAtmSubaddress = pArpContents->pSrcAtmSubaddress;
|
|
pArpContents->DstAtmSubaddrTypeLen = pArpContents->SrcAtmSubaddrTypeLen;
|
|
pArpContents->pSrcAtmSubaddress = NULL;
|
|
pArpContents->SrcAtmSubaddrTypeLen = 0;
|
|
|
|
//
|
|
// Build the InARP Reply packet
|
|
//
|
|
pNdisPacket = AtmArpBuildARPPacket(
|
|
AA_PKT_OP_TYPE_INARP_REPLY,
|
|
pInterface,
|
|
&pArpPacket,
|
|
pArpContents
|
|
);
|
|
|
|
if (pNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Before we send it off, check if this is a PVC being InARP'ed.
|
|
// If so, restart the InARP Wait timer so that it expires soon.
|
|
//
|
|
// It is also possible that this PVC was once resolved, but
|
|
// the remote end had gone away long enough for us to age out
|
|
// the corresponding IP entry. This packet might be due to the
|
|
// remote end coming back up. Start off an Inverse ARP operation
|
|
// to get our end of the PVC re-resolved.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_TYPE_MASK,
|
|
AA_VC_TYPE_PVC) &&
|
|
|
|
(AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_ARP_STATE_MASK,
|
|
AA_VC_INARP_IN_PROGRESS) ||
|
|
|
|
((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) &&
|
|
(pVc->pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY))))
|
|
{
|
|
BOOLEAN TimerWasRunning;
|
|
|
|
#if DBG
|
|
if ((pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY) &&
|
|
(pVc->pAtmEntry->pIpEntryList == NULL_PATMARP_IP_ENTRY))
|
|
{
|
|
AADEBUGP(AAD_LOUD,
|
|
("InARPReq: PVC %p, AtmEntry %p has NULL IP Entry, will InARP again!\n",
|
|
pVc, pVc->pAtmEntry));
|
|
}
|
|
#endif
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_ARP_STATE_MASK,
|
|
AA_VC_INARP_IN_PROGRESS);
|
|
|
|
//
|
|
// Stop the currently running InARP Wait timer
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pVc->Timer), pInterface);
|
|
|
|
//
|
|
// Start it again, to fire in 1 second
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pVc->Timer),
|
|
AtmArpPVCInARPWaitTimeout,
|
|
1,
|
|
(PVOID)pVc // Context
|
|
);
|
|
|
|
if (!TimerWasRunning)
|
|
{
|
|
AtmArpReferenceVc(pVc); // Timer reference
|
|
}
|
|
}
|
|
|
|
AtmArpSendPacketOnVc(pVc, pNdisPacket);
|
|
//
|
|
// The VC lock is released by SendPacketOnVc
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpHandleInARPReply(
|
|
IN PATMARP_VC pVc,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PAA_ARP_PKT_HEADER pArpHeader,
|
|
IN PAA_ARP_PKT_CONTENTS pArpContents
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an InARP Reply packet, which should be a response to an InARP
|
|
Request we sent earlier.
|
|
|
|
There are two circumstances under which we send InARP Requests:
|
|
(1) To obtain the addresses at the other end of a PVC.
|
|
(2) In the process of revalidating an IP Address, if we aren't able
|
|
to contact the server AND a VC exists to this IP address, we send
|
|
an InARP Request to revalidate the IP entry.
|
|
|
|
In Case (1), we link the PVC to an ATM Address Entry. In Case (2),
|
|
we mark the IP entry for this VC as being "resolved", and start
|
|
data transfer to this IP address.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC on which this packet arrived
|
|
pInterface - Pointer to ATMARP Interface
|
|
pArpHeader - Pointer to ARP Header for this packet
|
|
pArpContents - Parsed contents of received ARP Request packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ATM_ENTRY pAtmEntry; // ATM entry to which this VC is linked
|
|
PATMARP_IP_ENTRY pIpEntry; // IP address entry
|
|
BOOLEAN TimerWasRunning;
|
|
PATMARP_VC * ppVc; // Used to unlink VC from unresolved list
|
|
ULONG rc; // Ref Count
|
|
PNDIS_PACKET PacketList; // Packets queued for sending
|
|
BOOLEAN IsBroadcast; // Is the IP Addr a broadcast/Class D addr?
|
|
|
|
|
|
if (pArpContents->pSrcIPAddress == NULL)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("HandleInARPReply: IF %x, Null source address, discarding pkt\n", pInterface));
|
|
return;
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("HandleInARPReply: IF %x, IP addr %d.%d.%d.%d\n",
|
|
pInterface,
|
|
((PUCHAR)pArpContents->pSrcIPAddress)[0],
|
|
((PUCHAR)pArpContents->pSrcIPAddress)[1],
|
|
((PUCHAR)pArpContents->pSrcIPAddress)[2],
|
|
((PUCHAR)pArpContents->pSrcIPAddress)[3]));
|
|
|
|
//
|
|
// Update our ARP cache with this information (regardless of whether
|
|
// this is a PVC or SVC).
|
|
//
|
|
pIpEntry = AtmArpLearnIPToAtm(
|
|
pInterface,
|
|
(PIP_ADDRESS)pArpContents->pSrcIPAddress,
|
|
pArpContents->SrcAtmNumberTypeLen,
|
|
pArpContents->pSrcAtmNumber,
|
|
pArpContents->SrcAtmSubaddrTypeLen,
|
|
pArpContents->pSrcAtmSubaddress,
|
|
FALSE // Not a static entry
|
|
);
|
|
|
|
//
|
|
// Acquire the locks that we need, in an ordered fashion...
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
|
|
pAtmEntry = pIpEntry->pAtmEntry;
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AA_ACQUIRE_AE_LOCK_DPC(pAtmEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAtmEntry = NULL_PATMARP_ATM_ENTRY;
|
|
}
|
|
|
|
AA_ACQUIRE_VC_LOCK_DPC(pVc);
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pVc->Flags,
|
|
AA_VC_TYPE_MASK,
|
|
AA_VC_TYPE_PVC) &&
|
|
(pVc->pAtmEntry == NULL_PATMARP_ATM_ENTRY) )
|
|
{
|
|
//
|
|
// This is an unresolved PVC, whose remote address info
|
|
// we were trying to InARP for.
|
|
//
|
|
|
|
//
|
|
// Stop the InARP Wait timer running on this VC
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pVc->Timer), pInterface);
|
|
AA_ASSERT(TimerWasRunning == TRUE);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AtmArpDereferenceVc(pVc); // Timer reference
|
|
}
|
|
else
|
|
{
|
|
rc = pVc->RefCount;
|
|
}
|
|
|
|
//
|
|
// Do the rest only if the VC hasn't gone away.
|
|
//
|
|
if (rc != 0)
|
|
{
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_ARP_STATE_MASK,
|
|
AA_VC_ARP_STATE_IDLE);
|
|
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
//
|
|
// We are all set now. Take the VC out of the list of
|
|
// unresolved VCs on this Interface, and put it in the
|
|
// list of VCs attached to this ATM Entry.
|
|
//
|
|
// NOTE: we don't dereference the VC because we are just
|
|
// moving it from one list (Unresolved VCs) to another
|
|
// (ATM Entry's VC list).
|
|
//
|
|
ppVc = &(pInterface->pUnresolvedVcs);
|
|
while (*ppVc != pVc)
|
|
{
|
|
AA_ASSERT(*ppVc != NULL_PATMARP_VC);
|
|
ppVc = &((*ppVc)->pNextVc);
|
|
}
|
|
*ppVc = pVc->pNextVc;
|
|
|
|
AtmArpLinkVcToAtmEntry(pVc, pAtmEntry);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No matching ATM Entry.
|
|
//
|
|
// We are really low on resources if we are here.
|
|
// Start the InARP Wait timer; when it fires, we'll try to
|
|
// send another InARP Request to resolve this VC.
|
|
//
|
|
AADEBUGP(AAD_FATAL,
|
|
("HandleInARPReply: no matching ATM entry: pInterface %x, pVc %x, pIpEntry %x\n",
|
|
pInterface,
|
|
pVc,
|
|
pIpEntry));
|
|
|
|
AA_ASSERT(FALSE);
|
|
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pVc->Timer),
|
|
AtmArpPVCInARPWaitTimeout,
|
|
pInterface->InARPWaitTimeout,
|
|
(PVOID)pVc // Context
|
|
);
|
|
|
|
AtmArpReferenceVc(pVc); // InARP Timer ref
|
|
|
|
}
|
|
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The VC went away while we were InARPing
|
|
//
|
|
}
|
|
|
|
//
|
|
// Release any locks that we still hold.
|
|
//
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
}
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
}
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Revalidating on a PVC/SVC: case (2) in Routine Description
|
|
//
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_ARP_STATE_MASK,
|
|
AA_VC_ARP_STATE_IDLE);
|
|
|
|
//
|
|
// Stop the INARP timer, if it is running.
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&pVc->Timer, pInterface);
|
|
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AtmArpDereferenceVc(pVc); // InARP reply: stop InARP timer
|
|
}
|
|
else
|
|
{
|
|
rc = pVc->RefCount;
|
|
}
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_VC_LOCK_DPC(pVc);
|
|
}
|
|
|
|
//
|
|
// Update the IP Entry we were revaldating.
|
|
//
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
//
|
|
// Stop the InARP timer running here
|
|
//
|
|
TimerWasRunning = AtmArpStopTimer(&(pIpEntry->Timer), pInterface);
|
|
if (TimerWasRunning)
|
|
{
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TIMER); // timer ref
|
|
}
|
|
else
|
|
{
|
|
rc = pIpEntry->RefCount;
|
|
}
|
|
|
|
//
|
|
// Continue only if the IP Entry hasn't gone away.
|
|
//
|
|
if (rc > 0)
|
|
{
|
|
//
|
|
// Update its state
|
|
//
|
|
AA_SET_FLAG(
|
|
pIpEntry->Flags,
|
|
AA_IP_ENTRY_STATE_MASK,
|
|
AA_IP_ENTRY_RESOLVED
|
|
);
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("InARP Reply: Revalidated pIpEntry 0x%x, IP Addr: %d.%d.%d.%d\n",
|
|
pIpEntry,
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[0],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[1],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[2],
|
|
((PUCHAR)(&(pIpEntry->IPAddress)))[3]
|
|
));
|
|
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
|
|
//
|
|
// Start the Aging timer.
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpIPEntryAgingTimeout,
|
|
pInterface->ARPEntryAgingTimeout,
|
|
(PVOID)pIpEntry
|
|
);
|
|
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
|
|
|
|
//
|
|
// Take out the list of pending packets on this Entry
|
|
//
|
|
PacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
IsBroadcast = AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_ADDR_TYPE_MASK,
|
|
AA_IP_ENTRY_ADDR_TYPE_NUCAST);
|
|
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
//
|
|
// Send out all these packets
|
|
//
|
|
AtmArpSendPacketListOnAtmEntry(
|
|
pInterface,
|
|
pAtmEntry,
|
|
PacketList,
|
|
IsBroadcast
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the IP Entry is gone
|
|
//
|
|
AA_RELEASE_AE_LOCK_DPC(pAtmEntry);
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No matching IP Entry
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|