1
0
mirror of https://github.com/FreeRTOS/FreeRTOS-Plus-TCP synced 2025-10-20 22:10:04 +08:00
Files
FreeRTOS-Plus-TCP/source/FreeRTOS_IPv6.c
Hein Tibosch ff11a1484a Dev integration hein.v8 (#738)
* Updating tcp utilities

* Some more change in dev_integration_hein.v8

* In FreeRTOS_DNS_Parser.c : use 'ipUDP_PAYLOAD_OFFSET_IPv4' in stead of 'ipIP_PAYLOAD_OFFSET'

* And a few more corrections

* Changes to WinPCap network interface, removed debugging code

* After applying uncrustify

* Oops, I forgot the push changes in include files.

* Now removing it, hopefully

---------

Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com>
Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com>
2023-02-23 14:50:27 +05:30

402 lines
14 KiB
C

/*
* FreeRTOS+TCP <DEVELOPMENT BRANCH>
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_IP.c
* @brief Implements the basic functionality for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
/* *INDENT-OFF* */
#if( ipconfigUSE_IPv6 != 0 )
/* *INDENT-ON* */
const struct xIPv6_Address in6addr_any = { 0 };
const struct xIPv6_Address in6addr_loopback = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } };
BaseType_t xIsIPv6Multicast( const IPv6_Address_t * pxIPAddress )
{
BaseType_t xReturn;
if( pxIPAddress->ucBytes[ 0 ] == 0xffU )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xCompareIPv6_Address( const IPv6_Address_t * pxLeft,
const IPv6_Address_t * pxRight,
size_t uxPrefixLength )
{
BaseType_t xResult;
/* 0 2 4 6 8 10 12 14 */
/* ff02:0000:0000:0000:0000:0001:ff66:4a81 */
if( ( pxRight->ucBytes[ 0 ] == 0xffU ) &&
( pxRight->ucBytes[ 1 ] == 0x02U ) &&
( pxRight->ucBytes[ 12 ] == 0xffU ) )
{
/* This is an LLMNR address. */
xResult = memcmp( &( pxLeft->ucBytes[ 13 ] ), &( pxRight->ucBytes[ 13 ] ), 3 );
}
else
if( ( pxRight->ucBytes[ 0 ] == 0xffU ) &&
( pxRight->ucBytes[ 1 ] == 0x02U ) )
{
/* FF02::1 is all node address to reach out all nodes in the same link. */
xResult = 0;
}
else
if( ( pxRight->ucBytes[ 0 ] == 0xfeU ) &&
( pxRight->ucBytes[ 1 ] == 0x80U ) &&
( pxLeft->ucBytes[ 0 ] == 0xfeU ) &&
( pxLeft->ucBytes[ 1 ] == 0x80U ) )
{
/* Both are local addresses. */
xResult = 0;
}
else
{
if( uxPrefixLength == 0U )
{
xResult = 0;
}
else if( uxPrefixLength == ( 8U * ipSIZE_OF_IPv6_ADDRESS ) )
{
xResult = memcmp( pxLeft->ucBytes, pxRight->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
}
else
{
size_t uxLength = uxPrefixLength / 8U;
xResult = 0;
if( uxLength > 0U )
{
xResult = memcmp( pxLeft->ucBytes, pxRight->ucBytes, uxLength );
}
if( ( xResult == 0 ) && ( ( uxPrefixLength % 8U ) != 0U ) )
{
/* One byte has both a network- and a host-address. */
size_t uxBits = uxPrefixLength % 8U;
size_t uxHostLen = 8U - uxBits;
uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
if( ( pxLeft->ucBytes[ uxLength ] & ucNetMask ) != ( pxRight->ucBytes[ uxLength ] & ucNetMask ) )
{
xResult = 1;
}
}
}
}
return xResult;
}
/*-----------------------------------------------------------*/
/**
* @brief Check whether this IPv6 packet is to be allowed or to be dropped.
*
* @param[in] pxIPv6Header: The IP packet under consideration.
* @param[in] pxNetworkBuffer: The whole network buffer.
* @param[in] uxHeaderLength: The length of the header.
*
* @return Whether the packet should be processed or dropped.
*/
eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxIPv6Header,
const NetworkBufferDescriptor_t * const pxNetworkBuffer,
UBaseType_t uxHeaderLength )
{
eFrameProcessingResult_t eReturn;
#if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
{
/* In systems with a very small amount of RAM, it might be advantageous
* to have incoming messages checked earlier, by the network card driver.
* This method may decrease the usage of sparse network buffers. */
const IPv6_Address_t * pxDestinationIPAddress = &( pxIPv6Header->xDestinationAddress );
/* Is the packet for this IP address? */
if( ( pxNetworkBuffer->pxEndPoint != NULL ) ||
/* Is it the multicast address FF00::/8 ? */
( xIsIPv6Multicast( pxDestinationIPAddress ) != pdFALSE ) ||
/* Or (during DHCP negotiation) we have no IP-address yet? */
( FreeRTOS_IsNetworkUp() == 0 ) )
{
/* Packet is not for this node, or the network is still not up,
* release it */
eReturn = eProcessBuffer;
}
else
{
eReturn = eReleaseBuffer;
FreeRTOS_printf( ( "prvAllowIPPacketIPv6: drop %pip (from %pip)\n", pxDestinationIPAddress->ucBytes, pxIPv6Header->xSourceAddress.ucBytes ) );
}
}
#else /* if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) */
{
( void ) pxIPv6Header;
/* The packet has been checked by the network interface. */
eReturn = eProcessBuffer;
}
#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
#if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )
{
/* Some drivers of NIC's with checksum-offloading will enable the above
* define, so that the checksum won't be checked again here */
if( eReturn == eProcessBuffer )
{
const IPPacket_t * pxIPPacket = ( ( const IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxIPPacket->xEthernetHeader.xSourceAddress ), NULL );
/* IPv6 does not have a separate checksum in the IP-header */
/* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
/* Do not check the checksum of loop-back messages. */
if( pxEndPoint == NULL )
{
if( usGenerateProtocolChecksum( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
{
/* Protocol checksum not accepted. */
eReturn = eReleaseBuffer;
}
}
}
}
#else /* if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) */
{
/* to avoid warning unused parameters */
( void ) pxNetworkBuffer;
}
#endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
( void ) uxHeaderLength;
return eReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xGetExtensionOrder( uint8_t ucProtocol,
uint8_t ucNextHeader )
{
BaseType_t xReturn;
switch( ucProtocol )
{
case ipIPv6_EXT_HEADER_HOP_BY_HOP:
xReturn = 1;
break;
case ipIPv6_EXT_HEADER_DESTINATION_OPTIONS:
xReturn = 7;
if( ucNextHeader == ipIPv6_EXT_HEADER_ROUTING_HEADER )
{
xReturn = 2;
}
break;
case ipIPv6_EXT_HEADER_ROUTING_HEADER:
xReturn = 3;
break;
case ipIPv6_EXT_HEADER_FRAGMENT_HEADER:
xReturn = 4;
break;
case ipIPv6_EXT_HEADER_AUTHEN_HEADER:
xReturn = 5;
break;
case ipIPv6_EXT_HEADER_SECURE_PAYLOAD:
xReturn = 6;
break;
/* Destination options may follow here in case there are no routing options. */
case ipIPv6_EXT_HEADER_MOBILITY_HEADER:
xReturn = 8;
break;
default:
xReturn = -1;
break;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Handle the IPv6 extension headers.
*
* @param[in,out] pxNetworkBuffer: The received packet that contains IPv6 extension headers.
*
* @return eProcessBuffer in case the options are removed successfully, otherwise
* eReleaseBuffer.
*/
eFrameProcessingResult_t eHandleIPv6ExtensionHeaders( NetworkBufferDescriptor_t * const pxNetworkBuffer,
BaseType_t xDoRemove )
{
eFrameProcessingResult_t eResult = eReleaseBuffer;
const size_t uxMaxLength = pxNetworkBuffer->xDataLength;
const uint8_t * pucSource = pxNetworkBuffer->pucEthernetBuffer;
/* 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] */
IPPacket_IPv6_t * pxIPPacket_IPv6 = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
size_t uxIndex = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER;
size_t uxHopSize = 0U;
size_t xMoveLen = 0U;
size_t uxRemovedBytes = 0U;
uint8_t ucCurrentHeader = pxIPPacket_IPv6->xIPHeader.ucNextHeader;
uint8_t ucNextHeader = 0U;
BaseType_t xNextOrder = 0;
while( ( uxIndex + 8U ) < uxMaxLength )
{
BaseType_t xCurrentOrder;
ucNextHeader = pucSource[ uxIndex ];
xCurrentOrder = xGetExtensionOrder( ucCurrentHeader, ucNextHeader );
/* Read the length expressed in number of octets. */
uxHopSize = ( size_t ) pucSource[ uxIndex + 1U ];
/* And multiply by 8 and add the minimum size of 8. */
uxHopSize = ( uxHopSize * 8U ) + 8U;
if( ( uxIndex + uxHopSize ) >= uxMaxLength )
{
uxIndex = uxMaxLength;
break;
}
uxIndex = uxIndex + uxHopSize;
if( ( ucNextHeader == ipPROTOCOL_TCP ) ||
( ucNextHeader == ipPROTOCOL_UDP ) ||
( ucNextHeader == ipPROTOCOL_ICMP_IPv6 ) )
{
FreeRTOS_debug_printf( ( "Stop at header %u\n", ucNextHeader ) );
break;
}
xNextOrder = xGetExtensionOrder( ucNextHeader, pucSource[ uxIndex ] );
FreeRTOS_debug_printf( ( "Going from header %2u (%d) to %2u (%d)\n",
ucCurrentHeader,
( int ) xCurrentOrder,
ucNextHeader,
( int ) xNextOrder ) );
if( xNextOrder <= xCurrentOrder )
{
FreeRTOS_printf( ( "Wrong order\n" ) );
uxIndex = uxMaxLength;
break;
}
ucCurrentHeader = ucNextHeader;
}
if( uxIndex < uxMaxLength )
{
uint8_t * pucTo;
const uint8_t * pucFrom;
uint16_t usPayloadLength = FreeRTOS_ntohs( pxIPPacket_IPv6->xIPHeader.usPayloadLength );
uxRemovedBytes = uxIndex - ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER );
if( uxRemovedBytes >= ( size_t ) usPayloadLength )
{
/* Can not remove more bytes than the payload length. */
}
else if( xDoRemove == pdTRUE )
{
pxIPPacket_IPv6->xIPHeader.ucNextHeader = ucNextHeader;
pucTo = &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ] );
pucFrom = &( pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] );
xMoveLen = uxMaxLength - uxIndex;
( void ) memmove( pucTo, pucFrom, xMoveLen );
pxNetworkBuffer->xDataLength -= uxRemovedBytes;
usPayloadLength -= ( uint16_t ) uxRemovedBytes;
pxIPPacket_IPv6->xIPHeader.usPayloadLength = FreeRTOS_htons( usPayloadLength );
eResult = eProcessBuffer;
}
else
{
/* xDoRemove is false, so the function is not supposed to
* remove extension headers. */
}
}
FreeRTOS_printf( ( "Extension headers : %s Truncated %u bytes. Removed %u, Payload %u xDataLength now %u\n",
( eResult == eProcessBuffer ) ? "good" : "bad",
xMoveLen,
uxRemovedBytes,
FreeRTOS_ntohs( pxIPPacket_IPv6->xIPHeader.usPayloadLength ),
pxNetworkBuffer->xDataLength ) );
return eResult;
}
/*-----------------------------------------------------------*/
/* *INDENT-OFF* */
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
/* *INDENT-ON* */