You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1228 lines
36 KiB
1228 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
arp.c
|
|
|
|
Abstract:
|
|
|
|
ARP1394 ARP request/response handling code.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
josephj 03-28-99 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include <precomp.h>
|
|
|
|
//
|
|
// File-specific debugging defaults.
|
|
//
|
|
#define TM_CURRENT TM_ARP
|
|
|
|
// #define ARP_DEFAULT_MAXREC 0xD
|
|
#define ARP_DEFAULT_MAXREC 0x8
|
|
|
|
|
|
#define LOGSTATS_SuccessfulArpQueries(_pIF) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.arpcache.SuccessfulQueries))
|
|
#define LOGSTATS_FailedArpQueried(_pIF) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.arpcache.FailedQueries))
|
|
#define LOGSTATS_TotalQueries(_pIF) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.arpcache.TotalQueries))
|
|
#define LOGSTATS_TotalArpResponses(_pIF) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.arpcache.TotalResponses))
|
|
|
|
//=========================================================================
|
|
// L O C A L P R O T O T Y P E S
|
|
//=========================================================================
|
|
|
|
NDIS_STATUS
|
|
arpSendArpRequest(
|
|
PARPCB_REMOTE_IP pRemoteIp,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpProcessArpRequest(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
PIP1394_ARP_PKT_INFO pPktInfo,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpProcessArpResponse(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
PIP1394_ARP_PKT_INFO pPktInfo,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpTryAbortResolutionTask(
|
|
PARPCB_REMOTE_IP pRemoteIp,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
NDIS_STATUS
|
|
arpParseArpPkt(
|
|
IN PIP1394_ARP_PKT pArpPkt,
|
|
IN UINT cbBufferSize,
|
|
OUT PIP1394_ARP_PKT_INFO pPktInfo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Parse the contents of IP/1394 ARP packet data starting at
|
|
pArpPkt. Place the results into pPktInfo.
|
|
|
|
Arguments:
|
|
|
|
pArpPkt - Contains the unaligned contents of an ip/1394 ARP Pkt.
|
|
pPktInfo - Unitialized structure to be filled with the parsed contents of the
|
|
pkt.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_FAILURE if the parse failed (typically because of invalid pkt
|
|
contents.)
|
|
NDIS_STATUS_SUCCESS on successful parsing.
|
|
|
|
--*/
|
|
{
|
|
ENTER("arpParseArpPkt", 0x20098dc0)
|
|
NDIS_STATUS Status;
|
|
DBGSTMT(CHAR *szError = "General failure";)
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
do
|
|
{
|
|
UINT SenderMaxRec;
|
|
UINT OpCode;
|
|
|
|
// Verify length.
|
|
//
|
|
if (cbBufferSize < sizeof(*pArpPkt))
|
|
{
|
|
DBGSTMT(szError = "pkt size too small";)
|
|
break;
|
|
}
|
|
|
|
// Verify constant fields.
|
|
//
|
|
|
|
#if 0 // Reserved is no "NodeId, which contains the nodeid of the sending
|
|
// node, if known (0 otherwise).
|
|
if (pArpPkt->header.Reserved != 0)
|
|
{
|
|
DBGSTMT(szError = "header.Reserved!=0";)
|
|
break;
|
|
}
|
|
#endif // 0
|
|
|
|
if (N2H_USHORT(pArpPkt->header.EtherType) != NIC1394_ETHERTYPE_ARP)
|
|
{
|
|
DBGSTMT(szError = "header.EtherType!=ARP";)
|
|
break;
|
|
}
|
|
|
|
if (N2H_USHORT(pArpPkt->hardware_type) != IP1394_HARDWARE_TYPE)
|
|
{
|
|
DBGSTMT(szError = "Invalid hardware_type";)
|
|
break;
|
|
}
|
|
|
|
if (N2H_USHORT(pArpPkt->protocol_type) != IP1394_PROTOCOL_TYPE)
|
|
{
|
|
DBGSTMT(szError = "Invalid protocol_type";)
|
|
break;
|
|
}
|
|
|
|
if (pArpPkt->hw_addr_len != IP1394_HW_ADDR_LEN)
|
|
{
|
|
DBGSTMT(szError = "Invalid hw_addr_len";)
|
|
break;
|
|
}
|
|
|
|
|
|
if (pArpPkt->IP_addr_len != sizeof(ULONG))
|
|
{
|
|
DBGSTMT(szError = "Invalid IP_addr_len";)
|
|
break;
|
|
}
|
|
|
|
|
|
// Opcode
|
|
//
|
|
{
|
|
OpCode = N2H_USHORT(pArpPkt->opcode);
|
|
|
|
if ( OpCode != IP1394_ARP_REQUEST
|
|
&& OpCode != IP1394_ARP_RESPONSE)
|
|
{
|
|
DBGSTMT(szError = "Invalid opcode";)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Max send block size...
|
|
//
|
|
{
|
|
UINT maxrec = pArpPkt->sender_maxrec;
|
|
|
|
if (IP1394_IS_VALID_MAXREC(maxrec))
|
|
{
|
|
SenderMaxRec = maxrec;
|
|
}
|
|
else
|
|
{
|
|
DBGSTMT(szError = "Invalid sender_maxrec";)
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pkt appears valid, let's fill out the parsed information....
|
|
//
|
|
|
|
ARP_ZEROSTRUCT(pPktInfo);
|
|
|
|
pPktInfo->OpCode = OpCode;
|
|
pPktInfo->SenderMaxRec = SenderMaxRec;
|
|
|
|
// Speed code...
|
|
//
|
|
{
|
|
UINT SenderMaxSpeedCode;
|
|
|
|
//
|
|
// We rely on the fact that the RFC speed code constants
|
|
// (IP1394_SSPD_*) are identical to the corresponding
|
|
// constants defined in 1394.h (SCODE_*). Let's ensure this...
|
|
//
|
|
|
|
#if (IP1394_SSPD_S100 != SCODE_100_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
#if (IP1394_SSPD_S200 != SCODE_200_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
#if (IP1394_SSPD_S400 != SCODE_400_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
#if (IP1394_SSPD_S800 != SCODE_800_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
#if (IP1394_SSPD_S1600 != SCODE_1600_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
#if (IP1394_SSPD_S3200 != SCODE_3200_RATE)
|
|
#error "RFC Speed code out of sync with 1394.h"
|
|
#endif
|
|
|
|
SenderMaxSpeedCode = pArpPkt->sspd;
|
|
|
|
if (SenderMaxSpeedCode > SCODE_3200_RATE)
|
|
{
|
|
//
|
|
// This is either a bad value, or a rate higher than we know about.
|
|
// We can't distinguish between the two, so we just set the speed to
|
|
// the highest we know about.
|
|
// TODO: 3/28/99 JosephJ not sure if this is the correct
|
|
// behaviour -- maybe we should fail -- I'll be asking the
|
|
// working group to rule on this shortly...
|
|
//
|
|
SenderMaxSpeedCode = SCODE_3200_RATE;
|
|
}
|
|
|
|
pPktInfo->SenderMaxSpeedCode = SenderMaxSpeedCode;
|
|
}
|
|
|
|
|
|
// Unique ID -- we also need to swap DWORDS to convert from network byte
|
|
// order.
|
|
//
|
|
{
|
|
PUINT puSrc = (PUINT) & (pArpPkt->sender_unique_ID);
|
|
PUINT puDest = (PUINT) & (pPktInfo->SenderHwAddr.UniqueID);
|
|
// pPktInfo->SenderHwAddr.UniqueID = pArpPkt->sender_unique_ID;
|
|
puDest[0] = puSrc[1];
|
|
puDest[1] = puSrc[0];
|
|
}
|
|
|
|
pPktInfo->SenderHwAddr.Off_Low =H2N_ULONG(pArpPkt->sender_unicast_FIFO_lo);
|
|
pPktInfo->SenderHwAddr.Off_High =H2N_USHORT(pArpPkt->sender_unicast_FIFO_hi);
|
|
|
|
// These remain network byte order...
|
|
//
|
|
pPktInfo->SenderIpAddress = (IP_ADDRESS) pArpPkt->sender_IP_address;
|
|
pPktInfo->TargetIpAddress = (IP_ADDRESS) pArpPkt->target_IP_address;
|
|
|
|
// Extract the Src Node Address
|
|
//
|
|
{
|
|
PNDIS1394_UNFRAGMENTED_HEADER pHeader = (PNDIS1394_UNFRAGMENTED_HEADER)&pArpPkt->header;
|
|
|
|
if (pHeader->u1.fHeaderHasSourceAddress == TRUE)
|
|
{
|
|
pPktInfo->SourceNodeAdddress = pHeader->u1.SourceAddress;
|
|
pPktInfo->fPktHasNodeAddress = TRUE;
|
|
}
|
|
|
|
}
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
TR_INFO(("Bad arp pkt data at 0x%p (%s)\n", pArpPkt, szError));
|
|
}
|
|
else
|
|
{
|
|
TR_INFO(("Received ARP PKT. UID=0x%I64x FIFO=0x%04lx:0x%08lx OP=%lu SIP=0x%04lx TIP=0x%04lx.\n",
|
|
pPktInfo->SenderHwAddr.UniqueID,
|
|
pPktInfo->SenderHwAddr.Off_High,
|
|
pPktInfo->SenderHwAddr.Off_Low,
|
|
pPktInfo->OpCode,
|
|
pPktInfo->SenderIpAddress,
|
|
pPktInfo->TargetIpAddress
|
|
));
|
|
|
|
}
|
|
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
arpPrepareArpPkt(
|
|
IN PIP1394_ARP_PKT_INFO pPktInfo,
|
|
// IN UINT SenderMaxRec,
|
|
OUT PIP1394_ARP_PKT pArpPkt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Use information in pArpPktInfo to prepare an arp packet starting at
|
|
pvArpPkt.
|
|
|
|
Arguments:
|
|
|
|
pPktInfo - Parsed version of the arp request/response packet.
|
|
// SenderMaxRec - max_rec value of the local host
|
|
pArpPkt - unitialized memory in which to store the packet contents.
|
|
This memory must have a min size of sizeof(*pArpPkt).
|
|
--*/
|
|
{
|
|
// UINT SenderMaxRec;
|
|
UINT OpCode;
|
|
|
|
ARP_ZEROSTRUCT(pArpPkt);
|
|
|
|
pArpPkt->header.EtherType = H2N_USHORT(NIC1394_ETHERTYPE_ARP);
|
|
pArpPkt->hardware_type = H2N_USHORT(IP1394_HARDWARE_TYPE);
|
|
pArpPkt->protocol_type = H2N_USHORT(IP1394_PROTOCOL_TYPE);
|
|
pArpPkt->hw_addr_len = (UCHAR) IP1394_HW_ADDR_LEN;
|
|
pArpPkt->IP_addr_len = (UCHAR) sizeof(ULONG);
|
|
pArpPkt->opcode = H2N_USHORT(pPktInfo->OpCode);
|
|
pArpPkt->sender_maxrec = (UCHAR) pPktInfo->SenderMaxRec;
|
|
|
|
//
|
|
// We rely on the fact that the RFC speed code constants
|
|
// (IP1394_SSPD_*) are identical to the corresponding
|
|
// constants defined in 1394.h (SCODE_*). We have a bunch of compiler-time
|
|
// checks to ensure this (see arpParseArpPkt(...)).
|
|
//
|
|
pArpPkt->sspd = (UCHAR) pPktInfo->SenderMaxSpeedCode;
|
|
|
|
// Unique ID -- we also need to swap DWORDS to convert to network byte order.
|
|
//
|
|
{
|
|
PUINT puSrc = (PUINT) & (pPktInfo->SenderHwAddr.UniqueID);
|
|
PUINT puDest = (PUINT) & (pArpPkt->sender_unique_ID);
|
|
// pArpPkt->sender_unique_ID = pPktInfo->SenderHwAddr.UniqueID;
|
|
puDest[0] = puSrc[1];
|
|
puDest[1] = puSrc[0];
|
|
}
|
|
|
|
pArpPkt->sender_unicast_FIFO_lo = N2H_ULONG(pPktInfo->SenderHwAddr.Off_Low);
|
|
pArpPkt->sender_unicast_FIFO_hi = N2H_USHORT(pPktInfo->SenderHwAddr.Off_High);
|
|
|
|
// These are already in network byte order...
|
|
//
|
|
pArpPkt->sender_IP_address = (ULONG) pPktInfo->SenderIpAddress;
|
|
pArpPkt->target_IP_address = (ULONG) pPktInfo->TargetIpAddress;
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
arpPrepareArpResponse(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PIP1394_ARP_PKT_INFO pArpRequest,
|
|
OUT PIP1394_ARP_PKT_INFO pArpResponse,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If it makes sense to do so, prepare (in pArpResponse) an arp response to
|
|
the arp request in pArpRequest.
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface control block.
|
|
pArpRequest - Parsed version of the ARP request packet.
|
|
pArpResponse - Uninitialized memory to hold the parsed version of the
|
|
ARP response packet (if there is a response).
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if the response was filled out.
|
|
Some NDIS error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
ENTER("arpPrepareArpResponse", 0x0d7e0e60)
|
|
NDIS_STATUS Status;
|
|
PARPCB_LOCAL_IP pLocalIp;
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
pLocalIp = NULL;
|
|
|
|
RM_ASSERT_OBJUNLOCKED(&pIF->Hdr, pSR);
|
|
|
|
do
|
|
{
|
|
IP_ADDRESS TargetIpAddress = pArpRequest->TargetIpAddress;
|
|
|
|
// Lookup local IP
|
|
//
|
|
Status = RM_LOOKUP_AND_LOCK_OBJECT_IN_GROUP(
|
|
&pIF->LocalIpGroup,
|
|
(PVOID) ULongToPtr (TargetIpAddress),
|
|
(RM_OBJECT_HEADER**) &pLocalIp,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pLocalIp = NULL;
|
|
break;
|
|
}
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR);
|
|
ASSERT(TargetIpAddress == pLocalIp->IpAddress);
|
|
|
|
if (ARP_LOCAL_IP_IS_UNLOADING(pLocalIp)) break;
|
|
|
|
//
|
|
// If the local IP is non-unicast, don't respond!
|
|
//
|
|
if (pLocalIp->IpAddressType != LLIP_ADDR_LOCAL)
|
|
{
|
|
TR_WARN(("Ignoring arp request for non-unicast address 0x%08lx.\n",
|
|
TargetIpAddress));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We do serve the target IP address. Let's fill out pArpResponse...
|
|
//
|
|
|
|
ARP_ZEROSTRUCT(pArpResponse);
|
|
pArpResponse->OpCode = IP1394_ARP_RESPONSE;
|
|
pArpResponse->SenderIpAddress = TargetIpAddress;
|
|
|
|
// This field is unused in the response, but we fill it anyway..
|
|
// 11/19/1999 From Kaz Honda of Sony: we should fill it with destination
|
|
// IP address (i.e. the ip address of the sender of the arp request).
|
|
// because that is analogous to what ethernet arp does. Note that
|
|
// the ip/1394 rfc says that the field should be ignored, but we do
|
|
// this anyway.
|
|
//
|
|
// pArpResponse->TargetIpAddress = TargetIpAddress;
|
|
pArpResponse->TargetIpAddress = pArpRequest->SenderIpAddress;
|
|
|
|
// Fill out adapter info..
|
|
//
|
|
{
|
|
PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF);
|
|
pArpResponse->SenderHwAddr.UniqueID = pAdapter->info.LocalUniqueID;
|
|
pArpResponse->SenderHwAddr.Off_Low = pIF->recvinfo.offset.Off_Low;
|
|
pArpResponse->SenderHwAddr.Off_High = pIF->recvinfo.offset.Off_High;
|
|
pArpResponse->SenderMaxRec= pAdapter->info.MaxRec;
|
|
pArpResponse->SenderMaxSpeedCode= pAdapter->info.MaxSpeedCode;
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (pLocalIp != NULL)
|
|
{
|
|
UNLOCKOBJ(pLocalIp, pSR);
|
|
RmTmpDereferenceObject(&pLocalIp->Hdr, pSR);
|
|
}
|
|
|
|
RM_ASSERT_OBJUNLOCKED(&pIF->Hdr, pSR);
|
|
|
|
EXIT()
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
arpTaskResolveIpAddress(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
PARPCB_REMOTE_IP pRemoteIp;
|
|
PTASK_RESOLVE_IP_ADDRESS pResolutionTask;
|
|
enum
|
|
{
|
|
PEND_ResponseTimeout
|
|
};
|
|
ENTER("TaskResolveIpAddress", 0x3dd4b434)
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
pRemoteIp = (PARPCB_REMOTE_IP) RM_PARENT_OBJECT(pTask);
|
|
pResolutionTask = (PTASK_RESOLVE_IP_ADDRESS) pTask;
|
|
|
|
switch(Code)
|
|
{
|
|
case RM_TASKOP_START:
|
|
{
|
|
DBGMARK(0x7de307cc);
|
|
//
|
|
// There should NOT be another resolution task running
|
|
// on pRemoteIp. Why? Because a resolution task is ONLY
|
|
// started in the context of a send-pkts task, and there can be
|
|
// ONLY one active send-pkts task on pRemoteIp at any one time.
|
|
//
|
|
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
if (pRemoteIp->pResolutionTask != NULL)
|
|
{
|
|
ASSERT(!"pRemoteIp->pResolutionTask != NULL");
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make ourselves the official resolution task.
|
|
//
|
|
// Although it's tempting to put pTask as entity1 and
|
|
// pTask->Hdr.szDescption as entity2 below, we specify NULL for both so
|
|
// that we can be sure that ONLY one resolution task can be active at any
|
|
// one time. TODO: modify addassoc semantics to get both advantages.
|
|
//
|
|
DBG_ADDASSOC(
|
|
&pRemoteIp->Hdr,
|
|
NULL, // Entity1
|
|
NULL, // Entity2
|
|
ARPASSOC_RESOLUTION_IF_TASK,
|
|
" Resolution task\n",
|
|
pSR
|
|
);
|
|
pRemoteIp->pResolutionTask = pTask;
|
|
pResolutionTask->RetriesLeft = 3;
|
|
|
|
// Now we do a fake suspend/resume so we move on to the next stage.
|
|
//
|
|
RmSuspendTask(pTask, PEND_ResponseTimeout, pSR);
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
RmResumeTask(pTask, NDIS_STATUS_SUCCESS, pSR);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
{
|
|
switch(RM_PEND_CODE(pTask))
|
|
{
|
|
case PEND_ResponseTimeout:
|
|
{
|
|
DBGMARK(0x3b5562e6);
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
|
|
//
|
|
// Let's see if the address is resolved and/or we're
|
|
// to abort the resolution task because perhaps pRemoteIp
|
|
// is going away.
|
|
//
|
|
|
|
if (pRemoteIp->pUnloadTask != NULL)
|
|
{
|
|
OBJLOG0(
|
|
pRemoteIp,
|
|
"Aborting address resolution because we're unloading.\n"
|
|
);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
break;
|
|
}
|
|
if (pRemoteIp->pDest != NULL)
|
|
{
|
|
LOGSTATS_SuccessfulArpQueries(IF_FROM_REMOTEIP(pRemoteIp));
|
|
OBJLOG1(
|
|
pRemoteIp,
|
|
"Resolved Ip Address; pDest = 0x%p\n",
|
|
pRemoteIp->pDest
|
|
);
|
|
ASSERT(
|
|
CHECK_REMOTEIP_RESOLVE_STATE(pRemoteIp, ARPREMOTEIP_RESOLVED)
|
|
);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We need to resolve this address..
|
|
//
|
|
|
|
if (pResolutionTask->RetriesLeft)
|
|
{
|
|
pResolutionTask->RetriesLeft--;
|
|
|
|
// Build an ARP request and send it out.
|
|
//
|
|
Status = arpSendArpRequest(pRemoteIp, pSR);
|
|
|
|
// pRemoteIp's lock is released by the above call.
|
|
//
|
|
RM_ASSERT_OBJUNLOCKED(&pRemoteIp->Hdr, pSR);
|
|
|
|
//
|
|
// We ignore the return status of the above call -- so
|
|
// whether or not the request could be sent out,
|
|
// we suspend this task for resolution-timeout seconds.
|
|
//
|
|
|
|
RmSuspendTask(pTask, PEND_ResponseTimeout, pSR);
|
|
|
|
RmResumeTaskDelayed(
|
|
pTask,
|
|
0,
|
|
ARP1394_ADDRESS_RESOLUTION_TIMEOUT,
|
|
&pResolutionTask->Timer,
|
|
pSR
|
|
);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
LOGSTATS_FailedArpQueried(IF_FROM_REMOTEIP(pRemoteIp));
|
|
// Oops -- couldn't resolve this address.
|
|
//
|
|
OBJLOG1(
|
|
pRemoteIp,
|
|
"Timed out trying to resolve address 0x%08lx\n",
|
|
pRemoteIp->IpAddress
|
|
);
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
{
|
|
//
|
|
// We are done with address resolution. Clear ourselves
|
|
// as the official address resolution task of pRemoteIp.
|
|
//
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
|
|
DBGMARK(0x6bd6d27a);
|
|
|
|
if (pRemoteIp->pResolutionTask != pTask)
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Delete the association added when setting the resolution task
|
|
//
|
|
DBG_DELASSOC(
|
|
&pRemoteIp->Hdr,
|
|
NULL,
|
|
NULL,
|
|
ARPASSOC_RESOLUTION_IF_TASK,
|
|
pSR
|
|
);
|
|
|
|
pRemoteIp->pResolutionTask = NULL;
|
|
|
|
}
|
|
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
|
|
// Propagate the status code
|
|
//
|
|
Status = (NDIS_STATUS) UserParam;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
arpSendArpRequest(
|
|
PARPCB_REMOTE_IP pRemoteIp, // LOCKIN NOLOCKOUT
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
PARP1394_INTERFACE pIF;
|
|
PNDIS_PACKET pNdisPacket;
|
|
PIP1394_ARP_PKT pPktData;
|
|
IPAddr TargetIpAddress = 0;
|
|
|
|
ENTER("arpSendArpRequest", 0xcecfc632)
|
|
RM_ASSERT_OBJLOCKED(&pRemoteIp->Hdr, pSR);
|
|
|
|
pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pRemoteIp);
|
|
|
|
DBGMARK(0xb90e9ffc);
|
|
|
|
Status = arpAllocateControlPacket(
|
|
pIF,
|
|
sizeof(IP1394_ARP_PKT),
|
|
ARP1394_PACKET_FLAGS_ARP,
|
|
&pNdisPacket,
|
|
&pPktData,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
}
|
|
else
|
|
{
|
|
IP1394_ARP_PKT_INFO PktInfo;
|
|
PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF);
|
|
|
|
//
|
|
// If we are running in bridge the Target Ip Address is stored in
|
|
// the BridgeTargetIpAddress Field. Otherwise it is in the Key.
|
|
//
|
|
ASSERT (pRemoteIp->IpAddress != 0);
|
|
|
|
// Prepare the packet.
|
|
//
|
|
PktInfo.SenderHwAddr.UniqueID = pAdapter->info.LocalUniqueID;
|
|
PktInfo.SenderHwAddr.Off_Low = pIF->recvinfo.offset.Off_Low;
|
|
PktInfo.SenderHwAddr.Off_High = pIF->recvinfo.offset.Off_High;
|
|
PktInfo.OpCode = IP1394_ARP_REQUEST;
|
|
PktInfo.SenderMaxRec = pAdapter->info.MaxRec;
|
|
PktInfo.SenderMaxSpeedCode = pAdapter->info.MaxSpeedCode;
|
|
PktInfo.TargetIpAddress = pRemoteIp->IpAddress;
|
|
PktInfo.SenderIpAddress = pIF->ip.DefaultLocalAddress;
|
|
|
|
|
|
arpPrepareArpPkt(
|
|
&PktInfo,
|
|
// ARP_DEFAULT_MAXREC, // SenderMaxRec TODO
|
|
pPktData
|
|
);
|
|
|
|
RmTmpReferenceObject(&pIF->Hdr, pSR);
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
TR_INFO(("Attempting to send ARP Req PKT. UID=0x%I64x FIFO=0x%04lx:0x%08lx OP=%lu SIP=0x%04lx TIP=0x%04lx.\n",
|
|
PktInfo.SenderHwAddr.UniqueID,
|
|
PktInfo.SenderHwAddr.Off_High,
|
|
PktInfo.SenderHwAddr.Off_Low,
|
|
PktInfo.OpCode,
|
|
PktInfo.SenderIpAddress,
|
|
PktInfo.TargetIpAddress
|
|
));
|
|
|
|
LOGSTATS_TotalQueries(pIF);
|
|
|
|
ARP_FASTREADLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
// Actually send the packet (this will silently fail and free the pkt
|
|
// if we're not in a position to send the pkt.)
|
|
//
|
|
arpSendControlPkt(
|
|
pIF, // LOCKIN NOLOCKOUT (IF send lk)
|
|
pNdisPacket,
|
|
pIF->pBroadcastDest,
|
|
pSR
|
|
);
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
RmTmpDereferenceObject(&pIF->Hdr, pSR);
|
|
}
|
|
|
|
EXIT()
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
arpSendControlPkt(
|
|
IN ARP1394_INTERFACE * pIF, // LOCKIN NOLOCKOUT (IF send lk)
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
PARPCB_DEST pDest,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
|
|
Routine Description:
|
|
|
|
Send a packet on the broadcast channel.
|
|
|
|
Arguments:
|
|
|
|
pIF - Our interface object
|
|
pNdisPacket - Packet to send
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
MYBOOL fRet;
|
|
ENTER("arpSendControlPkt", 0x2debf9b7)
|
|
|
|
DBGMARK(0xe6823818);
|
|
|
|
//
|
|
// If we can't send now, we fail.
|
|
//
|
|
if (pDest==NULL || !ARP_CAN_SEND_ON_DEST(pDest))
|
|
{
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
TR_WARN(("Couldn't send control pkt 0x%p.\n", pNdisPacket));
|
|
|
|
arpFreeControlPacket(
|
|
pIF,
|
|
pNdisPacket,
|
|
pSR
|
|
);
|
|
|
|
return; // EARLY RETURN
|
|
}
|
|
|
|
arpRefSendPkt( pNdisPacket, pDest);
|
|
|
|
// Release the IF send lock.
|
|
//
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
// Actually send the packet
|
|
//
|
|
#if ARPDBG_FAKE_SEND
|
|
arpDbgFakeNdisCoSendPackets(
|
|
pDest->VcHdr.NdisVcHandle,
|
|
&pNdisPacket,
|
|
1,
|
|
&pDest->Hdr,
|
|
&pDest->VcHdr
|
|
);
|
|
#else // !ARPDBG_FAKE_SEND
|
|
NdisCoSendPackets(
|
|
pDest->VcHdr.NdisVcHandle,
|
|
&pNdisPacket,
|
|
1
|
|
);
|
|
#endif // !ARPDBG_FAKE_SEND
|
|
|
|
EXIT()
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
arpProcessArpPkt(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
PIP1394_ARP_PKT pArpPkt,
|
|
UINT cbBufferSize
|
|
)
|
|
/*++
|
|
Process an arp packet (request OR response) from the 1394 bus.
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
IP1394_ARP_PKT_INFO PktInfo;
|
|
ENTER("arpProcessArpPkt", 0x6e81a8fa)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
DBGMARK(0x03f6830e);
|
|
|
|
Status = arpParseArpPkt(
|
|
pArpPkt,
|
|
cbBufferSize,
|
|
&PktInfo
|
|
);
|
|
|
|
|
|
if (!FAIL(Status))
|
|
{
|
|
if (PktInfo.OpCode == IP1394_ARP_REQUEST)
|
|
{
|
|
arpProcessArpRequest(pIF, &PktInfo, &sr);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(PktInfo.OpCode == IP1394_ARP_RESPONSE);
|
|
arpProcessArpResponse(pIF, &PktInfo, &sr);
|
|
}
|
|
}
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
|
|
EXIT()
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
arpProcessArpRequest(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
PIP1394_ARP_PKT_INFO pPktInfo,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
IP1394_ARP_PKT_INFO ResponsePktInfo;
|
|
NDIS_STATUS Status;
|
|
ENTER("arpProcessArpRequest", 0xd33fa61d)
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
// pStatsCmd->TotalResponses = pIF->stats.arpcache.TotalResponses;
|
|
// pStatsCmd->TotalLookups = pIF->stats.arpcache.TotalLookups;
|
|
|
|
//
|
|
// First check to see if this is an ARP that was originated by us.
|
|
//
|
|
do
|
|
{
|
|
UINT64 DestUniqueId = pPktInfo->SenderHwAddr.UniqueID;
|
|
ARP1394_ADAPTER *pAdapter = (ARP1394_ADAPTER *) RM_PARENT_OBJECT(pIF);
|
|
UINT64 LocalUniqueId = pAdapter->info.LocalUniqueID;
|
|
ARP_DEST_PARAMS DestParams;
|
|
PNDIS_PACKET pNdisPacket;
|
|
PIP1394_ARP_PKT pPktData;
|
|
|
|
|
|
//
|
|
// This arp packet was originated by this machine. Do not respond to it.
|
|
//
|
|
if (LocalUniqueId == DestUniqueId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Prepare the structure that will be used to generate the arp response.
|
|
//
|
|
|
|
Status = arpPrepareArpResponse(
|
|
pIF, // NOLOCKIN NOLOCKOUT
|
|
pPktInfo,
|
|
&ResponsePktInfo,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
ARP_ZEROSTRUCT(&DestParams);
|
|
DestParams.HwAddr.AddressType = NIC1394AddressType_FIFO;
|
|
DestParams.HwAddr.FifoAddress = pPktInfo->SenderHwAddr; // Struct copy
|
|
|
|
//
|
|
// Update our arp cache with information from the sender's portion of
|
|
// the arp request.
|
|
//
|
|
arpUpdateArpCache(
|
|
pIF,
|
|
pPktInfo->SenderIpAddress, // Remote IP Address,
|
|
NULL, // Sender's Ethernet Address
|
|
&DestParams, // Remote Destination HW Address
|
|
TRUE, // If required, create an entry for this.,
|
|
pSR
|
|
);
|
|
|
|
//
|
|
// Let's send the response!
|
|
//
|
|
|
|
Status = arpAllocateControlPacket(
|
|
pIF,
|
|
sizeof(IP1394_ARP_PKT),
|
|
ARP1394_PACKET_FLAGS_ARP,
|
|
&pNdisPacket,
|
|
&pPktData,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
LOGSTATS_TotalArpResponses(pIF);
|
|
|
|
// Prepare the packet.
|
|
//
|
|
arpPrepareArpPkt(
|
|
&ResponsePktInfo,
|
|
// ARP_DEFAULT_MAXREC, // SenderMaxRec TODO
|
|
pPktData
|
|
);
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
TR_WARN(("Attempting to send ARP Resp PKT. UID=0x%I64x FIFO=0x%04lx:0x%08lx OP=%lu SIP=0x%04lx TIP=0x%04lx.\n",
|
|
pPktInfo->SenderHwAddr.UniqueID,
|
|
pPktInfo->SenderHwAddr.Off_High,
|
|
pPktInfo->SenderHwAddr.Off_Low,
|
|
pPktInfo->OpCode,
|
|
pPktInfo->SenderIpAddress,
|
|
pPktInfo->TargetIpAddress
|
|
));
|
|
|
|
ARP_FASTREADLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
// Actually send the packet (this will silently fail and free the pkt
|
|
// if we're not in a position to send the pkt.)
|
|
//
|
|
arpSendControlPkt(
|
|
pIF, // LOCKIN NOLOCKOUT (IF send lk)
|
|
pNdisPacket,
|
|
pIF->pBroadcastDest,
|
|
pSR
|
|
);
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
}
|
|
|
|
VOID
|
|
arpProcessArpResponse(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
PIP1394_ARP_PKT_INFO pPktInfo,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
ARP_DEST_PARAMS DestParams;
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
ARP_ZEROSTRUCT(&DestParams);
|
|
|
|
DestParams.HwAddr.AddressType = NIC1394AddressType_FIFO;
|
|
DestParams.HwAddr.FifoAddress = pPktInfo->SenderHwAddr; // Struct copy
|
|
|
|
arpUpdateArpCache(
|
|
pIF,
|
|
pPktInfo->SenderIpAddress, // Remote IP Address
|
|
NULL, // Senders Mac Address (Bridge only)
|
|
&DestParams, // Remote Destination HW Address
|
|
FALSE, // Don't update unless we already have an entry for it.
|
|
pSR
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpUpdateArpCache(
|
|
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IP_ADDRESS RemoteIpAddress,
|
|
ENetAddr *pRemoteEthAddress,
|
|
PARP_DEST_PARAMS pDestParams,
|
|
MYBOOL fCreateIfRequired,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
Update cache and also abort any resolution task that may be going on.
|
|
--*/
|
|
{
|
|
REMOTE_DEST_KEY RemoteDestKey;
|
|
PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER)RM_PARENT_OBJECT(pIF);
|
|
ENTER("arpUpdateArpCache", 0x3a16a415)
|
|
LOCKOBJ(pIF, pSR);
|
|
|
|
do
|
|
{
|
|
ARPCB_REMOTE_IP *pRemoteIp = NULL;
|
|
INT fCreated = FALSE;
|
|
UINT RemoteIpCreateFlags = 0;
|
|
NDIS_STATUS Status;
|
|
|
|
DBGMARK(0xd3b27d1f);
|
|
|
|
if (fCreateIfRequired)
|
|
{
|
|
RemoteIpCreateFlags |= RM_CREATE;
|
|
}
|
|
|
|
// Create the Key from the passed in parameters
|
|
//
|
|
if (ARP_BRIDGE_ENABLED(pAdapter) == TRUE)
|
|
{
|
|
ASSERT (pRemoteEthAddress != NULL);
|
|
RemoteDestKey.ENetAddress = *pRemoteEthAddress;
|
|
TR_INFO(("Arp1394 - Bridge update cache Mac Address %x %x %x %x %x %x\n",
|
|
RemoteDestKey.ENetAddress.addr[0],
|
|
RemoteDestKey.ENetAddress.addr[1],
|
|
RemoteDestKey.ENetAddress.addr[2],
|
|
RemoteDestKey.ENetAddress.addr[3],
|
|
RemoteDestKey.ENetAddress.addr[4],
|
|
RemoteDestKey.ENetAddress.addr[5]));
|
|
}
|
|
else
|
|
{
|
|
REMOTE_DEST_KEY_INIT(&RemoteDestKey);
|
|
|
|
RemoteDestKey.IpAddress = RemoteIpAddress;
|
|
|
|
TR_INFO( ("Arp1394 - Non-Bridge update cache Mac Address %x %x %x %x %x %x\n",
|
|
RemoteDestKey.ENetAddress.addr[0],
|
|
RemoteDestKey.ENetAddress.addr[1],
|
|
RemoteDestKey.ENetAddress.addr[2],
|
|
RemoteDestKey.ENetAddress.addr[3],
|
|
RemoteDestKey.ENetAddress.addr[4],
|
|
RemoteDestKey.ENetAddress.addr[5]));
|
|
}
|
|
// Lookup/Create Remote IP Address
|
|
//
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
RemoteIpCreateFlags,
|
|
(PVOID) (&RemoteDestKey),
|
|
(PVOID) (&RemoteDestKey), // pCreateParams
|
|
(RM_OBJECT_HEADER**) &pRemoteIp,
|
|
&fCreated, // pfCreated
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
OBJLOG1(
|
|
pIF,
|
|
"Couldn't add localIp entry with addr 0x%lx\n",
|
|
RemoteIpAddress
|
|
);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update the RemoteIp Last time checked here. This will refresh the
|
|
// Arp Entry for this Remote Ip struct
|
|
//
|
|
pRemoteIp->sendinfo.TimeLastChecked = 0;
|
|
|
|
UNLOCKOBJ(pIF, pSR);
|
|
|
|
arpUpdateRemoteIpDest(
|
|
pIF,
|
|
pRemoteIp,
|
|
pDestParams,
|
|
pSR
|
|
);
|
|
|
|
// If there is a resolution task going on for pRemoteIp we abort it.
|
|
//
|
|
arpTryAbortResolutionTask(pRemoteIp, pSR);
|
|
|
|
// Finally, remove the tmprefs added in the lookups.
|
|
//
|
|
RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR);
|
|
|
|
return; // EARLY RETURN
|
|
|
|
} while (FALSE);
|
|
|
|
UNLOCKOBJ(pIF, pSR);
|
|
EXIT()
|
|
}
|
|
|
|
|
|
VOID
|
|
arpTryAbortResolutionTask(
|
|
PARPCB_REMOTE_IP pRemoteIp, // NOLOCKIN NOLOCKOUT
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
ENTER("arpTryAbortResolutionTask", 0xf34f16f2)
|
|
PTASK_RESOLVE_IP_ADDRESS pResolutionTask;
|
|
UINT TaskResumed;
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
pResolutionTask = (PTASK_RESOLVE_IP_ADDRESS) pRemoteIp->pResolutionTask;
|
|
if (pResolutionTask != NULL)
|
|
{
|
|
RmTmpReferenceObject(&pResolutionTask->TskHdr.Hdr, pSR);
|
|
}
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
|
|
DBGMARK(0x5b93ad3e);
|
|
|
|
if (pResolutionTask != NULL)
|
|
{
|
|
RmResumeDelayedTaskNow(
|
|
&pResolutionTask->TskHdr,
|
|
&pResolutionTask->Timer,
|
|
&TaskResumed,
|
|
pSR
|
|
);
|
|
|
|
RmTmpDereferenceObject(&pResolutionTask->TskHdr.Hdr, pSR);
|
|
}
|
|
|
|
EXIT()
|
|
}
|
|
|