1
0
mirror of https://github.com/FreeRTOS/FreeRTOS-Plus-TCP synced 2025-10-21 06:40:08 +08:00
Files
FreeRTOS-Plus-TCP/source/FreeRTOS_IPv4.c
Tony Josi 0e9628796c Fixing doxygen comments (#728)
* updating doxygen config

* fixing doxygen comments

* adding IPv6 files and fixing comments

* fix doxygen cfg and file names in comments

* wip doxygen v6 docs

* adding doxygen comments

* include RA src file to doxgendocs generation

* fix spell check issues

* Uncrustify: triggered by comment.

* fix minor build issue

* fix spell check issues

* Uncrustify: triggered by comment

* fix trailing white space

* 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>

* Fix CBMC proofs for DNS (#718)

* Use CBMC XML output to enable VSCode debugger (#673)

Prior to this commit, CBMC would emit logging information in plain text
format, which does not contain information required for the CBMC VSCode
debugger. This commit makes CBMC use XML instead of plain text.

Co-authored-by: Mark Tuttle <tuttle@acm.org>

* wip

* wip DNSgetHostByName

* wip DNSgetHostByName

* fixed cbmc proof for DNS_ReadNameField

* wip DNSgetHostByName_a_harness

* Fix CBMC prooff for DNSgetHostByName

* wip fix DNSgetHostByName_a CBMC proof

* fixed cbmc target func not called issue in DNSclear

* fixed cbmc target func not called issue in DNSlookup

* fix DNSgetHostByName_a CBMC proof

* update comments

* more asserts

* fixing formatting

* updating as per review comments

* fix dns after review comments

* adding more asserts

* adds more asserts

* minor fix

* fixing comments

* fixing comments

* fixing minor issue

* fixing DNS_ReadReply() signature

* making code more consistant

* adding more  asserts

* making code more consistent

---------

Co-authored-by: Kareem Khazem <karkhaz@amazon.com>
Co-authored-by: Mark Tuttle <tuttle@acm.org>

* Uncrustify: triggered by comment

* fixing formatting

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Hein Tibosch <hein_tibosch@yahoo.es>
Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com>
Co-authored-by: Monika Singh <108652024+moninom1@users.noreply.github.com>
Co-authored-by: Kareem Khazem <karkhaz@amazon.com>
Co-authored-by: Mark Tuttle <tuttle@acm.org>
2023-02-24 13:58:53 +05:30

335 lines
16 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_IPv4.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"
#include "FreeRTOS_IPv4.h"
/* IPv4 multi-cast addresses range from 224.0.0.0.0 to 240.0.0.0. */
#define ipFIRST_MULTI_CAST_IPv4 0xE0000000U /**< Lower bound of the IPv4 multicast address. */
#define ipLAST_MULTI_CAST_IPv4 0xF0000000U /**< Higher bound of the IPv4 multicast address. */
/**
* @brief Is the IP address an IPv4 multicast address.
*
* @param[in] ulIPAddress: The IP address being checked.
*
* @return pdTRUE if the IP address is a multicast address or else, pdFALSE.
*/
BaseType_t xIsIPv4Multicast( uint32_t ulIPAddress )
{
BaseType_t xReturn;
uint32_t ulIP = FreeRTOS_ntohl( ulIPAddress );
if( ( ulIP >= ipFIRST_MULTI_CAST_IPv4 ) && ( ulIP < ipLAST_MULTI_CAST_IPv4 ) )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Check whether this IPv4 packet is to be allowed or to be dropped.
*
* @param[in] pxIPPacket: 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 prvAllowIPPacketIPv4( const IPPacket_t * const pxIPPacket,
const NetworkBufferDescriptor_t * const pxNetworkBuffer,
UBaseType_t uxHeaderLength )
{
eFrameProcessingResult_t eReturn = eProcessBuffer;
#if ( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
#else
/* or else, the parameter won't be used and the function will be optimised
* away */
( void ) pxIPPacket;
#endif
#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. */
uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
uint32_t ulSourceIPAddress = pxIPHeader->ulSourceIPAddress;
/* Ensure that the incoming packet is not fragmented because the stack
* doesn't not support IP fragmentation. All but the last fragment coming in will have their
* "more fragments" flag set and the last fragment will have a non-zero offset.
* We need to drop the packet in either of those cases. */
if( ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U ) || ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_FLAGS_MORE_FRAGMENTS ) != 0U ) )
{
/* Can not handle, fragmented packet. */
eReturn = eReleaseBuffer;
}
/* Test if the length of the IP-header is between 20 and 60 bytes,
* and if the IP-version is 4. */
else if( ( pxIPHeader->ucVersionHeaderLength < ipIPV4_VERSION_HEADER_LENGTH_MIN ) ||
( pxIPHeader->ucVersionHeaderLength > ipIPV4_VERSION_HEADER_LENGTH_MAX ) )
{
/* Can not handle, unknown or invalid header version. */
eReturn = eReleaseBuffer;
}
else if(
( FreeRTOS_FindEndPointOnIP_IPv4( ulDestinationIPAddress, 4 ) == NULL ) &&
( pxNetworkBuffer->pxEndPoint == NULL ) &&
/* Is it an IPv4 broadcast address x.x.x.255 ? */
( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xffU ) != 0xffU ) &&
( xIsIPv4Multicast( ulDestinationIPAddress ) == pdFALSE ) &&
/* Or (during DHCP negotiation) we have no IP-address yet? */
( FreeRTOS_IsNetworkUp() != pdFALSE ) )
{
/* Packet is not for this node, release it */
eReturn = eReleaseBuffer;
}
/* Is the source address correct? */
else if( ( FreeRTOS_ntohl( ulSourceIPAddress ) & 0xffU ) == 0xffU )
{
/* The source address cannot be broadcast address. Replying to this
* packet may cause network storms. Drop the packet. */
eReturn = eReleaseBuffer;
}
else if( ( memcmp( xBroadcastMACAddress.ucBytes,
pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes,
sizeof( MACAddress_t ) ) == 0 ) &&
( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xffU ) != 0xffU ) )
{
/* Ethernet address is a broadcast address, but the IP address is not a
* broadcast address. */
eReturn = eReleaseBuffer;
}
else if( memcmp( xBroadcastMACAddress.ucBytes,
pxIPPacket->xEthernetHeader.xSourceAddress.ucBytes,
sizeof( MACAddress_t ) ) == 0 )
{
/* Ethernet source is a broadcast address. Drop the packet. */
eReturn = eReleaseBuffer;
}
else if( xIsIPv4Multicast( ulSourceIPAddress ) == pdTRUE )
{
/* Source is a multicast IP address. Drop the packet in conformity with RFC 1112 section 7.2. */
eReturn = eReleaseBuffer;
}
else
{
/* Packet is not fragmented, destination is this device, source IP and MAC
* addresses are correct. */
}
}
#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 )
{
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxIPPacket->xEthernetHeader.xSourceAddress ), NULL );
/* Do not check the checksum of loop-back messages. */
if( pxEndPoint == NULL )
{
/* Is the IP header checksum correct?
*
* NOTE: When the checksum of IP header is calculated while not omitting
* the checksum field, the resulting value of the checksum always is 0xffff
* which is denoted by ipCORRECT_CRC. See this wiki for more information:
* https://en.wikipedia.org/wiki/IPv4_header_checksum#Verifying_the_IPv4_header_checksum
* and this RFC: https://tools.ietf.org/html/rfc1624#page-4
*/
if( usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC )
{
/* Check sum in IP-header not correct. */
eReturn = eReleaseBuffer;
}
/* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
else if( usGenerateProtocolChecksum( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
{
/* Protocol checksum not accepted. */
eReturn = eReleaseBuffer;
}
else
{
/* The checksum of the received packet is OK. */
}
}
}
}
#else /* if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) */
{
if( eReturn == eProcessBuffer )
{
if( xCheckSizeFields( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength ) != pdPASS )
{
/* Some of the length checks were not successful. */
eReturn = eReleaseBuffer;
}
}
#if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 )
{
/* Check if this is a UDP packet without a checksum. */
if( eReturn == eProcessBuffer )
{
uint8_t ucProtocol;
const ProtocolHeaders_t * pxProtocolHeaders;
/* ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS is defined as 0,
* and so UDP packets carrying a protocol checksum of 0, will
* be dropped. */
ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
/* 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] */
pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ( size_t ) ipSIZE_OF_IPv4_HEADER ] ) );
/* Identify the next protocol. */
if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
{
if( pxProtocolHeaders->xUDPHeader.usChecksum == ( uint16_t ) 0U )
{
#if ( ipconfigHAS_PRINTF != 0 )
{
static BaseType_t xCount = 0;
/* Exclude this from branch coverage as this is only used for debugging. */
if( xCount < 5 ) /* LCOV_EXCL_BR_LINE */
{
FreeRTOS_printf( ( "prvAllowIPPacket: UDP packet from %xip without CRC dropped\n",
FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ) ) );
xCount++;
}
}
#endif /* ( ipconfigHAS_PRINTF != 0 ) */
/* Protocol checksum not accepted. */
eReturn = eReleaseBuffer;
}
}
}
}
#endif /* ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
/* to avoid warning unused parameters */
( void ) pxNetworkBuffer;
( void ) uxHeaderLength;
}
#endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
return eReturn;
}
/*-----------------------------------------------------------*/
/** @brief Check if the IP-header is carrying options.
* @param[in] pxNetworkBuffer: the network buffer that contains the packet.
*
* @return Either 'eProcessBuffer' or 'eReleaseBuffer'
*/
eFrameProcessingResult_t prvCheckIP4HeaderOptions( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
eFrameProcessingResult_t eReturn = eProcessBuffer;
/* This function is only called for IPv4 packets, with an IP-header
* which is larger than 20 bytes. The extra space is used for IP-options.
* The options will either be removed, or the packet shall be dropped,
* depending on a user define. */
#if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 )
{
/* 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] */
IPHeader_t * pxIPHeader = ( ( IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
/* All structs of headers expect a IP header size of 20 bytes
* IP header options were included, we'll ignore them and cut them out. */
size_t uxLength = ( size_t ) pxIPHeader->ucVersionHeaderLength;
/* Check if the IP headers are acceptable and if it has our destination.
* The lowest four bits of 'ucVersionHeaderLength' indicate the IP-header
* length in multiples of 4. */
size_t uxHeaderLength = ( size_t ) ( ( uxLength & 0x0FU ) << 2 );
/* Number of bytes contained in IPv4 header options. */
const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
/* From: the previous start of UDP/ICMP/TCP data. */
const uint8_t * pucSource = ( const uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + uxHeaderLength ] );
/* To: the usual start of UDP/ICMP/TCP data at offset 20 (decimal ) from IP header. */
uint8_t * pucTarget = ( uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER ] );
/* How many: total length minus the options and the lower headers. */
const size_t xMoveLen = pxNetworkBuffer->xDataLength - ( optlen + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_ETH_HEADER );
( void ) memmove( pucTarget, pucSource, xMoveLen );
pxNetworkBuffer->xDataLength -= optlen;
/* Update the total length of the IP packet after removing options. */
pxIPHeader->usLength = FreeRTOS_htons( FreeRTOS_ntohs( pxIPHeader->usLength ) - optlen );
/* Rewrite the Version/IHL byte to indicate that this packet has no IP options. */
pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0U ) | /* High nibble is the version. */
( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0FU );
}
#else /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
{
/* 'ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS' is not set, so packets carrying
* IP-options will be dropped. */
eReturn = eReleaseBuffer;
}
#endif /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
return eReturn;
}
/*-----------------------------------------------------------*/