1
0
mirror of https://github.com/FreeRTOS/FreeRTOS-Plus-TCP synced 2025-10-22 16:37:41 +08:00
Files
FreeRTOS-Plus-TCP/source/FreeRTOS_IP.c
ActoryOu 31c7a360a9 [IPv6] Add Unit Test for FreeRTOS_IP/FreeRTOS_IPv4. (#862)
* Add network down test in prvIPTask

* Align IP test configurations

* Remove redundant define check

* Fix unit test cases

* Fix stubs in some UT

* Add test cases for DHCPv6 and backward compatible

* Add test cases for FreeRTOS_GetUDPPayloadBuffer_Multi IPv6

* Test case for FreeRTOS_IPInit_Multi

* FreeRTOS_ReleaseUDPPayloadBuffer

* FreeRTOS_GetEndPointConfiguration

* FreeRTOS_GetAddressConfiguration

* FreeRTOS_GetEndPointConfiguration

* FreeRTOS_SetEndPointConfiguration

* FreeRTOS_GetAddressConfiguration

* Fix UT

* eConsiderFrameForProcessing

* prvProcessIPPacket

* vReturnEthernetFrame

* FreeRTOS_GetIPAddress

* Move IPv4 test under IPv4.

* Move IPv4 unit test cases from IP folders to IPv4 folders.

* prvProcessIPPacket

* vReturnEthernetFrame

* FreeRTOS_GetIPAddress

* FreeRTOS_IsNetworkUp

* FreeRTOS_AllEndPointsUp

* uxIPHeaderSizeSocket

* IP coverage

* FreeRTOS_SetIPAddress

* FreeRTOS_GetGatewayAddress

* FreeRTOS_GetDNSServerAddress

* FreeRTOS_GetNetmask

* FreeRTOS_UpdateMACAddress

* FreeRTOS_GetMACAddress

* FreeRTOS_SetNetmask

* FreeRTOS_SetGatewayAddress

* FreeRTOS_GetUDPPayloadBuffer_Multi

* IP coverage

* Code beautify

* prvAllowIPPacketIPv4

* prvCheckIP4HeaderOptions

* Remove legacy ipLOCAL_IP_ADDRESS_POINTER

* Add descriptions for IP test cases

* Remove redundant includes in test files.

* Add test description for IPv4 unit test

* Remove unnecessary config change

* Code beautify.

* Spelling

* Fix UT
2023-05-17 15:02:55 +08:00

2507 lines
95 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"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_ICMP.h"
#include "FreeRTOS_IP_Timers.h"
#include "FreeRTOS_IP_Utils.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#if ( ipconfigUSE_DHCPv6 == 1 )
#include "FreeRTOS_DHCPv6.h"
#endif
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_Routing.h"
#include "FreeRTOS_ND.h"
/** @brief Time delay between repeated attempts to initialise the network hardware. */
#ifndef ipINITIALISATION_RETRY_DELAY
#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000U ) )
#endif
#if ( ipconfigUSE_TCP_MEM_STATS != 0 )
#include "tcp_mem_stats.h"
#endif
/** @brief Maximum time to wait for an ARP resolution while holding a packet. */
#ifndef ipARP_RESOLUTION_MAX_DELAY
#define ipARP_RESOLUTION_MAX_DELAY ( pdMS_TO_TICKS( 2000U ) )
#endif
#ifndef iptraceIP_TASK_STARTING
#define iptraceIP_TASK_STARTING() do {} while( ipFALSE_BOOL ) /**< Empty definition in case iptraceIP_TASK_STARTING is not defined. */
#endif
#if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
/** @brief When initialising the TCP timer, give it an initial time-out of 1 second. */
#define ipTCP_TIMER_PERIOD_MS ( 1000U )
#endif
/** @brief Defines how often the ARP timer callback function is executed. The time is
* shorter in the Windows simulator as simulated time is not real time. */
#ifndef ipARP_TIMER_PERIOD_MS
#ifdef _WINDOWS_
#define ipARP_TIMER_PERIOD_MS ( 500U ) /* For windows simulator builds. */
#else
#define ipARP_TIMER_PERIOD_MS ( 10000U )
#endif
#endif
#if ( ipconfigUSE_TCP != 0 )
/** @brief Set to a non-zero value if one or more TCP message have been processed
* within the last round. */
BaseType_t xProcessedTCPMessage;
#endif
/** @brief If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
* driver will filter incoming packets and only pass the stack those packets it
* considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
* be #-defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
* then the Ethernet driver will pass all received packets to the stack, and the
* stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
* needs to call eConsiderFrameForProcessing.
*/
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#endif
static void prvCallDHCP_RA_Handler( NetworkEndPoint_t * pxEndPoint );
static void prvIPTask_Initialise( void );
static void prvIPTask_CheckPendingEvents( void );
/*-----------------------------------------------------------*/
/** @brief The pointer to buffer with packet waiting for ARP resolution. */
NetworkBufferDescriptor_t * pxARPWaitingNetworkBuffer = NULL;
/*-----------------------------------------------------------*/
static void prvProcessIPEventsAndTimers( void );
/*
* The main TCP/IP stack processing task. This task receives commands/events
* from the network hardware drivers and tasks that are using sockets. It also
* maintains a set of protocol timers.
*/
static void prvIPTask( void * pvParameters );
/*
* Called when new data is available from the network interface.
*/
static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
#if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 )
/*
* The stack will call this user hook for all Ethernet frames that it
* does not support, i.e. other than IPv4, IPv6 and ARP ( for the moment )
* If this hook returns eReleaseBuffer or eProcessBuffer, the stack will
* release and reuse the network buffer. If this hook returns
* eReturnEthernetFrame, that means user code has reused the network buffer
* to generate a response and the stack will send that response out.
* If this hook returns eFrameConsumed, the user code has ownership of the
* network buffer and has to release it when it's done.
*/
extern eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t * const pxNetworkBuffer );
#endif /* ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 ) */
/*
* Process incoming IP packets.
*/
static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacket,
NetworkBufferDescriptor_t * const pxNetworkBuffer );
/*
* The network card driver has received a packet. In the case that it is part
* of a linked packet chain, walk through it to handle every message.
*/
static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer );
/* Handle the 'eNetworkTxEvent': forward a packet from an application to the NIC. */
static void prvForwardTxPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t xReleaseAfterSend );
static eFrameProcessingResult_t prvProcessUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
/*-----------------------------------------------------------*/
/** @brief The queue used to pass events into the IP-task for processing. */
QueueHandle_t xNetworkEventQueue = NULL;
/** @brief The IP packet ID. */
uint16_t usPacketIdentifier = 0U;
/** @brief For convenience, a MAC address of all 0xffs is defined const for quick
* reference. */
const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
/** @brief Default values for the above struct in case DHCP
* does not lead to a confirmed request. */
/* MISRA Ref 8.9.1 [File scoped variables] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
/* coverity[misra_c_2012_rule_8_9_violation] */
NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
/** @brief Used to ensure network down events cannot be missed when they cannot be
* posted to the network event queue because the network event queue is already
* full. */
static volatile BaseType_t xNetworkDownEventPending = pdFALSE;
/** @brief Stores the handle of the task that handles the stack. The handle is used
* (indirectly) by some utility function to determine if the utility function is
* being called by a task (in which case it is ok to block) or by the IP task
* itself (in which case it is not ok to block). */
static TaskHandle_t xIPTaskHandle = NULL;
/** @brief Set to pdTRUE when the IP task is ready to start processing packets. */
static BaseType_t xIPTaskInitialised = pdFALSE;
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
/** @brief Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
#endif
/*-----------------------------------------------------------*/
/* Coverity wants to make pvParameters const, which would make it incompatible. Leave the
* function signature as is. */
/**
* @brief The IP task handles all requests from the user application and the
* network interface. It receives messages through a FreeRTOS queue called
* 'xNetworkEventQueue'. prvIPTask() is the only task which has access to
* the data of the IP-stack, and so it has no need of using mutexes.
*
* @param[in] pvParameters Not used.
*/
/** @brief Stores interface structures. */
/* MISRA Ref 8.13.1 [Not decorating a pointer to const parameter with const] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-813 */
/* coverity[misra_c_2012_rule_8_13_violation] */
static void prvIPTask( void * pvParameters )
{
/* Just to prevent compiler warnings about unused parameters. */
( void ) pvParameters;
prvIPTask_Initialise();
FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
/* Loop, processing IP events. */
while( ipFOREVER() == pdTRUE )
{
prvProcessIPEventsAndTimers();
}
}
/*-----------------------------------------------------------*/
/**
* @brief Process the events sent to the IP task and process the timers.
*/
static void prvProcessIPEventsAndTimers( void )
{
IPStackEvent_t xReceivedEvent;
TickType_t xNextIPSleep;
FreeRTOS_Socket_t * pxSocket;
struct freertos_sockaddr xAddress;
ipconfigWATCHDOG_TIMER();
/* Check the ARP, DHCP and TCP timers to see if there is any periodic
* or timeout processing to perform. */
vCheckNetworkTimers();
/* Calculate the acceptable maximum sleep time. */
xNextIPSleep = xCalculateSleepTime();
/* Wait until there is something to do. If the following call exits
* due to a time out rather than a message being received, set a
* 'NoEvent' value. */
if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
{
xReceivedEvent.eEventType = eNoEvent;
}
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
{
if( xReceivedEvent.eEventType != eNoEvent )
{
UBaseType_t uxCount;
uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
if( uxQueueMinimumSpace > uxCount )
{
uxQueueMinimumSpace = uxCount;
}
}
}
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
switch( xReceivedEvent.eEventType )
{
case eNetworkDownEvent:
/* Attempt to establish a connection. */
prvProcessNetworkDownEvent( ( ( NetworkInterface_t * ) xReceivedEvent.pvData ) );
break;
case eNetworkRxEvent:
/* The network hardware driver has received a new packet. A
* pointer to the received buffer is located in the pvData member
* of the received event structure. */
prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData );
break;
case eNetworkTxEvent:
/* Send a network packet. The ownership will be transferred to
* the driver, which will release it after delivery. */
prvForwardTxPacket( ( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData ), pdTRUE );
break;
case eARPTimerEvent:
/* The ARP timer has expired, process the ARP cache. */
#if ( ipconfigUSE_IPv4 != 0 )
vARPAgeCache();
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
vNDAgeCache();
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
break;
case eSocketBindEvent:
/* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
* to a port. The port number is communicated in the socket field
* usLocalPort. vSocketBind() will actually bind the socket and the
* API will unblock as soon as the eSOCKET_BOUND event is
* triggered. */
pxSocket = ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData );
xAddress.sin_len = ( uint8_t ) sizeof( xAddress );
switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */
{
#if ( ipconfigUSE_IPv4 != 0 )
case pdFALSE_UNSIGNED:
xAddress.sin_family = FREERTOS_AF_INET;
xAddress.sin_address.ulIP_IPv4 = FreeRTOS_htonl( pxSocket->xLocalAddress.ulIP_IPv4 );
/* 'ulLocalAddress' will be set again by vSocketBind(). */
pxSocket->xLocalAddress.ulIP_IPv4 = 0;
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
case pdTRUE_UNSIGNED:
xAddress.sin_family = FREERTOS_AF_INET6;
( void ) memcpy( xAddress.sin_address.xIP_IPv6.ucBytes, pxSocket->xLocalAddress.xIP_IPv6.ucBytes, sizeof( xAddress.sin_address.xIP_IPv6.ucBytes ) );
/* 'ulLocalAddress' will be set again by vSocketBind(). */
( void ) memset( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, 0, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
default:
/* MISRA 16.4 Compliance */
break;
}
xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
/* 'usLocalPort' will be set again by vSocketBind(). */
pxSocket->usLocalPort = 0U;
( void ) vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );
/* Before 'eSocketBindEvent' was sent it was tested that
* ( xEventGroup != NULL ) so it can be used now to wake up the
* user. */
pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_BOUND;
vSocketWakeUpUser( pxSocket );
break;
case eSocketCloseEvent:
/* The user API FreeRTOS_closesocket() has sent a message to the
* IP-task to actually close a socket. This is handled in
* vSocketClose(). As the socket gets closed, there is no way to
* report back to the API, so the API won't wait for the result */
( void ) vSocketClose( ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData ) );
break;
case eStackTxEvent:
/* The network stack has generated a packet to send. A
* pointer to the generated buffer is located in the pvData
* member of the received event structure. */
vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData );
break;
case eDHCPEvent:
prvCallDHCP_RA_Handler( ( ( NetworkEndPoint_t * ) xReceivedEvent.pvData ) );
break;
case eSocketSelectEvent:
/* FreeRTOS_select() has got unblocked by a socket event,
* vSocketSelect() will check which sockets actually have an event
* and update the socket field xSocketBits. */
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
#if ( ipconfigSELECT_USES_NOTIFY != 0 )
{
SocketSelectMessage_t * pxMessage = ( ( SocketSelectMessage_t * ) xReceivedEvent.pvData );
vSocketSelect( pxMessage->pxSocketSet );
( void ) xTaskNotifyGive( pxMessage->xTaskhandle );
}
#else
{
vSocketSelect( ( ( SocketSelect_t * ) xReceivedEvent.pvData ) );
}
#endif /* ( ipconfigSELECT_USES_NOTIFY != 0 ) */
#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
break;
case eSocketSignalEvent:
#if ( ipconfigSUPPORT_SIGNALS != 0 )
/* Some task wants to signal the user of this socket in
* order to interrupt a call to recv() or a call to select(). */
( void ) FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );
#endif /* ipconfigSUPPORT_SIGNALS */
break;
case eTCPTimerEvent:
#if ( ipconfigUSE_TCP == 1 )
/* Simply mark the TCP timer as expired so it gets processed
* the next time prvCheckNetworkTimers() is called. */
vIPSetTCPTimerExpiredState( pdTRUE );
#endif /* ipconfigUSE_TCP */
break;
case eTCPAcceptEvent:
/* The API FreeRTOS_accept() was called, the IP-task will now
* check if the listening socket (communicated in pvData) actually
* received a new connection. */
#if ( ipconfigUSE_TCP == 1 )
pxSocket = ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData );
if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
{
pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
vSocketWakeUpUser( pxSocket );
}
#endif /* ipconfigUSE_TCP */
break;
case eTCPNetStat:
/* FreeRTOS_netstat() was called to have the IP-task print an
* overview of all sockets and their connections */
#if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
vTCPNetStat();
#endif /* ipconfigUSE_TCP */
break;
case eSocketSetDeleteEvent:
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) ( xReceivedEvent.pvData );
iptraceMEM_STATS_DELETE( pxSocketSet );
vEventGroupDelete( pxSocketSet->xSelectGroup );
vPortFree( ( void * ) pxSocketSet );
}
#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
break;
case eNoEvent:
/* xQueueReceive() returned because of a normal time-out. */
break;
default:
/* Should not get here. */
break;
}
prvIPTask_CheckPendingEvents();
}
/*-----------------------------------------------------------*/
/**
* @brief Helper function for prvIPTask, it does the first initializations
* at start-up. No parameters, no return type.
*/
static void prvIPTask_Initialise( void )
{
NetworkInterface_t * pxInterface;
/* A possibility to set some additional task properties. */
iptraceIP_TASK_STARTING();
/* Generate a dummy message to say that the network connection has gone
* down. This will cause this task to initialise the network interface. After
* this it is the responsibility of the network interface hardware driver to
* send this message if a previously connected network is disconnected. */
vNetworkTimerReload( pdMS_TO_TICKS( ipINITIALISATION_RETRY_DELAY ) );
for( pxInterface = pxNetworkInterfaces; pxInterface != NULL; pxInterface = pxInterface->pxNext )
{
/* Post a 'eNetworkDownEvent' for every interface. */
FreeRTOS_NetworkDown( pxInterface );
}
#if ( ipconfigUSE_TCP == 1 )
{
/* Initialise the TCP timer. */
vTCPTimerReload( pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
}
#endif
/* Mark the timer as inactive since we are not waiting on any ARP resolution as of now. */
vIPSetARPResolutionTimerEnableState( pdFALSE );
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
/* The following function is declared in FreeRTOS_DNS.c and 'private' to
* this library */
vDNSInitialise();
}
#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
/* Initialisation is complete and events can now be processed. */
xIPTaskInitialised = pdTRUE;
}
/*-----------------------------------------------------------*/
/**
* @brief Check the value of 'xNetworkDownEventPending'. When non-zero, pending
* network-down events will be handled.
*/
static void prvIPTask_CheckPendingEvents( void )
{
NetworkInterface_t * pxInterface;
if( xNetworkDownEventPending != pdFALSE )
{
/* A network down event could not be posted to the network event
* queue because the queue was full.
* As this code runs in the IP-task, it can be done directly by
* calling prvProcessNetworkDownEvent(). */
xNetworkDownEventPending = pdFALSE;
for( pxInterface = FreeRTOS_FirstNetworkInterface();
pxInterface != NULL;
pxInterface = FreeRTOS_NextNetworkInterface( pxInterface ) )
{
if( pxInterface->bits.bCallDownEvent != pdFALSE_UNSIGNED )
{
prvProcessNetworkDownEvent( pxInterface );
pxInterface->bits.bCallDownEvent = pdFALSE_UNSIGNED;
}
}
}
}
/*-----------------------------------------------------------*/
/**
* @brief Call the state machine of either DHCP, DHCPv6, or RA, whichever is activated.
*
* @param[in] pxEndPoint The end-point for which the state-machine will be called.
*/
static void prvCallDHCP_RA_Handler( NetworkEndPoint_t * pxEndPoint )
{
BaseType_t xIsIPv6 = pdFALSE;
#if ( ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_RA == 1 ) )
if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
{
xIsIPv6 = pdTRUE;
}
#endif
/* The DHCP state machine needs processing. */
#if ( ipconfigUSE_DHCP == 1 )
{
if( ( pxEndPoint->bits.bWantDHCP != pdFALSE_UNSIGNED ) && ( xIsIPv6 == pdFALSE ) )
{
/* Process DHCP messages for a given end-point. */
vDHCPProcess( pdFALSE, pxEndPoint );
}
}
#endif /* ipconfigUSE_DHCP */
#if ( ( ipconfigUSE_DHCPv6 == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
{
if( ( xIsIPv6 == pdTRUE ) && ( pxEndPoint->bits.bWantDHCP != pdFALSE_UNSIGNED ) )
{
/* Process DHCPv6 messages for a given end-point. */
vDHCPv6Process( pdFALSE, pxEndPoint );
}
}
#endif /* ipconfigUSE_DHCPv6 */
#if ( ( ipconfigUSE_RA == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
{
if( ( xIsIPv6 == pdTRUE ) && ( pxEndPoint->bits.bWantRA != pdFALSE_UNSIGNED ) )
{
/* Process RA messages for a given end-point. */
vRAProcess( pdFALSE, pxEndPoint );
}
}
#endif /* ( ( ipconfigUSE_RA == 1 ) && ( ipconfigUSE_IPv6 != 0 ) ) */
/* Mention pxEndPoint and xIsIPv6 in case they have not been used. */
( void ) pxEndPoint;
( void ) xIsIPv6;
}
/*-----------------------------------------------------------*/
/**
* @brief The variable 'xIPTaskHandle' is declared static. This function
* gives read-only access to it.
*
* @return The handle of the IP-task.
*/
TaskHandle_t FreeRTOS_GetIPTaskHandle( void )
{
return xIPTaskHandle;
}
/*-----------------------------------------------------------*/
/**
* @brief Perform all the required tasks when the network gets connected.
*
* @param pxEndPoint The end-point which goes up.
*/
void vIPNetworkUpCalls( NetworkEndPoint_t * pxEndPoint )
{
pxEndPoint->bits.bEndPointUp = pdTRUE_UNSIGNED;
#if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
{
vApplicationIPNetworkEventHook( eNetworkUp );
}
#else
{
vApplicationIPNetworkEventHook_Multi( eNetworkUp, pxEndPoint );
}
#endif
#endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
/* The following function is declared in FreeRTOS_DNS.c and 'private' to
* this library */
extern void vDNSInitialise( void );
vDNSInitialise();
}
#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
/* Set remaining time to 0 so it will become active immediately. */
vARPTimerReload( pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
}
/*-----------------------------------------------------------*/
/**
* @brief Handle the incoming Ethernet packets.
*
* @param[in] pxBuffer Linked/un-linked network buffer descriptor(s)
* to be processed.
*/
static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer )
{
#if ( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
{
/* When ipconfigUSE_LINKED_RX_MESSAGES is set to 0 then only one
* buffer will be sent at a time. This is the default way for +TCP to pass
* messages from the MAC to the TCP/IP stack. */
prvProcessEthernetPacket( pxBuffer );
}
#else /* ipconfigUSE_LINKED_RX_MESSAGES */
{
NetworkBufferDescriptor_t * pxNextBuffer;
/* An optimisation that is useful when there is high network traffic.
* Instead of passing received packets into the IP task one at a time the
* network interface can chain received packets together and pass them into
* the IP task in one go. The packets are chained using the pxNextBuffer
* member. The loop below walks through the chain processing each packet
* in the chain in turn. */
/* While there is another packet in the chain. */
while( pxBuffer != NULL )
{
/* Store a pointer to the buffer after pxBuffer for use later on. */
pxNextBuffer = pxBuffer->pxNextBuffer;
/* Make it NULL to avoid using it later on. */
pxBuffer->pxNextBuffer = NULL;
prvProcessEthernetPacket( pxBuffer );
pxBuffer = pxNextBuffer;
}
}
#endif /* ipconfigUSE_LINKED_RX_MESSAGES */
}
/*-----------------------------------------------------------*/
/**
* @brief Send a network packet.
*
* @param[in] pxNetworkBuffer The message buffer.
* @param[in] xReleaseAfterSend When true, the network interface will own the buffer and is responsible for it's release.
*/
static void prvForwardTxPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
{
iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
if( pxNetworkBuffer->pxInterface != NULL )
{
( void ) pxNetworkBuffer->pxInterface->pfOutput( pxNetworkBuffer->pxInterface, pxNetworkBuffer, xReleaseAfterSend );
}
}
/*-----------------------------------------------------------*/
/**
* @brief Send a network down event to the IP-task. If it fails to post a message,
* the failure will be noted in the variable 'xNetworkDownEventPending'
* and later on a 'network-down' event, it will be executed.
*
* @param[in] pxNetworkInterface The interface that goes down.
*/
void FreeRTOS_NetworkDown( struct xNetworkInterface * pxNetworkInterface )
{
IPStackEvent_t xNetworkDownEvent;
const TickType_t xDontBlock = ( TickType_t ) 0;
pxNetworkInterface->bits.bInterfaceUp = pdFALSE_UNSIGNED;
xNetworkDownEvent.eEventType = eNetworkDownEvent;
xNetworkDownEvent.pvData = pxNetworkInterface;
/* Simply send the network task the appropriate event. */
if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
{
/* Could not send the message, so it is still pending. */
pxNetworkInterface->bits.bCallDownEvent = pdTRUE;
xNetworkDownEventPending = pdTRUE;
}
else
{
/* Message was sent so it is not pending. */
pxNetworkInterface->bits.bCallDownEvent = pdFALSE;
}
iptraceNETWORK_DOWN();
}
/*-----------------------------------------------------------*/
/**
* @brief Utility function. Process Network Down event from ISR.
* This function is supposed to be called form an ISR. It is recommended
* - * use 'FreeRTOS_NetworkDown()', when calling from a normal task.
*
* @param[in] pxNetworkInterface The interface that goes down.
*
* @return If the event was processed successfully, then return pdTRUE.
* Else pdFALSE.
*/
BaseType_t FreeRTOS_NetworkDownFromISR( struct xNetworkInterface * pxNetworkInterface )
{
IPStackEvent_t xNetworkDownEvent;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xNetworkDownEvent.eEventType = eNetworkDownEvent;
xNetworkDownEvent.pvData = pxNetworkInterface;
/* Simply send the network task the appropriate event. */
if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
{
/* Could not send the message, so it is still pending. */
pxNetworkInterface->bits.bCallDownEvent = pdTRUE;
xNetworkDownEventPending = pdTRUE;
}
else
{
/* Message was sent so it is not pending. */
pxNetworkInterface->bits.bCallDownEvent = pdFALSE;
xNetworkDownEventPending = pdFALSE;
}
iptraceNETWORK_DOWN();
return xHigherPriorityTaskWoken;
}
/*-----------------------------------------------------------*/
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
/**
* @brief Obtain a buffer big enough for a UDP payload of given size.
* NOTE: This function is kept for backward compatibility and will
* only allocate IPv4 payload buffers. Newer designs should use
* FreeRTOS_GetUDPPayloadBuffer_Multi(), which can
* allocate a IPv4 or IPv6 buffer based on ucIPType parameter .
*
* @param[in] uxRequestedSizeBytes The size of the UDP payload.
* @param[in] uxBlockTimeTicks Maximum amount of time for which this call
* can block. This value is capped internally.
*
* @return If a buffer was created then the pointer to that buffer is returned,
* else a NULL pointer is returned.
*/
void * FreeRTOS_GetUDPPayloadBuffer( size_t uxRequestedSizeBytes,
TickType_t uxBlockTimeTicks )
{
return FreeRTOS_GetUDPPayloadBuffer_Multi( uxRequestedSizeBytes, uxBlockTimeTicks, ipTYPE_IPv4 );
}
#endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
/*-----------------------------------------------------------*/
/**
* @brief Obtain a buffer big enough for a UDP payload of given size and
* given IP type.
*
* @param[in] uxRequestedSizeBytes The size of the UDP payload.
* @param[in] uxBlockTimeTicks Maximum amount of time for which this call
* can block. This value is capped internally.
* @param[in] ucIPType Either ipTYPE_IPv4 (0x40) or ipTYPE_IPv6 (0x60)
*
* @return If a buffer was created then the pointer to that buffer is returned,
* else a NULL pointer is returned.
*/
void * FreeRTOS_GetUDPPayloadBuffer_Multi( size_t uxRequestedSizeBytes,
TickType_t uxBlockTimeTicks,
uint8_t ucIPType )
{
NetworkBufferDescriptor_t * pxNetworkBuffer;
void * pvReturn = NULL;
TickType_t uxBlockTime = uxBlockTimeTicks;
size_t uxPayloadOffset = 0U;
configASSERT( ( ucIPType == ipTYPE_IPv6 ) || ( ucIPType == ipTYPE_IPv4 ) );
/* Cap the block time. The reason for this is explained where
* ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
* FreeRTOSIPConfig.h header file is being used). */
if( uxBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
{
uxBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
}
switch( ucIPType ) /* LCOV_EXCL_BR_LINE */
{
#if ( ipconfigUSE_IPv4 != 0 )
case ipTYPE_IPv4:
uxPayloadOffset = sizeof( UDPPacket_t );
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
case ipTYPE_IPv6:
uxPayloadOffset = sizeof( UDPPacket_IPv6_t );
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
default:
/* Shouldn't reach here. */
/* MISRA 16.4 Compliance */
break;
}
if( uxPayloadOffset != 0U )
{
/* Obtain a network buffer with the required amount of storage. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPayloadOffset + uxRequestedSizeBytes, uxBlockTime );
if( pxNetworkBuffer != NULL )
{
size_t uxIndex = ipUDP_PAYLOAD_IP_TYPE_OFFSET;
BaseType_t xPayloadIPTypeOffset = ( BaseType_t ) uxIndex;
/* Set the actual packet size in case a bigger buffer was returned. */
pxNetworkBuffer->xDataLength = uxPayloadOffset + uxRequestedSizeBytes;
/* Skip 3 headers. */
pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ] );
uint8_t * pucIPType;
/* Later a pointer to a UDP payload is used to retrieve a NetworkBuffer.
* Store the packet type at 48 bytes before the start of the UDP payload. */
pucIPType = ( uint8_t * ) pvReturn;
pucIPType = &( pucIPType[ -xPayloadIPTypeOffset ] );
/* For a IPv4 packet, pucIPType points to 6 bytes before the
* pucEthernetBuffer, for a IPv6 packet, pucIPType will point to the
* first byte of the IP-header: 'ucVersionTrafficClass'. */
*pucIPType = ucIPType;
}
}
return ( void * ) pvReturn;
}
/*-----------------------------------------------------------*/
/*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */
/*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.
* As that bug has been repaired, there is not an urgent reason to warn.
* It is better though to use the advised priority scheme. */
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) && ( ipconfigUSE_IPv4 != 0 )
/* Provide backward-compatibility with the earlier FreeRTOS+TCP which only had
* single network interface. */
BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
{
static NetworkInterface_t xInterfaces[ 1 ];
static NetworkEndPoint_t xEndPoints[ 1 ];
/* IF the following function should be declared in the NetworkInterface.c
* linked in the project. */
pxFillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) );
FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
#if ( ipconfigUSE_DHCP != 0 )
{
xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE;
}
#endif /* ipconfigUSE_DHCP */
return FreeRTOS_IPInit_Multi();
}
#endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) && ( ipconfigUSE_IPv4 != 0 ) */
/*-----------------------------------------------------------*/
/**
* @brief Initialise the FreeRTOS-Plus-TCP network stack and initialise the IP-task.
* Before calling this function, at least 1 interface and 1 end-point must
* have been set-up.
*/
BaseType_t FreeRTOS_IPInit_Multi( void )
{
BaseType_t xReturn = pdFALSE;
/* There must be at least one interface and one end-point. */
configASSERT( FreeRTOS_FirstNetworkInterface() != NULL );
/* Check that the configuration values are correct and that the IP-task has not
* already been initialized. */
vPreCheckConfigs();
/* Attempt to create the queue used to communicate with the IP task. */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
static StaticQueue_t xNetworkEventStaticQueue;
static uint8_t ucNetworkEventQueueStorageArea[ ipconfigEVENT_QUEUE_LENGTH * sizeof( IPStackEvent_t ) ];
xNetworkEventQueue = xQueueCreateStatic( ipconfigEVENT_QUEUE_LENGTH,
sizeof( IPStackEvent_t ),
ucNetworkEventQueueStorageArea,
&xNetworkEventStaticQueue );
}
#else
{
xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( IPStackEvent_t ) );
configASSERT( xNetworkEventQueue != NULL );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
if( xNetworkEventQueue != NULL )
{
#if ( configQUEUE_REGISTRY_SIZE > 0 )
{
/* A queue registry is normally used to assist a kernel aware
* debugger. If one is in use then it will be helpful for the debugger
* to show information about the network event queue. */
vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
}
#endif /* configQUEUE_REGISTRY_SIZE */
if( xNetworkBuffersInitialise() == pdPASS )
{
/* Prepare the sockets interface. */
vNetworkSocketsInit();
/* Create the task that processes Ethernet and stack events. */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
static StaticTask_t xIPTaskBuffer;
static StackType_t xIPTaskStack[ ipconfigIP_TASK_STACK_SIZE_WORDS ];
xIPTaskHandle = xTaskCreateStatic( prvIPTask,
"IP-Task",
ipconfigIP_TASK_STACK_SIZE_WORDS,
NULL,
ipconfigIP_TASK_PRIORITY,
xIPTaskStack,
&xIPTaskBuffer );
if( xIPTaskHandle != NULL )
{
xReturn = pdTRUE;
}
}
#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
{
xReturn = xTaskCreate( prvIPTask,
"IP-task",
ipconfigIP_TASK_STACK_SIZE_WORDS,
NULL,
ipconfigIP_TASK_PRIORITY,
&( xIPTaskHandle ) );
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
}
else
{
FreeRTOS_debug_printf( ( "FreeRTOS_IPInit_Multi: xNetworkBuffersInitialise() failed\n" ) );
/* Clean up. */
vQueueDelete( xNetworkEventQueue );
xNetworkEventQueue = NULL;
}
}
else
{
FreeRTOS_debug_printf( ( "FreeRTOS_IPInit_Multi: Network event queue could not be created\n" ) );
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Release the UDP payload buffer.
*
* @param[in] pvBuffer Pointer to the UDP buffer that is to be released.
*/
void FreeRTOS_ReleaseUDPPayloadBuffer( void const * pvBuffer )
{
NetworkBufferDescriptor_t * pxBuffer;
pxBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer );
configASSERT( pxBuffer != NULL );
vReleaseNetworkBufferAndDescriptor( pxBuffer );
}
/*-----------------------------------------------------------*/
/**
* @brief Get the current IPv4 address configuration. Only non-NULL pointers will
* be filled in. pxEndPoint must be non-NULL.
*
* @param[out] pulIPAddress The current IP-address assigned.
* @param[out] pulNetMask The netmask used for current subnet.
* @param[out] pulGatewayAddress The gateway address.
* @param[out] pulDNSServerAddress The DNS server address.
* @param[in] pxEndPoint The end-point which is being questioned.
*/
void FreeRTOS_GetEndPointConfiguration( uint32_t * pulIPAddress,
uint32_t * pulNetMask,
uint32_t * pulGatewayAddress,
uint32_t * pulDNSServerAddress,
const struct xNetworkEndPoint * pxEndPoint )
{
if( ENDPOINT_IS_IPv4( pxEndPoint ) )
{
/* Return the address configuration to the caller. */
if( pulIPAddress != NULL )
{
*pulIPAddress = pxEndPoint->ipv4_settings.ulIPAddress;
}
if( pulNetMask != NULL )
{
*pulNetMask = pxEndPoint->ipv4_settings.ulNetMask;
}
if( pulGatewayAddress != NULL )
{
*pulGatewayAddress = pxEndPoint->ipv4_settings.ulGatewayAddress;
}
if( pulDNSServerAddress != NULL )
{
*pulDNSServerAddress = pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ]; /*_RB_ Only returning the address of the first DNS server. */
}
}
}
/*-----------------------------------------------------------*/
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
/**
* @brief Get the current IPv4 address configuration of the first endpoint.
* Only non-NULL pointers will be filled in.
* NOTE: This function is kept for backward compatibility. Newer
* designs should use FreeRTOS_SetEndPointConfiguration().
*
* @param[out] pulIPAddress The current IP-address assigned.
* @param[out] pulNetMask The netmask used for current subnet.
* @param[out] pulGatewayAddress The gateway address.
* @param[out] pulDNSServerAddress The DNS server address.
*/
void FreeRTOS_GetAddressConfiguration( uint32_t * pulIPAddress,
uint32_t * pulNetMask,
uint32_t * pulGatewayAddress,
uint32_t * pulDNSServerAddress )
{
NetworkEndPoint_t * pxEndPoint;
/* Get first end point. */
pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
FreeRTOS_GetEndPointConfiguration( pulIPAddress, pulNetMask,
pulGatewayAddress, pulDNSServerAddress, pxEndPoint );
}
}
#endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
/*-----------------------------------------------------------*/
/**
* @brief Set the current IPv4 network address configuration. Only non-NULL pointers will
* pointers will be used. pxEndPoint must pointer to a valid end-point.
*
* @param[in] pulIPAddress The current IP-address assigned.
* @param[in] pulNetMask The netmask used for current subnet.
* @param[in] pulGatewayAddress The gateway address.
* @param[in] pulDNSServerAddress The DNS server address.
* @param[in] pxEndPoint The end-point which is being questioned.
*/
void FreeRTOS_SetEndPointConfiguration( const uint32_t * pulIPAddress,
const uint32_t * pulNetMask,
const uint32_t * pulGatewayAddress,
const uint32_t * pulDNSServerAddress,
struct xNetworkEndPoint * pxEndPoint )
{
/* Update the address configuration. */
if( ENDPOINT_IS_IPv4( pxEndPoint ) )
{
if( pulIPAddress != NULL )
{
pxEndPoint->ipv4_settings.ulIPAddress = *pulIPAddress;
}
if( pulNetMask != NULL )
{
pxEndPoint->ipv4_settings.ulNetMask = *pulNetMask;
}
if( pulGatewayAddress != NULL )
{
pxEndPoint->ipv4_settings.ulGatewayAddress = *pulGatewayAddress;
}
if( pulDNSServerAddress != NULL )
{
pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ] = *pulDNSServerAddress;
}
}
}
/*-----------------------------------------------------------*/
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
/**
* @brief Set the current IPv4 network address configuration. Only non-NULL
* pointers will be used.
* NOTE: This function is kept for backward compatibility. Newer
* designs should use FreeRTOS_SetEndPointConfiguration().
*
* @param[in] pulIPAddress The current IP-address assigned.
* @param[in] pulNetMask The netmask used for current subnet.
* @param[in] pulGatewayAddress The gateway address.
* @param[in] pulDNSServerAddress The DNS server address.
*/
void FreeRTOS_SetAddressConfiguration( const uint32_t * pulIPAddress,
const uint32_t * pulNetMask,
const uint32_t * pulGatewayAddress,
const uint32_t * pulDNSServerAddress )
{
NetworkEndPoint_t * pxEndPoint;
/* Get first end point. */
pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
FreeRTOS_SetEndPointConfiguration( pulIPAddress, pulNetMask,
pulGatewayAddress, pulDNSServerAddress, pxEndPoint );
}
}
#endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP == 1 )
/**
* @brief Release the memory that was previously obtained by calling FreeRTOS_recv()
* with the flag 'FREERTOS_ZERO_COPY'.
*
* @param[in] xSocket The socket that was read from.
* @param[in] pvBuffer The buffer returned in the call to FreeRTOS_recv().
* @param[in] xByteCount The number of bytes that have been used.
*
* @return pdPASS if the buffer was released successfully, otherwise pdFAIL is returned.
*/
BaseType_t FreeRTOS_ReleaseTCPPayloadBuffer( Socket_t xSocket,
void const * pvBuffer,
BaseType_t xByteCount )
{
BaseType_t xByteCountReleased;
BaseType_t xReturn = pdFAIL;
uint8_t * pucData;
size_t uxBytesAvailable = uxStreamBufferGetPtr( xSocket->u.xTCP.rxStream, &( pucData ) );
/* Make sure the pointer is correct. */
configASSERT( pucData == ( uint8_t * ) pvBuffer );
/* Avoid releasing more bytes than available. */
configASSERT( uxBytesAvailable >= ( size_t ) xByteCount );
if( ( pucData == pvBuffer ) && ( uxBytesAvailable >= ( size_t ) xByteCount ) )
{
/* Call recv with NULL pointer to advance the circular buffer. */
xByteCountReleased = FreeRTOS_recv( xSocket,
NULL,
( size_t ) xByteCount,
FREERTOS_MSG_DONTWAIT );
configASSERT( xByteCountReleased == xByteCount );
if( xByteCountReleased == xByteCount )
{
xReturn = pdPASS;
}
}
return xReturn;
}
#endif /* ( ipconfigUSE_TCP == 1 ) */
/*-----------------------------------------------------------*/
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/**
* @brief Send a ping request to the given IP address. After receiving a reply,
* IP-task will call a user-supplied function 'vApplicationPingReplyHook()'.
*
* @param[in] ulIPAddress The IP address to which the ping is to be sent.
* @param[in] uxNumberOfBytesToSend Number of bytes in the ping request.
* @param[in] uxBlockTimeTicks Maximum number of ticks to wait.
*
* @return If successfully sent to IP task for processing then the sequence
* number of the ping packet or else, pdFAIL.
*/
BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress,
size_t uxNumberOfBytesToSend,
TickType_t uxBlockTimeTicks )
{
NetworkBufferDescriptor_t * pxNetworkBuffer;
ICMPHeader_t * pxICMPHeader;
EthernetHeader_t * pxEthernetHeader;
BaseType_t xReturn = pdFAIL;
static uint16_t usSequenceNumber = 0;
uint8_t * pucChar;
size_t uxTotalLength;
BaseType_t xEnoughSpace;
IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
uxTotalLength = uxNumberOfBytesToSend + sizeof( ICMPPacket_t );
if( uxNumberOfBytesToSend < ( ipconfigNETWORK_MTU - ( sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) ) ) )
{
xEnoughSpace = pdTRUE;
}
else
{
xEnoughSpace = pdFALSE;
}
if( ( uxGetNumberOfFreeNetworkBuffers() >= 4U ) && ( uxNumberOfBytesToSend >= 1U ) && ( xEnoughSpace != pdFALSE ) )
{
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxTotalLength, uxBlockTimeTicks );
if( pxNetworkBuffer != NULL )
{
pxEthernetHeader = ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
pxEthernetHeader->usFrameType = ipIPv4_FRAME_TYPE;
pxICMPHeader = ( ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] ) );
usSequenceNumber++;
/* Fill in the basic header information. */
pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
pxICMPHeader->ucTypeOfService = 0;
pxICMPHeader->usIdentifier = usSequenceNumber;
pxICMPHeader->usSequenceNumber = usSequenceNumber;
/* Find the start of the data. */
pucChar = ( uint8_t * ) pxICMPHeader;
pucChar = &( pucChar[ sizeof( ICMPHeader_t ) ] );
/* Just memset the data to a fixed value. */
( void ) memset( pucChar, ( int ) ipECHO_DATA_FILL_BYTE, uxNumberOfBytesToSend );
/* The message is complete, IP and checksum's are handled by
* vProcessGeneratedUDPPacket */
pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
pxNetworkBuffer->xIPAddress.ulIP_IPv4 = ulIPAddress;
pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
/* xDataLength is the size of the total packet, including the Ethernet header. */
pxNetworkBuffer->xDataLength = uxTotalLength;
/* Send to the stack. */
xStackTxEvent.pvData = pxNetworkBuffer;
if( xSendEventStructToIPTask( &( xStackTxEvent ), uxBlockTimeTicks ) != pdPASS )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
}
else
{
xReturn = ( BaseType_t ) usSequenceNumber;
}
}
}
else
{
/* The requested number of bytes will not fit in the available space
* in the network buffer. */
}
return xReturn;
}
#endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
/*-----------------------------------------------------------*/
/**
* @brief Send an event to the IP task. It calls 'xSendEventStructToIPTask' internally.
*
* @param[in] eEvent The event to be sent.
*
* @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
*/
BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )
{
IPStackEvent_t xEventMessage;
const TickType_t xDontBlock = ( TickType_t ) 0;
xEventMessage.eEventType = eEvent;
xEventMessage.pvData = ( void * ) NULL;
return xSendEventStructToIPTask( &xEventMessage, xDontBlock );
}
/*-----------------------------------------------------------*/
/**
* @brief Send an event (in form of struct) to the IP task to be processed.
*
* @param[in] pxEvent The event to be sent.
* @param[in] uxTimeout Timeout for waiting in case the queue is full. 0 for non-blocking calls.
*
* @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
*/
BaseType_t xSendEventStructToIPTask( const IPStackEvent_t * pxEvent,
TickType_t uxTimeout )
{
BaseType_t xReturn, xSendMessage;
TickType_t uxUseTimeout = uxTimeout;
if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )
{
/* Only allow eNetworkDownEvent events if the IP task is not ready
* yet. Not going to attempt to send the message so the send failed. */
xReturn = pdFAIL;
}
else
{
xSendMessage = pdTRUE;
#if ( ipconfigUSE_TCP == 1 )
{
if( pxEvent->eEventType == eTCPTimerEvent )
{
/* TCP timer events are sent to wake the timer task when
* xTCPTimer has expired, but there is no point sending them if the
* IP task is already awake processing other message. */
vIPSetTCPTimerExpiredState( pdTRUE );
if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0U )
{
/* Not actually going to send the message but this is not a
* failure as the message didn't need to be sent. */
xSendMessage = pdFALSE;
}
}
}
#endif /* ipconfigUSE_TCP */
if( xSendMessage != pdFALSE )
{
/* The IP task cannot block itself while waiting for itself to
* respond. */
if( ( xIsCallingFromIPTask() == pdTRUE ) && ( uxUseTimeout > ( TickType_t ) 0U ) )
{
uxUseTimeout = ( TickType_t ) 0;
}
xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, uxUseTimeout );
if( xReturn == pdFAIL )
{
/* A message should have been sent to the IP task, but wasn't. */
FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );
iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );
}
}
else
{
/* It was not necessary to send the message to process the event so
* even though the message was not sent the call was successful. */
xReturn = pdPASS;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Decide whether this packet should be processed or not based on the IP address in the packet.
*
* @param[in] pucEthernetBuffer The ethernet packet under consideration.
*
* @return Enum saying whether to release or to process the packet.
*/
eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
{
eFrameProcessingResult_t eReturn = eProcessBuffer;
const EthernetHeader_t * pxEthernetHeader = NULL;
const NetworkEndPoint_t * pxEndPoint = NULL;
if( pucEthernetBuffer == NULL )
{
eReturn = eReleaseBuffer;
}
else
{
/* Map the buffer onto Ethernet Header struct for easy access to fields. */
/* 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] */
pxEthernetHeader = ( ( const EthernetHeader_t * ) pucEthernetBuffer );
/* Examine the destination MAC from the Ethernet header to see if it matches
* that of an end point managed by FreeRTOS+TCP. */
pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxEthernetHeader->xDestinationAddress ), NULL );
if( pxEndPoint != NULL )
{
/* The packet was directed to this node - process it. */
eReturn = eProcessBuffer;
}
else if( memcmp( xBroadcastMACAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
{
/* The packet was a broadcast - process it. */
eReturn = eProcessBuffer;
}
else
#if ( ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_DNS != 0 ) )
if( memcmp( xLLMNR_MacAdress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
{
/* The packet is a request for LLMNR - process it. */
eReturn = eProcessBuffer;
}
else
#endif /* ipconfigUSE_LLMNR */
#if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_DNS != 0 ) )
if( memcmp( xMDNS_MacAdress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
{
/* The packet is a request for MDNS - process it. */
eReturn = eProcessBuffer;
}
else
#endif /* ipconfigUSE_MDNS */
if( ( pxEthernetHeader->xDestinationAddress.ucBytes[ 0 ] == ipMULTICAST_MAC_ADDRESS_IPv6_0 ) &&
( pxEthernetHeader->xDestinationAddress.ucBytes[ 1 ] == ipMULTICAST_MAC_ADDRESS_IPv6_1 ) )
{
/* The packet is a request for LLMNR - process it. */
eReturn = eProcessBuffer;
}
else
{
/* The packet was not a broadcast, or for this node, just release
* the buffer without taking any other action. */
eReturn = eReleaseBuffer;
}
}
#if ( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )
{
uint16_t usFrameType;
if( eReturn == eProcessBuffer )
{
usFrameType = pxEthernetHeader->usFrameType;
usFrameType = FreeRTOS_ntohs( usFrameType );
if( usFrameType <= 0x600U )
{
/* Not an Ethernet II frame. */
eReturn = eReleaseBuffer;
}
}
}
#endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
return eReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Process the Ethernet packet.
*
* @param[in,out] pxNetworkBuffer the network buffer containing the ethernet packet. If the
* buffer is large enough, it may be reused to send a reply.
*/
static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
const EthernetHeader_t * pxEthernetHeader;
eFrameProcessingResult_t eReturned = eReleaseBuffer;
configASSERT( pxNetworkBuffer != NULL );
iptraceNETWORK_INTERFACE_INPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
/* Interpret the Ethernet frame. */
if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
{
eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
/* Map the buffer onto the Ethernet Header struct for easy access to the fields. */
/* 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] */
pxEthernetHeader = ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
/* The condition "eReturned == eProcessBuffer" must be true. */
#if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
if( eReturned == eProcessBuffer )
#endif
{
/* Interpret the received Ethernet packet. */
switch( pxEthernetHeader->usFrameType )
{
#if ( ipconfigUSE_IPv4 != 0 )
case ipARP_FRAME_TYPE:
/* The Ethernet frame contains an ARP packet. */
if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
{
/* 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] */
eReturned = eARPProcessPacket( pxNetworkBuffer );
}
else
{
eReturned = eReleaseBuffer;
}
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
case ipIPv4_FRAME_TYPE:
case ipIPv6_FRAME_TYPE:
/* The Ethernet frame contains an IP packet. */
if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
{
/* 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] */
eReturned = prvProcessIPPacket( ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer );
}
else
{
eReturned = eReleaseBuffer;
}
break;
default:
#if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 )
/* Custom frame handler. */
eReturned = eApplicationProcessCustomFrameHook( pxNetworkBuffer );
#else
/* No other packet types are handled. Nothing to do. */
eReturned = eReleaseBuffer;
#endif
break;
}
}
}
/* Perform any actions that resulted from processing the Ethernet frame. */
switch( eReturned )
{
case eReturnEthernetFrame:
/* The Ethernet frame will have been updated (maybe it was
* an ARP request or a PING request?) and should be sent back to
* its source. */
vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );
/* parameter pdTRUE: the buffer must be released once
* the frame has been transmitted */
break;
case eFrameConsumed:
/* The frame is in use somewhere, don't release the buffer
* yet. */
break;
case eWaitingARPResolution:
if( pxARPWaitingNetworkBuffer == NULL )
{
pxARPWaitingNetworkBuffer = pxNetworkBuffer;
vIPTimerStartARPResolution( ipARP_RESOLUTION_MAX_DELAY );
iptraceDELAYED_ARP_REQUEST_STARTED();
}
else
{
/* We are already waiting on one ARP resolution. This frame will be dropped. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceDELAYED_ARP_BUFFER_FULL();
}
break;
case eReleaseBuffer:
case eProcessBuffer:
default:
/* The frame is not being used anywhere, and the
* NetworkBufferDescriptor_t structure containing the frame should
* just be released back to the list of free buffers. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
break;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Check the sizes of the UDP packet and forward it to the UDP module
* ( xProcessReceivedUDPPacket() )
* @param[in] pxNetworkBuffer The network buffer containing the UDP packet.
* @return eReleaseBuffer ( please release the buffer ).
* eFrameConsumed ( the buffer has now been released ).
*/
static eFrameProcessingResult_t prvProcessUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
eFrameProcessingResult_t eReturn = eReleaseBuffer;
BaseType_t xIsWaitingARPResolution = pdFALSE;
/* The IP packet contained a UDP frame. */
/* 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 UDPPacket_t * pxUDPPacket = ( ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
const UDPHeader_t * pxUDPHeader = &( pxUDPPacket->xUDPHeader );
size_t uxMinSize = ipSIZE_OF_ETH_HEADER + ( size_t ) uxIPHeaderSizePacket( pxNetworkBuffer ) + ipSIZE_OF_UDP_HEADER;
size_t uxLength;
uint16_t usLength;
#if ( ipconfigUSE_IPv6 != 0 )
if( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
{
const ProtocolHeaders_t * pxProtocolHeaders;
/* 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 + ipSIZE_OF_IPv6_HEADER ] ) );
pxUDPHeader = &( pxProtocolHeaders->xUDPHeader );
}
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
usLength = FreeRTOS_ntohs( pxUDPHeader->usLength );
uxLength = ( size_t ) usLength;
/* Note the header values required prior to the checksum
* generation as the checksum pseudo header may clobber some of
* these values. */
if( ( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) &&
( usLength > ( FreeRTOS_ntohs( pxUDPPacket->xIPHeader.usLength ) - uxIPHeaderSizePacket( pxNetworkBuffer ) ) ) )
{
eReturn = eReleaseBuffer;
}
else if( ( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) &&
( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) ) &&
( ( FreeRTOS_ntohl( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) < ipLAST_LOOPBACK_IPv4 ) )
{
/* The local loopback addresses must never appear outside a host. See RFC 1122
* section 3.2.1.3. */
eReturn = eReleaseBuffer;
}
else if( ( pxNetworkBuffer->xDataLength >= uxMinSize ) &&
( uxLength >= sizeof( UDPHeader_t ) ) )
{
size_t uxPayloadSize_1, uxPayloadSize_2;
/* Ensure that downstream UDP packet handling has the lesser
* of: the actual network buffer Ethernet frame length, or
* the sender's UDP packet header payload length, minus the
* size of the UDP header.
*
* The size of the UDP packet structure in this implementation
* includes the size of the Ethernet header, the size of
* the IP header, and the size of the UDP header. */
uxPayloadSize_1 = pxNetworkBuffer->xDataLength - uxMinSize;
uxPayloadSize_2 = uxLength - ipSIZE_OF_UDP_HEADER;
if( uxPayloadSize_1 > uxPayloadSize_2 )
{
pxNetworkBuffer->xDataLength = uxPayloadSize_2 + uxMinSize;
}
pxNetworkBuffer->usPort = pxUDPHeader->usSourcePort;
pxNetworkBuffer->xIPAddress.ulIP_IPv4 = pxUDPPacket->xIPHeader.ulSourceIPAddress;
/* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
* In some cases, the upper-layer checksum has been calculated
* by the NIC driver. */
/* Pass the packet payload to the UDP sockets
* implementation. */
if( xProcessReceivedUDPPacket( pxNetworkBuffer,
pxUDPHeader->usDestinationPort,
&( xIsWaitingARPResolution ) ) == pdPASS )
{
eReturn = eFrameConsumed;
}
else
{
/* Is this packet to be set aside for ARP resolution. */
if( xIsWaitingARPResolution == pdTRUE )
{
eReturn = eWaitingARPResolution;
}
}
}
else
{
/* Length checks failed, the buffer will be released. */
}
return eReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Process an IP-packet.
*
* @param[in] pxIPPacket The IP packet to be processed.
* @param[in] pxNetworkBuffer The networkbuffer descriptor having the IP packet.
*
* @return An enum to show whether the packet should be released/kept/processed etc.
*/
static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacket,
NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
eFrameProcessingResult_t eReturn;
UBaseType_t uxHeaderLength;
uint8_t ucProtocol = 0U;
#if ( ipconfigUSE_IPv6 != 0 )
const IPHeader_IPv6_t * pxIPHeader_IPv6 = NULL;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
switch( pxIPPacket->xEthernetHeader.usFrameType )
{
#if ( ipconfigUSE_IPv6 != 0 )
case ipIPv6_FRAME_TYPE:
/* 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] */
pxIPHeader_IPv6 = ( ( const IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
uxHeaderLength = ipSIZE_OF_IPv6_HEADER;
ucProtocol = pxIPHeader_IPv6->ucNextHeader;
/* 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] */
eReturn = prvAllowIPPacketIPv6( ( ( const IPHeader_IPv6_t * ) &( pxIPPacket->xIPHeader ) ), pxNetworkBuffer, uxHeaderLength );
/* The IP-header type is copied to a location 6 bytes before the messages
* starts. It might be needed later on when a UDP-payload buffer is being
* used. */
pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = pxIPHeader_IPv6->ucVersionTrafficClass;
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
case ipIPv4_FRAME_TYPE:
{
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. */
uxHeaderLength = ( size_t ) ( ( uxLength & 0x0FU ) << 2 );
if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
{
eReturn = eReleaseBuffer;
}
else
{
ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
/* Check if the IP headers are acceptable and if it has our destination. */
eReturn = prvAllowIPPacketIPv4( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
{
/* The IP-header type is copied to a location 6 bytes before the
* messages starts. It might be needed later on when a UDP-payload
* buffer is being used. */
pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = pxIPHeader->ucVersionHeaderLength;
}
}
break;
}
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
default:
eReturn = eReleaseBuffer;
FreeRTOS_debug_printf( ( "prvProcessIPPacket: Undefined Frame Type \n" ) );
/* MISRA 16.4 Compliance */
break;
}
/* MISRA Ref 14.3.1 [Configuration dependent invariant] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-143 */
/* coverity[misra_c_2012_rule_14_3_violation] */
/* coverity[cond_const] */
if( eReturn == eProcessBuffer )
{
/* Are there IP-options. */
/* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
switch( pxIPPacket->xEthernetHeader.usFrameType ) /* LCOV_EXCL_BR_LINE */
{
#if ( ipconfigUSE_IPv4 != 0 )
case ipIPv4_FRAME_TYPE:
if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
{
/* The size of the IP-header is larger than 20 bytes.
* The extra space is used for IP-options. */
eReturn = prvCheckIP4HeaderOptions( pxNetworkBuffer );
}
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
case ipIPv6_FRAME_TYPE:
if( xGetExtensionOrder( ucProtocol, 0U ) > 0 )
{
eReturn = eHandleIPv6ExtensionHeaders( pxNetworkBuffer, pdTRUE );
if( eReturn != eReleaseBuffer )
{
/* Ignore warning for `pxIPHeader_IPv6`. */
ucProtocol = pxIPHeader_IPv6->ucNextHeader;
}
}
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
/* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
default: /* LCOV_EXCL_LINE */
/* MISRA 16.4 Compliance */
break; /* LCOV_EXCL_LINE */
}
/* MISRA Ref 14.3.1 [Configuration dependent invariant] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-143 */
/* coverity[misra_c_2012_rule_14_3_violation] */
/* coverity[const] */
if( eReturn != eReleaseBuffer )
{
/* Add the IP and MAC addresses to the ARP table if they are not
* already there - otherwise refresh the age of the existing
* entry. */
if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
{
if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
{
eReturn = eWaitingARPResolution;
}
else
{
/* Refresh the ARP cache with the IP/MAC-address of the received
* packet. For UDP packets, this will be done later in
* xProcessReceivedUDPPacket(), as soon as it's know that the message
* will be handled. This will prevent the ARP cache getting
* overwritten with the IP address of useless broadcast packets. */
/* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
switch( pxIPPacket->xEthernetHeader.usFrameType ) /* LCOV_EXCL_BR_LINE */
{
#if ( ipconfigUSE_IPv6 != 0 )
case ipIPv6_FRAME_TYPE:
vNDRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), &( pxIPHeader_IPv6->xSourceAddress ), pxNetworkBuffer->pxEndPoint );
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
case ipIPv4_FRAME_TYPE:
/* IP address is not on the same subnet, ARP table can be updated.
* Refresh the ARP cache with the IP/MAC-address of the received
* packet. For UDP packets, this will be done later in
* xProcessReceivedUDPPacket(), as soon as it's know that the message
* will be handled. This will prevent the ARP cache getting
* overwritten with the IP address of useless broadcast packets.
*/
vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress, pxNetworkBuffer->pxEndPoint );
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
/* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
default: /* LCOV_EXCL_LINE */
/* MISRA 16.4 Compliance */
break; /* LCOV_EXCL_LINE */
}
}
}
if( eReturn != eWaitingARPResolution ) /*TODO eReturn != eReleaseBuffer */
{
switch( ucProtocol )
{
#if ( ipconfigUSE_IPv4 != 0 )
case ipPROTOCOL_ICMP:
/* The IP packet contained an ICMP frame. Don't bother checking
* the ICMP checksum, as if it is wrong then the wrong data will
* also be returned, and the source of the ping will know something
* went wrong because it will not be able to validate what it
* receives. */
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
{
eReturn = ProcessICMPPacket( pxNetworkBuffer );
}
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
case ipPROTOCOL_ICMP_IPv6:
eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer );
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
case ipPROTOCOL_UDP:
/* The IP packet contained a UDP frame. */
eReturn = prvProcessUDPPacket( pxNetworkBuffer );
break;
#if ipconfigUSE_TCP == 1
case ipPROTOCOL_TCP:
if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
{
eReturn = eFrameConsumed;
}
/* Setting this variable will cause xTCPTimerCheck()
* to be called just before the IP-task blocks. */
xProcessedTCPMessage++;
break;
#endif /* if ipconfigUSE_TCP == 1 */
default:
/* Not a supported frame type. */
eReturn = eReleaseBuffer;
break;
}
}
}
}
return eReturn;
}
/*-----------------------------------------------------------*/
/* This function is used in other files, has external linkage e.g. in
* FreeRTOS_DNS.c. Not to be made static. */
/**
* @brief Send the Ethernet frame after checking for some conditions.
*
* @param[in,out] pxNetworkBuffer The network buffer which is to be sent.
* @param[in] xReleaseAfterSend Whether this network buffer is to be released or not.
*/
void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
{
IPPacket_t * pxIPPacket;
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
NetworkBufferDescriptor_t * pxNewBuffer;
#endif
#if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
{
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
BaseType_t xIndex;
FreeRTOS_printf( ( "vReturnEthernetFrame: length %u\n", ( unsigned ) pxNetworkBuffer->xDataLength ) );
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
{
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
}
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
}
}
#endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
if( xReleaseAfterSend == pdFALSE )
{
pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, pxNetworkBuffer->xDataLength );
if( pxNewBuffer != NULL )
{
xReleaseAfterSend = pdTRUE;
/* Want no rounding up. */
pxNewBuffer->xDataLength = pxNetworkBuffer->xDataLength;
}
pxNetworkBuffer = pxNewBuffer;
}
if( pxNetworkBuffer != NULL )
#endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 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] */
pxIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
/* Send! */
if( pxNetworkBuffer->pxEndPoint == NULL )
{
/* _HT_ I wonder if this ad-hoc search of an end-point it necessary. */
FreeRTOS_printf( ( "vReturnEthernetFrame: No pxEndPoint yet for %x ip?\n", ( unsigned int ) FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ) ) );
/* 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] */
switch( ( ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer ) )->usFrameType )
{
#if ( ipconfigUSE_IPv6 != 0 )
case ipIPv6_FRAME_TYPE:
/* No IPv6 endpoint found */
break;
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
case ipIPv4_FRAME_TYPE:
pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnNetMask( pxIPPacket->xIPHeader.ulDestinationIPAddress, 7 );
break;
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
default:
/* MISRA 16.4 Compliance */
break;
}
}
if( pxNetworkBuffer->pxEndPoint != NULL )
{
NetworkInterface_t * pxInterface = pxNetworkBuffer->pxEndPoint->pxNetworkInterface; /*_RB_ Why not use the pxNetworkBuffer->pxNetworkInterface directly? */
/* Swap source and destination MAC addresses. */
pvCopySource = &( pxIPPacket->xEthernetHeader.xSourceAddress );
pvCopyDest = &( pxIPPacket->xEthernetHeader.xDestinationAddress );
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxIPPacket->xEthernetHeader.xDestinationAddress ) );
pvCopySource = pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes;
pvCopyDest = &( pxIPPacket->xEthernetHeader.xSourceAddress );
( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
/* Send! */
if( xIsCallingFromIPTask() == pdTRUE )
{
iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
( void ) pxInterface->pfOutput( pxInterface, pxNetworkBuffer, xReleaseAfterSend );
}
else if( xReleaseAfterSend != pdFALSE )
{
IPStackEvent_t xSendEvent;
/* Send a message to the IP-task to send this ARP packet. */
xSendEvent.eEventType = eNetworkTxEvent;
xSendEvent.pvData = pxNetworkBuffer;
if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
{
/* Failed to send the message, so release the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
else
{
/* This should never reach or the packet is gone. */
configASSERT( pdFALSE );
}
}
}
}
/*-----------------------------------------------------------*/
/**
* @brief Returns the IP address of the NIC.
*
* @return The IP address of the NIC.
*/
uint32_t FreeRTOS_GetIPAddress( void )
{
NetworkEndPoint_t * pxEndPoint;
uint32_t ulIPAddress;
pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
#if ( ipconfigUSE_IPv6 != 0 )
if( ENDPOINT_IS_IPv6( pxEndPoint ) )
{
for( ;
pxEndPoint != NULL;
pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
{
/* Break if the endpoint is IPv4. */
if( pxEndPoint->bits.bIPv6 == 0U )
{
break;
}
}
}
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
/* Returns the IP address of the NIC. */
if( pxEndPoint == NULL )
{
ulIPAddress = 0U;
}
else if( pxEndPoint->ipv4_settings.ulIPAddress != 0U )
{
ulIPAddress = pxEndPoint->ipv4_settings.ulIPAddress;
}
else
{
ulIPAddress = pxEndPoint->ipv4_defaults.ulIPAddress;
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
#if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
/*
* The helper functions here below assume that there is a single
* interface and a single end-point (ipconfigIPv4_BACKWARD_COMPATIBLE)
*/
/**
* @brief Sets the IP address of the NIC.
*
* @param[in] ulIPAddress IP address of the NIC to be set.
*/
void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
{
/* Sets the IP address of the NIC. */
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
pxEndPoint->ipv4_settings.ulIPAddress = ulIPAddress;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Get the gateway address of the subnet.
*
* @return The IP-address of the gateway, zero if a gateway is
* not used/defined.
*/
uint32_t FreeRTOS_GetGatewayAddress( void )
{
uint32_t ulIPAddress = 0U;
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
ulIPAddress = pxEndPoint->ipv4_settings.ulGatewayAddress;
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
/**
* @brief Get the DNS server address.
*
* @return The IP address of the DNS server.
*/
uint32_t FreeRTOS_GetDNSServerAddress( void )
{
uint32_t ulIPAddress = 0U;
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
ulIPAddress = pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ];
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
/**
* @brief Get the netmask for the subnet.
*
* @return The 32 bit netmask for the subnet.
*/
uint32_t FreeRTOS_GetNetmask( void )
{
uint32_t ulIPAddress = 0U;
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
ulIPAddress = pxEndPoint->ipv4_settings.ulNetMask;
}
return ulIPAddress;
}
/*-----------------------------------------------------------*/
/**
* @brief Update the MAC address.
*
* @param[in] ucMACAddress the MAC address to be set.
*/
void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
{
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
/* Copy the MAC address at the start of the default packet header fragment. */
( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ( const void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
}
}
/*-----------------------------------------------------------*/
/**
* @brief Get the MAC address.
*
* @return The pointer to MAC address.
*/
const uint8_t * FreeRTOS_GetMACAddress( void )
{
const uint8_t * pucReturn = NULL;
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
/* Copy the MAC address at the start of the default packet header fragment. */
pucReturn = pxEndPoint->xMACAddress.ucBytes;
}
return pucReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Set the netmask for the subnet.
*
* @param[in] ulNetmask The 32 bit netmask of the subnet.
*/
void FreeRTOS_SetNetmask( uint32_t ulNetmask )
{
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
pxEndPoint->ipv4_settings.ulNetMask = ulNetmask;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Set the gateway address.
*
* @param[in] ulGatewayAddress The gateway address.
*/
void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress )
{
NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
if( pxEndPoint != NULL )
{
pxEndPoint->ipv4_settings.ulGatewayAddress = ulGatewayAddress;
}
}
/*-----------------------------------------------------------*/
#endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
/**
* @brief Returns whether the IP task is ready.
*
* @return pdTRUE if IP task is ready, else pdFALSE.
*/
BaseType_t xIPIsNetworkTaskReady( void )
{
return xIPTaskInitialised;
}
/*-----------------------------------------------------------*/
/**
* @brief Returns whether all end-points are up.
*
* @return pdTRUE if all defined end-points are up.
*/
BaseType_t FreeRTOS_IsNetworkUp( void )
{
/* IsNetworkUp() is kept for backward compatibility. */
return FreeRTOS_IsEndPointUp( NULL );
}
/*-----------------------------------------------------------*/
/**
* @brief The variable 'xNetworkDownEventPending' is declared static. This function
* gives read-only access to it.
*
* @return pdTRUE if there a network-down event pending. pdFALSE otherwise.
*/
BaseType_t xIsNetworkDownEventPending( void )
{
return xNetworkDownEventPending;
}
/*-----------------------------------------------------------*/
/**
* @brief Returns whether a particular end-point is up.
*
* @return pdTRUE if a particular end-points is up.
*/
BaseType_t FreeRTOS_IsEndPointUp( const struct xNetworkEndPoint * pxEndPoint )
{
BaseType_t xReturn;
if( pxEndPoint != NULL )
{
/* Is this particular end-point up? */
xReturn = ( BaseType_t ) pxEndPoint->bits.bEndPointUp;
}
else
{
/* Are all end-points up? */
xReturn = FreeRTOS_AllEndPointsUp( NULL );
}
return xReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Return pdTRUE if all end-points belonging to a given interface are up. When
* pxInterface is null, all end-points will be checked.
*
* @param[in] pxInterface The network interface of interest, or NULL to check all end-points.
*
* @return pdTRUE if all end-points are up, otherwise pdFALSE;
*/
BaseType_t FreeRTOS_AllEndPointsUp( const struct xNetworkInterface * pxInterface )
{
BaseType_t xResult = pdTRUE;
const NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
while( pxEndPoint != NULL )
{
if( ( pxInterface == NULL ) ||
( pxEndPoint->pxNetworkInterface == pxInterface ) )
{
if( pxEndPoint->bits.bEndPointUp == pdFALSE_UNSIGNED )
{
xResult = pdFALSE;
break;
}
}
pxEndPoint = pxEndPoint->pxNext;
}
return xResult;
}
/*-----------------------------------------------------------*/
#if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
/**
* @brief Get the minimum space in the IP task queue.
*
* @return The minimum possible space in the IP task queue.
*/
UBaseType_t uxGetMinimumIPQueueSpace( void )
{
return uxQueueMinimumSpace;
}
#endif
/*-----------------------------------------------------------*/
/**
* @brief Get the size of the IP-header, by checking the type of the network buffer.
* @param[in] pxNetworkBuffer The network buffer.
* @return The size of the corresponding IP-header.
*/
size_t uxIPHeaderSizePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
{
size_t uxResult;
/* Map the buffer onto Ethernet Header struct for easy access to fields. */
/* 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 EthernetHeader_t * pxHeader = ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
if( pxHeader->usFrameType == ( uint16_t ) ipIPv6_FRAME_TYPE )
{
uxResult = ipSIZE_OF_IPv6_HEADER;
}
else
{
uxResult = ipSIZE_OF_IPv4_HEADER;
}
return uxResult;
}
/*-----------------------------------------------------------*/
/**
* @brief Get the size of the IP-header, by checking if the socket bIsIPv6 set.
* @param[in] pxSocket The socket.
* @return The size of the corresponding IP-header.
*/
size_t uxIPHeaderSizeSocket( const FreeRTOS_Socket_t * pxSocket )
{
size_t uxResult;
if( ( pxSocket != NULL ) && ( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED ) )
{
uxResult = ipSIZE_OF_IPv6_HEADER;
}
else
{
uxResult = ipSIZE_OF_IPv4_HEADER;
}
return uxResult;
}
/*-----------------------------------------------------------*/
/* Provide access to private members for verification. */
#ifdef FREERTOS_TCP_ENABLE_VERIFICATION
#include "aws_freertos_ip_verification_access_ip_define.h"
#endif