diff --git a/source/FreeRTOS_ARP.c b/source/FreeRTOS_ARP.c index 677770a4c..cfaed6e6f 100644 --- a/source/FreeRTOS_ARP.c +++ b/source/FreeRTOS_ARP.c @@ -82,15 +82,15 @@ #define arpIP_CLASH_MAX_RETRIES 1U #endif -static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame, - NetworkEndPoint_t * pxTargetEndPoint, - uint32_t ulSenderProtocolAddress ); +#if ( ipconfigUSE_IPv4 != 0 ) -static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame, - NetworkEndPoint_t * pxTargetEndPoint, - uint32_t ulSenderProtocolAddress ); + static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame, + NetworkEndPoint_t * pxTargetEndPoint, + uint32_t ulSenderProtocolAddress ); -#if ( ipconfigUSE_IPv4 != 0 ) + static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame, + NetworkEndPoint_t * pxTargetEndPoint, + uint32_t ulSenderProtocolAddress ); /* * Lookup an MAC address in the ARP cache from the IP address. @@ -133,6 +133,8 @@ static TickType_t xLastGratuitousARPTime = 0U; /*-----------------------------------------------------------*/ +#if ( ipconfigUSE_IPv4 != 0 ) + /** * @brief Process the ARP packets. * @@ -140,185 +142,206 @@ static TickType_t xLastGratuitousARPTime = 0U; * * @return An enum which says whether to return the frame or to release it. */ -eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer ) -{ - /* MISRA Ref 11.3.1 [Misaligned access] */ - /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ - /* coverity[misra_c_2012_rule_11_3_violation] */ - ARPPacket_t * pxARPFrame = ( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); - eFrameProcessingResult_t eReturn = eReleaseBuffer; - const ARPHeader_t * pxARPHeader; - uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress; - - /* memcpy() helper variables for MISRA Rule 21.15 compliance*/ - const void * pvCopySource; - void * pvCopyDest; - NetworkEndPoint_t * pxTargetEndPoint = pxNetworkBuffer->pxEndPoint; - - /* Next defensive request must not be sent for arpIP_CLASH_RESET_TIMEOUT_MS - * period. */ - static TickType_t uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS ); - - /* This local variable is used to keep track of number of ARP requests sent and - * also to limit the requests to arpIP_CLASH_MAX_RETRIES per arpIP_CLASH_RESET_TIMEOUT_MS - * period. */ - static UBaseType_t uxARPClashCounter = 0U; - /* The time at which the last ARP clash was sent. */ - static TimeOut_t xARPClashTimeOut; - - pxARPHeader = &( pxARPFrame->xARPHeader ); - - /* Only Ethernet hardware type is supported. - * Only IPv4 address can be present in the ARP packet. - * The hardware length (the MAC address) must be 6 bytes. And, - * The Protocol address length must be 4 bytes as it is IPv4. */ - if( ( pxARPHeader->usHardwareType == ipARP_HARDWARE_TYPE_ETHERNET ) && - ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) && - ( pxARPHeader->ucHardwareAddressLength == ipMAC_ADDRESS_LENGTH_BYTES ) && - ( pxARPHeader->ucProtocolAddressLength == ipIP_ADDRESS_LENGTH_BYTES ) ) + eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer ) { - /* The field ucSenderProtocolAddress is badly aligned, copy byte-by-byte. */ - - /* - * Use helper variables for memcpy() to remain - * compliant with MISRA Rule 21.15. These should be - * optimized away. - */ - pvCopySource = pxARPHeader->ucSenderProtocolAddress; - pvCopyDest = &ulSenderProtocolAddress; - ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) ); - /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */ - ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress; - - if( uxARPClashCounter != 0U ) + /* MISRA Ref 11.3.1 [Misaligned access] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ + /* coverity[misra_c_2012_rule_11_3_violation] */ + ARPPacket_t * pxARPFrame = ( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); + eFrameProcessingResult_t eReturn = eReleaseBuffer; + const ARPHeader_t * pxARPHeader; + uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress; + + /* memcpy() helper variables for MISRA Rule 21.15 compliance*/ + const void * pvCopySource; + void * pvCopyDest; + NetworkEndPoint_t * pxTargetEndPoint = pxNetworkBuffer->pxEndPoint; + + /* Next defensive request must not be sent for arpIP_CLASH_RESET_TIMEOUT_MS + * period. */ + static TickType_t uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS ); + + /* This local variable is used to keep track of number of ARP requests sent and + * also to limit the requests to arpIP_CLASH_MAX_RETRIES per arpIP_CLASH_RESET_TIMEOUT_MS + * period. */ + static UBaseType_t uxARPClashCounter = 0U; + /* The time at which the last ARP clash was sent. */ + static TimeOut_t xARPClashTimeOut; + + pxARPHeader = &( pxARPFrame->xARPHeader ); + + /* Only Ethernet hardware type is supported. + * Only IPv4 address can be present in the ARP packet. + * The hardware length (the MAC address) must be 6 bytes. And, + * The Protocol address length must be 4 bytes as it is IPv4. */ + if( ( pxARPHeader->usHardwareType == ipARP_HARDWARE_TYPE_ETHERNET ) && + ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) && + ( pxARPHeader->ucHardwareAddressLength == ipMAC_ADDRESS_LENGTH_BYTES ) && + ( pxARPHeader->ucProtocolAddressLength == ipIP_ADDRESS_LENGTH_BYTES ) ) { - /* Has the timeout been reached? */ - if( xTaskCheckForTimeOut( &xARPClashTimeOut, &uxARPClashTimeoutPeriod ) == pdTRUE ) + /* The field ucSenderProtocolAddress is badly aligned, copy byte-by-byte. */ + + /* + * Use helper variables for memcpy() to remain + * compliant with MISRA Rule 21.15. These should be + * optimized away. + */ + pvCopySource = pxARPHeader->ucSenderProtocolAddress; + pvCopyDest = &ulSenderProtocolAddress; + ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) ); + /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */ + ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress; + + if( uxARPClashCounter != 0U ) { - /* We have waited long enough, reset the counter. */ - uxARPClashCounter = 0; + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xARPClashTimeOut, &uxARPClashTimeoutPeriod ) == pdTRUE ) + { + /* We have waited long enough, reset the counter. */ + uxARPClashCounter = 0; + } } - } - /* Check whether the lowest bit of the highest byte is 1 to check for - * multicast address or even a broadcast address (FF:FF:FF:FF:FF:FF). */ - if( ( pxARPHeader->xSenderHardwareAddress.ucBytes[ 0 ] & 0x01U ) == 0x01U ) - { - /* Senders address is a multicast OR broadcast address which is not - * allowed for an ARP packet. Drop the packet. See RFC 1812 section - * 3.3.2. */ - iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); - } - else if( ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) ) && - ( ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) < ipLAST_LOOPBACK_IPv4 ) ) - { - /* The local loopback addresses must never appear outside a host. See RFC 1122 - * section 3.2.1.3. */ - iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); - } - /* Check whether there is a clash with another device for this IP address. */ - else if( ( pxTargetEndPoint != NULL ) && ( ulSenderProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) ) - { - if( uxARPClashCounter < arpIP_CLASH_MAX_RETRIES ) + /* Check whether the lowest bit of the highest byte is 1 to check for + * multicast address or even a broadcast address (FF:FF:FF:FF:FF:FF). */ + if( ( pxARPHeader->xSenderHardwareAddress.ucBytes[ 0 ] & 0x01U ) == 0x01U ) { - /* Increment the counter. */ - uxARPClashCounter++; - - /* Send out a defensive ARP request. */ - FreeRTOS_OutputARPRequest( pxTargetEndPoint->ipv4_settings.ulIPAddress ); + /* Senders address is a multicast OR broadcast address which is not + * allowed for an ARP packet. Drop the packet. See RFC 1812 section + * 3.3.2. */ + iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); + } + else if( ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) ) && + ( ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) < ipLAST_LOOPBACK_IPv4 ) ) + { + /* The local loopback addresses must never appear outside a host. See RFC 1122 + * section 3.2.1.3. */ + iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); + } + /* Check whether there is a clash with another device for this IP address. */ + else if( ( pxTargetEndPoint != NULL ) && ( ulSenderProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) ) + { + if( uxARPClashCounter < arpIP_CLASH_MAX_RETRIES ) + { + /* Increment the counter. */ + uxARPClashCounter++; - /* Since an ARP Request for this IP was just sent, do not send a gratuitous - * ARP for arpGRATUITOUS_ARP_PERIOD. */ - xLastGratuitousARPTime = xTaskGetTickCount(); + /* Send out a defensive ARP request. */ + FreeRTOS_OutputARPRequest( pxTargetEndPoint->ipv4_settings.ulIPAddress ); - /* Note the time at which this request was sent. */ - vTaskSetTimeOutState( &xARPClashTimeOut ); + /* Since an ARP Request for this IP was just sent, do not send a gratuitous + * ARP for arpGRATUITOUS_ARP_PERIOD. */ + xLastGratuitousARPTime = xTaskGetTickCount(); - /* Reset the time-out period to the given value. */ - uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS ); - } + /* Note the time at which this request was sent. */ + vTaskSetTimeOutState( &xARPClashTimeOut ); - /* Process received ARP frame to see if there is a clash. */ - #if ( ipconfigARP_USE_CLASH_DETECTION != 0 ) - { - NetworkEndPoint_t * pxSourceEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( ulSenderProtocolAddress, 2 ); + /* Reset the time-out period to the given value. */ + uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS ); + } - if( ( pxSourceEndPoint != NULL ) && ( pxSourceEndPoint->ipv4_settings.ulIPAddress == ulSenderProtocolAddress ) ) + /* Process received ARP frame to see if there is a clash. */ + #if ( ipconfigARP_USE_CLASH_DETECTION != 0 ) { - xARPHadIPClash = pdTRUE; - /* Remember the MAC-address of the other device which has the same IP-address. */ - ( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) ); + NetworkEndPoint_t * pxSourceEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( ulSenderProtocolAddress, 2 ); + + if( ( pxSourceEndPoint != NULL ) && ( pxSourceEndPoint->ipv4_settings.ulIPAddress == ulSenderProtocolAddress ) ) + { + xARPHadIPClash = pdTRUE; + /* Remember the MAC-address of the other device which has the same IP-address. */ + ( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) ); + } } - } - #endif /* ipconfigARP_USE_CLASH_DETECTION */ - } - else - { - traceARP_PACKET_RECEIVED(); + #endif /* ipconfigARP_USE_CLASH_DETECTION */ + } + else + { + traceARP_PACKET_RECEIVED(); - /* Some extra logging while still testing. */ - #if ( ipconfigHAS_PRINTF != 0 ) - if( pxARPHeader->usOperation == ( uint16_t ) ipARP_REPLY ) - { - FreeRTOS_printf( ( "ipARP_REPLY from %xip to %xip end-point %xip\n", - ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ), - ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ), - ( unsigned ) FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) ); - } - #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ + /* Some extra logging while still testing. */ + #if ( ipconfigHAS_PRINTF != 0 ) + if( pxARPHeader->usOperation == ( uint16_t ) ipARP_REPLY ) + { + FreeRTOS_printf( ( "ipARP_REPLY from %xip to %xip end-point %xip\n", + ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ), + ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ), + ( unsigned ) FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) ); + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ - #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) - if( ( pxARPHeader->usOperation == ( uint16_t ) ipARP_REQUEST ) && - ( ulSenderProtocolAddress != ulTargetProtocolAddress ) && - ( pxTargetEndPoint != NULL ) ) - { - FreeRTOS_debug_printf( ( "ipARP_REQUEST from %xip to %xip end-point %xip\n", - ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ), - ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ), - ( unsigned ) ( FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) ) ); - } - #endif /* ( ipconfigHAS_PRINTF != 0 ) */ + #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) + if( ( pxARPHeader->usOperation == ( uint16_t ) ipARP_REQUEST ) && + ( ulSenderProtocolAddress != ulTargetProtocolAddress ) && + ( pxTargetEndPoint != NULL ) ) + { + FreeRTOS_debug_printf( ( "ipARP_REQUEST from %xip to %xip end-point %xip\n", + ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ), + ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ), + ( unsigned ) ( FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) ) ); + } + #endif /* ( ipconfigHAS_PRINTF != 0 ) */ - /* ulTargetProtocolAddress won't be used unless logging is enabled. */ - ( void ) ulTargetProtocolAddress; + /* ulTargetProtocolAddress won't be used unless logging is enabled. */ + ( void ) ulTargetProtocolAddress; - /* Don't do anything if the local IP address is zero because - * that means a DHCP request has not completed. */ - if( ( pxTargetEndPoint != NULL ) && ( pxTargetEndPoint->bits.bEndPointUp != pdFALSE_UNSIGNED ) ) - { - switch( pxARPHeader->usOperation ) + /* Don't do anything if the local IP address is zero because + * that means a DHCP request has not completed. */ + if( ( pxTargetEndPoint != NULL ) && ( pxTargetEndPoint->bits.bEndPointUp != pdFALSE_UNSIGNED ) ) { - case ipARP_REQUEST: + switch( pxARPHeader->usOperation ) + { + case ipARP_REQUEST: - if( ( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) && - ( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes, - ( pxARPHeader->xSenderHardwareAddress.ucBytes ), - ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) ) - { - vARPProcessPacketRequest( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress ); - eReturn = eReturnEthernetFrame; - } + if( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) + { + if( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes, + ( pxARPHeader->xSenderHardwareAddress.ucBytes ), + ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) + { + vARPProcessPacketRequest( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress ); + eReturn = eReturnEthernetFrame; + } + } + else if( ulSenderProtocolAddress == ulTargetProtocolAddress ) /* Gratuitous ARP request? */ + { + 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 ) + { + /* Check if the endpoint matches with the one present in the ARP cache */ + if( pxCachedEndPoint == pxTargetEndPoint ) + { + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); + } + } + } - break; + break; - case ipARP_REPLY: - vARPProcessPacketReply( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress ); - break; + case ipARP_REPLY: + vARPProcessPacketReply( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress ); + break; - default: - /* Invalid. */ - break; + default: + /* Invalid. */ + break; + } } } } - } - else - { - iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); - } + else + { + iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader ); + } - return eReturn; -} + return eReturn; + } /*-----------------------------------------------------------*/ /** @@ -329,53 +352,53 @@ eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * px * @param[in] ulSenderProtocolAddress the IP-address of the sender. * */ -static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame, - NetworkEndPoint_t * pxTargetEndPoint, - uint32_t ulSenderProtocolAddress ) -{ - ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader ); + static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame, + NetworkEndPoint_t * pxTargetEndPoint, + uint32_t ulSenderProtocolAddress ) + { + ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader ); /* memcpy() helper variables for MISRA Rule 21.15 compliance*/ - const void * pvCopySource; - void * pvCopyDest; + const void * pvCopySource; + void * pvCopyDest; - /* The packet contained an ARP request. Was it for the IP - * address of one of the end-points? */ - /* It has been confirmed that pxTargetEndPoint is not NULL. */ - iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress ); + /* The packet contained an ARP request. Was it for the IP + * address of one of the end-points? */ + /* It has been confirmed that pxTargetEndPoint is not NULL. */ + iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress ); - /* The request is for the address of this node. Add the - * entry into the ARP cache, or refresh the entry if it - * already exists. */ - vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); + /* The request is for the address of this node. Add the + * entry into the ARP cache, or refresh the entry if it + * already exists. */ + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); - /* Generate a reply payload in the same buffer. */ - pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY; + /* Generate a reply payload in the same buffer. */ + pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY; - /* A double IP address cannot be detected here, it is taken care in the Process ARP Packets path */ + /* A double IP address cannot be detected here, it is taken care in the Process ARP Packets path */ - /* - * Use helper variables for memcpy() to remain - * compliant with MISRA Rule 21.15. These should be - * optimized away. - */ - pvCopySource = pxARPHeader->xSenderHardwareAddress.ucBytes; - pvCopyDest = pxARPHeader->xTargetHardwareAddress.ucBytes; - ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) ); - pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress; + /* + * Use helper variables for memcpy() to remain + * compliant with MISRA Rule 21.15. These should be + * optimized away. + */ + pvCopySource = pxARPHeader->xSenderHardwareAddress.ucBytes; + pvCopyDest = pxARPHeader->xTargetHardwareAddress.ucBytes; + ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) ); + pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress; - /* - * Use helper variables for memcpy() to remain - * compliant with MISRA Rule 21.15. These should be - * optimized away. - */ - pvCopySource = pxTargetEndPoint->xMACAddress.ucBytes; - pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes; - ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) ); - pvCopySource = &( pxTargetEndPoint->ipv4_settings.ulIPAddress ); - pvCopyDest = pxARPHeader->ucSenderProtocolAddress; - ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) ); -} + /* + * Use helper variables for memcpy() to remain + * compliant with MISRA Rule 21.15. These should be + * optimized away. + */ + pvCopySource = pxTargetEndPoint->xMACAddress.ucBytes; + pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes; + ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) ); + pvCopySource = &( pxTargetEndPoint->ipv4_settings.ulIPAddress ); + pvCopyDest = pxARPHeader->ucSenderProtocolAddress; + ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) ); + } /*-----------------------------------------------------------*/ /** @@ -384,56 +407,58 @@ static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame, * @param[in] pxTargetEndPoint The end-point on which it is received. * @param[in] ulSenderProtocolAddress The IPv4 address involved. */ -static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame, - NetworkEndPoint_t * pxTargetEndPoint, - uint32_t ulSenderProtocolAddress ) -{ - const ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader ); - uint32_t ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress; - - /* If the packet is meant for this device or if the entry already exists. */ - if( ( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) || - ( xIsIPInARPCache( ulSenderProtocolAddress ) == pdTRUE ) ) - { - iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress ); - vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); - } - - if( ( pxARPWaitingNetworkBuffer != NULL ) && - ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv4_HEADER ) ) + static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame, + NetworkEndPoint_t * pxTargetEndPoint, + uint32_t ulSenderProtocolAddress ) { - /* MISRA Ref 11.3.1 [Misaligned access] */ -/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ - /* coverity[misra_c_2012_rule_11_3_violation] */ - const IPPacket_t * pxARPWaitingIPPacket = ( ( IPPacket_t * ) pxARPWaitingNetworkBuffer->pucEthernetBuffer ); - const IPHeader_t * pxARPWaitingIPHeader = &( pxARPWaitingIPPacket->xIPHeader ); + const ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader ); + uint32_t ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress; - if( ulSenderProtocolAddress == pxARPWaitingIPHeader->ulSourceIPAddress ) + /* If the packet is meant for this device or if the entry already exists. */ + if( ( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) || + ( xIsIPInARPCache( ulSenderProtocolAddress ) == pdTRUE ) ) { - IPStackEvent_t xEventMessage; - const TickType_t xDontBlock = ( TickType_t ) 0; + iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress ); + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint ); + } - xEventMessage.eEventType = eNetworkRxEvent; - xEventMessage.pvData = ( void * ) pxARPWaitingNetworkBuffer; + if( ( pxARPWaitingNetworkBuffer != NULL ) && + ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv4_HEADER ) ) + { + /* MISRA Ref 11.3.1 [Misaligned access] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ + /* coverity[misra_c_2012_rule_11_3_violation] */ + const IPPacket_t * pxARPWaitingIPPacket = ( ( IPPacket_t * ) pxARPWaitingNetworkBuffer->pucEthernetBuffer ); + const IPHeader_t * pxARPWaitingIPHeader = &( pxARPWaitingIPPacket->xIPHeader ); - if( xSendEventStructToIPTask( &xEventMessage, xDontBlock ) != pdPASS ) + if( ulSenderProtocolAddress == pxARPWaitingIPHeader->ulSourceIPAddress ) { - /* Failed to send the message, so release the network buffer. */ - vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer ); - } + IPStackEvent_t xEventMessage; + const TickType_t xDontBlock = ( TickType_t ) 0; - /* Clear the buffer. */ - pxARPWaitingNetworkBuffer = NULL; + xEventMessage.eEventType = eNetworkRxEvent; + xEventMessage.pvData = ( void * ) pxARPWaitingNetworkBuffer; - /* Found an ARP resolution, disable ARP resolution timer. */ - vIPSetARPResolutionTimerEnableState( pdFALSE ); + if( xSendEventStructToIPTask( &xEventMessage, xDontBlock ) != pdPASS ) + { + /* Failed to send the message, so release the network buffer. */ + vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer ); + } + + /* Clear the buffer. */ + pxARPWaitingNetworkBuffer = NULL; + + /* Found an ARP resolution, disable ARP resolution timer. */ + vIPSetARPResolutionTimerEnableState( pdFALSE ); - iptrace_DELAYED_ARP_REQUEST_REPLIED(); + iptrace_DELAYED_ARP_REQUEST_REPLIED(); + } } } -} /*-----------------------------------------------------------*/ +#endif /* ( ipconfigUSE_IPv4 != 0 ) */ + /** * @brief Check whether an IP address is in the ARP cache. * diff --git a/test/cbmc/proofs/ARP/ARPProcessPacket/ARPProcessPacket_harness.c b/test/cbmc/proofs/ARP/ARPProcessPacket/ARPProcessPacket_harness.c index f3b9326d1..ee315e3f7 100644 --- a/test/cbmc/proofs/ARP/ARPProcessPacket/ARPProcessPacket_harness.c +++ b/test/cbmc/proofs/ARP/ARPProcessPacket/ARPProcessPacket_harness.c @@ -17,6 +17,21 @@ void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress ) { } +/* This function is proved elsewhere hence stubbing it out */ +eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress, + MACAddress_t * const pxMACAddress, + struct xNetworkEndPoint ** ppxEndPoint ) +{ + eARPLookupResult_t eReturn; + + __CPROVER_assert( pulIPAddress != NULL, "pulIPAddress cannot be NULL." ); + __CPROVER_assert( pxMACAddress != NULL, "pxMACAddress cannot be NULL." ); + __CPROVER_assert( ppxEndPoint != NULL, "ppxEndPoint cannot be NULL." ); + + /* Return random value */ + return eReturn; +} + void harness() { NetworkBufferDescriptor_t xLocalBuffer; diff --git a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c index 107d18c37..a18510b3e 100644 --- a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c +++ b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c @@ -696,6 +696,257 @@ void test_eARPProcessPacket_Request_SenderAndTargetSame( void ) /* =================================================== */ } +/** + * @brief This function verify receiving Gratuitous ARP packet + * and updating the ARP cache with respect to the new ARP request. + */ +void test_eARPProcessPacket_Request_GratuitousARP( 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; + /* 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, 0x34, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + FreeRTOS_FindEndPointOnIP_IPv4_ExpectAnyArgsAndReturn( &xEndPoint ); + xIsIPv4Multicast_ExpectAndReturn( ulTargetIP, 0UL ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + + 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( ipconfigMAX_ARP_AGE, 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 + * and updating the ARP cache with respect to the new ARP request + * where there is no change in the MAC address compared to what is present + * in the ARP cache. + */ +void test_eARPProcessPacket_Request_GratuitousARP_MACUnchanged( 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; + /* 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(); + + FreeRTOS_FindEndPointOnIP_IPv4_ExpectAnyArgsAndReturn( &xEndPoint ); + xIsIPv4Multicast_ExpectAndReturn( ulTargetIP, 0UL ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + + 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( ipconfigMAX_ARP_AGE, 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 + * to the entry present in the ARP cache. Hence its supposed to + * be not updated in the ARP cache. + */ +void test_eARPProcessPacket_Request_GratuitousARP_NonMatchingEndpoint( void ) +{ + ARPPacket_t xARPFrame = { 0 }; + eFrameProcessingResult_t eResult; + NetworkInterface_t xInterface; + struct xNetworkEndPoint xEndPoint = { 0 }; + struct xNetworkEndPoint xEndPoint2 = { 0 }; + NetworkBufferDescriptor_t xNetworkBuffer = { 0 }; + uint32_t ulTargetIP = 0xAACCDDBB; + uint8_t ucMAC[ 6 ] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; + + 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; + /* 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, 0x34, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint2; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + FreeRTOS_FindEndPointOnIP_IPv4_ExpectAnyArgsAndReturn( &xEndPoint ); + xIsIPv4Multicast_ExpectAndReturn( ulTargetIP, 0UL ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + + 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( &xEndPoint2, xARPCache[ 0 ].pxEndPoint ); + TEST_ASSERT_EQUAL_MEMORY( ucMAC, xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* =================================================== */ +} + +/** + * @brief This function verify receiving Gratuitous ARP packet + * but the ARP cache doesn't have an entry for the IP in the + * ARP request. + */ +void test_eARPProcessPacket_Request_GratuitousARP_NonMatchingIP( void ) +{ + ARPPacket_t xARPFrame = { 0 }; + eFrameProcessingResult_t eResult; + NetworkInterface_t xInterface; + struct xNetworkEndPoint xEndPoint = { 0 }; + struct xNetworkEndPoint xEndPoint2 = { 0 }; + NetworkBufferDescriptor_t xNetworkBuffer = { 0 }; + uint32_t ulTargetIP = 0xAACCDDBB; + uint8_t ucMAC[ 6 ] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; + + 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; + /* 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 = 0xAABBCCDF; + xARPCache[ 0 ].ucAge = 1; + xARPCache[ 0 ].ucValid = pdTRUE; + memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x34, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + xARPCache[ 0 ].pxEndPoint = &xEndPoint2; + + /* Reset the private variable uxARPClashCounter. */ + vResetARPClashCounter(); + + FreeRTOS_FindEndPointOnIP_IPv4_ExpectAnyArgsAndReturn( &xEndPoint ); + xIsIPv4Multicast_ExpectAndReturn( ulTargetIP, 0UL ); + FreeRTOS_FindEndPointOnNetMask_ExpectAnyArgsAndReturn( &xEndPoint ); + + 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( 0xAABBCCDF, xARPCache[ 0 ].ulIPAddress ); + TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge ); + TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid ); + TEST_ASSERT_EQUAL( &xEndPoint2, xARPCache[ 0 ].pxEndPoint ); + TEST_ASSERT_EQUAL_MEMORY( ucMAC, xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) ); + /* =================================================== */ +} + void test_eARPProcessPacket_Reply_TargetIPSameAsLocalIP( void ) { ARPPacket_t xARPFrame = { 0 };