Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1200 lines
34 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_WARN(("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_WARN(("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;
Status = arpPrepareArpResponse(
pIF, // NOLOCKIN NOLOCKOUT
pPktInfo,
&ResponsePktInfo,
pSR
);
if (!FAIL(Status))
{
ARP_DEST_PARAMS DestParams;
PNDIS_PACKET pNdisPacket;
PIP1394_ARP_PKT pPktData;
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))
{
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
);
}
}
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()
}