diff --git a/source/FreeRTOS_ARP.c b/source/FreeRTOS_ARP.c index 252e38ab0c..d901d03548 100644 --- a/source/FreeRTOS_ARP.c +++ b/source/FreeRTOS_ARP.c @@ -302,22 +302,33 @@ static TickType_t xLastGratuitousARPTime = 0U; eReturn = eReturnEthernetFrame; } } - else if( ulSenderProtocolAddress == ulTargetProtocolAddress ) /* Gratuitous ARP request? */ + /* Check if its a Gratuitous ARP request and verify if it belongs to same subnet mask. */ + else if( ( ulSenderProtocolAddress == ulTargetProtocolAddress ) && + ( ( ulSenderProtocolAddress & pxTargetEndPoint->ipv4_settings.ulNetMask ) == ( pxTargetEndPoint->ipv4_settings.ulNetMask & pxTargetEndPoint->ipv4_settings.ulIPAddress ) ) ) { - MACAddress_t xHardwareAddress; - NetworkEndPoint_t * pxCachedEndPoint; + const MACAddress_t xGARPTargetAddress = { { 0, 0, 0, 0, 0, 0 } }; - pxCachedEndPoint = NULL; - - /* The request is a Gratuitous ARP message. - * Refresh the entry if it already exists. */ - /* Determine the ARP cache status for the requested IP address. */ - if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEndPoint ) ) == eARPCacheHit ) + /* Make sure target MAC address is either ff:ff:ff:ff:ff:ff or 00:00:00:00:00:00 and senders MAC + * address is not matching with the endpoint MAC address. */ + if( ( ( memcmp( &( pxARPHeader->xTargetHardwareAddress ), xBroadcastMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) || + ( ( memcmp( &( pxARPHeader->xTargetHardwareAddress ), xGARPTargetAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ) ) && + ( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes, ( pxARPHeader->xSenderHardwareAddress.ucBytes ), ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) ) { - /* Check if the endpoint matches with the one present in the ARP cache */ - if( pxCachedEndPoint == pxTargetEndPoint ) + MACAddress_t xHardwareAddress; + NetworkEndPoint_t * pxCachedEndPoint; + + pxCachedEndPoint = NULL; + + /* The request is a Gratuitous ARP message. + * Refresh the entry if it already exists. */ + /* Determine the ARP cache status for the requested IP address. */ + if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEndPoint ) ) == eARPCacheHit ) { - vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); + /* Check if the endpoint matches with the one present in the ARP cache */ + if( pxCachedEndPoint == pxTargetEndPoint ) + { + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); + } } } } diff --git a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c index a18510b3e2..6cff20d53e 100644 --- a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c +++ b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c @@ -734,6 +734,8 @@ void test_eARPProcessPacket_Request_GratuitousARP( void ) memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x34, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); xARPCache[ 0 ].pxEndPoint = &xEndPoint; + memset( &( xARPFrame.xARPHeader.xTargetHardwareAddress.ucBytes ), 0xff, sizeof( MACAddress_t ) ); + /* Reset the private variable uxARPClashCounter. */ vResetARPClashCounter(); @@ -820,6 +822,183 @@ void test_eARPProcessPacket_Request_GratuitousARP_MACUnchanged( void ) /* =================================================== */ } +/** + * @brief This function verify receiving Gratuitous ARP packet + * but the sender protocol address is outside the subnet. + */ +void test_eARPProcessPacket_Request_GratuitousARP_OutOfSubnetIP( void ) +{ + ARPPacket_t xARPFrame = { 0 }; + eFrameProcessingResult_t eResult; + NetworkInterface_t xInterface; + struct xNetworkEndPoint xEndPoint = { 0 }; + NetworkBufferDescriptor_t xNetworkBuffer = { 0 }; + uint32_t ulTargetIP = 0xAACCDDBB; + + memset( &xARPFrame, 0, sizeof( ARPPacket_t ) ); + memset( xARPCache, 0, sizeof( xARPCache ) ); + + /* =================================================== */ + /* Add settings required for ARP header to pass checks */ + xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET; + xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE; + xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES; + xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES; + + /* Process an ARP request - meant for this node with target and source same. */ + xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD; + xEndPoint.ipv4_settings.ulNetMask = 0xFFFF0000; + /* Fill in the request option. */ + xARPFrame.xARPHeader.usOperation = ipARP_REQUEST; + xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP; + memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) ); + + memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) ); + + xARPCache[ 0 ].ulIPAddress = ulTargetIP; + xARPCache[ 0 ].ucAge = 1; + xARPCache[ 0 ].ucValid = pdTRUE; + memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + xNetworkBuffer.pucEthernetBuffer = &xARPFrame; + xNetworkBuffer.xDataLength = sizeof( ARPPacket_t ); + xNetworkBuffer.pxEndPoint = &xEndPoint; + xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED; + + eResult = eARPProcessPacket( &xNetworkBuffer ); + TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); + TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress ); + TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge ); + TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid ); + TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint ); + TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* =================================================== */ +} + +/** + * @brief This function verify receiving Gratuitous ARP packet + * but the new MAC address matches with the MAC address of the + * endpoint. + */ +void test_eARPProcessPacket_Request_GratuitousARP_MACMatchesWithEndpoint( void ) +{ + ARPPacket_t xARPFrame = { 0 }; + eFrameProcessingResult_t eResult; + NetworkInterface_t xInterface; + struct xNetworkEndPoint xEndPoint = { 0 }; + NetworkBufferDescriptor_t xNetworkBuffer = { 0 }; + uint32_t ulTargetIP = 0xAACCDDBB; + + memset( &xARPFrame, 0, sizeof( ARPPacket_t ) ); + memset( xARPCache, 0, sizeof( xARPCache ) ); + + /* =================================================== */ + /* Add settings required for ARP header to pass checks */ + xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET; + xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE; + xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES; + xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES; + + /* Process an ARP request - meant for this node with target and source same. */ + xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD; + xEndPoint.ipv4_settings.ulNetMask = 0; + memset( xEndPoint.xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* Fill in the request option. */ + xARPFrame.xARPHeader.usOperation = ipARP_REQUEST; + xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP; + memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) ); + + memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) ); + + xARPCache[ 0 ].ulIPAddress = ulTargetIP; + xARPCache[ 0 ].ucAge = 1; + xARPCache[ 0 ].ucValid = pdTRUE; + memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + xNetworkBuffer.pucEthernetBuffer = &xARPFrame; + xNetworkBuffer.xDataLength = sizeof( ARPPacket_t ); + xNetworkBuffer.pxEndPoint = &xEndPoint; + xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED; + + eResult = eARPProcessPacket( &xNetworkBuffer ); + TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); + TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress ); + TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge ); + TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid ); + TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint ); + TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* =================================================== */ +} + +/** + * @brief This function verify receiving Gratuitous ARP packet + * but the target MAC address in the ARP request is not a + * broadcast address. + */ +void test_eARPProcessPacket_Request_GratuitousARP_TargetHWAddressNotBroadcast( void ) +{ + ARPPacket_t xARPFrame = { 0 }; + eFrameProcessingResult_t eResult; + NetworkInterface_t xInterface; + struct xNetworkEndPoint xEndPoint = { 0 }; + NetworkBufferDescriptor_t xNetworkBuffer = { 0 }; + uint32_t ulTargetIP = 0xAACCDDBB; + + memset( &xARPFrame, 0, sizeof( ARPPacket_t ) ); + memset( xARPCache, 0, sizeof( xARPCache ) ); + + /* =================================================== */ + /* Add settings required for ARP header to pass checks */ + xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET; + xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE; + xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES; + xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES; + + /* Process an ARP request - meant for this node with target and source same. */ + xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD; + xEndPoint.ipv4_settings.ulNetMask = 0; + memset( xEndPoint.xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* Fill in the request option. */ + xARPFrame.xARPHeader.usOperation = ipARP_REQUEST; + xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP; + memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) ); + + memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) ); + memset( &( xARPFrame.xARPHeader.xTargetHardwareAddress.ucBytes ), 0x11, sizeof( MACAddress_t ) ); + + xARPCache[ 0 ].ulIPAddress = ulTargetIP; + xARPCache[ 0 ].ucAge = 1; + xARPCache[ 0 ].ucValid = pdTRUE; + memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + xNetworkBuffer.pucEthernetBuffer = &xARPFrame; + xNetworkBuffer.xDataLength = sizeof( ARPPacket_t ); + xNetworkBuffer.pxEndPoint = &xEndPoint; + xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED; + + eResult = eARPProcessPacket( &xNetworkBuffer ); + TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); + TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress ); + TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge ); + TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid ); + TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint ); + TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* =================================================== */ +} + + /** * @brief This function verify receiving Gratuitous ARP packet * but the packet is received in a different endpoint compared