Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gratuituous ARP fixes #988

Merged
merged 12 commits into from
Aug 4, 2023
35 changes: 23 additions & 12 deletions source/FreeRTOS_ARP.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) &&
tony-josi-aws marked this conversation as resolved.
Show resolved Hide resolved
( ( 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 );
}
}
}
}
Expand Down
179 changes: 179 additions & 0 deletions test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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
Expand Down