/*++ 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 // // 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() }