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 bf816e2b0d..159add0960 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 9c82fa4855..4862c07aaf 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.3.4 and V4.3.3 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.3.3 and V4.3.2 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 722881c6d4..57bd1b6dc8 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.3.3 +PROJECT_NUMBER = V4.3.4 # 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 8a9a77b1b3..99f3855252 100644 --- a/manifest.yml +++ b/manifest.yml @@ -1,5 +1,5 @@ name: "FreeRTOS-Plus-TCP" -version: "V4.3.3" +version: "V4.3.4" 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 c202db9bf8..082476c2f8 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 9be64737c2..66dc8932c9 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 fab6014f1c..4e7efa975e 100644 --- a/source/FreeRTOS_ND.c +++ b/source/FreeRTOS_ND.c @@ -153,7 +153,7 @@ MACAddress_t * const pxMACAddress, NetworkEndPoint_t ** ppxEndPoint ) { - eResolutionLookupResult_t eReturn; + eResolutionLookupResult_t eReturn = eResolutionCacheMiss; /* Mostly used multi-cast address is ff02::. */ if( xIsIPv6AllowedMulticast( pxAddressToLookup ) != pdFALSE ) @@ -163,14 +163,20 @@ if( ppxEndPoint != NULL ) { *ppxEndPoint = pxFindLocalEndpoint(); - } - eReturn = eResolutionCacheHit; + if( *ppxEndPoint != NULL ) + { + eReturn = eResolutionCacheHit; + } + else + { + /* No link-local endpoint configured, eResolutionCacheMiss */ + } + } } else { - /* Not a multicast IP address. */ - eReturn = eResolutionCacheMiss; + /* Not a multicast IP address, eResolutionCacheMiss */ } return eReturn; @@ -258,12 +264,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; + } } } } @@ -978,194 +987,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( ( pxNDWaitingNetworkBuffer != NULL ) && - ( uxIPHeaderSizePacket( pxNDWaitingNetworkBuffer ) == 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( ( pxNDWaitingNetworkBuffer != NULL ) && + ( uxIPHeaderSizePacket( pxNDWaitingNetworkBuffer ) == 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 d82e474c8c..473c0110e2 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 8fdbc87a71..602d429797 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 3dc315ed47..6a9dd7a39a 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 e570916220..5c1d78323f 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,47 @@ 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 6b5837fbdf..fe8d59849e 100644 --- a/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c +++ b/test/unit-test/FreeRTOS_ND/FreeRTOS_ND_utest.c @@ -114,18 +114,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( eResolutionCacheHit, eResult ); } +/** + * @brief This function find the MAC-address of a multicast IPv6 address + * with a multiple endpoints endpoint. + */ +void test_eNDGetCacheEntry_MulticastEndPoint_NoEP( void ) +{ + eResolutionLookupResult_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( eResolutionCacheMiss, eResult ); +} + + /** * @brief This function find the MAC-address of a multicast IPv6 address * with a valid endpoint. @@ -166,17 +201,49 @@ void test_eNDGetCacheEntry_Multicast_InvalidEndPoint( void ) eResolutionLookupResult_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( eResolutionCacheHit, eResult ); + TEST_ASSERT_EQUAL( eResolutionCacheMiss, 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; + eResolutionLookupResult_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( eResolutionCacheMiss, eResult ); +} + + /** * @brief This function find the MAC-address of an IPv6 address which is * not multi cast address, but the entry is present on the ND Cache, @@ -1188,6 +1255,29 @@ 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 ); @@ -1209,6 +1299,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 ); @@ -1437,7 +1528,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; @@ -1448,6 +1539,48 @@ 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. @@ -1467,6 +1600,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 ); @@ -1531,7 +1665,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 ); @@ -1576,6 +1710,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; + pxNDWaitingNetworkBuffer = NULL; + + + eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer ); + + TEST_ASSERT_EQUAL( eReturn, eReleaseBuffer ); +} + /** * @brief This function process ICMP message when message type is * ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6. @@ -1592,6 +1752,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; pxNDWaitingNetworkBuffer = NULL; @@ -1618,6 +1779,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; pxNDWaitingNetworkBuffer = &xNDWaitingNetworkBuffer; @@ -1684,6 +1846,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 ); @@ -1724,6 +1887,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 ); @@ -2058,6 +2222,8 @@ void test_xCheckRequiresNDResolution_Hit( void ) ( void ) memset( xNDCache, 0, sizeof( xNDCache ) ); + xEndPoint.bits.bIPv6 = pdTRUE; + pxNetworkBuffer = &xNetworkBuffer; pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ucEthernetBuffer; @@ -2071,7 +2237,8 @@ void test_xCheckRequiresNDResolution_Hit( void ) xIsIPv6AllowedMulticast_ExpectAndReturn( pxIPAddress, pdTRUE ); vSetMultiCastIPv6MacAddress_Expect( pxIPAddress, NULL ); vSetMultiCastIPv6MacAddress_IgnoreArg_pxMACAddress(); - FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( NULL ); + FreeRTOS_FirstEndPoint_ExpectAnyArgsAndReturn( &xEndPoint ); + xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); xResult = xCheckRequiresNDResolution( pxNetworkBuffer ); TEST_ASSERT_EQUAL( pdFALSE, xResult ); @@ -2083,15 +2250,17 @@ void test_xCheckRequiresNDResolution_Hit( void ) void test_xCheckRequiresNDResolution_Miss( void ) { struct xNetworkEndPoint xEndPoint, * pxEndPoint = &xEndPoint; - NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer; + NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer, * pxNewNetworkBuffer = &xNetworkBuffer; uint8_t ucEthernetBuffer[ ipconfigNETWORK_MTU ]; BaseType_t xResult; ( void ) memset( xNDCache, 0, sizeof( xNDCache ) ); + xEndPoint.bits.bIPv6 = pdTRUE; pxNetworkBuffer = &xNetworkBuffer; pxNetworkBuffer->pxEndPoint = &xEndPoint; pxNetworkBuffer->pucEthernetBuffer = ucEthernetBuffer; + pxNetworkBuffer->xDataLength = ipconfigNETWORK_MTU; IPPacket_IPv6_t * pxIPPacket_V6 = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); IPHeader_IPv6_t * pxIPHeader_V6 = &( pxIPPacket_V6->xIPHeader ); IPv6_Address_t * pxIPAddress = &( pxIPHeader_V6->xSourceAddress ); @@ -2103,19 +2272,29 @@ void test_xCheckRequiresNDResolution_Miss( void ) xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); FreeRTOS_FindEndPointOnIP_IPv6_ExpectAnyArgsAndReturn( pxEndPoint ); pxGetNetworkBufferWithDescriptor_ExpectAnyArgsAndReturn( pxNetworkBuffer ); - vReleaseNetworkBufferAndDescriptor_Expect( pxNetworkBuffer ); + usGenerateProtocolChecksum_ExpectAnyArgsAndReturn( 0 ); + vReturnEthernetFrame_ExpectAnyArgs(); xResult = xCheckRequiresNDResolution( pxNetworkBuffer ); TEST_ASSERT_EQUAL( pdTRUE, xResult ); + pxNetworkBuffer = &xNetworkBuffer; + pxNetworkBuffer->pxEndPoint = &xEndPoint; + pxNetworkBuffer->pucEthernetBuffer = ucEthernetBuffer; + pxNetworkBuffer->xDataLength = ipconfigNETWORK_MTU; + pxIPPacket_V6 = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); + pxIPHeader_V6 = &( pxIPPacket_V6->xIPHeader ); + pxIPAddress = &( pxIPHeader_V6->xSourceAddress ); + pxIPPacket_V6->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE; + pxIPHeader_V6->ucNextHeader = ipPROTOCOL_TCP; xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); xIsIPv6AllowedMulticast_ExpectAndReturn( pxIPAddress, pdFALSE ); xIPv6_GetIPType_ExpectAnyArgsAndReturn( eIPv6_LinkLocal ); FreeRTOS_FindEndPointOnIP_IPv6_ExpectAnyArgsAndReturn( pxEndPoint ); pxGetNetworkBufferWithDescriptor_ExpectAnyArgsAndReturn( NULL ); - xResult = xCheckRequiresNDResolution( pxNetworkBuffer ); + xResult = xCheckRequiresNDResolution( &xNetworkBuffer ); TEST_ASSERT_EQUAL( pdTRUE, xResult ); }