diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index af9725ba09..c9b5d6ec4b 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -10,6 +10,10 @@ on: description: 'Release Version Number (Eg, v1.0.0-rc1)' required: true +# Workflow permissions block +permissions: + contents: write # This grants write access to repository content, including pushing commits/tags and creating releases. + jobs: tag-commit: name: Tag commit @@ -32,4 +36,4 @@ jobs: git tag -d ${{ github.event.inputs.version_number }} git remote update git checkout tags/${{ github.event.inputs.version_number }} - git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }} + git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 757b79479e..5b6ce0b3ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,10 @@ on: description: 'Release Version Number (Eg, v1.0.0)' required: true +# Workflow permissions block +permissions: + contents: write # This grants write access to repository content, including pushing commits/tags and creating releases. + jobs: tag-commit: name: Tag commit @@ -140,6 +144,9 @@ jobs: ref: ${{ github.event.inputs.version_number }} add_release: "true" create-release: + permissions: + contents: write + id-token: write needs: - create-zip - deploy-doxygen @@ -171,6 +178,11 @@ jobs: asset_path: ./FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip asset_name: FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip asset_content_type: application/zip + - name: Backup Release Asset + uses: FreeRTOS/CI-CD-Github-Actions/artifact-backup@main + with: + artifact_path: ./FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip + release_tag: ${{ github.event.inputs.version_number }} cleanup: needs: - create-release diff --git a/History.txt b/History.txt index bf1801bfdd..1c21ba6877 100644 --- a/History.txt +++ b/History.txt @@ -1,5 +1,30 @@ Documentation and download available at https://www.FreeRTOS.org/ +Changes between FreeRTOS-plus-TCP V4.2.5 and V4.2.4 released October 10, 2025: + + The implementation lacked sufficient checks to ensure that received packets + meet the minimum size requirements for certain ICMPv6 message types, leading to + out-of-bounds read operations when processing packets smaller than the expected + size. This issue has been fixed by adding checks to prevent out-of-bounds reads. + The implementation lacked sufficient checks to prevent null pointer dereference + when an IPv6 multicast packet is received on a device not configured with a + link-local endpoint. This issue has been fixed by adding checks to prevent + null pointer dereference. + + The implementation lacked sufficient checks to validate the payload length field + in the IPv6 packet header. This allowed malicious packets with incorrect payload + lengths to cause integer wraparound, resulting in erroneously large calculated + payload length. This inflated payload length bypassed the existing + bounds-checking mechanisms, leading to out-of-bounds read operations. This issue + has been fixed by adding checks to validate the payload length field in the IPv6 + packet header. + + The implementation lacked sufficient checks to validate the IP version field + when a UDP/IPv6 packet is received with ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM + disabled. This allowed the processing of packets with an incorrect IP version + field instead of rejecting them early. Subsequent attempts to extract network + buffers from these invalid UDP packets could result in dereferencing of an + invalid pointer due to incorrect pointer arithmetic. + We would like to thank Ivan Gotovchits of Mayhem Security for collaborating on + this issue through the coordinated vulnerability disclosure process. + Changes between FreeRTOS-plus-TCP V4.2.4 and V4.2.3 released June 10, 2025: + Fixed maximum network buffer allocation size check when buffer allocation scheme 1 is used which caused allocation failure on diff --git a/docs/doxygen/config.doxyfile b/docs/doxygen/config.doxyfile index 3bcdc7ee8a..61f7fce318 100644 --- a/docs/doxygen/config.doxyfile +++ b/docs/doxygen/config.doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = FreeRTOS-Plus-TCP # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = V4.2.4 +PROJECT_NUMBER = V4.2.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/manifest.yml b/manifest.yml index eefdb9dc7b..e9366602bf 100644 --- a/manifest.yml +++ b/manifest.yml @@ -1,5 +1,5 @@ name: "FreeRTOS-Plus-TCP" -version: "V4.2.4" +version: "V4.2.5" description: "Thread safe FreeRTOS TCP/IP stack working on top of the FreeRTOS-Kernel to implement the TCP/IP protocol. Suitable for microcontrollers." diff --git a/source/FreeRTOS_IPv6.c b/source/FreeRTOS_IPv6.c index f0c4265430..0ff89a6d00 100644 --- a/source/FreeRTOS_IPv6.c +++ b/source/FreeRTOS_IPv6.c @@ -93,7 +93,6 @@ const struct xIPv6_Address FreeRTOS_in6addr_loopback = { { 0U, 0U, 0U, 0U, 0U, 0 size_t uxBufferLength ) { BaseType_t xResult = pdFAIL; - uint16_t ucVersionTrafficClass; uint16_t usPayloadLength; uint8_t ucNextHeader; size_t uxMinimumLength; @@ -116,15 +115,6 @@ const struct xIPv6_Address FreeRTOS_in6addr_loopback = { { 0U, 0U, 0U, 0U, 0U, 0 break; } - ucVersionTrafficClass = pxIPv6Packet->xIPHeader.ucVersionTrafficClass; - - /* Test if the IP-version is 6. */ - if( ( ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) != 6U ) - { - DEBUG_SET_TRACE_VARIABLE( xLocation, 2 ); - break; - } - /* Check if the IPv6-header is transferred. */ if( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ) ) { @@ -497,6 +487,7 @@ eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxI const IPv6_Address_t * pxDestinationIPAddress = &( pxIPv6Header->xDestinationAddress ); const IPv6_Address_t * pxSourceIPAddress = &( pxIPv6Header->xSourceAddress ); BaseType_t xHasUnspecifiedAddress = pdFALSE; + uint16_t ucVersionTrafficClass = pxIPv6Header->ucVersionTrafficClass; /* Drop if packet has unspecified IPv6 address (defined in RFC4291 - sec 2.5.2) * either in source or destination address. */ @@ -506,10 +497,17 @@ eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxI xHasUnspecifiedAddress = pdTRUE; } + /* Test if the IP-version is 6. */ + if( ( ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) != 6U ) + { + /* Can not handle, unknown or invalid header version. */ + eReturn = eReleaseBuffer; + FreeRTOS_printf( ( "prvAllowIPPacketIPv6: drop packet, invalid header version: %u\n", ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) ); + } /* Is the packet for this IP address? */ - if( ( xHasUnspecifiedAddress == pdFALSE ) && - ( pxNetworkBuffer->pxEndPoint != NULL ) && - ( memcmp( pxDestinationIPAddress->ucBytes, pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) ) + else if( ( xHasUnspecifiedAddress == pdFALSE ) && + ( pxNetworkBuffer->pxEndPoint != NULL ) && + ( memcmp( pxDestinationIPAddress->ucBytes, pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) ) { eReturn = eProcessBuffer; } diff --git a/source/FreeRTOS_IPv6_Utils.c b/source/FreeRTOS_IPv6_Utils.c index 806fc4ec8d..a99a6f01d1 100644 --- a/source/FreeRTOS_IPv6_Utils.c +++ b/source/FreeRTOS_IPv6_Utils.c @@ -92,7 +92,7 @@ BaseType_t prvChecksumIPv6Checks( uint8_t * pucEthernetBuffer, { uxExtensionHeaderLength = usGetExtensionHeaderLength( pucEthernetBuffer, uxBufferLength, &pxSet->ucProtocol ); - if( uxExtensionHeaderLength >= uxBufferLength ) + if( ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtensionHeaderLength ) >= uxBufferLength ) { /* Error detected when parsing extension header. */ pxSet->usChecksum = ipINVALID_LENGTH; @@ -107,8 +107,18 @@ BaseType_t prvChecksumIPv6Checks( uint8_t * pucEthernetBuffer, /* coverity[misra_c_2012_rule_11_3_violation] */ pxSet->pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtensionHeaderLength ] ) ); pxSet->usPayloadLength = FreeRTOS_ntohs( pxSet->pxIPPacket_IPv6->usPayloadLength ); + /* For IPv6, the number of bytes in the protocol is indicated. */ - pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength ); + if( pxSet->usPayloadLength < uxExtensionHeaderLength ) + { + /* Invalid payload length - extension headers exceed payload. */ + pxSet->usChecksum = ipINVALID_LENGTH; + xReturn = 4; + } + else + { + pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength ); + } uxNeeded = ( size_t ) pxSet->usPayloadLength; uxNeeded += ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER; diff --git a/source/FreeRTOS_ND.c b/source/FreeRTOS_ND.c index da287d9f30..2cec3e37fa 100644 --- a/source/FreeRTOS_ND.c +++ b/source/FreeRTOS_ND.c @@ -147,7 +147,7 @@ MACAddress_t * const pxMACAddress, NetworkEndPoint_t ** ppxEndPoint ) { - eARPLookupResult_t eReturn; + eARPLookupResult_t eReturn = eARPCacheMiss; /* Mostly used multi-cast address is ff02::. */ if( xIsIPv6AllowedMulticast( pxAddressToLookup ) != pdFALSE ) @@ -157,14 +157,20 @@ if( ppxEndPoint != NULL ) { *ppxEndPoint = pxFindLocalEndpoint(); - } - eReturn = eARPCacheHit; + if( *ppxEndPoint != NULL ) + { + eReturn = eARPCacheHit; + } + else + { + /* No link-local endpoint configured, eARPCacheHit */ + } + } } else { - /* Not a multicast IP address. */ - eReturn = eARPCacheMiss; + /* Not a multicast IP address, eARPCacheHit */ } return eReturn; @@ -252,12 +258,15 @@ /* See if the gateway has an entry in the cache. */ eReturn = prvNDCacheLookup( pxIPAddress, pxMACAddress, ppxEndPoint ); - if( *ppxEndPoint != NULL ) + if( ( ppxEndPoint != NULL ) && ( *ppxEndPoint != NULL ) ) { FreeRTOS_printf( ( "eNDGetCacheEntry: found end-point %pip\n", ( void * ) ( *ppxEndPoint )->ipv6_settings.xIPAddress.ucBytes ) ); } - *( ppxEndPoint ) = pxEndPoint; + if( ppxEndPoint != NULL ) + { + *( ppxEndPoint ) = pxEndPoint; + } } } } @@ -955,194 +964,238 @@ */ eFrameProcessingResult_t prvProcessICMPMessage_IPv6( NetworkBufferDescriptor_t * const 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] */ - ICMPPacket_IPv6_t * pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); - /* coverity[misra_c_2012_rule_11_3_violation] */ - ICMPHeader_IPv6_t * pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); - /* Note: pxNetworkBuffer->pxEndPoint is already verified to be non-NULL in prvProcessEthernetPacket() */ - NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; - size_t uxNeededSize; - - #if ( ipconfigHAS_PRINTF == 1 ) + /* + * ICMPv6 messages have the following general format: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + Message Body + + | | + | + | The packet should contain atleast 4 bytes of general fields + | + */ + if( pxNetworkBuffer->xDataLength >= ( ( size_t ) ipSIZE_OF_ETH_HEADER + ( size_t ) ipSIZE_OF_IPv6_HEADER + ( size_t ) ipICMPv6_GENERAL_FIELD_SIZE ) ) { - if( pxICMPHeader_IPv6->ucTypeOfMessage != ipICMP_PING_REQUEST_IPv6 ) + /* 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] */ + ICMPPacket_IPv6_t * pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); + /* coverity[misra_c_2012_rule_11_3_violation] */ + ICMPHeader_IPv6_t * pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); + /* Note: pxNetworkBuffer->pxEndPoint is already verified to be non-NULL in prvProcessEthernetPacket() */ + NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; + size_t uxNeededSize; + + #if ( ipconfigHAS_PRINTF == 1 ) { - char pcAddress[ 40 ]; - FreeRTOS_printf( ( "ICMPv6_recv %d (%s) from %pip to %pip end-point = %s\n", - pxICMPHeader_IPv6->ucTypeOfMessage, - pcMessageType( ( BaseType_t ) pxICMPHeader_IPv6->ucTypeOfMessage ), - ( void * ) pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, - ( void * ) pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, - pcEndpointName( pxEndPoint, pcAddress, sizeof( pcAddress ) ) ) ); + if( pxICMPHeader_IPv6->ucTypeOfMessage != ipICMP_PING_REQUEST_IPv6 ) + { + char pcAddress[ 40 ]; + FreeRTOS_printf( ( "ICMPv6_recv %d (%s) from %pip to %pip end-point = %s\n", + pxICMPHeader_IPv6->ucTypeOfMessage, + pcMessageType( ( BaseType_t ) pxICMPHeader_IPv6->ucTypeOfMessage ), + ( void * ) pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, + ( void * ) pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, + pcEndpointName( pxEndPoint, pcAddress, sizeof( pcAddress ) ) ) ); + } } - } - #endif /* ( ipconfigHAS_PRINTF == 1 ) */ + #endif /* ( ipconfigHAS_PRINTF == 1 ) */ - if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) - { - switch( pxICMPHeader_IPv6->ucTypeOfMessage ) + if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) { - case ipICMP_DEST_UNREACHABLE_IPv6: - case ipICMP_PACKET_TOO_BIG_IPv6: - case ipICMP_TIME_EXCEEDED_IPv6: - case ipICMP_PARAMETER_PROBLEM_IPv6: - /* These message types are not implemented. They are logged here above. */ - break; + switch( pxICMPHeader_IPv6->ucTypeOfMessage ) + { + case ipICMP_DEST_UNREACHABLE_IPv6: + case ipICMP_PACKET_TOO_BIG_IPv6: + case ipICMP_TIME_EXCEEDED_IPv6: + case ipICMP_PARAMETER_PROBLEM_IPv6: + /* These message types are not implemented. They are logged here above. */ + break; + + case ipICMP_PING_REQUEST_IPv6: + { + size_t uxICMPSize; + uint16_t usICMPSize; - case ipICMP_PING_REQUEST_IPv6: - { - size_t uxICMPSize; - uint16_t usICMPSize; + /* Lint would complain about casting '()' immediately. */ + usICMPSize = FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ); + uxICMPSize = ( size_t ) usICMPSize; + uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); + + if( uxNeededSize > pxNetworkBuffer->xDataLength ) + { + FreeRTOS_printf( ( "Too small\n" ) ); + break; + } - /* Lint would complain about casting '()' immediately. */ - usICMPSize = FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ); - uxICMPSize = ( size_t ) usICMPSize; - uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); + pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_PING_REPLY_IPv6; - if( uxNeededSize > pxNetworkBuffer->xDataLength ) - { - FreeRTOS_printf( ( "Too small\n" ) ); - break; + /* MISRA Ref 4.14.1 [The validity of values received from external sources]. */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#directive-414. */ + /* coverity[misra_c_2012_directive_4_14_violation] */ + prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); } + break; - pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_PING_REPLY_IPv6; + #if ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) + case ipICMP_PING_REPLY_IPv6: + { + ePingReplyStatus_t eStatus = eSuccess; + /* 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 ICMPEcho_IPv6_t * pxICMPEchoHeader = ( ( const ICMPEcho_IPv6_t * ) pxICMPHeader_IPv6 ); + size_t uxDataLength, uxCount; + const uint8_t * pucByte; - /* MISRA Ref 4.14.1 [The validity of values received from external sources]. */ - /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#directive-414. */ - /* coverity[misra_c_2012_directive_4_14_violation] */ - prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); - } - break; + /* Find the total length of the IP packet. */ + uxDataLength = ipNUMERIC_CAST( size_t, FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ) ); - #if ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) - case ipICMP_PING_REPLY_IPv6: - { - ePingReplyStatus_t eStatus = eSuccess; - /* 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 ICMPEcho_IPv6_t * pxICMPEchoHeader = ( ( const ICMPEcho_IPv6_t * ) pxICMPHeader_IPv6 ); - size_t uxDataLength, uxCount; - const uint8_t * pucByte; - - /* Find the total length of the IP packet. */ - uxDataLength = ipNUMERIC_CAST( size_t, FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ) ); - uxDataLength = uxDataLength - sizeof( *pxICMPEchoHeader ); - - /* Find the first byte of the data within the ICMP packet. */ - pucByte = ( const uint8_t * ) pxICMPEchoHeader; - pucByte = &( pucByte[ sizeof( *pxICMPEchoHeader ) ] ); - - /* Check each byte. */ - for( uxCount = 0; uxCount < uxDataLength; uxCount++ ) - { - if( *pucByte != ( uint8_t ) ipECHO_DATA_FILL_BYTE ) + uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxDataLength ); + + if( uxNeededSize > pxNetworkBuffer->xDataLength ) { - eStatus = eInvalidData; + FreeRTOS_printf( ( "Too small\n" ) ); break; } - pucByte++; - } + uxDataLength = uxDataLength - sizeof( *pxICMPEchoHeader ); - /* Call back into the application to pass it the result. */ - vApplicationPingReplyHook( eStatus, pxICMPEchoHeader->usIdentifier ); - } - break; - #endif /* ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) */ - case ipICMP_NEIGHBOR_SOLICITATION_IPv6: - { - size_t uxICMPSize; - BaseType_t xCompare; - const NetworkEndPoint_t * pxTargetedEndPoint = pxEndPoint; - const NetworkEndPoint_t * pxEndPointInSameSubnet = FreeRTOS_InterfaceEPInSameSubnet_IPv6( pxNetworkBuffer->pxInterface, &( pxICMPHeader_IPv6->xIPv6Address ) ); + /* Find the first byte of the data within the ICMP packet. */ + pucByte = ( const uint8_t * ) pxICMPEchoHeader; + pucByte = &( pucByte[ sizeof( *pxICMPEchoHeader ) ] ); - if( pxEndPointInSameSubnet != NULL ) - { - pxTargetedEndPoint = pxEndPointInSameSubnet; - } - else - { - FreeRTOS_debug_printf( ( "prvProcessICMPMessage_IPv6: No match for %pip\n", - pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); - } + /* Check each byte. */ + for( uxCount = 0; uxCount < uxDataLength; uxCount++ ) + { + if( *pucByte != ( uint8_t ) ipECHO_DATA_FILL_BYTE ) + { + eStatus = eInvalidData; + break; + } - uxICMPSize = sizeof( ICMPHeader_IPv6_t ); - uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); + pucByte++; + } - if( uxNeededSize > pxNetworkBuffer->xDataLength ) + /* Call back into the application to pass it the result. */ + vApplicationPingReplyHook( eStatus, pxICMPEchoHeader->usIdentifier ); + } + break; + #endif /* ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) */ + case ipICMP_NEIGHBOR_SOLICITATION_IPv6: { - FreeRTOS_printf( ( "Too small\n" ) ); - break; - } + size_t uxICMPSize; + BaseType_t xCompare; + const NetworkEndPoint_t * pxTargetedEndPoint = pxEndPoint; + const NetworkEndPoint_t * pxEndPointInSameSubnet = FreeRTOS_InterfaceEPInSameSubnet_IPv6( pxNetworkBuffer->pxInterface, &( pxICMPHeader_IPv6->xIPv6Address ) ); - xCompare = memcmp( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxTargetedEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + if( pxEndPointInSameSubnet != NULL ) + { + pxTargetedEndPoint = pxEndPointInSameSubnet; + } + else + { + FreeRTOS_debug_printf( ( "prvProcessICMPMessage_IPv6: No match for %pip\n", + pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); + } - FreeRTOS_printf( ( "ND NS for %pip endpoint %pip %s\n", - ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes, - ( void * ) pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, - ( xCompare == 0 ) ? "Reply" : "Ignore" ) ); + uxICMPSize = sizeof( ICMPHeader_IPv6_t ); + uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); - if( xCompare == 0 ) - { - pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; - pxICMPHeader_IPv6->ucTypeOfService = 0U; - pxICMPHeader_IPv6->ulReserved = ndICMPv6_FLAG_SOLICITED | ndICMPv6_FLAG_UPDATE; - pxICMPHeader_IPv6->ulReserved = FreeRTOS_htonl( pxICMPHeader_IPv6->ulReserved ); - - /* Type of option. */ - pxICMPHeader_IPv6->ucOptionType = ndICMP_TARGET_LINK_LAYER_ADDRESS; - /* Length of option in units of 8 bytes. */ - pxICMPHeader_IPv6->ucOptionLength = 1U; - ( void ) memcpy( pxICMPHeader_IPv6->ucOptionBytes, pxTargetedEndPoint->xMACAddress.ucBytes, sizeof( MACAddress_t ) ); - pxICMPPacket->xIPHeader.ucHopLimit = 255U; - ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxTargetedEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); - prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); - } - } - break; + if( uxNeededSize > pxNetworkBuffer->xDataLength ) + { + FreeRTOS_printf( ( "Too small\n" ) ); + break; + } - case ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6: - /* 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] */ - vNDRefreshCacheEntry( ( ( const MACAddress_t * ) pxICMPHeader_IPv6->ucOptionBytes ), - &( pxICMPHeader_IPv6->xIPv6Address ), - pxEndPoint ); - FreeRTOS_printf( ( "NEIGHBOR_ADV from %pip\n", - ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); + xCompare = memcmp( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxTargetedEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); - #if ( ipconfigUSE_RA != 0 ) + FreeRTOS_printf( ( "ND NS for %pip endpoint %pip %s\n", + ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes, + ( void * ) pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, + ( xCompare == 0 ) ? "Reply" : "Ignore" ) ); - /* Receive a NA ( Neighbour Advertisement ) message to see if a chosen IP-address is already in use. - * This is important during SLAAC. */ - vReceiveNA( pxNetworkBuffer ); - #endif + if( xCompare == 0 ) + { + pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; + pxICMPHeader_IPv6->ucTypeOfService = 0U; + pxICMPHeader_IPv6->ulReserved = ndICMPv6_FLAG_SOLICITED | ndICMPv6_FLAG_UPDATE; + pxICMPHeader_IPv6->ulReserved = FreeRTOS_htonl( pxICMPHeader_IPv6->ulReserved ); + + /* Type of option. */ + pxICMPHeader_IPv6->ucOptionType = ndICMP_TARGET_LINK_LAYER_ADDRESS; + /* Length of option in units of 8 bytes. */ + pxICMPHeader_IPv6->ucOptionLength = 1U; + ( void ) memcpy( pxICMPHeader_IPv6->ucOptionBytes, pxTargetedEndPoint->xMACAddress.ucBytes, sizeof( MACAddress_t ) ); + pxICMPPacket->xIPHeader.ucHopLimit = 255U; + ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxTargetedEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); + prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); + } + } + break; - if( ( pxARPWaitingNetworkBuffer != NULL ) && - ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER ) ) - { - prvCheckWaitingBuffer( &( pxICMPHeader_IPv6->xIPv6Address ) ); - } + case ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6: + { + size_t uxICMPSize; + uxICMPSize = sizeof( ICMPHeader_IPv6_t ); + uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); - break; + if( uxNeededSize > pxNetworkBuffer->xDataLength ) + { + FreeRTOS_printf( ( "Too small\n" ) ); + break; + } - case ipICMP_ROUTER_SOLICITATION_IPv6: - break; + /* 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] */ + vNDRefreshCacheEntry( ( ( const MACAddress_t * ) pxICMPHeader_IPv6->ucOptionBytes ), + &( pxICMPHeader_IPv6->xIPv6Address ), + pxEndPoint ); + FreeRTOS_printf( ( "NEIGHBOR_ADV from %pip\n", + ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); - #if ( ipconfigUSE_RA != 0 ) - case ipICMP_ROUTER_ADVERTISEMENT_IPv6: - vReceiveRA( pxNetworkBuffer ); - break; - #endif /* ( ipconfigUSE_RA != 0 ) */ + #if ( ipconfigUSE_RA != 0 ) - default: - /* All possible values are included here above. */ - break; - } /* switch( pxICMPHeader_IPv6->ucTypeOfMessage ) */ - } /* if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) */ + /* Receive a NA ( Neighbour Advertisement ) message to see if a chosen IP-address is already in use. + * This is important during SLAAC. */ + vReceiveNA( pxNetworkBuffer ); + #endif + + if( ( pxARPWaitingNetworkBuffer != NULL ) && + ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER ) ) + { + prvCheckWaitingBuffer( &( pxICMPHeader_IPv6->xIPv6Address ) ); + } + } + break; + + case ipICMP_ROUTER_SOLICITATION_IPv6: + break; + + #if ( ipconfigUSE_RA != 0 ) + case ipICMP_ROUTER_ADVERTISEMENT_IPv6: + /* Size check is done inside vReceiveRA */ + vReceiveRA( pxNetworkBuffer ); + break; + #endif /* ( ipconfigUSE_RA != 0 ) */ + + default: + /* All possible values are included here above. */ + break; + } /* switch( pxICMPHeader_IPv6->ucTypeOfMessage ) */ + } /* if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) */ + } + else + { + /* Malformed ICMPv6 packet, release the network buffer (performed + * in prvProcessEthernetPacket)*/ + } return eReleaseBuffer; } diff --git a/source/include/FreeRTOS_IPv6_Private.h b/source/include/FreeRTOS_IPv6_Private.h index b4eff48121..29c8bb972d 100644 --- a/source/include/FreeRTOS_IPv6_Private.h +++ b/source/include/FreeRTOS_IPv6_Private.h @@ -132,6 +132,8 @@ struct xNetworkEndPoint; struct xNetworkInterface; +#define ipICMPv6_GENERAL_FIELD_SIZE ( 4U ) + #include "pack_struct_start.h" struct xIP_HEADER_IPv6 { diff --git a/test/cbmc/proofs/ND/prvProcessICMPMessage_IPv6/ProcessICMPMessage_IPv6_harness.c b/test/cbmc/proofs/ND/prvProcessICMPMessage_IPv6/ProcessICMPMessage_IPv6_harness.c index 0b02ac8ed2..a6c1bc1ec7 100644 --- a/test/cbmc/proofs/ND/prvProcessICMPMessage_IPv6/ProcessICMPMessage_IPv6_harness.c +++ b/test/cbmc/proofs/ND/prvProcessICMPMessage_IPv6/ProcessICMPMessage_IPv6_harness.c @@ -137,7 +137,9 @@ void harness() uint16_t usEthernetBufferSize; NetworkBufferDescriptor_t * pxLocalARPWaitingNetworkBuffer; - __CPROVER_assume( ( ulLen >= sizeof( ICMPPacket_IPv6_t ) ) && ( ulLen < ipconfigNETWORK_MTU ) ); + /* Following assumption is to make sure ulLen doesn't go + * beyond CBMC_MAX_OBJECT_SIZE */ + __CPROVER_assume( ulLen < ( CBMC_MAX_OBJECT_SIZE - ipBUFFER_PADDING ) ); pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ulLen, 0 ); diff --git a/test/cbmc/proofs/prvChecksumIPv6Checks/prvChecksumIPv6Checks_harness.c b/test/cbmc/proofs/prvChecksumIPv6Checks/prvChecksumIPv6Checks_harness.c index bcb8d4a12f..e43f2db645 100644 --- a/test/cbmc/proofs/prvChecksumIPv6Checks/prvChecksumIPv6Checks_harness.c +++ b/test/cbmc/proofs/prvChecksumIPv6Checks/prvChecksumIPv6Checks_harness.c @@ -21,6 +21,7 @@ void harness() size_t uxBufferSize; uint8_t * pucEthernetBuffer; struct xPacketSummary xSet; + BaseType_t xReturn; /* We must have ethernet header to get frame type. */ __CPROVER_assume( uxBufferSize >= sizeof( IPPacket_IPv6_t ) && uxBufferSize <= ipconfigNETWORK_MTU ); @@ -28,12 +29,18 @@ void harness() /* Ethernet buffer is not possible to be NULL. */ pucEthernetBuffer = ( uint8_t * ) safeMalloc( uxBufferSize ); __CPROVER_assume( pucEthernetBuffer != NULL ); + __CPROVER_havoc_object( pucEthernetBuffer ); /* This is set before calling prvChecksumIPv6Checks. */ xSet.pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer; xSet.pxIPPacket_IPv6 = ( const IPHeader_IPv6_t * ) ( pucEthernetBuffer + ipSIZE_OF_ETH_HEADER ); - prvChecksumIPv6Checks( pucEthernetBuffer, - uxBufferSize, - &xSet ); + xReturn = prvChecksumIPv6Checks( pucEthernetBuffer, + uxBufferSize, + &xSet ); + + if( xReturn == 0 ) + { + __CPROVER_assert( ( xSet.usProtocolBytes <= FreeRTOS_ntohs( xSet.pxIPPacket_IPv6->usPayloadLength ) ), "xSet.usProtocolBytes shouldn't be greater than IPv6 usPayloadLength" ); + } } diff --git a/test/unit-test/FreeRTOS_IPv6/FreeRTOS_IPv6_utest.c b/test/unit-test/FreeRTOS_IPv6/FreeRTOS_IPv6_utest.c index c184972955..cfbb743f16 100644 --- a/test/unit-test/FreeRTOS_IPv6/FreeRTOS_IPv6_utest.c +++ b/test/unit-test/FreeRTOS_IPv6/FreeRTOS_IPv6_utest.c @@ -68,6 +68,7 @@ void test_prvAllowIPPacketIPv6_SourceUnspecifiedAddress() memset( &xIPv6Address, 0, sizeof( xIPv6Address ) ); memcpy( xIPv6Address.xDestinationAddress.ucBytes, xIPAddressFive.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); memcpy( xIPv6Address.xSourceAddress.ucBytes, FreeRTOS_in6addr_any.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + xIPv6Address.ucVersionTrafficClass = 0x60U; eResult = prvAllowIPPacketIPv6( &xIPv6Address, NULL, 0U ); TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); @@ -85,6 +86,7 @@ void test_prvAllowIPPacketIPv6_DestinationUnspecifiedAddress() memset( &xIPv6Address, 0, sizeof( xIPv6Address ) ); memcpy( xIPv6Address.xDestinationAddress.ucBytes, FreeRTOS_in6addr_any.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); memcpy( xIPv6Address.xSourceAddress.ucBytes, xIPAddressFive.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + xIPv6Address.ucVersionTrafficClass = 0x60U; eResult = prvAllowIPPacketIPv6( &xIPv6Address, NULL, 0U ); TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); @@ -100,6 +102,8 @@ void test_prvAllowIPPacketIPv6_HappyPath() NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptor(); TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnMAC_ExpectAndReturn( &pxTCPPacket->xEthernetHeader.xSourceAddress, NULL, NULL ); usGenerateProtocolChecksum_ExpectAndReturn( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, pdFALSE, ipCORRECT_CRC ); @@ -118,6 +122,7 @@ void test_prvAllowIPPacketIPv6_MulticastAddress() /* Multicast IPv6 address is FF02::1 */ IPv6_Address_t xMCIPAddress = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; memcpy( pxTCPPacket->xIPHeader.xDestinationAddress.ucBytes, xMCIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &( pxTCPPacket->xIPHeader.xSourceAddress ), pxNetworkBuffer->pxEndPoint ); @@ -139,6 +144,7 @@ void test_prvAllowIPPacketIPv6_LoopbackAddress() TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; NetworkEndPoint_t xEndPoint; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; memcpy( pxTCPPacket->xIPHeader.xSourceAddress.ucBytes, FreeRTOS_in6addr_loopback.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); memcpy( pxTCPPacket->xIPHeader.xDestinationAddress.ucBytes, FreeRTOS_in6addr_loopback.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); @@ -163,6 +169,7 @@ void test_prvAllowIPPacketIPv6_LoopbackNotMatchDest() NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptor(); TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; pxTCPPacket->xIPHeader.xDestinationAddress.ucBytes[ 15 ] = 0x11; FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &pxTCPPacket->xIPHeader.xSourceAddress, pxNetworkBuffer->pxEndPoint ); @@ -185,6 +192,7 @@ void test_prvAllowIPPacketIPv6_LoopbackNotMatchSrc() TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; NetworkEndPoint_t xEndPoint; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; memcpy( pxTCPPacket->xIPHeader.xDestinationAddress.ucBytes, FreeRTOS_in6addr_loopback.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &pxTCPPacket->xIPHeader.xSourceAddress, &xEndPoint ); @@ -206,6 +214,8 @@ void test_prvAllowIPPacketIPv6_NetworkDown() pxNetworkBuffer->pxEndPoint = NULL; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &pxTCPPacket->xIPHeader.xSourceAddress, NULL ); FreeRTOS_IsNetworkUp_IgnoreAndReturn( 0 ); FreeRTOS_FindEndPointOnMAC_ExpectAndReturn( &pxTCPPacket->xEthernetHeader.xSourceAddress, NULL, NULL ); @@ -225,6 +235,8 @@ void test_prvAllowIPPacketIPv6_SelfSend() NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptor(); TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnMAC_ExpectAndReturn( &pxTCPPacket->xEthernetHeader.xSourceAddress, NULL, pxNetworkBuffer->pxEndPoint ); eResult = prvAllowIPPacketIPv6( &pxTCPPacket->xIPHeader, pxNetworkBuffer, 0U ); @@ -241,6 +253,8 @@ void test_prvAllowIPPacketIPv6_ChecksumError() NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptor(); TCPPacket_IPv6_t * pxTCPPacket = ( TCPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnMAC_ExpectAndReturn( &pxTCPPacket->xEthernetHeader.xSourceAddress, NULL, NULL ); usGenerateProtocolChecksum_ExpectAndReturn( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, pdFALSE, ipWRONG_CRC ); @@ -260,6 +274,8 @@ void test_prvAllowIPPacketIPv6_InvalidPacket() pxNetworkBuffer->pxEndPoint = NULL; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &pxTCPPacket->xIPHeader.xSourceAddress, NULL ); FreeRTOS_IsNetworkUp_IgnoreAndReturn( 1 ); @@ -285,6 +301,8 @@ void test_prvAllowIPPacketIPv6_EndpointDifferentAddress() memcpy( xEndpoint.ipv6_settings.xIPAddress.ucBytes, xDiffIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); pxNetworkBuffer->pxEndPoint = &xEndpoint; + pxTCPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAndReturn( &( pxTCPPacket->xIPHeader.xSourceAddress ), NULL ); FreeRTOS_IsNetworkUp_IgnoreAndReturn( 1 ); diff --git a/test/unit-test/FreeRTOS_IPv6_Utils/FreeRTOS_IPv6_Utils_utest.c b/test/unit-test/FreeRTOS_IPv6_Utils/FreeRTOS_IPv6_Utils_utest.c index ad7e3daaa2..059b3a38d8 100644 --- a/test/unit-test/FreeRTOS_IPv6_Utils/FreeRTOS_IPv6_Utils_utest.c +++ b/test/unit-test/FreeRTOS_IPv6_Utils/FreeRTOS_IPv6_Utils_utest.c @@ -131,7 +131,7 @@ void test_prvChecksumIPv6Checks_IncompleteIPv6Packet( void ) BaseType_t usReturn; uint8_t pucEthernetBuffer[ ipconfigTCPv6_MSS ]; IPHeader_IPv6_t * pxIPv6Packet; - size_t uxBufferLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER; + size_t uxBufferLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 4; struct xPacketSummary xSet; memset( pucEthernetBuffer, 0, ipconfigTCPv6_MSS ); @@ -205,6 +205,46 @@ void test_prvChecksumIPv6Checks_LargeExtensionHeader( void ) TEST_ASSERT_EQUAL( 3, usReturn ); } +/** + * @brief Prepare a packet with large extension header length. + * - ipIPv6_EXT_HEADER_ROUTING_HEADER + * - ipIPv6_EXT_HEADER_HOP_BY_HOP + * - ipPROTOCOL_TCP + */ +void test_prvChecksumIPv6Checks_IncorrectPayloadLength( void ) +{ + BaseType_t usReturn; + struct xPacketSummary xSet; + NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptorWithExtensionHeader( ipPROTOCOL_TCP ); + IPHeader_IPv6_t * pxIPv6Header = ( IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ); + size_t uxIndex = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER; + + /* Modify the extension header */ + pxIPv6Header->ucNextHeader = ipIPv6_EXT_HEADER_HOP_BY_HOP; + pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] = ipIPv6_EXT_HEADER_ROUTING_HEADER; + pxNetworkBuffer->pucEthernetBuffer[ uxIndex + 1 ] = 5U; /* Extension header length is set to 200*8 + 8, which is larger than buffer size. */ + uxIndex += 8; + pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] = ipPROTOCOL_TCP; + pxNetworkBuffer->pucEthernetBuffer[ uxIndex + 1 ] = 0; + uxIndex += 8; + + xSet.pxIPPacket_IPv6 = ( ( const IPHeader_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); + IPHeader_IPv6_t * pxIPPacket_IPv6 = ( IPHeader_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer; + + /* Incorrect payload length */ + pxIPPacket_IPv6->usPayloadLength = FreeRTOS_ntohs( 20 ); + + xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_HOP_BY_HOP, 0U, 1 ); + xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_HOP_BY_HOP, ipIPv6_EXT_HEADER_ROUTING_HEADER, 1 ); + xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_ROUTING_HEADER, ipPROTOCOL_TCP, 2 ); + xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_ROUTING_HEADER, ipPROTOCOL_TCP, 2 ); + + usReturn = prvChecksumIPv6Checks( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, &xSet ); + + TEST_ASSERT_EQUAL( 4, usReturn ); +} + + /** * @brief Prepare a packet have extension with following order. * - ipIPv6_EXT_HEADER_ROUTING_HEADER diff --git a/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c b/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c index e75c5fdd5a..ed2c356487 100644 --- a/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c +++ b/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c @@ -115,18 +115,53 @@ void test_eNDGetCacheEntry_MulticastEndPoint( void ) IPv6_Address_t xIPAddress; NetworkEndPoint_t xEndPoint, * pxEndPoint = &xEndPoint; + xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; ( void ) memcpy( xIPAddress.ucBytes, xMultiCastIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); xIsIPv6AllowedMulticast_ExpectAnyArgsAndReturn( pdTRUE ); vSetMultiCastIPv6MacAddress_ExpectAnyArgs(); - FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( NULL ); + FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( &xEndPoint ); + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); eResult = eNDGetCacheEntry( &xIPAddress, &xMACAddress, &pxEndPoint ); TEST_ASSERT_EQUAL( eARPCacheHit, eResult ); } + +/** + * @brief This function find the MAC-address of a multicast IPv6 address + * with a multiple endpoints endpoint. + */ +void test_eNDGetCacheEntry_MulticastEndPoint_NoEP( void ) +{ + eARPLookupResult_t eResult; + MACAddress_t xMACAddress; + IPv6_Address_t xIPAddress; + NetworkEndPoint_t xEndPoint, xEndPoint2, * pxEndPoint = &xEndPoint; + + xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; + xEndPoint2.bits.bIPv6 = pdFALSE_UNSIGNED; + ( void ) memcpy( xIPAddress.ucBytes, xMultiCastIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + + xIsIPv6AllowedMulticast_ExpectAnyArgsAndReturn( pdTRUE ); + vSetMultiCastIPv6MacAddress_ExpectAnyArgs(); + + FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( NULL ); + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); + + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAnyArgsAndReturn( NULL ); + + FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( pxEndPoint ); + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_Global ); + FreeRTOS_NextEndPoint_ExpectAnyArgsAndReturn( NULL ); + + eResult = eNDGetCacheEntry( &xIPAddress, &xMACAddress, &pxEndPoint ); + + TEST_ASSERT_EQUAL( eARPCacheMiss, eResult ); +} + /** * @brief This function find the MAC-address of a multicast IPv6 address * with a valid endpoint. @@ -167,15 +202,45 @@ void test_eNDGetCacheEntry_Multicast_InvalidEndPoint( void ) eARPLookupResult_t eResult; MACAddress_t xMACAddress; IPv6_Address_t xIPAddress; + NetworkEndPoint_t xEndPoint, * pxEndPoint = &xEndPoint; + + ( void ) memcpy( xIPAddress.ucBytes, xMultiCastIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); + + xIsIPv6AllowedMulticast_ExpectAnyArgsAndReturn( pdTRUE ); + vSetMultiCastIPv6MacAddress_ExpectAnyArgs(); + + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_Multicast ); + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAnyArgsAndReturn( pxEndPoint ); + + eResult = eNDGetCacheEntry( &xIPAddress, &xMACAddress, ppxEndPoint ); + + TEST_ASSERT_EQUAL( eARPCacheMiss, eResult ); +} + +/** + * @brief This function find the MAC-address of a multicast IPv6 address + * with a NULL endpoint, but no active IPv6 endpoints. + */ +void test_eNDGetCacheEntry_Multicast_InvalidEndPoint_NoEP( void ) +{ + NetworkEndPoint_t ** ppxEndPoint = NULL; + eARPLookupResult_t eResult; + MACAddress_t xMACAddress; + IPv6_Address_t xIPAddress; + NetworkEndPoint_t xEndPoint, * pxEndPoint = &xEndPoint, xEndPoint1; ( void ) memcpy( xIPAddress.ucBytes, xMultiCastIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); xIsIPv6AllowedMulticast_ExpectAnyArgsAndReturn( pdTRUE ); vSetMultiCastIPv6MacAddress_ExpectAnyArgs(); + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_Multicast ); + FreeRTOS_FindEndPointOnIP_IPv6_ExpectAnyArgsAndReturn( NULL ); + FreeRTOS_FindGateWay_ExpectAnyArgsAndReturn( &xEndPoint1 ); + eResult = eNDGetCacheEntry( &xIPAddress, &xMACAddress, ppxEndPoint ); - TEST_ASSERT_EQUAL( eARPCacheHit, eResult ); + TEST_ASSERT_EQUAL( eARPCacheMiss, eResult ); } /** @@ -1155,12 +1220,36 @@ void test_prvProcessICMPMessage_IPv6_EP( void ) pxNetworkBuffer->pxEndPoint = &xEndPoint; xEndPoint.bits.bIPv6 = pdFALSE_UNSIGNED; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); + + eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); + + TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); +} + +/** + * @brief This function process ICMP message when message has size + * less than ICMPv6 header size + */ +void test_prvProcessICMPMessage_IPv6_PacketSizeBelowHeaderSize( void ) +{ + NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer = &xNetworkBuffer; + ICMPPacket_IPv6_t xICMPPacket; + NetworkEndPoint_t xEndPoint; + eFrameProcessingResult_t eReturn; + + xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; + xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_DEST_UNREACHABLE_IPv6; + pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; + pxNetworkBuffer->xDataLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 2U; eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); } + /** * @brief This function process ICMP message when message type is * ipICMP_DEST_UNREACHABLE_IPv6. @@ -1176,6 +1265,7 @@ void test_prvProcessICMPMessage_IPv6_ipICMP_DEST_UNREACHABLE_IPv6( void ) xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_DEST_UNREACHABLE_IPv6; pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); @@ -1404,7 +1494,7 @@ void test_prvProcessICMPMessage_IPv6_ipICMP_PING_REPLY_IPv6_eInvalidData( void ) uxICMPSize = ( size_t ) usICMPSize; uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); /* Assign less size than expected */ - pxNetworkBuffer->xDataLength = uxICMPSize; + pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; @@ -1415,6 +1505,47 @@ void test_prvProcessICMPMessage_IPv6_ipICMP_PING_REPLY_IPv6_eInvalidData( void ) TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); } +/** + * @brief This function process ICMP message when message type is + * ipICMP_PING_REPLY_IPv6. + * It handles case where A reply was received to an outgoing + * ping but the payload of the reply was not correct. + */ +void test_prvProcessICMPMessage_IPv6_ipICMP_PING_REPLY_IPv6_IncorrectSize( void ) +{ + NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer = &xNetworkBuffer; + ICMPPacket_IPv6_t * pxICMPPacket; + ICMPHeader_IPv6_t * pxICMPHeader_IPv6; + ICMPEcho_IPv6_t * pxICMPEchoHeader; + uint8_t ucBuffer[ sizeof( ICMPPacket_IPv6_t ) + ipBUFFER_PADDING ], * pucByte; + NetworkEndPoint_t xEndPoint; + size_t uxDataLength; + eFrameProcessingResult_t eReturn; + + pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &ucBuffer; + pxNetworkBuffer->xDataLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 5; + pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); + pxICMPPacket->xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_PING_REPLY_IPv6; + pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_ntohs( ipBUFFER_PADDING ); + pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); + pxICMPEchoHeader = ( ( ICMPEcho_IPv6_t * ) pxICMPHeader_IPv6 ); + xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; + + uxDataLength = ipNUMERIC_CAST( size_t, FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ) ); + uxDataLength = uxDataLength - sizeof( ICMPEcho_IPv6_t ); + + pucByte = ( ucBuffer + sizeof( EthernetHeader_t ) + sizeof( IPHeader_IPv6_t ) + sizeof( ICMPEcho_IPv6_t ) ); + + ( void ) memset( pucByte, ipECHO_DATA_FILL_BYTE, uxDataLength ); + + /* vApplicationPingReplyHook_Expect( eSuccess, pxICMPEchoHeader->usIdentifier ); */ + + eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); + + TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); +} + /** * @brief This function process ICMP message when message type is * ipICMP_PING_REPLY_IPv6. @@ -1434,6 +1565,7 @@ void test_prvProcessICMPMessage_IPv6_ipICMP_PING_REPLY_IPv6_eSuccess( void ) pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &ucBuffer; + pxNetworkBuffer->xDataLength = sizeof( ucBuffer ); pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); pxICMPPacket->xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_PING_REPLY_IPv6; pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_ntohs( ipBUFFER_PADDING ); @@ -1498,7 +1630,7 @@ void test_prvProcessICMPMessage_IPv6_NeighborSolicitationIncorrectLen( void ) xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_SOLICITATION_IPv6; pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; - pxNetworkBuffer->xDataLength = 0; + pxNetworkBuffer->xDataLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 5; FreeRTOS_InterfaceEPInSameSubnet_IPv6_ExpectAnyArgsAndReturn( &xEndPoint ); @@ -1543,6 +1675,32 @@ void test_prvProcessICMPMessage_IPv6_NeighborSolicitation( void ) TEST_ASSERT_EQUAL( xICMPPacket.xIPHeader.ucHopLimit, 255U ); } +/** + * @brief This function process ICMP message when message type is + * ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6. + * It handles case buffer size is less than expected. + */ +void test_prvProcessICMPMessage_IPv6_NeighborAdvertisement0( void ) +{ + NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer = &xNetworkBuffer; + ICMPPacket_IPv6_t xICMPPacket; + ICMPHeader_IPv6_t * pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( xICMPPacket.xICMPHeaderIPv6 ) ); + NetworkEndPoint_t xEndPoint; + eFrameProcessingResult_t eReturn; + + xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; + pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; + pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->xDataLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 5; + xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; + pxARPWaitingNetworkBuffer = NULL; + + + eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); + + TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); +} + /** * @brief This function process ICMP message when message type is * ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6. @@ -1559,6 +1717,7 @@ void test_prvProcessICMPMessage_IPv6_NeighborAdvertisement1( void ) xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; pxARPWaitingNetworkBuffer = NULL; @@ -1585,6 +1744,7 @@ void test_prvProcessICMPMessage_IPv6_NeighborAdvertisement2( void ) xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; pxARPWaitingNetworkBuffer = &xARPWaitingNetworkBuffer; @@ -1651,6 +1811,7 @@ void test_prvProcessICMPMessage_IPv6_NeighborAdvertisement4( void ) xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, xDefaultIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); ( void ) memcpy( pxIPHeader->xSourceAddress.ucBytes, xDefaultIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); @@ -1691,6 +1852,7 @@ void test_prvProcessICMPMessage_IPv6_NeighborAdvertisement5( void ) xEndPoint.bits.bIPv6 = pdTRUE_UNSIGNED; pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket; pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->xDataLength = sizeof( ICMPPacket_IPv6_t ); xICMPPacket.xICMPHeaderIPv6.ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, xDefaultIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); ( void ) memcpy( pxIPHeader->xSourceAddress.ucBytes, xDefaultIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );