]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_IP.c
index c94f55dd74d5ecdd829f090f21a822194551c9d8..48e632a01f8c8d9706cddf295c0e42d76e574a6e 100644 (file)
-/*\r
- * FreeRTOS+TCP V2.2.0\r
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "FreeRTOS_ARP.h"\r
-#include "FreeRTOS_UDP_IP.h"\r
-#include "FreeRTOS_TCP_IP.h"\r
-#include "FreeRTOS_DHCP.h"\r
-#include "NetworkInterface.h"\r
-#include "NetworkBufferManagement.h"\r
-#include "FreeRTOS_DNS.h"\r
-\r
-\r
-/* Used to ensure the structure packing is having the desired effect.  The\r
-'volatile' is used to prevent compiler warnings about comparing a constant with\r
-a constant. */\r
-#define ipEXPECTED_EthernetHeader_t_SIZE       ( ( size_t ) 14 )\r
-#define ipEXPECTED_ARPHeader_t_SIZE                    ( ( size_t ) 28 )\r
-#define ipEXPECTED_IPHeader_t_SIZE                     ( ( size_t ) 20 )\r
-#define ipEXPECTED_IGMPHeader__SIZE                    ( ( size_t ) 8 )\r
-#define ipEXPECTED_ICMPHeader_t_SIZE           ( ( size_t ) 8 )\r
-#define ipEXPECTED_UDPHeader_t_SIZE                    ( ( size_t ) 8 )\r
-#define ipEXPECTED_TCPHeader_t_SIZE                    ( ( size_t ) 20 )\r
-\r
-\r
-/* ICMP protocol definitions. */\r
-#define ipICMP_ECHO_REQUEST                            ( ( uint8_t ) 8 )\r
-#define ipICMP_ECHO_REPLY                              ( ( uint8_t ) 0 )\r
-\r
-\r
-/* Time delay between repeated attempts to initialise the network hardware. */\r
-#ifndef ipINITIALISATION_RETRY_DELAY\r
-       #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000 ) )\r
-#endif\r
-\r
-/* Defines how often the ARP timer callback function is executed.  The time is\r
-shorted in the Windows simulator as simulated time is not real time. */\r
-#ifndef        ipARP_TIMER_PERIOD_MS\r
-       #ifdef _WINDOWS_\r
-               #define ipARP_TIMER_PERIOD_MS   ( 500 ) /* For windows simulator builds. */\r
-       #else\r
-               #define ipARP_TIMER_PERIOD_MS   ( 10000 )\r
-       #endif\r
-#endif\r
-\r
-#ifndef iptraceIP_TASK_STARTING\r
-       #define iptraceIP_TASK_STARTING()       do {} while( 0 )\r
-#endif\r
-\r
-#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )\r
-       /* When initialising the TCP timer,\r
-       give it an initial time-out of 1 second. */\r
-       #define ipTCP_TIMER_PERIOD_MS   ( 1000 )\r
-#endif\r
-\r
-/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet\r
-driver will filter incoming packets and only pass the stack those packets it\r
-considers need processing.  In this case ipCONSIDER_FRAME_FOR_PROCESSING() can\r
-be #defined away.  If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0\r
-then the Ethernet driver will pass all received packets to the stack, and the\r
-stack must do the filtering itself.  In this case ipCONSIDER_FRAME_FOR_PROCESSING\r
-needs to call eConsiderFrameForProcessing. */\r
-#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0\r
-       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
-#else\r
-       #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
-#endif\r
-\r
-/* The character used to fill ICMP echo requests, and therefore also the\r
-character expected to fill ICMP echo replies. */\r
-#define ipECHO_DATA_FILL_BYTE                                          'x'\r
-\r
-#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )\r
-       /* The bits in the two byte IP header field that make up the fragment offset value. */\r
-       #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0xff0f )\r
-#else\r
-       /* The bits in the two byte IP header field that make up the fragment offset value. */\r
-       #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0x0fff )\r
-#endif /* ipconfigBYTE_ORDER */\r
-\r
-/* The maximum time the IP task is allowed to remain in the Blocked state if no\r
-events are posted to the network event queue. */\r
-#ifndef        ipconfigMAX_IP_TASK_SLEEP_TIME\r
-       #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )\r
-#endif\r
-\r
-/* When a new TCP connection is established, the value of\r
-'ulNextInitialSequenceNumber' will be used as the initial sequence number.  It\r
-is very important that at start-up, 'ulNextInitialSequenceNumber' contains a\r
-random value.  Also its value must be increased continuously in time, to prevent\r
-a third party guessing the next sequence number and take-over a TCP connection.\r
-It is advised to increment it by 1 ever 4us, which makes about 256 times\r
-per ms: */\r
-#define ipINITIAL_SEQUENCE_NUMBER_FACTOR       256UL\r
-\r
-/* Returned as the (invalid) checksum when the protocol being checked is not\r
-handled.  The value is chosen simply to be easy to spot when debugging. */\r
-#define ipUNHANDLED_PROTOCOL           0x4321u\r
-\r
-/* Returned to indicate a valid checksum when the checksum does not need to be\r
-calculated. */\r
-#define ipCORRECT_CRC                          0xffffu\r
-\r
-/* Returned as the (invalid) checksum when the length of the data being checked\r
-had an invalid length. */\r
-#define ipINVALID_LENGTH                       0x1234u\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-typedef struct xIP_TIMER\r
-{\r
-       uint32_t\r
-               bActive : 1,    /* This timer is running and must be processed. */\r
-               bExpired : 1;   /* Timer has expired and a task must be processed. */\r
-       TimeOut_t xTimeOut;\r
-       TickType_t ulRemainingTime;\r
-       TickType_t ulReloadTime;\r
-} IPTimer_t;\r
-\r
-/* Used in checksum calculation. */\r
-typedef union _xUnion32\r
-{\r
-       uint32_t u32;\r
-       uint16_t u16[ 2 ];\r
-       uint8_t u8[ 4 ];\r
-} xUnion32;\r
-\r
-/* Used in checksum calculation. */\r
-typedef union _xUnionPtr\r
-{\r
-       uint32_t *u32ptr;\r
-       uint16_t *u16ptr;\r
-       uint8_t *u8ptr;\r
-} xUnionPtr;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * The main TCP/IP stack processing task.  This task receives commands/events\r
- * from the network hardware drivers and tasks that are using sockets.  It also\r
- * maintains a set of protocol timers.\r
- */\r
-static void prvIPTask( void *pvParameters );\r
-\r
-/*\r
- * Called when new data is available from the network interface.\r
- */\r
-static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
-\r
-/*\r
- * Process incoming IP packets.\r
- */\r
-static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
-\r
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-       /*\r
-        * Process incoming ICMP packets.\r
-        */\r
-       static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );\r
-#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
-\r
-/*\r
- * Turns around an incoming ping request to convert it into a ping reply.\r
- */\r
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
-       static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );\r
-#endif /* ipconfigREPLY_TO_INCOMING_PINGS */\r
-\r
-/*\r
- * Processes incoming ping replies.  The application callback function\r
- * vApplicationPingReplyHook() is called with the results.\r
- */\r
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-       static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );\r
-#endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
-\r
-/*\r
- * Called to create a network connection when the stack is first started, or\r
- * when the network connection is lost.\r
- */\r
-static void prvProcessNetworkDownEvent( void );\r
-\r
-/*\r
- * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout\r
- * processing is required.\r
- */\r
-static void prvCheckNetworkTimers( void );\r
-\r
-/*\r
- * Determine how long the IP task can sleep for, which depends on when the next\r
- * periodic or timeout processing must be performed.\r
- */\r
-static TickType_t prvCalculateSleepTime( void );\r
-\r
-/*\r
- * The network card driver has received a packet.  In the case that it is part\r
- * of a linked packet chain, walk through it to handle every message.\r
- */\r
-static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer );\r
-\r
-/*\r
- * Utility functions for the light weight IP timers.\r
- */\r
-static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime );\r
-static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer );\r
-static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime );\r
-\r
-static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,\r
-       NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The queue used to pass events into the IP-task for processing. */\r
-QueueHandle_t xNetworkEventQueue = NULL;\r
-\r
-/*_RB_ Requires comment. */\r
-uint16_t usPacketIdentifier = 0U;\r
-\r
-/* For convenience, a MAC address of all 0xffs is defined const for quick\r
-reference. */\r
-const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };\r
-\r
-/* Structure that stores the netmask, gateway address and DNS server addresses. */\r
-NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };\r
-\r
-/* Default values for the above struct in case DHCP\r
-does not lead to a confirmed request. */\r
-NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };\r
-\r
-/* Used to ensure network down events cannot be missed when they cannot be\r
-posted to the network event queue because the network event queue is already\r
-full. */\r
-static BaseType_t xNetworkDownEventPending = pdFALSE;\r
-\r
-/* Stores the handle of the task that handles the stack.  The handle is used\r
-(indirectly) by some utility function to determine if the utility function is\r
-being called by a task (in which case it is ok to block) or by the IP task\r
-itself (in which case it is not ok to block). */\r
-static TaskHandle_t xIPTaskHandle = NULL;\r
-\r
-#if( ipconfigUSE_TCP != 0 )\r
-       /* Set to a non-zero value if one or more TCP message have been processed\r
-       within the last round. */\r
-       static BaseType_t xProcessedTCPMessage;\r
-#endif\r
-\r
-/* Simple set to pdTRUE or pdFALSE depending on whether the network is up or\r
-down (connected, not connected) respectively. */\r
-static BaseType_t xNetworkUp = pdFALSE;\r
-\r
-/*\r
-A timer for each of the following processes, all of which need attention on a\r
-regular basis:\r
-       1. ARP, to check its table entries\r
-       2. DPHC, to send requests and to renew a reservation\r
-       3. TCP, to check for timeouts, resends\r
-       4. DNS, to check for timeouts when looking-up a domain.\r
- */\r
-static IPTimer_t xARPTimer;\r
-#if( ipconfigUSE_DHCP != 0 )\r
-       static IPTimer_t xDHCPTimer;\r
-#endif\r
-#if( ipconfigUSE_TCP != 0 )\r
-       static IPTimer_t xTCPTimer;\r
-#endif\r
-#if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       static IPTimer_t xDNSTimer;\r
-#endif\r
-\r
-/* Set to pdTRUE when the IP task is ready to start processing packets. */\r
-static BaseType_t xIPTaskInitialised = pdFALSE;\r
-\r
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-       /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */\r
-       static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvIPTask( void *pvParameters )\r
-{\r
-IPStackEvent_t xReceivedEvent;\r
-TickType_t xNextIPSleep;\r
-FreeRTOS_Socket_t *pxSocket;\r
-struct freertos_sockaddr xAddress;\r
-\r
-       /* Just to prevent compiler warnings about unused parameters. */\r
-       ( void ) pvParameters;\r
-\r
-       /* A possibility to set some additional task properties. */\r
-       iptraceIP_TASK_STARTING();\r
-\r
-       /* Generate a dummy message to say that the network connection has gone\r
-       down.  This will cause this task to initialise the network interface.  After\r
-       this it is the responsibility of the network interface hardware driver to\r
-       send this message if a previously connected network is disconnected. */\r
-       FreeRTOS_NetworkDown();\r
-\r
-       #if( ipconfigUSE_TCP == 1 )\r
-       {\r
-               /* Initialise the TCP timer. */\r
-               prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );\r
-       }\r
-       #endif\r
-\r
-       /* Initialisation is complete and events can now be processed. */\r
-       xIPTaskInitialised = pdTRUE;\r
-\r
-       FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );\r
-\r
-       /* Loop, processing IP events. */\r
-       for( ;; )\r
-       {\r
-               ipconfigWATCHDOG_TIMER();\r
-\r
-               /* Check the ARP, DHCP and TCP timers to see if there is any periodic\r
-               or timeout processing to perform. */\r
-               prvCheckNetworkTimers();\r
-\r
-               /* Calculate the acceptable maximum sleep time. */\r
-               xNextIPSleep = prvCalculateSleepTime();\r
-\r
-               /* Wait until there is something to do. If the following call exits\r
-                * due to a time out rather than a message being received, set a\r
-                * 'NoEvent' value. */\r
-               if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE ) \r
-               {\r
-                       xReceivedEvent.eEventType = eNoEvent;\r
-               }\r
-\r
-               #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-               {\r
-                       if( xReceivedEvent.eEventType != eNoEvent )\r
-                       {\r
-                       UBaseType_t uxCount;\r
-\r
-                               uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );\r
-                               if( uxQueueMinimumSpace > uxCount )\r
-                               {\r
-                                       uxQueueMinimumSpace = uxCount;\r
-                               }\r
-                       }\r
-               }\r
-               #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
-\r
-               iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );\r
-\r
-               switch( xReceivedEvent.eEventType )\r
-               {\r
-                       case eNetworkDownEvent :\r
-                               /* Attempt to establish a connection. */\r
-                               xNetworkUp = pdFALSE;\r
-                               prvProcessNetworkDownEvent();\r
-                               break;\r
-\r
-                       case eNetworkRxEvent:\r
-                               /* The network hardware driver has received a new packet.  A\r
-                               pointer to the received buffer is located in the pvData member\r
-                               of the received event structure. */\r
-                               prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );\r
-                               break;\r
-\r
-                       case eNetworkTxEvent:\r
-                               /* Send a network packet. The ownership will  be transferred to\r
-                               the driver, which will release it after delivery. */\r
-                               xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE );\r
-                               break;\r
-\r
-                       case eARPTimerEvent :\r
-                               /* The ARP timer has expired, process the ARP cache. */\r
-                               vARPAgeCache();\r
-                               break;\r
-\r
-                       case eSocketBindEvent:\r
-                               /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket\r
-                               to a port. The port number is communicated in the socket field\r
-                               usLocalPort. vSocketBind() will actually bind the socket and the\r
-                               API will unblock as soon as the eSOCKET_BOUND event is\r
-                               triggered. */\r
-                               pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );\r
-                               xAddress.sin_addr = 0u; /* For the moment. */\r
-                               xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );\r
-                               pxSocket->usLocalPort = 0u;\r
-                               vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );\r
-\r
-                               /* Before 'eSocketBindEvent' was sent it was tested that\r
-                               ( xEventGroup != NULL ) so it can be used now to wake up the\r
-                               user. */\r
-                               pxSocket->xEventBits |= eSOCKET_BOUND;\r
-                               vSocketWakeUpUser( pxSocket );\r
-                               break;\r
-\r
-                       case eSocketCloseEvent :\r
-                               /* The user API FreeRTOS_closesocket() has sent a message to the\r
-                               IP-task to actually close a socket. This is handled in\r
-                               vSocketClose().  As the socket gets closed, there is no way to\r
-                               report back to the API, so the API won't wait for the result */\r
-                               vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) );\r
-                               break;\r
-\r
-                       case eStackTxEvent :\r
-                               /* The network stack has generated a packet to send.  A\r
-                               pointer to the generated buffer is located in the pvData\r
-                               member of the received event structure. */\r
-                               vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );\r
-                               break;\r
-\r
-                       case eDHCPEvent:\r
-                               /* The DHCP state machine needs processing. */\r
-                               #if( ipconfigUSE_DHCP == 1 )\r
-                               {\r
-                                       vDHCPProcess( pdFALSE );\r
-                               }\r
-                               #endif /* ipconfigUSE_DHCP */\r
-                               break;\r
-\r
-                       case eSocketSelectEvent :\r
-                               /* FreeRTOS_select() has got unblocked by a socket event,\r
-                               vSocketSelect() will check which sockets actually have an event\r
-                               and update the socket field xSocketBits. */\r
-                               #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
-                               {\r
-                                       vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) );\r
-                               }\r
-                               #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */\r
-                               break;\r
-\r
-                       case eSocketSignalEvent :\r
-                               #if( ipconfigSUPPORT_SIGNALS != 0 )\r
-                               {\r
-                                       /* Some task wants to signal the user of this socket in\r
-                                       order to interrupt a call to recv() or a call to select(). */\r
-                                       FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );\r
-                               }\r
-                               #endif /* ipconfigSUPPORT_SIGNALS */\r
-                               break;\r
-\r
-                       case eTCPTimerEvent :\r
-                               #if( ipconfigUSE_TCP == 1 )\r
-                               {\r
-                                       /* Simply mark the TCP timer as expired so it gets processed\r
-                                       the next time prvCheckNetworkTimers() is called. */\r
-                                       xTCPTimer.bExpired = pdTRUE_UNSIGNED;\r
-                               }\r
-                               #endif /* ipconfigUSE_TCP */\r
-                               break;\r
-\r
-                       case eTCPAcceptEvent:\r
-                               /* The API FreeRTOS_accept() was called, the IP-task will now\r
-                               check if the listening socket (communicated in pvData) actually\r
-                               received a new connection. */\r
-                               #if( ipconfigUSE_TCP == 1 )\r
-                               {\r
-                                       pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );\r
-\r
-                                       if( xTCPCheckNewClient( pxSocket ) != pdFALSE )\r
-                                       {\r
-                                               pxSocket->xEventBits |= eSOCKET_ACCEPT;\r
-                                               vSocketWakeUpUser( pxSocket );\r
-                                       }\r
-                               }\r
-                               #endif /* ipconfigUSE_TCP */\r
-                               break;\r
-\r
-                       case eTCPNetStat:\r
-                               /* FreeRTOS_netstat() was called to have the IP-task print an\r
-                               overview of all sockets and their connections */\r
-                               #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )\r
-                               {\r
-                                       vTCPNetStat();\r
-                               }\r
-                               #endif /* ipconfigUSE_TCP */\r
-                               break;\r
-\r
-                       default :\r
-                               /* Should not get here. */\r
-                               break;\r
-               }\r
-\r
-               if( xNetworkDownEventPending != pdFALSE )\r
-               {\r
-                       /* A network down event could not be posted to the network event\r
-                       queue because the queue was full.  Try posting again. */\r
-                       FreeRTOS_NetworkDown();\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xIsCallingFromIPTask( void )\r
-{\r
-BaseType_t xReturn;\r
-\r
-       if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )\r
-       {\r
-               xReturn = pdTRUE;\r
-       }\r
-       else\r
-       {\r
-               xReturn = pdFALSE;\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer )\r
-{\r
-       #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )\r
-       {\r
-               /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one\r
-               buffer will be sent at a time.  This is the default way for +TCP to pass\r
-               messages from the MAC to the TCP/IP stack. */\r
-               prvProcessEthernetPacket( pxBuffer );\r
-       }\r
-       #else /* ipconfigUSE_LINKED_RX_MESSAGES */\r
-       {\r
-       NetworkBufferDescriptor_t *pxNextBuffer;\r
-\r
-               /* An optimisation that is useful when there is high network traffic.\r
-               Instead of passing received packets into the IP task one at a time the\r
-               network interface can chain received packets together and pass them into\r
-               the IP task in one go.  The packets are chained using the pxNextBuffer\r
-               member.  The loop below walks through the chain processing each packet\r
-               in the chain in turn. */\r
-               do\r
-               {\r
-                       /* Store a pointer to the buffer after pxBuffer for use later on. */\r
-                       pxNextBuffer = pxBuffer->pxNextBuffer;\r
-\r
-                       /* Make it NULL to avoid using it later on. */\r
-                       pxBuffer->pxNextBuffer = NULL;\r
-\r
-                       prvProcessEthernetPacket( pxBuffer );\r
-                       pxBuffer = pxNextBuffer;\r
-\r
-               /* While there is another packet in the chain. */\r
-               } while( pxBuffer != NULL );\r
-       }\r
-       #endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static TickType_t prvCalculateSleepTime( void )\r
-{\r
-TickType_t xMaximumSleepTime;\r
-\r
-       /* Start with the maximum sleep time, then check this against the remaining\r
-       time in any other timers that are active. */\r
-       xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;\r
-\r
-       if( xARPTimer.bActive != pdFALSE_UNSIGNED )\r
-       {\r
-               if( xARPTimer.ulRemainingTime < xMaximumSleepTime )\r
-               {\r
-                       xMaximumSleepTime = xARPTimer.ulReloadTime;\r
-               }\r
-       }\r
-\r
-       #if( ipconfigUSE_DHCP == 1 )\r
-       {\r
-               if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )\r
-               {\r
-                       if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )\r
-                       {\r
-                               xMaximumSleepTime = xDHCPTimer.ulRemainingTime;\r
-                       }\r
-               }\r
-       }\r
-       #endif /* ipconfigUSE_DHCP */\r
-\r
-       #if( ipconfigUSE_TCP == 1 )\r
-       {\r
-               if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )\r
-               {\r
-                       xMaximumSleepTime = xTCPTimer.ulRemainingTime;\r
-               }\r
-       }\r
-       #endif\r
-\r
-       #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       {\r
-               if( xDNSTimer.bActive != pdFALSE )\r
-               {\r
-                       if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )\r
-                       {\r
-                               xMaximumSleepTime = xDNSTimer.ulRemainingTime;\r
-                       }\r
-               }\r
-       }\r
-       #endif\r
-\r
-       return xMaximumSleepTime;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckNetworkTimers( void )\r
-{\r
-       /* Is it time for ARP processing? */\r
-       if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )\r
-       {\r
-               xSendEventToIPTask( eARPTimerEvent );\r
-       }\r
-\r
-       #if( ipconfigUSE_DHCP == 1 )\r
-       {\r
-               /* Is it time for DHCP processing? */\r
-               if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )\r
-               {\r
-                       xSendEventToIPTask( eDHCPEvent );\r
-               }\r
-       }\r
-       #endif /* ipconfigUSE_DHCP */\r
-\r
-       #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       {\r
-       extern void vDNSCheckCallBack( void *pvSearchID );\r
-\r
-               /* Is it time for DNS processing? */\r
-               if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )\r
-               {\r
-                       vDNSCheckCallBack( NULL );\r
-               }\r
-       }\r
-       #endif /* ipconfigDNS_USE_CALLBACKS */\r
-\r
-       #if( ipconfigUSE_TCP == 1 )\r
-       {\r
-       BaseType_t xWillSleep;\r
-       TickType_t xNextTime;\r
-       BaseType_t xCheckTCPSockets;\r
-\r
-               if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )\r
-               {\r
-                       xWillSleep = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       xWillSleep = pdFALSE;\r
-               }\r
-\r
-               /* Sockets need to be checked if the TCP timer has expired. */\r
-               xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );\r
-\r
-               /* Sockets will also be checked if there are TCP messages but the\r
-               message queue is empty (indicated by xWillSleep being true). */\r
-               if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )\r
-               {\r
-                       xCheckTCPSockets = pdTRUE;\r
-               }\r
-\r
-               if( xCheckTCPSockets != pdFALSE )\r
-               {\r
-                       /* Attend to the sockets, returning the period after which the\r
-                       check must be repeated. */\r
-                       xNextTime = xTCPTimerCheck( xWillSleep );\r
-                       prvIPTimerStart( &xTCPTimer, xNextTime );\r
-                       xProcessedTCPMessage = 0;\r
-               }\r
-       }\r
-       #endif /* ipconfigUSE_TCP == 1 */\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime )\r
-{\r
-       vTaskSetTimeOutState( &pxTimer->xTimeOut );\r
-       pxTimer->ulRemainingTime = xTime;\r
-\r
-       if( xTime == ( TickType_t ) 0 )\r
-       {\r
-               pxTimer->bExpired = pdTRUE_UNSIGNED;\r
-       }\r
-       else\r
-       {\r
-               pxTimer->bExpired = pdFALSE_UNSIGNED;\r
-       }\r
-\r
-       pxTimer->bActive = pdTRUE_UNSIGNED;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime )\r
-{\r
-       pxTimer->ulReloadTime = xTime;\r
-       prvIPTimerStart( pxTimer, xTime );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer )\r
-{\r
-BaseType_t xReturn;\r
-\r
-       if( pxTimer->bActive == pdFALSE_UNSIGNED )\r
-       {\r
-               /* The timer is not enabled. */\r
-               xReturn = pdFALSE;\r
-       }\r
-       else\r
-       {\r
-               /* The timer might have set the bExpired flag already, if not, check the\r
-               value of xTimeOut against ulRemainingTime. */\r
-               if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) ||\r
-                       ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) )\r
-               {\r
-                       prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );\r
-                       xReturn = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       xReturn = pdFALSE;\r
-               }\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_NetworkDown( void )\r
-{\r
-static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
-const TickType_t xDontBlock = ( TickType_t ) 0;\r
-\r
-       /* Simply send the network task the appropriate event. */\r
-       if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )\r
-       {\r
-               /* Could not send the message, so it is still pending. */\r
-               xNetworkDownEventPending = pdTRUE;\r
-       }\r
-       else\r
-       {\r
-               /* Message was sent so it is not pending. */\r
-               xNetworkDownEventPending = pdFALSE;\r
-       }\r
-\r
-       iptraceNETWORK_DOWN();\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t FreeRTOS_NetworkDownFromISR( void )\r
-{\r
-static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
-BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
-\r
-       /* Simply send the network task the appropriate event. */\r
-       if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )\r
-       {\r
-               xNetworkDownEventPending = pdTRUE;\r
-       }\r
-       else\r
-       {\r
-               xNetworkDownEventPending = pdFALSE;\r
-       }\r
-\r
-       iptraceNETWORK_DOWN();\r
-\r
-       return xHigherPriorityTaskWoken;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )\r
-{\r
-NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-void *pvReturn;\r
-\r
-       /* Cap the block time.  The reason for this is explained where\r
-       ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official\r
-       FreeRTOSIPConfig.h header file is being used). */\r
-       if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )\r
-       {\r
-               xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;\r
-       }\r
-\r
-       /* Obtain a network buffer with the required amount of storage. */\r
-       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );\r
-\r
-       if( pxNetworkBuffer != NULL )\r
-       {\r
-               /* Set the actual packet size in case a bigger buffer was returned. */\r
-               pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes;\r
-\r
-               /* Leave space for the UPD header. */\r
-               pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );\r
-       }\r
-       else\r
-       {\r
-               pvReturn = NULL;\r
-       }\r
-\r
-       return ( void * ) pvReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,\r
-       size_t uxNewLength )\r
-{\r
-NetworkBufferDescriptor_t * pxNewBuffer;\r
-\r
-       /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.\r
-       The transmit routine wants to have ownership of the network buffer\r
-       descriptor, because it will pass the buffer straight to DMA. */\r
-       pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );\r
-\r
-       if( pxNewBuffer != NULL )\r
-       {\r
-               /* Set the actual packet size in case a bigger buffer than requested\r
-               was returned. */\r
-               pxNewBuffer->xDataLength = uxNewLength;\r
-\r
-               /* Copy the original packet information. */\r
-               pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;\r
-               pxNewBuffer->usPort = pxNetworkBuffer->usPort;\r
-               pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;\r
-               memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );\r
-       }\r
-\r
-       return pxNewBuffer;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
-\r
-       NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer )\r
-       {\r
-       uint8_t *pucBuffer;\r
-       NetworkBufferDescriptor_t *pxResult;\r
-\r
-               if( pvBuffer == NULL )\r
-               {\r
-                       pxResult = NULL;\r
-               }\r
-               else\r
-               {\r
-                       /* Obtain the network buffer from the zero copy pointer. */\r
-                       pucBuffer = ( uint8_t * ) pvBuffer;\r
-\r
-                       /* The input here is a pointer to a payload buffer.  Subtract the\r
-                       size of the header in the network buffer, usually 8 + 2 bytes. */\r
-                       pucBuffer -= ipBUFFER_PADDING;\r
-\r
-                       /* Here a pointer was placed to the network descriptor.  As a\r
-                       pointer is dereferenced, make sure it is well aligned. */\r
-                       if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 )\r
-                       {\r
-                               pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );\r
-                       }\r
-                       else\r
-                       {\r
-                               pxResult = NULL;\r
-                       }\r
-               }\r
-\r
-               return pxResult;\r
-       }\r
-\r
-#endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer )\r
-{\r
-uint8_t *pucBuffer;\r
-NetworkBufferDescriptor_t *pxResult;\r
-\r
-       if( pvBuffer == NULL )\r
-       {\r
-               pxResult = NULL;\r
-       }\r
-       else\r
-       {\r
-               /* Obtain the network buffer from the zero copy pointer. */\r
-               pucBuffer = ( uint8_t * ) pvBuffer;\r
-\r
-               /* The input here is a pointer to a payload buffer.  Subtract\r
-               the total size of a UDP/IP header plus the size of the header in\r
-               the network buffer, usually 8 + 2 bytes. */\r
-               pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING );\r
-\r
-               /* Here a pointer was placed to the network descriptor,\r
-               As a pointer is dereferenced, make sure it is well aligned */\r
-               if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 )\r
-               {\r
-                       /* The following statement may trigger a:\r
-                       warning: cast increases required alignment of target type [-Wcast-align].\r
-                       It has been confirmed though that the alignment is suitable. */\r
-                       pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );\r
-               }\r
-               else\r
-               {\r
-                       pxResult = NULL;\r
-               }\r
-       }\r
-\r
-       return pxResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )\r
-{\r
-       vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */\r
-/*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.\r
- As that bug has been repaired, there is not an urgent reason to warn.\r
- It is better though to use the advised priority scheme. */\r
-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 ] )\r
-{\r
-BaseType_t xReturn = pdFALSE;\r
-\r
-       /* This function should only be called once. */\r
-       configASSERT( xIPIsNetworkTaskReady() == pdFALSE );\r
-       configASSERT( xNetworkEventQueue == NULL );\r
-       configASSERT( xIPTaskHandle == NULL );\r
-\r
-       /* Check structure packing is correct. */\r
-       configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );\r
-       configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );\r
-       configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );\r
-       configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );\r
-       configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );\r
-\r
-       /* Attempt to create the queue used to communicate with the IP task. */\r
-       xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) );\r
-       configASSERT( xNetworkEventQueue );\r
-\r
-       if( xNetworkEventQueue != NULL )\r
-       {\r
-               #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
-               {\r
-                       /* A queue registry is normally used to assist a kernel aware\r
-                       debugger.  If one is in use then it will be helpful for the debugger\r
-                       to show information about the network event queue. */\r
-                       vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );\r
-               }\r
-               #endif /* configQUEUE_REGISTRY_SIZE */\r
-\r
-               if( xNetworkBuffersInitialise() == pdPASS )\r
-               {\r
-                       /* Store the local IP and MAC address. */\r
-                       xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );\r
-                       xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );\r
-                       xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );\r
-                       xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );\r
-                       xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;\r
-\r
-                       memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );\r
-\r
-                       #if ipconfigUSE_DHCP == 1\r
-                       {\r
-                               /* The IP address is not set until DHCP completes. */\r
-                               *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;\r
-                       }\r
-                       #else\r
-                       {\r
-                               /* The IP address is set from the value passed in. */\r
-                               *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;\r
-\r
-                               /* Added to prevent ARP flood to gateway.  Ensure the\r
-                               gateway is on the same subnet as the IP address. */\r
-                               if( xNetworkAddressing.ulGatewayAddress != 0ul )\r
-                               {\r
-                                       configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );\r
-                               }\r
-                       }\r
-                       #endif /* ipconfigUSE_DHCP == 1 */\r
-\r
-                       /* The MAC address is stored in the start of the default packet\r
-                       header fragment, which is used when sending UDP packets. */\r
-                       memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
-\r
-                       /* Prepare the sockets interface. */\r
-                       xReturn = vNetworkSocketsInit();\r
-\r
-                       if( pdTRUE == xReturn )\r
-                       {\r
-                               /* Create the task that processes Ethernet and stack events. */\r
-                               xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") );\r
-\r
-                       /* Clean up. */\r
-                       vQueueDelete( xNetworkEventQueue );\r
-                       xNetworkEventQueue = NULL;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") );\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )\r
-{\r
-       /* Return the address configuration to the caller. */\r
-\r
-       if( pulIPAddress != NULL )\r
-       {\r
-               *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
-       }\r
-\r
-       if( pulNetMask != NULL )\r
-       {\r
-               *pulNetMask = xNetworkAddressing.ulNetMask;\r
-       }\r
-\r
-       if( pulGatewayAddress != NULL )\r
-       {\r
-               *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;\r
-       }\r
-\r
-       if( pulDNSServerAddress != NULL )\r
-       {\r
-               *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress )\r
-{\r
-       /* Update the address configuration. */\r
-\r
-       if( pulIPAddress != NULL )\r
-       {\r
-               *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;\r
-       }\r
-\r
-       if( pulNetMask != NULL )\r
-       {\r
-               xNetworkAddressing.ulNetMask = *pulNetMask;\r
-       }\r
-\r
-       if( pulGatewayAddress != NULL )\r
-       {\r
-               xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;\r
-       }\r
-\r
-       if( pulDNSServerAddress != NULL )\r
-       {\r
-               xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-\r
-       BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks )\r
-       {\r
-       NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-       ICMPHeader_t *pxICMPHeader;\r
-       BaseType_t xReturn = pdFAIL;\r
-       static uint16_t usSequenceNumber = 0;\r
-       uint8_t *pucChar;\r
-       IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };\r
-\r
-               if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) )\r
-               {\r
-                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks );\r
-\r
-                       if( pxNetworkBuffer != NULL )\r
-                       {\r
-                               pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );\r
-                               usSequenceNumber++;\r
-\r
-                               /* Fill in the basic header information. */\r
-                               pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;\r
-                               pxICMPHeader->ucTypeOfService = 0;\r
-                               pxICMPHeader->usIdentifier = usSequenceNumber;\r
-                               pxICMPHeader->usSequenceNumber = usSequenceNumber;\r
-\r
-                               /* Find the start of the data. */\r
-                               pucChar = ( uint8_t * ) pxICMPHeader;\r
-                               pucChar += sizeof( ICMPHeader_t );\r
-\r
-                               /* Just memset the data to a fixed value. */\r
-                               memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );\r
-\r
-                               /* The message is complete, IP and checksum's are handled by\r
-                               vProcessGeneratedUDPPacket */\r
-                               pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;\r
-                               pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
-                               pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;\r
-                               /* xDataLength is the size of the total packet, including the Ethernet header. */\r
-                               pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t );\r
-\r
-                               /* Send to the stack. */\r
-                               xStackTxEvent.pvData = pxNetworkBuffer;\r
-\r
-                               if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS )\r
-                               {\r
-                                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-                                       iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );\r
-                               }\r
-                               else\r
-                               {\r
-                                       xReturn = usSequenceNumber;\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* The requested number of bytes will not fit in the available space\r
-                       in the network buffer. */\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )\r
-{\r
-IPStackEvent_t xEventMessage;\r
-const TickType_t xDontBlock = ( TickType_t ) 0;\r
-\r
-       xEventMessage.eEventType = eEvent;\r
-       xEventMessage.pvData = ( void* )NULL;\r
-\r
-       return xSendEventStructToIPTask( &xEventMessage, xDontBlock );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout )\r
-{\r
-BaseType_t xReturn, xSendMessage;\r
-\r
-       if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )\r
-       {\r
-               /* Only allow eNetworkDownEvent events if the IP task is not ready\r
-               yet.  Not going to attempt to send the message so the send failed. */\r
-               xReturn = pdFAIL;\r
-       }\r
-       else\r
-       {\r
-               xSendMessage = pdTRUE;\r
-\r
-               #if( ipconfigUSE_TCP == 1 )\r
-               {\r
-                       if( pxEvent->eEventType == eTCPTimerEvent )\r
-                       {\r
-                               /* TCP timer events are sent to wake the timer task when\r
-                               xTCPTimer has expired, but there is no point sending them if the\r
-                               IP task is already awake processing other message. */\r
-                               xTCPTimer.bExpired = pdTRUE_UNSIGNED;\r
-\r
-                               if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u )\r
-                               {\r
-                                       /* Not actually going to send the message but this is not a\r
-                                       failure as the message didn't need to be sent. */\r
-                                       xSendMessage = pdFALSE;\r
-                               }\r
-                       }\r
-               }\r
-               #endif /* ipconfigUSE_TCP */\r
-\r
-               if( xSendMessage != pdFALSE )\r
-               {\r
-                       /* The IP task cannot block itself while waiting for itself to\r
-                       respond. */\r
-                       if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) )\r
-                       {\r
-                               xTimeout = ( TickType_t ) 0;\r
-                       }\r
-\r
-                       xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout );\r
-\r
-                       if( xReturn == pdFAIL )\r
-                       {\r
-                               /* A message should have been sent to the IP task, but wasn't. */\r
-                               FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );\r
-                               iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* It was not necessary to send the message to process the event so\r
-                       even though the message was not sent the call was successful. */\r
-                       xReturn = pdPASS;\r
-               }\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )\r
-{\r
-eFrameProcessingResult_t eReturn;\r
-const EthernetHeader_t *pxEthernetHeader;\r
-\r
-       pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer;\r
-\r
-       if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 )\r
-       {\r
-               /* The packet was directed to this node directly - process it. */\r
-               eReturn = eProcessBuffer;\r
-       }\r
-       else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
-       {\r
-               /* The packet was a broadcast - process it. */\r
-               eReturn = eProcessBuffer;\r
-       }\r
-       else\r
-#if( ipconfigUSE_LLMNR == 1 )\r
-       if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
-       {\r
-               /* The packet is a request for LLMNR - process it. */\r
-               eReturn = eProcessBuffer;\r
-       }\r
-       else\r
-#endif /* ipconfigUSE_LLMNR */\r
-       {\r
-               /* The packet was not a broadcast, or for this node, just release\r
-               the buffer without taking any other action. */\r
-               eReturn = eReleaseBuffer;\r
-       }\r
-\r
-       #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )\r
-       {\r
-       uint16_t usFrameType;\r
-\r
-               if( eReturn == eProcessBuffer )\r
-               {\r
-                       usFrameType = pxEthernetHeader->usFrameType;\r
-                       usFrameType = FreeRTOS_ntohs( usFrameType );\r
-\r
-                       if( usFrameType <= 0x600U )\r
-                       {\r
-                               /* Not an Ethernet II frame. */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-               }\r
-       }\r
-       #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1  */\r
-\r
-       return eReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvProcessNetworkDownEvent( void )\r
-{\r
-       /* Stop the ARP timer while there is no network. */\r
-       xARPTimer.bActive = pdFALSE_UNSIGNED;\r
-\r
-       #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
-       {\r
-               static BaseType_t xCallEventHook = pdFALSE;\r
-\r
-               /* The first network down event is generated by the IP stack itself to\r
-               initialise the network hardware, so do not call the network down event\r
-               the first time through. */\r
-               if( xCallEventHook == pdTRUE )\r
-               {\r
-                       vApplicationIPNetworkEventHook( eNetworkDown );\r
-               }\r
-               xCallEventHook = pdTRUE;\r
-       }\r
-       #endif\r
-\r
-       /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122, \r
-       treat network down as a "delivery problem" and flush the ARP cache for this\r
-       interface. */\r
-       FreeRTOS_ClearARP( );\r
-\r
-       /* The network has been disconnected (or is being initialised for the first\r
-       time).  Perform whatever hardware processing is necessary to bring it up\r
-       again, or wait for it to be available again.  This is hardware dependent. */\r
-       if( xNetworkInterfaceInitialise() != pdPASS )\r
-       {\r
-               /* Ideally the network interface initialisation function will only\r
-               return when the network is available.  In case this is not the case,\r
-               wait a while before retrying the initialisation. */\r
-               vTaskDelay( ipINITIALISATION_RETRY_DELAY );\r
-               FreeRTOS_NetworkDown();\r
-       }\r
-       else\r
-       {\r
-               /* Set remaining time to 0 so it will become active immediately. */\r
-               #if ipconfigUSE_DHCP == 1\r
-               {\r
-                       /* The network is not up until DHCP has completed. */\r
-                       vDHCPProcess( pdTRUE );\r
-                       xSendEventToIPTask( eDHCPEvent );\r
-               }\r
-               #else\r
-               {\r
-                       /* Perform any necessary 'network up' processing. */\r
-                       vIPNetworkUpCalls();\r
-               }\r
-               #endif\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vIPNetworkUpCalls( void )\r
-{\r
-       xNetworkUp = pdTRUE;\r
-\r
-       #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )\r
-       {\r
-               vApplicationIPNetworkEventHook( eNetworkUp );\r
-       }\r
-       #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */\r
-\r
-       #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       {\r
-               /* The following function is declared in FreeRTOS_DNS.c and 'private' to\r
-               this library */\r
-               extern void vDNSInitialise( void );\r
-               vDNSInitialise();\r
-       }\r
-       #endif /* ipconfigDNS_USE_CALLBACKS != 0 */\r
-\r
-       /* Set remaining time to 0 so it will become active immediately. */\r
-       prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
-{\r
-EthernetHeader_t *pxEthernetHeader;\r
-eFrameProcessingResult_t eReturned = eReleaseBuffer;\r
-\r
-       configASSERT( pxNetworkBuffer );\r
-\r
-       /* Interpret the Ethernet frame. */\r
-       if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )\r
-       {\r
-               eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
-               pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
-\r
-               if( eReturned == eProcessBuffer )\r
-               {\r
-                       /* Interpret the received Ethernet packet. */\r
-                       switch( pxEthernetHeader->usFrameType )\r
-                       {\r
-                       case ipARP_FRAME_TYPE:\r
-                               /* The Ethernet frame contains an ARP packet. */\r
-                               if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )\r
-                               {\r
-                                       eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer );\r
-                               }\r
-                               else\r
-                               {\r
-                                       eReturned = eReleaseBuffer;\r
-                               }\r
-                               break;\r
-\r
-                       case ipIPv4_FRAME_TYPE:\r
-                               /* The Ethernet frame contains an IP packet. */\r
-                               if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )\r
-                               {\r
-                                       eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );\r
-                               }\r
-                               else\r
-                               {\r
-                                       eReturned = eReleaseBuffer;\r
-                               }\r
-                               break;\r
-\r
-                       default:\r
-                               /* No other packet types are handled.  Nothing to do. */\r
-                               eReturned = eReleaseBuffer;\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       /* Perform any actions that resulted from processing the Ethernet frame. */\r
-       switch( eReturned )\r
-       {\r
-               case eReturnEthernetFrame :\r
-                       /* The Ethernet frame will have been updated (maybe it was\r
-                       an ARP request or a PING request?) and should be sent back to\r
-                       its source. */\r
-                       vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );\r
-                       /* parameter pdTRUE: the buffer must be released once\r
-                       the frame has been transmitted */\r
-                       break;\r
-\r
-               case eFrameConsumed :\r
-                       /* The frame is in use somewhere, don't release the buffer\r
-                       yet. */\r
-                       break;\r
-\r
-               default :\r
-                       /* The frame is not being used anywhere, and the\r
-                       NetworkBufferDescriptor_t structure containing the frame should\r
-                       just be released back to the list of free buffers. */\r
-                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-                       break;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,\r
-       NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength )\r
-{\r
-eFrameProcessingResult_t eReturn = eProcessBuffer;\r
-\r
-#if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )\r
-       const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
-#else\r
-       /* or else, the parameter won't be used and the function will be optimised\r
-       away */\r
-       ( void ) pxIPPacket;\r
-#endif\r
-\r
-       #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )\r
-       {\r
-               /* In systems with a very small amount of RAM, it might be advantageous\r
-               to have incoming messages checked earlier, by the network card driver.\r
-               This method may decrease the usage of sparse network buffers. */\r
-               uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;\r
-\r
-                       /* Ensure that the incoming packet is not fragmented (only outgoing\r
-                       packets can be fragmented) as these are the only handled IP frames\r
-                       currently. */\r
-                       if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )\r
-                       {\r
-                               /* Can not handle, fragmented packet. */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-                       /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes\r
-                        * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */\r
-                       else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) )\r
-                       {\r
-                               /* Can not handle, unknown or invalid header version. */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-                               /* Is the packet for this IP address? */\r
-                       else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&\r
-                               /* Is it the global broadcast address 255.255.255.255 ? */\r
-                               ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&\r
-                               /* Is it a specific broadcast address 192.168.1.255 ? */\r
-                               ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&\r
-                       #if( ipconfigUSE_LLMNR == 1 )\r
-                               /* Is it the LLMNR multicast address? */\r
-                               ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&\r
-                       #endif\r
-                               /* Or (during DHCP negotiation) we have no IP-address yet? */\r
-                               ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )\r
-                       {\r
-                               /* Packet is not for this node, release it */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-       }\r
-       #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */\r
-\r
-       #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )\r
-       {\r
-               /* Some drivers of NIC's with checksum-offloading will enable the above\r
-               define, so that the checksum won't be checked again here */\r
-               if (eReturn == eProcessBuffer )\r
-               {\r
-                       /* Is the IP header checksum correct? */\r
-                       if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&\r
-                               ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) )\r
-                       {\r
-                               /* Check sum in IP-header not correct. */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-                       /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */\r
-                       else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )\r
-                       {\r
-                               /* Protocol checksum not accepted. */\r
-                               eReturn = eReleaseBuffer;\r
-                       }\r
-               }\r
-       }\r
-       #else\r
-       {\r
-               /* to avoid warning unused parameters */\r
-               ( void ) pxNetworkBuffer;\r
-               ( void ) uxHeaderLength;\r
-       }\r
-       #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */\r
-\r
-       return eReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
-{\r
-eFrameProcessingResult_t eReturn;\r
-IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
-UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );\r
-uint8_t ucProtocol;\r
-\r
-       /* Bound the calculated header length: take away the Ethernet header size,\r
-       then check if the IP header is claiming to be longer than the remaining\r
-       total packet size. Also check for minimal header field length. */\r
-       if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||\r
-               ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )\r
-       {\r
-               return eReleaseBuffer;\r
-       }\r
-\r
-       ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
-       /* Check if the IP headers are acceptable and if it has our destination. */\r
-       eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );\r
-\r
-       if( eReturn == eProcessBuffer )\r
-       {\r
-               if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )\r
-               {\r
-                       /* All structs of headers expect a IP header size of 20 bytes\r
-                        * IP header options were included, we'll ignore them and cut them out\r
-                        * Note: IP options are mostly use in Multi-cast protocols */\r
-                       const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;\r
-                       /* From: the previous start of UDP/ICMP/TCP data */\r
-                       uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength);\r
-                       /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */\r
-                       uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER);\r
-                       /* How many: total length minus the options and the lower headers */\r
-                       const size_t  xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER;\r
-\r
-                       memmove( pucTarget, pucSource, xMoveLen );\r
-                       pxNetworkBuffer->xDataLength -= optlen;\r
-\r
-                       /* Fix-up new version/header length field in IP packet. */\r
-                       pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */\r
-                                                                                               ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */\r
-               }\r
-\r
-               /* Add the IP and MAC addresses to the ARP table if they are not\r
-               already there - otherwise refresh the age of the existing\r
-               entry. */\r
-               if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )\r
-               {\r
-                       /* Refresh the ARP cache with the IP/MAC-address of the received packet\r
-                        * For UDP packets, this will be done later in xProcessReceivedUDPPacket()\r
-                        * as soon as know that the message will be handled by someone\r
-                        * This will prevent that the ARP cache will get overwritten\r
-                        * with the IP-address of useless broadcast packets\r
-                        */\r
-                       vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );\r
-               }\r
-               switch( ucProtocol )\r
-               {\r
-                       case ipPROTOCOL_ICMP :\r
-                               /* The IP packet contained an ICMP frame.  Don't bother\r
-                               checking the ICMP checksum, as if it is wrong then the\r
-                               wrong data will also be returned, and the source of the\r
-                               ping will know something went wrong because it will not\r
-                               be able to validate what it receives. */\r
-                               #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-                               {\r
-                                       if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )\r
-                                       {\r
-                                               ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
-                                               if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
-                                               {\r
-                                                       eReturn = prvProcessICMPPacket( pxICMPPacket );\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               eReturn = eReleaseBuffer;\r
-                                       }\r
-                               }\r
-                               #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
-                               break;\r
-\r
-                       case ipPROTOCOL_UDP :\r
-                               {\r
-                                       /* The IP packet contained a UDP frame. */\r
-                                       UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-\r
-                                       /* Only proceed if the payload length indicated in the header\r
-                                       appears to be valid. */\r
-                                       if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) )\r
-                                       {\r
-                                       size_t uxPayloadSize_1, uxPayloadSize_2;\r
-                                               /* The UDP payload size can be calculated by subtracting the\r
-                                                * header size from `xDataLength`.\r
-                                                * However, the `xDataLength` may be longer that expected,\r
-                                                * e.g. when a small packet is padded with zero's.\r
-                                                * The UDP header contains a field `usLength` reflecting\r
-                                                * the payload size plus the UDP header ( 8 bytes ).\r
-                                                * Set `xDataLength` to the size of the headers,\r
-                                                * plus the lower of the two calculated payload sizes.\r
-                                                */\r
-\r
-                                               uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );\r
-                                               uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );\r
-                                               if( uxPayloadSize_1 > uxPayloadSize_2 )\r
-                                               {\r
-                                                       pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );\r
-                                               }\r
-\r
-                                               /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */\r
-                                               pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;\r
-                                               pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
-\r
-                                               /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:\r
-                                                * In some cases, the upper-layer checksum has been calculated\r
-                                                * by the NIC driver.\r
-                                                *\r
-                                                * Pass the packet payload to the UDP sockets implementation. */\r
-                                               if( xProcessReceivedUDPPacket( pxNetworkBuffer,\r
-                                                                                                          pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )\r
-                                               {\r
-                                                       eReturn = eFrameConsumed;\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               eReturn = eReleaseBuffer;\r
-                                       }\r
-                               }\r
-                               break;\r
-\r
-#if ipconfigUSE_TCP == 1\r
-                       case ipPROTOCOL_TCP :\r
-                               {\r
-\r
-                                       if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )\r
-                                       {\r
-                                               eReturn = eFrameConsumed;\r
-                                       }\r
-\r
-                                       /* Setting this variable will cause xTCPTimerCheck()\r
-                                       to be called just before the IP-task blocks. */\r
-                                       xProcessedTCPMessage++;\r
-                               }\r
-                               break;\r
-#endif\r
-                       default :\r
-                               /* Not a supported frame type. */\r
-                               break;\r
-               }\r
-       }\r
-\r
-       return eReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-\r
-       static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )\r
-       {\r
-       ePingReplyStatus_t eStatus = eSuccess;\r
-       uint16_t usDataLength, usCount;\r
-       uint8_t *pucByte;\r
-\r
-               /* Find the total length of the IP packet. */\r
-               usDataLength = pxICMPPacket->xIPHeader.usLength;\r
-               usDataLength = FreeRTOS_ntohs( usDataLength );\r
-\r
-               /* Remove the length of the IP headers to obtain the length of the ICMP\r
-               message itself. */\r
-               usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );\r
-\r
-               /* Remove the length of the ICMP header, to obtain the length of\r
-               data contained in the ping. */\r
-               usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );\r
-\r
-               /* Checksum has already been checked before in prvProcessIPPacket */\r
-\r
-               /* Find the first byte of the data within the ICMP packet. */\r
-               pucByte = ( uint8_t * ) pxICMPPacket;\r
-               pucByte += sizeof( ICMPPacket_t );\r
-\r
-               /* Check each byte. */\r
-               for( usCount = 0; usCount < usDataLength; usCount++ )\r
-               {\r
-                       if( *pucByte != ipECHO_DATA_FILL_BYTE )\r
-                       {\r
-                               eStatus = eInvalidData;\r
-                               break;\r
-                       }\r
-\r
-                       pucByte++;\r
-               }\r
-\r
-               /* Call back into the application to pass it the result. */\r
-               vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );\r
-       }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
-\r
-       static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )\r
-       {\r
-       ICMPHeader_t *pxICMPHeader;\r
-       IPHeader_t *pxIPHeader;\r
-       uint16_t usRequest;\r
-\r
-               pxICMPHeader = &( pxICMPPacket->xICMPHeader );\r
-               pxIPHeader = &( pxICMPPacket->xIPHeader );\r
-\r
-               /* HT:endian: changed back */\r
-               iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );\r
-\r
-               /* The checksum can be checked here - but a ping reply should be\r
-               returned even if the checksum is incorrect so the other end can\r
-               tell that the ping was received - even if the ping reply contains\r
-               invalid data. */\r
-               pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;\r
-               pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
-               pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
-\r
-               /* Update the checksum because the ucTypeOfMessage member in the header\r
-               has been changed to ipICMP_ECHO_REPLY.  This is faster than calling\r
-               usGenerateChecksum(). */\r
-\r
-               /* due to compiler warning "integer operation result is out of range" */\r
-\r
-               usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 );\r
-\r
-               if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) )\r
-               {\r
-                       pxICMPHeader->usChecksum = ( uint16_t )\r
-                               ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +\r
-                                       FreeRTOS_htons( usRequest + 1UL ) );\r
-               }\r
-               else\r
-               {\r
-                       pxICMPHeader->usChecksum = ( uint16_t )\r
-                               ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +\r
-                                       FreeRTOS_htons( usRequest ) );\r
-               }\r
-               return eReturnEthernetFrame;\r
-       }\r
-\r
-#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-\r
-       static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )\r
-       {\r
-       eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
-\r
-               iptraceICMP_PACKET_RECEIVED();\r
-               switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )\r
-               {\r
-                       case ipICMP_ECHO_REQUEST        :\r
-                               #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
-                               {\r
-                                       eReturn = prvProcessICMPEchoRequest( pxICMPPacket );\r
-                               }\r
-                               #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */\r
-                               break;\r
-\r
-                       case ipICMP_ECHO_REPLY          :\r
-                               #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
-                               {\r
-                                       prvProcessICMPEchoReply( pxICMPPacket );\r
-                               }\r
-                               #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
-                               break;\r
-\r
-                       default :\r
-                               break;\r
-               }\r
-\r
-               return eReturn;\r
-       }\r
-\r
-#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
-/*-----------------------------------------------------------*/\r
-\r
-uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket )\r
-{\r
-uint32_t ulLength;\r
-uint16_t usChecksum, *pusChecksum;\r
-const IPPacket_t * pxIPPacket;\r
-UBaseType_t uxIPHeaderLength;\r
-ProtocolPacket_t *pxProtPack;\r
-uint8_t ucProtocol;\r
-#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-       const char *pcType;\r
-#endif\r
-\r
-       /* Check for minimum packet size. */\r
-       if( uxBufferLength < sizeof( IPPacket_t ) )\r
-       {\r
-               return ipINVALID_LENGTH;\r
-       }\r
-\r
-       /* Parse the packet length. */\r
-       pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;\r
-\r
-       /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header\r
-       Length field contains the length of the internet header in 32-bit words. */\r
-       uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) );\r
-\r
-       /* Check for minimum packet size. */\r
-       if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER )\r
-       {\r
-               return ipINVALID_LENGTH;\r
-       }\r
-       if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) )\r
-       {\r
-               return ipINVALID_LENGTH;\r
-       }\r
-\r
-       /* Identify the next protocol. */\r
-       ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
-\r
-       /* N.B., if this IP packet header includes Options, then the following\r
-       assignment results in a pointer into the protocol packet with the Ethernet\r
-       and IP headers incorrectly aligned. However, either way, the "third"\r
-       protocol (Layer 3 or 4) header will be aligned, which is the convenience\r
-       of this calculation. */\r
-       pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );\r
-\r
-       /* Switch on the Layer 3/4 protocol. */\r
-       if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )\r
-       {\r
-               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )\r
-               {\r
-                       return ipINVALID_LENGTH;\r
-               }\r
-\r
-               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );\r
-               #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-               {\r
-                       pcType = "UDP";\r
-               }\r
-               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-       }\r
-       else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )\r
-       {\r
-               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )\r
-               {\r
-                       return ipINVALID_LENGTH;\r
-               }\r
-\r
-               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );\r
-               #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-               {\r
-                       pcType = "TCP";\r
-               }\r
-               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-       }\r
-       else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||\r
-                       ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )\r
-       {\r
-               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )\r
-               {\r
-                       return ipINVALID_LENGTH;\r
-               }\r
-\r
-               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );\r
-               #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-               {\r
-                       if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )\r
-                       {\r
-                               pcType = "ICMP";\r
-                       }\r
-                       else\r
-                       {\r
-                               pcType = "IGMP";\r
-                       }\r
-               }\r
-               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-       }\r
-       else\r
-       {\r
-               /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */\r
-               return ipUNHANDLED_PROTOCOL;\r
-       }\r
-\r
-       /* The protocol and checksum field have been identified. Check the direction\r
-       of the packet. */\r
-       if( xOutgoingPacket != pdFALSE )\r
-       {\r
-               /* This is an outgoing packet. Before calculating the checksum, set it\r
-               to zero. */\r
-               *( pusChecksum ) = 0u;\r
-       }\r
-       else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )\r
-       {\r
-               /* Sender hasn't set the checksum, no use to calculate it. */\r
-               return ipCORRECT_CRC;\r
-       }\r
-\r
-       ulLength = ( uint32_t )\r
-               ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */\r
-\r
-       if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ||\r
-               ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) )\r
-       {\r
-               #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );\r
-               }\r
-               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-\r
-               /* Again, in a 16-bit return value there is no space to indicate an\r
-               error.  For incoming packets, 0x1234 will cause dropping of the packet.\r
-               For outgoing packets, there is a serious problem with the\r
-               format/length */\r
-               return ipINVALID_LENGTH;\r
-       }\r
-       if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )\r
-       {\r
-               /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */\r
-               usChecksum = ( uint16_t )\r
-                       ( ~usGenerateChecksum( 0UL,\r
-                               ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );\r
-       }\r
-       else\r
-       {\r
-               /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length\r
-               fields */\r
-               usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );\r
-\r
-               /* And then continue at the IPv4 source and destination addresses. */\r
-               usChecksum = ( uint16_t )\r
-                       ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),\r
-                               ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );\r
-\r
-               /* Sum TCP header and data. */\r
-       }\r
-\r
-       if( xOutgoingPacket == pdFALSE )\r
-       {\r
-               /* This is in incoming packet. If the CRC is correct, it should be zero. */\r
-               if( usChecksum == 0u )\r
-               {\r
-                       usChecksum = ( uint16_t )ipCORRECT_CRC;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )\r
-               {\r
-                       /* In case of UDP, a calculated checksum of 0x0000 is transmitted\r
-                       as 0xffff. A value of zero would mean that the checksum is not used. */\r
-                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-                       {\r
-                               if( xOutgoingPacket != pdFALSE )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );\r
-                               }\r
-                       }\r
-                       #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-\r
-                       usChecksum = ( uint16_t )0xffffu;\r
-               }\r
-       }\r
-       usChecksum = FreeRTOS_htons( usChecksum );\r
-\r
-       if( xOutgoingPacket != pdFALSE )\r
-       {\r
-               *( pusChecksum ) = usChecksum;\r
-       }\r
-       #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-       else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )\r
-       {\r
-               FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",\r
-                       pcType,\r
-                       FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),\r
-                       FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),\r
-                       FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),\r
-                       FreeRTOS_ntohs( *pusChecksum ) ) );\r
-       }\r
-       #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-\r
-       return usChecksum;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/**\r
- * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).\r
- * The checksum algorithm is decribed as:\r
- *   "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the\r
- *   header.  For purposes of computing the checksum, the value of the checksum field is zero."\r
- *\r
- * In a nutshell, that means that each 16-bit 'word' must be summed, after which\r
- * the number of 'carries' (overflows) is added to the result. If that addition\r
- * produces an overflow, that 'carry' must also be added to the final result. The final checksum\r
- * should be the bitwise 'not' (ones-complement) of the result if the packet is\r
- * meant to be transmitted, but this method simply returns the raw value, probably\r
- * because when a packet is received, the checksum is verified by checking that\r
- * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.\r
- *\r
- * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.\r
- * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit\r
- * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,\r
- * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.\r
- * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.\r
- * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found\r
- * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue\r
- * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:\r
- *   union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];\r
- *\r
- * Arguments:\r
- *   ulSum: This argument provides a value to initialize the progressive summation\r
- *      of the header's values to. It is often 0, but protocols like TCP or UDP\r
- *      can have pseudo-header fields which need to be included in the checksum.\r
- *   pucNextData: This argument contains the address of the first byte which this\r
- *      method should process. The method's memory iterator is initialized to this value.\r
- *   uxDataLengthBytes: This argument contains the number of bytes that this method\r
- *      should process.\r
- */\r
-uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )\r
-{\r
-xUnion32 xSum2, xSum, xTerm;\r
-xUnionPtr xSource;             /* Points to first byte */\r
-xUnionPtr xLastSource; /* Points to last byte plus one */\r
-uint32_t ulAlignBits, ulCarry = 0ul;\r
-\r
-       /* Small MCUs often spend up to 30% of the time doing checksum calculations\r
-       This function is optimised for 32-bit CPUs; Each time it will try to fetch\r
-       32-bits, sums it with an accumulator and counts the number of carries. */\r
-\r
-       /* Swap the input (little endian platform only). */\r
-       xSum.u32 = FreeRTOS_ntohs( ulSum );\r
-       xTerm.u32 = 0ul;\r
-\r
-       xSource.u8ptr = ( uint8_t * ) pucNextData;\r
-       ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */\r
-\r
-       /* If byte (8-bit) aligned... */\r
-       if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )\r
-       {\r
-               xTerm.u8[ 1 ] = *( xSource.u8ptr );\r
-               ( xSource.u8ptr )++;\r
-               uxDataLengthBytes--;\r
-               /* Now xSource is word (16-bit) aligned. */\r
-       }\r
-\r
-       /* If half-word (16-bit) aligned... */\r
-       if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) )\r
-       {\r
-               xSum.u32 += *(xSource.u16ptr);\r
-               ( xSource.u16ptr )++;\r
-               uxDataLengthBytes -= 2u;\r
-               /* Now xSource is word (32-bit) aligned. */\r
-       }\r
-\r
-       /* Word (32-bit) aligned, do the most part. */\r
-       xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u;\r
-\r
-       /* In this loop, four 32-bit additions will be done, in total 16 bytes.\r
-       Indexing with constants (0,1,2,3) gives faster code than using\r
-       post-increments. */\r
-       while( xSource.u32ptr < xLastSource.u32ptr )\r
-       {\r
-               /* Use a secondary Sum2, just to see if the addition produced an\r
-               overflow. */\r
-               xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];\r
-               if( xSum2.u32 < xSum.u32 )\r
-               {\r
-                       ulCarry++;\r
-               }\r
-\r
-               /* Now add the secondary sum to the major sum, and remember if there was\r
-               a carry. */\r
-               xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];\r
-               if( xSum2.u32 > xSum.u32 )\r
-               {\r
-                       ulCarry++;\r
-               }\r
-\r
-               /* And do the same trick once again for indexes 2 and 3 */\r
-               xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];\r
-               if( xSum2.u32 < xSum.u32 )\r
-               {\r
-                       ulCarry++;\r
-               }\r
-\r
-               xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];\r
-\r
-               if( xSum2.u32 > xSum.u32 )\r
-               {\r
-                       ulCarry++;\r
-               }\r
-\r
-               /* And finally advance the pointer 4 * 4 = 16 bytes. */\r
-               xSource.u32ptr += 4;\r
-       }\r
-\r
-       /* Now add all carries. */\r
-       xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;\r
-\r
-       uxDataLengthBytes %= 16u;\r
-       xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );\r
-\r
-       /* Half-word aligned. */\r
-       while( xSource.u16ptr < xLastSource.u16ptr )\r
-       {\r
-               /* At least one more short. */\r
-               xSum.u32 += xSource.u16ptr[ 0 ];\r
-               xSource.u16ptr++;\r
-       }\r
-\r
-       if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u )        /* Maybe one more ? */\r
-       {\r
-               xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];\r
-       }\r
-       xSum.u32 += xTerm.u32;\r
-\r
-       /* Now add all carries again. */\r
-       xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];\r
-\r
-       /* The previous summation might have given a 16-bit carry. */\r
-       xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];\r
-\r
-       if( ( ulAlignBits & 1u ) != 0u )\r
-       {\r
-               /* Quite unlikely, but pucNextData might be non-aligned, which would\r
-                mean that a checksum is calculated starting at an odd position. */\r
-               xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 );\r
-       }\r
-\r
-       /* swap the output (little endian platform only). */\r
-       return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend )\r
-{\r
-EthernetHeader_t *pxEthernetHeader;\r
-\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-       NetworkBufferDescriptor_t *pxNewBuffer;\r
-#endif\r
-\r
-       #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
-       {\r
-               if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
-               {\r
-               BaseType_t xIndex;\r
-\r
-                       FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) );\r
-                       for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
-                       {\r
-                               pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
-                       }\r
-                       pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
-               }\r
-       }\r
-       #endif\r
-\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-\r
-       if( xReleaseAfterSend == pdFALSE )\r
-       {\r
-               pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );\r
-               xReleaseAfterSend = pdTRUE;\r
-               pxNetworkBuffer = pxNewBuffer;\r
-       }\r
-\r
-       if( pxNetworkBuffer != NULL )\r
-#endif\r
-       {\r
-               pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-\r
-               /* Swap source and destination MAC addresses. */\r
-               memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );\r
-               memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
-\r
-               /* Send! */\r
-               xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-uint32_t FreeRTOS_GetIPAddress( void )\r
-{\r
-       /* Returns the IP address of the NIC. */\r
-       return *ipLOCAL_IP_ADDRESS_POINTER;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )\r
-{\r
-       /* Sets the IP address of the NIC. */\r
-       *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-uint32_t FreeRTOS_GetGatewayAddress( void )\r
-{\r
-       return xNetworkAddressing.ulGatewayAddress;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-uint32_t FreeRTOS_GetDNSServerAddress( void )\r
-{\r
-       return xNetworkAddressing.ulDNSServerAddress;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-uint32_t FreeRTOS_GetNetmask( void )\r
-{\r
-       return xNetworkAddressing.ulNetMask;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )\r
-{\r
-       /* Copy the MAC address at the start of the default packet header fragment. */\r
-       memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-const uint8_t * FreeRTOS_GetMACAddress( void )\r
-{\r
-       return ipLOCAL_MAC_ADDRESS;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_SetNetmask ( uint32_t ulNetmask )\r
-{\r
-       xNetworkAddressing.ulNetMask = ulNetmask;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress )\r
-{\r
-       xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_DHCP == 1 )\r
-       void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )\r
-       {\r
-               if( xEnableState != pdFALSE )\r
-               {\r
-                       xDHCPTimer.bActive = pdTRUE_UNSIGNED;\r
-               }\r
-               else\r
-               {\r
-                       xDHCPTimer.bActive = pdFALSE_UNSIGNED;\r
-               }\r
-       }\r
-#endif /* ipconfigUSE_DHCP */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_DHCP == 1 )\r
-       void vIPReloadDHCPTimer( uint32_t ulLeaseTime )\r
-       {\r
-               prvIPTimerReload( &xDHCPTimer, ulLeaseTime );\r
-       }\r
-#endif /* ipconfigUSE_DHCP */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigDNS_USE_CALLBACKS == 1 )\r
-       void vIPSetDnsTimerEnableState( BaseType_t xEnableState )\r
-       {\r
-               if( xEnableState != 0 )\r
-               {\r
-                       xDNSTimer.bActive = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       xDNSTimer.bActive = pdFALSE;\r
-               }\r
-       }\r
-#endif /* ipconfigUSE_DHCP */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       void vIPReloadDNSTimer( uint32_t ulCheckTime )\r
-       {\r
-               prvIPTimerReload( &xDNSTimer, ulCheckTime );\r
-       }\r
-#endif /* ipconfigDNS_USE_CALLBACKS != 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xIPIsNetworkTaskReady( void )\r
-{\r
-       return xIPTaskInitialised;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t FreeRTOS_IsNetworkUp( void )\r
-{\r
-       return xNetworkUp;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-       UBaseType_t uxGetMinimumIPQueueSpace( void )\r
-       {\r
-               return uxQueueMinimumSpace;\r
-       }\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Provide access to private members for verification. */\r
-#ifdef FREERTOS_TCP_ENABLE_VERIFICATION\r
-       #include "aws_freertos_ip_verification_access_ip_define.h"\r
-#endif\r
-\r
+/*
+ * FreeRTOS+TCP V2.2.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * 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
+ */
+
+/* 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_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+#include "FreeRTOS_DNS.h"
+
+
+/* Used to ensure the structure packing is having the desired effect.  The
+'volatile' is used to prevent compiler warnings about comparing a constant with
+a constant. */
+#define ipEXPECTED_EthernetHeader_t_SIZE       ( ( size_t ) 14 )
+#define ipEXPECTED_ARPHeader_t_SIZE                    ( ( size_t ) 28 )
+#define ipEXPECTED_IPHeader_t_SIZE                     ( ( size_t ) 20 )
+#define ipEXPECTED_IGMPHeader__SIZE                    ( ( size_t ) 8 )
+#define ipEXPECTED_ICMPHeader_t_SIZE           ( ( size_t ) 8 )
+#define ipEXPECTED_UDPHeader_t_SIZE                    ( ( size_t ) 8 )
+#define ipEXPECTED_TCPHeader_t_SIZE                    ( ( size_t ) 20 )
+
+
+/* ICMP protocol definitions. */
+#define ipICMP_ECHO_REQUEST                            ( ( uint8_t ) 8 )
+#define ipICMP_ECHO_REPLY                              ( ( uint8_t ) 0 )
+
+
+/* Time delay between repeated attempts to initialise the network hardware. */
+#ifndef ipINITIALISATION_RETRY_DELAY
+       #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000 ) )
+#endif
+
+/* Defines how often the ARP timer callback function is executed.  The time is
+shorted in the Windows simulator as simulated time is not real time. */
+#ifndef        ipARP_TIMER_PERIOD_MS
+       #ifdef _WINDOWS_
+               #define ipARP_TIMER_PERIOD_MS   ( 500 ) /* For windows simulator builds. */
+       #else
+               #define ipARP_TIMER_PERIOD_MS   ( 10000 )
+       #endif
+#endif
+
+#ifndef iptraceIP_TASK_STARTING
+       #define iptraceIP_TASK_STARTING()       do {} while( 0 )
+#endif
+
+#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
+       /* When initialising the TCP timer,
+       give it an initial time-out of 1 second. */
+       #define ipTCP_TIMER_PERIOD_MS   ( 1000 )
+#endif
+
+/* 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
+
+/* The character used to fill ICMP echo requests, and therefore also the
+character expected to fill ICMP echo replies. */
+#define ipECHO_DATA_FILL_BYTE                                          'x'
+
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+       /* The bits in the two byte IP header field that make up the fragment offset value. */
+       #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0xff0f )
+#else
+       /* The bits in the two byte IP header field that make up the fragment offset value. */
+       #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0x0fff )
+#endif /* ipconfigBYTE_ORDER */
+
+/* The maximum time the IP task is allowed to remain in the Blocked state if no
+events are posted to the network event queue. */
+#ifndef        ipconfigMAX_IP_TASK_SLEEP_TIME
+       #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )
+#endif
+
+/* When a new TCP connection is established, the value of
+'ulNextInitialSequenceNumber' will be used as the initial sequence number.  It
+is very important that at start-up, 'ulNextInitialSequenceNumber' contains a
+random value.  Also its value must be increased continuously in time, to prevent
+a third party guessing the next sequence number and take-over a TCP connection.
+It is advised to increment it by 1 ever 4us, which makes about 256 times
+per ms: */
+#define ipINITIAL_SEQUENCE_NUMBER_FACTOR       256UL
+
+/* Returned as the (invalid) checksum when the protocol being checked is not
+handled.  The value is chosen simply to be easy to spot when debugging. */
+#define ipUNHANDLED_PROTOCOL           0x4321u
+
+/* Returned to indicate a valid checksum when the checksum does not need to be
+calculated. */
+#define ipCORRECT_CRC                          0xffffu
+
+/* Returned as the (invalid) checksum when the length of the data being checked
+had an invalid length. */
+#define ipINVALID_LENGTH                       0x1234u
+
+/*-----------------------------------------------------------*/
+
+typedef struct xIP_TIMER
+{
+       uint32_t
+               bActive : 1,    /* This timer is running and must be processed. */
+               bExpired : 1;   /* Timer has expired and a task must be processed. */
+       TimeOut_t xTimeOut;
+       TickType_t ulRemainingTime;
+       TickType_t ulReloadTime;
+} IPTimer_t;
+
+/* Used in checksum calculation. */
+typedef union _xUnion32
+{
+       uint32_t u32;
+       uint16_t u16[ 2 ];
+       uint8_t u8[ 4 ];
+} xUnion32;
+
+/* Used in checksum calculation. */
+typedef union _xUnionPtr
+{
+       uint32_t *u32ptr;
+       uint16_t *u16ptr;
+       uint8_t *u8ptr;
+} xUnionPtr;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * 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 );
+
+/*
+ * Process incoming IP packets.
+ */
+static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );
+
+#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+       /*
+        * Process incoming ICMP packets.
+        */
+       static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );
+#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
+
+/*
+ * Turns around an incoming ping request to convert it into a ping reply.
+ */
+#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
+       static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );
+#endif /* ipconfigREPLY_TO_INCOMING_PINGS */
+
+/*
+ * Processes incoming ping replies.  The application callback function
+ * vApplicationPingReplyHook() is called with the results.
+ */
+#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+       static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );
+#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
+
+/*
+ * Called to create a network connection when the stack is first started, or
+ * when the network connection is lost.
+ */
+static void prvProcessNetworkDownEvent( void );
+
+/*
+ * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout
+ * processing is required.
+ */
+static void prvCheckNetworkTimers( void );
+
+/*
+ * Determine how long the IP task can sleep for, which depends on when the next
+ * periodic or timeout processing must be performed.
+ */
+static TickType_t prvCalculateSleepTime( void );
+
+/*
+ * 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 );
+
+/*
+ * Utility functions for the light weight IP timers.
+ */
+static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime );
+static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer );
+static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime );
+
+static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
+       NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength );
+
+/*-----------------------------------------------------------*/
+
+/* The queue used to pass events into the IP-task for processing. */
+QueueHandle_t xNetworkEventQueue = NULL;
+
+/*_RB_ Requires comment. */
+uint16_t usPacketIdentifier = 0U;
+
+/* For convenience, a MAC address of all 0xffs is defined const for quick
+reference. */
+const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+
+/* Structure that stores the netmask, gateway address and DNS server addresses. */
+NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };
+
+/* Default values for the above struct in case DHCP
+does not lead to a confirmed request. */
+NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
+
+/* 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 BaseType_t xNetworkDownEventPending = pdFALSE;
+
+/* 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;
+
+#if( ipconfigUSE_TCP != 0 )
+       /* Set to a non-zero value if one or more TCP message have been processed
+       within the last round. */
+       static BaseType_t xProcessedTCPMessage;
+#endif
+
+/* Simple set to pdTRUE or pdFALSE depending on whether the network is up or
+down (connected, not connected) respectively. */
+static BaseType_t xNetworkUp = pdFALSE;
+
+/*
+A timer for each of the following processes, all of which need attention on a
+regular basis:
+       1. ARP, to check its table entries
+       2. DPHC, to send requests and to renew a reservation
+       3. TCP, to check for timeouts, resends
+       4. DNS, to check for timeouts when looking-up a domain.
+ */
+static IPTimer_t xARPTimer;
+#if( ipconfigUSE_DHCP != 0 )
+       static IPTimer_t xDHCPTimer;
+#endif
+#if( ipconfigUSE_TCP != 0 )
+       static IPTimer_t xTCPTimer;
+#endif
+#if( ipconfigDNS_USE_CALLBACKS != 0 )
+       static IPTimer_t xDNSTimer;
+#endif
+
+/* Set to pdTRUE when the IP task is ready to start processing packets. */
+static BaseType_t xIPTaskInitialised = pdFALSE;
+
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+       /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
+       static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
+#endif
+
+/*-----------------------------------------------------------*/
+
+static void prvIPTask( void *pvParameters )
+{
+IPStackEvent_t xReceivedEvent;
+TickType_t xNextIPSleep;
+FreeRTOS_Socket_t *pxSocket;
+struct freertos_sockaddr xAddress;
+
+       /* Just to prevent compiler warnings about unused parameters. */
+       ( void ) pvParameters;
+
+       /* 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. */
+       FreeRTOS_NetworkDown();
+
+       #if( ipconfigUSE_TCP == 1 )
+       {
+               /* Initialise the TCP timer. */
+               prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
+       }
+       #endif
+
+       /* Initialisation is complete and events can now be processed. */
+       xIPTaskInitialised = pdTRUE;
+
+       FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
+
+       /* Loop, processing IP events. */
+       for( ;; )
+       {
+               ipconfigWATCHDOG_TIMER();
+
+               /* Check the ARP, DHCP and TCP timers to see if there is any periodic
+               or timeout processing to perform. */
+               prvCheckNetworkTimers();
+
+               /* Calculate the acceptable maximum sleep time. */
+               xNextIPSleep = prvCalculateSleepTime();
+
+               /* 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. */
+                               xNetworkUp = pdFALSE;
+                               prvProcessNetworkDownEvent();
+                               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. */
+                               xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE );
+                               break;
+
+                       case eARPTimerEvent :
+                               /* The ARP timer has expired, process the ARP cache. */
+                               vARPAgeCache();
+                               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_addr = 0u; /* For the moment. */
+                               xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
+                               pxSocket->usLocalPort = 0u;
+                               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 |= 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 */
+                               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:
+                               /* The DHCP state machine needs processing. */
+                               #if( ipconfigUSE_DHCP == 1 )
+                               {
+                                       vDHCPProcess( pdFALSE );
+                               }
+                               #endif /* ipconfigUSE_DHCP */
+                               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 )
+                               {
+                                       vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) );
+                               }
+                               #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(). */
+                                       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. */
+                                       xTCPTimer.bExpired = pdTRUE_UNSIGNED;
+                               }
+                               #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 |= 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;
+
+                       default :
+                               /* Should not get here. */
+                               break;
+               }
+
+               if( xNetworkDownEventPending != pdFALSE )
+               {
+                       /* A network down event could not be posted to the network event
+                       queue because the queue was full.  Try posting again. */
+                       FreeRTOS_NetworkDown();
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xIsCallingFromIPTask( void )
+{
+BaseType_t xReturn;
+
+       if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )
+       {
+               xReturn = pdTRUE;
+       }
+       else
+       {
+               xReturn = pdFALSE;
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer )
+{
+       #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
+       {
+               /* When ipconfigUSE_LINKED_RX_MESSAGES is not 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. */
+               do
+               {
+                       /* 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;
+
+               /* While there is another packet in the chain. */
+               } while( pxBuffer != NULL );
+       }
+       #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
+}
+/*-----------------------------------------------------------*/
+
+static TickType_t prvCalculateSleepTime( void )
+{
+TickType_t xMaximumSleepTime;
+
+       /* Start with the maximum sleep time, then check this against the remaining
+       time in any other timers that are active. */
+       xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
+
+       if( xARPTimer.bActive != pdFALSE_UNSIGNED )
+       {
+               if( xARPTimer.ulRemainingTime < xMaximumSleepTime )
+               {
+                       xMaximumSleepTime = xARPTimer.ulReloadTime;
+               }
+       }
+
+       #if( ipconfigUSE_DHCP == 1 )
+       {
+               if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
+               {
+                       if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )
+                       {
+                               xMaximumSleepTime = xDHCPTimer.ulRemainingTime;
+                       }
+               }
+       }
+       #endif /* ipconfigUSE_DHCP */
+
+       #if( ipconfigUSE_TCP == 1 )
+       {
+               if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )
+               {
+                       xMaximumSleepTime = xTCPTimer.ulRemainingTime;
+               }
+       }
+       #endif
+
+       #if( ipconfigDNS_USE_CALLBACKS != 0 )
+       {
+               if( xDNSTimer.bActive != pdFALSE )
+               {
+                       if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )
+                       {
+                               xMaximumSleepTime = xDNSTimer.ulRemainingTime;
+                       }
+               }
+       }
+       #endif
+
+       return xMaximumSleepTime;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckNetworkTimers( void )
+{
+       /* Is it time for ARP processing? */
+       if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
+       {
+               xSendEventToIPTask( eARPTimerEvent );
+       }
+
+       #if( ipconfigUSE_DHCP == 1 )
+       {
+               /* Is it time for DHCP processing? */
+               if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
+               {
+                       xSendEventToIPTask( eDHCPEvent );
+               }
+       }
+       #endif /* ipconfigUSE_DHCP */
+
+       #if( ipconfigDNS_USE_CALLBACKS != 0 )
+       {
+       extern void vDNSCheckCallBack( void *pvSearchID );
+
+               /* Is it time for DNS processing? */
+               if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
+               {
+                       vDNSCheckCallBack( NULL );
+               }
+       }
+       #endif /* ipconfigDNS_USE_CALLBACKS */
+
+       #if( ipconfigUSE_TCP == 1 )
+       {
+       BaseType_t xWillSleep;
+       TickType_t xNextTime;
+       BaseType_t xCheckTCPSockets;
+
+               if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )
+               {
+                       xWillSleep = pdTRUE;
+               }
+               else
+               {
+                       xWillSleep = pdFALSE;
+               }
+
+               /* Sockets need to be checked if the TCP timer has expired. */
+               xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
+
+               /* Sockets will also be checked if there are TCP messages but the
+               message queue is empty (indicated by xWillSleep being true). */
+               if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
+               {
+                       xCheckTCPSockets = pdTRUE;
+               }
+
+               if( xCheckTCPSockets != pdFALSE )
+               {
+                       /* Attend to the sockets, returning the period after which the
+                       check must be repeated. */
+                       xNextTime = xTCPTimerCheck( xWillSleep );
+                       prvIPTimerStart( &xTCPTimer, xNextTime );
+                       xProcessedTCPMessage = 0;
+               }
+       }
+       #endif /* ipconfigUSE_TCP == 1 */
+}
+/*-----------------------------------------------------------*/
+
+static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime )
+{
+       vTaskSetTimeOutState( &pxTimer->xTimeOut );
+       pxTimer->ulRemainingTime = xTime;
+
+       if( xTime == ( TickType_t ) 0 )
+       {
+               pxTimer->bExpired = pdTRUE_UNSIGNED;
+       }
+       else
+       {
+               pxTimer->bExpired = pdFALSE_UNSIGNED;
+       }
+
+       pxTimer->bActive = pdTRUE_UNSIGNED;
+}
+/*-----------------------------------------------------------*/
+
+static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime )
+{
+       pxTimer->ulReloadTime = xTime;
+       prvIPTimerStart( pxTimer, xTime );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer )
+{
+BaseType_t xReturn;
+
+       if( pxTimer->bActive == pdFALSE_UNSIGNED )
+       {
+               /* The timer is not enabled. */
+               xReturn = pdFALSE;
+       }
+       else
+       {
+               /* The timer might have set the bExpired flag already, if not, check the
+               value of xTimeOut against ulRemainingTime. */
+               if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) ||
+                       ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) )
+               {
+                       prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
+                       xReturn = pdTRUE;
+               }
+               else
+               {
+                       xReturn = pdFALSE;
+               }
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_NetworkDown( void )
+{
+static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
+const TickType_t xDontBlock = ( TickType_t ) 0;
+
+       /* Simply send the network task the appropriate event. */
+       if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
+       {
+               /* Could not send the message, so it is still pending. */
+               xNetworkDownEventPending = pdTRUE;
+       }
+       else
+       {
+               /* Message was sent so it is not pending. */
+               xNetworkDownEventPending = pdFALSE;
+       }
+
+       iptraceNETWORK_DOWN();
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t FreeRTOS_NetworkDownFromISR( void )
+{
+static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+       /* Simply send the network task the appropriate event. */
+       if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
+       {
+               xNetworkDownEventPending = pdTRUE;
+       }
+       else
+       {
+               xNetworkDownEventPending = pdFALSE;
+       }
+
+       iptraceNETWORK_DOWN();
+
+       return xHigherPriorityTaskWoken;
+}
+/*-----------------------------------------------------------*/
+
+void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+void *pvReturn;
+
+       /* 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( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
+       {
+               xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
+       }
+
+       /* Obtain a network buffer with the required amount of storage. */
+       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );
+
+       if( pxNetworkBuffer != NULL )
+       {
+               /* Set the actual packet size in case a bigger buffer was returned. */
+               pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes;
+
+               /* Leave space for the UPD header. */
+               pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
+       }
+       else
+       {
+               pvReturn = NULL;
+       }
+
+       return ( void * ) pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,
+       size_t uxNewLength )
+{
+NetworkBufferDescriptor_t * pxNewBuffer;
+
+       /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
+       The transmit routine wants to have ownership of the network buffer
+       descriptor, because it will pass the buffer straight to DMA. */
+       pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
+
+       if( pxNewBuffer != NULL )
+       {
+               /* Set the actual packet size in case a bigger buffer than requested
+               was returned. */
+               pxNewBuffer->xDataLength = uxNewLength;
+
+               /* Copy the original packet information. */
+               pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;
+               pxNewBuffer->usPort = pxNetworkBuffer->usPort;
+               pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
+               memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
+       }
+
+       return pxNewBuffer;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
+
+       NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer )
+       {
+       uint8_t *pucBuffer;
+       NetworkBufferDescriptor_t *pxResult;
+
+               if( pvBuffer == NULL )
+               {
+                       pxResult = NULL;
+               }
+               else
+               {
+                       /* Obtain the network buffer from the zero copy pointer. */
+                       pucBuffer = ( uint8_t * ) pvBuffer;
+
+                       /* The input here is a pointer to a payload buffer.  Subtract the
+                       size of the header in the network buffer, usually 8 + 2 bytes. */
+                       pucBuffer -= ipBUFFER_PADDING;
+
+                       /* Here a pointer was placed to the network descriptor.  As a
+                       pointer is dereferenced, make sure it is well aligned. */
+                       if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 )
+                       {
+                               pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
+                       }
+                       else
+                       {
+                               pxResult = NULL;
+                       }
+               }
+
+               return pxResult;
+       }
+
+#endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer )
+{
+uint8_t *pucBuffer;
+NetworkBufferDescriptor_t *pxResult;
+
+       if( pvBuffer == NULL )
+       {
+               pxResult = NULL;
+       }
+       else
+       {
+               /* Obtain the network buffer from the zero copy pointer. */
+               pucBuffer = ( uint8_t * ) pvBuffer;
+
+               /* The input here is a pointer to a payload buffer.  Subtract
+               the total size of a UDP/IP header plus the size of the header in
+               the network buffer, usually 8 + 2 bytes. */
+               pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING );
+
+               /* Here a pointer was placed to the network descriptor,
+               As a pointer is dereferenced, make sure it is well aligned */
+               if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 )
+               {
+                       /* The following statement may trigger a:
+                       warning: cast increases required alignment of target type [-Wcast-align].
+                       It has been confirmed though that the alignment is suitable. */
+                       pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
+               }
+               else
+               {
+                       pxResult = NULL;
+               }
+       }
+
+       return pxResult;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )
+{
+       vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );
+}
+/*-----------------------------------------------------------*/
+
+/*_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. */
+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 ] )
+{
+BaseType_t xReturn = pdFALSE;
+
+       /* This function should only be called once. */
+       configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
+       configASSERT( xNetworkEventQueue == NULL );
+       configASSERT( xIPTaskHandle == NULL );
+
+       /* Check structure packing is correct. */
+       configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );
+       configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );
+       configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );
+       configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );
+       configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );
+
+       /* Attempt to create the queue used to communicate with the IP task. */
+       xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) );
+       configASSERT( xNetworkEventQueue );
+
+       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 )
+               {
+                       /* Store the local IP and MAC address. */
+                       xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
+                       xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
+                       xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
+                       xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
+                       xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;
+
+                       memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );
+
+                       #if ipconfigUSE_DHCP == 1
+                       {
+                               /* The IP address is not set until DHCP completes. */
+                               *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
+                       }
+                       #else
+                       {
+                               /* The IP address is set from the value passed in. */
+                               *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
+
+                               /* Added to prevent ARP flood to gateway.  Ensure the
+                               gateway is on the same subnet as the IP address. */
+                               if( xNetworkAddressing.ulGatewayAddress != 0ul )
+                               {
+                                       configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
+                               }
+                       }
+                       #endif /* ipconfigUSE_DHCP == 1 */
+
+                       /* The MAC address is stored in the start of the default packet
+                       header fragment, which is used when sending UDP packets. */
+                       memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+                       /* Prepare the sockets interface. */
+                       xReturn = vNetworkSocketsInit();
+
+                       if( pdTRUE == xReturn )
+                       {
+                               /* Create the task that processes Ethernet and stack events. */
+                               xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );
+                       }
+               }
+               else
+               {
+                       FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") );
+
+                       /* Clean up. */
+                       vQueueDelete( xNetworkEventQueue );
+                       xNetworkEventQueue = NULL;
+               }
+       }
+       else
+       {
+               FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") );
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )
+{
+       /* Return the address configuration to the caller. */
+
+       if( pulIPAddress != NULL )
+       {
+               *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+       }
+
+       if( pulNetMask != NULL )
+       {
+               *pulNetMask = xNetworkAddressing.ulNetMask;
+       }
+
+       if( pulGatewayAddress != NULL )
+       {
+               *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
+       }
+
+       if( pulDNSServerAddress != NULL )
+       {
+               *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
+       }
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress )
+{
+       /* Update the address configuration. */
+
+       if( pulIPAddress != NULL )
+       {
+               *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;
+       }
+
+       if( pulNetMask != NULL )
+       {
+               xNetworkAddressing.ulNetMask = *pulNetMask;
+       }
+
+       if( pulGatewayAddress != NULL )
+       {
+               xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;
+       }
+
+       if( pulDNSServerAddress != NULL )
+       {
+               xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;
+       }
+}
+/*-----------------------------------------------------------*/
+
+#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+
+       BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks )
+       {
+       NetworkBufferDescriptor_t *pxNetworkBuffer;
+       ICMPHeader_t *pxICMPHeader;
+       BaseType_t xReturn = pdFAIL;
+       static uint16_t usSequenceNumber = 0;
+       uint8_t *pucChar;
+       IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
+
+               if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) )
+               {
+                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks );
+
+                       if( pxNetworkBuffer != NULL )
+                       {
+                               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 += sizeof( ICMPHeader_t );
+
+                               /* Just memset the data to a fixed value. */
+                               memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );
+
+                               /* The message is complete, IP and checksum's are handled by
+                               vProcessGeneratedUDPPacket */
+                               pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
+                               pxNetworkBuffer->ulIPAddress = ulIPAddress;
+                               pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
+                               /* xDataLength is the size of the total packet, including the Ethernet header. */
+                               pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t );
+
+                               /* Send to the stack. */
+                               xStackTxEvent.pvData = pxNetworkBuffer;
+
+                               if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS )
+                               {
+                                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+                                       iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
+                               }
+                               else
+                               {
+                                       xReturn = 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 */
+/*-----------------------------------------------------------*/
+
+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 );
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout )
+{
+BaseType_t xReturn, xSendMessage;
+
+       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. */
+                               xTCPTimer.bExpired = pdTRUE_UNSIGNED;
+
+                               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 ) && ( xTimeout > ( TickType_t ) 0 ) )
+                       {
+                               xTimeout = ( TickType_t ) 0;
+                       }
+
+                       xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout );
+
+                       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;
+}
+/*-----------------------------------------------------------*/
+
+eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
+{
+eFrameProcessingResult_t eReturn;
+const EthernetHeader_t *pxEthernetHeader;
+
+       pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer;
+
+       if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 )
+       {
+               /* The packet was directed to this node directly - process it. */
+               eReturn = eProcessBuffer;
+       }
+       else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
+       {
+               /* The packet was a broadcast - process it. */
+               eReturn = eProcessBuffer;
+       }
+       else
+#if( ipconfigUSE_LLMNR == 1 )
+       if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
+       {
+               /* The packet is a request for LLMNR - process it. */
+               eReturn = eProcessBuffer;
+       }
+       else
+#endif /* ipconfigUSE_LLMNR */
+       {
+               /* 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;
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessNetworkDownEvent( void )
+{
+       /* Stop the ARP timer while there is no network. */
+       xARPTimer.bActive = pdFALSE_UNSIGNED;
+
+       #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
+       {
+               static BaseType_t xCallEventHook = pdFALSE;
+
+               /* The first network down event is generated by the IP stack itself to
+               initialise the network hardware, so do not call the network down event
+               the first time through. */
+               if( xCallEventHook == pdTRUE )
+               {
+                       vApplicationIPNetworkEventHook( eNetworkDown );
+               }
+               xCallEventHook = pdTRUE;
+       }
+       #endif
+
+       /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122, 
+       treat network down as a "delivery problem" and flush the ARP cache for this
+       interface. */
+       FreeRTOS_ClearARP( );
+
+       /* The network has been disconnected (or is being initialised for the first
+       time).  Perform whatever hardware processing is necessary to bring it up
+       again, or wait for it to be available again.  This is hardware dependent. */
+       if( xNetworkInterfaceInitialise() != pdPASS )
+       {
+               /* Ideally the network interface initialisation function will only
+               return when the network is available.  In case this is not the case,
+               wait a while before retrying the initialisation. */
+               vTaskDelay( ipINITIALISATION_RETRY_DELAY );
+               FreeRTOS_NetworkDown();
+       }
+       else
+       {
+               /* Set remaining time to 0 so it will become active immediately. */
+               #if ipconfigUSE_DHCP == 1
+               {
+                       /* The network is not up until DHCP has completed. */
+                       vDHCPProcess( pdTRUE );
+                       xSendEventToIPTask( eDHCPEvent );
+               }
+               #else
+               {
+                       /* Perform any necessary 'network up' processing. */
+                       vIPNetworkUpCalls();
+               }
+               #endif
+       }
+}
+/*-----------------------------------------------------------*/
+
+void vIPNetworkUpCalls( void )
+{
+       xNetworkUp = pdTRUE;
+
+       #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
+       {
+               vApplicationIPNetworkEventHook( eNetworkUp );
+       }
+       #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. */
+       prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
+}
+/*-----------------------------------------------------------*/
+
+static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+EthernetHeader_t *pxEthernetHeader;
+eFrameProcessingResult_t eReturned = eReleaseBuffer;
+
+       configASSERT( pxNetworkBuffer );
+
+       /* Interpret the Ethernet frame. */
+       if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
+       {
+               eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
+               pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );
+
+               if( eReturned == eProcessBuffer )
+               {
+                       /* Interpret the received Ethernet packet. */
+                       switch( pxEthernetHeader->usFrameType )
+                       {
+                       case ipARP_FRAME_TYPE:
+                               /* The Ethernet frame contains an ARP packet. */
+                               if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
+                               {
+                                       eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer );
+                               }
+                               else
+                               {
+                                       eReturned = eReleaseBuffer;
+                               }
+                               break;
+
+                       case ipIPv4_FRAME_TYPE:
+                               /* The Ethernet frame contains an IP packet. */
+                               if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
+                               {
+                                       eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );
+                               }
+                               else
+                               {
+                                       eReturned = eReleaseBuffer;
+                               }
+                               break;
+
+                       default:
+                               /* No other packet types are handled.  Nothing to do. */
+                               eReturned = eReleaseBuffer;
+                               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;
+
+               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;
+       }
+}
+/*-----------------------------------------------------------*/
+
+static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
+       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;
+
+                       /* Ensure that the incoming packet is not fragmented (only outgoing
+                       packets can be fragmented) as these are the only handled IP frames
+                       currently. */
+                       if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )
+                       {
+                               /* Can not handle, fragmented packet. */
+                               eReturn = eReleaseBuffer;
+                       }
+                       /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
+                        * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
+                       else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) )
+                       {
+                               /* Can not handle, unknown or invalid header version. */
+                               eReturn = eReleaseBuffer;
+                       }
+                               /* Is the packet for this IP address? */
+                       else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
+                               /* Is it the global broadcast address 255.255.255.255 ? */
+                               ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&
+                               /* Is it a specific broadcast address 192.168.1.255 ? */
+                               ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&
+                       #if( ipconfigUSE_LLMNR == 1 )
+                               /* Is it the LLMNR multicast address? */
+                               ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
+                       #endif
+                               /* Or (during DHCP negotiation) we have no IP-address yet? */
+                               ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
+                       {
+                               /* Packet is not for this node, release it */
+                               eReturn = eReleaseBuffer;
+                       }
+       }
+       #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 )
+               {
+                       /* Is the IP header checksum correct? */
+                       if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&
+                               ( usGenerateChecksum( 0UL, ( 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
+       {
+               /* to avoid warning unused parameters */
+               ( void ) pxNetworkBuffer;
+               ( void ) uxHeaderLength;
+       }
+       #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
+
+       return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+eFrameProcessingResult_t eReturn;
+IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
+UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );
+uint8_t ucProtocol;
+
+       /* Bound the calculated header length: take away the Ethernet header size,
+       then check if the IP header is claiming to be longer than the remaining
+       total packet size. Also check for minimal header field length. */
+       if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
+               ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
+       {
+               return eReleaseBuffer;
+       }
+
+       ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
+       /* Check if the IP headers are acceptable and if it has our destination. */
+       eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
+
+       if( eReturn == eProcessBuffer )
+       {
+               if( uxHeaderLength > ipSIZE_OF_IPv4_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
+                        * Note: IP options are mostly use in Multi-cast protocols */
+                       const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
+                       /* From: the previous start of UDP/ICMP/TCP data */
+                       uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength);
+                       /* To: the usual start of UDP/ICMP/TCP data at offset 20 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;
+
+                       memmove( pucTarget, pucSource, xMoveLen );
+                       pxNetworkBuffer->xDataLength -= optlen;
+
+                       /* Fix-up new version/header length field in IP packet. */
+                       pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */
+                                                                                               ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */
+               }
+
+               /* 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 )
+               {
+                       /* 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 know that the message will be handled by someone
+                        * This will prevent that the ARP cache will get overwritten
+                        * with the IP-address of useless broadcast packets
+                        */
+                       vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
+               }
+               switch( ucProtocol )
+               {
+                       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 )
+                               {
+                                       if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )
+                                       {
+                                               ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
+                                               if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+                                               {
+                                                       eReturn = prvProcessICMPPacket( pxICMPPacket );
+                                               }
+                                       }
+                                       else
+                                       {
+                                               eReturn = eReleaseBuffer;
+                                       }
+                               }
+                               #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
+                               break;
+
+                       case ipPROTOCOL_UDP :
+                               {
+                                       /* The IP packet contained a UDP frame. */
+                                       UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+
+                                       /* Only proceed if the payload length indicated in the header
+                                       appears to be valid. */
+                                       if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) )
+                                       {
+                                       size_t uxPayloadSize_1, uxPayloadSize_2;
+                                               /* The UDP payload size can be calculated by subtracting the
+                                                * header size from `xDataLength`.
+                                                * However, the `xDataLength` may be longer that expected,
+                                                * e.g. when a small packet is padded with zero's.
+                                                * The UDP header contains a field `usLength` reflecting
+                                                * the payload size plus the UDP header ( 8 bytes ).
+                                                * Set `xDataLength` to the size of the headers,
+                                                * plus the lower of the two calculated payload sizes.
+                                                */
+
+                                               uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
+                                               uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );
+                                               if( uxPayloadSize_1 > uxPayloadSize_2 )
+                                               {
+                                                       pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );
+                                               }
+
+                                               /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */
+                                               pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
+                                               pxNetworkBuffer->ulIPAddress = 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,
+                                                                                                          pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
+                                               {
+                                                       eReturn = eFrameConsumed;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               eReturn = eReleaseBuffer;
+                                       }
+                               }
+                               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
+                       default :
+                               /* Not a supported frame type. */
+                               break;
+               }
+       }
+
+       return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+
+       static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )
+       {
+       ePingReplyStatus_t eStatus = eSuccess;
+       uint16_t usDataLength, usCount;
+       uint8_t *pucByte;
+
+               /* Find the total length of the IP packet. */
+               usDataLength = pxICMPPacket->xIPHeader.usLength;
+               usDataLength = FreeRTOS_ntohs( usDataLength );
+
+               /* Remove the length of the IP headers to obtain the length of the ICMP
+               message itself. */
+               usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );
+
+               /* Remove the length of the ICMP header, to obtain the length of
+               data contained in the ping. */
+               usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );
+
+               /* Checksum has already been checked before in prvProcessIPPacket */
+
+               /* Find the first byte of the data within the ICMP packet. */
+               pucByte = ( uint8_t * ) pxICMPPacket;
+               pucByte += sizeof( ICMPPacket_t );
+
+               /* Check each byte. */
+               for( usCount = 0; usCount < usDataLength; usCount++ )
+               {
+                       if( *pucByte != ipECHO_DATA_FILL_BYTE )
+                       {
+                               eStatus = eInvalidData;
+                               break;
+                       }
+
+                       pucByte++;
+               }
+
+               /* Call back into the application to pass it the result. */
+               vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
+
+       static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )
+       {
+       ICMPHeader_t *pxICMPHeader;
+       IPHeader_t *pxIPHeader;
+       uint16_t usRequest;
+
+               pxICMPHeader = &( pxICMPPacket->xICMPHeader );
+               pxIPHeader = &( pxICMPPacket->xIPHeader );
+
+               /* HT:endian: changed back */
+               iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
+
+               /* The checksum can be checked here - but a ping reply should be
+               returned even if the checksum is incorrect so the other end can
+               tell that the ping was received - even if the ping reply contains
+               invalid data. */
+               pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;
+               pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
+               pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+
+               /* Update the checksum because the ucTypeOfMessage member in the header
+               has been changed to ipICMP_ECHO_REPLY.  This is faster than calling
+               usGenerateChecksum(). */
+
+               /* due to compiler warning "integer operation result is out of range" */
+
+               usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 );
+
+               if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) )
+               {
+                       pxICMPHeader->usChecksum = ( uint16_t )
+                               ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
+                                       FreeRTOS_htons( usRequest + 1UL ) );
+               }
+               else
+               {
+                       pxICMPHeader->usChecksum = ( uint16_t )
+                               ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
+                                       FreeRTOS_htons( usRequest ) );
+               }
+               return eReturnEthernetFrame;
+       }
+
+#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
+/*-----------------------------------------------------------*/
+
+#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+
+       static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )
+       {
+       eFrameProcessingResult_t eReturn = eReleaseBuffer;
+
+               iptraceICMP_PACKET_RECEIVED();
+               switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
+               {
+                       case ipICMP_ECHO_REQUEST        :
+                               #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
+                               {
+                                       eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
+                               }
+                               #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
+                               break;
+
+                       case ipICMP_ECHO_REPLY          :
+                               #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+                               {
+                                       prvProcessICMPEchoReply( pxICMPPacket );
+                               }
+                               #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
+                               break;
+
+                       default :
+                               break;
+               }
+
+               return eReturn;
+       }
+
+#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
+/*-----------------------------------------------------------*/
+
+uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket )
+{
+uint32_t ulLength;
+uint16_t usChecksum, *pusChecksum;
+const IPPacket_t * pxIPPacket;
+UBaseType_t uxIPHeaderLength;
+ProtocolPacket_t *pxProtPack;
+uint8_t ucProtocol;
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+       const char *pcType;
+#endif
+
+       /* Check for minimum packet size. */
+       if( uxBufferLength < sizeof( IPPacket_t ) )
+       {
+               return ipINVALID_LENGTH;
+       }
+
+       /* Parse the packet length. */
+       pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;
+
+       /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header
+       Length field contains the length of the internet header in 32-bit words. */
+       uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) );
+
+       /* Check for minimum packet size. */
+       if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER )
+       {
+               return ipINVALID_LENGTH;
+       }
+       if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) )
+       {
+               return ipINVALID_LENGTH;
+       }
+
+       /* Identify the next protocol. */
+       ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
+
+       /* N.B., if this IP packet header includes Options, then the following
+       assignment results in a pointer into the protocol packet with the Ethernet
+       and IP headers incorrectly aligned. However, either way, the "third"
+       protocol (Layer 3 or 4) header will be aligned, which is the convenience
+       of this calculation. */
+       pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );
+
+       /* Switch on the Layer 3/4 protocol. */
+       if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
+       {
+               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )
+               {
+                       return ipINVALID_LENGTH;
+               }
+
+               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );
+               #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+               {
+                       pcType = "UDP";
+               }
+               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+       }
+       else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
+       {
+               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )
+               {
+                       return ipINVALID_LENGTH;
+               }
+
+               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );
+               #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+               {
+                       pcType = "TCP";
+               }
+               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+       }
+       else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
+                       ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
+       {
+               if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )
+               {
+                       return ipINVALID_LENGTH;
+               }
+
+               pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );
+               #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+               {
+                       if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
+                       {
+                               pcType = "ICMP";
+                       }
+                       else
+                       {
+                               pcType = "IGMP";
+                       }
+               }
+               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+       }
+       else
+       {
+               /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
+               return ipUNHANDLED_PROTOCOL;
+       }
+
+       /* The protocol and checksum field have been identified. Check the direction
+       of the packet. */
+       if( xOutgoingPacket != pdFALSE )
+       {
+               /* This is an outgoing packet. Before calculating the checksum, set it
+               to zero. */
+               *( pusChecksum ) = 0u;
+       }
+       else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
+       {
+               /* Sender hasn't set the checksum, no use to calculate it. */
+               return ipCORRECT_CRC;
+       }
+
+       ulLength = ( uint32_t )
+               ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */
+
+       if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ||
+               ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) )
+       {
+               #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+               {
+                       FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );
+               }
+               #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+               /* Again, in a 16-bit return value there is no space to indicate an
+               error.  For incoming packets, 0x1234 will cause dropping of the packet.
+               For outgoing packets, there is a serious problem with the
+               format/length */
+               return ipINVALID_LENGTH;
+       }
+       if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )
+       {
+               /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
+               usChecksum = ( uint16_t )
+                       ( ~usGenerateChecksum( 0UL,
+                               ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );
+       }
+       else
+       {
+               /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
+               fields */
+               usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );
+
+               /* And then continue at the IPv4 source and destination addresses. */
+               usChecksum = ( uint16_t )
+                       ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),
+                               ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );
+
+               /* Sum TCP header and data. */
+       }
+
+       if( xOutgoingPacket == pdFALSE )
+       {
+               /* This is in incoming packet. If the CRC is correct, it should be zero. */
+               if( usChecksum == 0u )
+               {
+                       usChecksum = ( uint16_t )ipCORRECT_CRC;
+               }
+       }
+       else
+       {
+               if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
+               {
+                       /* In case of UDP, a calculated checksum of 0x0000 is transmitted
+                       as 0xffff. A value of zero would mean that the checksum is not used. */
+                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+                       {
+                               if( xOutgoingPacket != pdFALSE )
+                               {
+                                       FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );
+                               }
+                       }
+                       #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+                       usChecksum = ( uint16_t )0xffffu;
+               }
+       }
+       usChecksum = FreeRTOS_htons( usChecksum );
+
+       if( xOutgoingPacket != pdFALSE )
+       {
+               *( pusChecksum ) = usChecksum;
+       }
+       #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+       else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )
+       {
+               FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",
+                       pcType,
+                       FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),
+                       FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),
+                       FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),
+                       FreeRTOS_ntohs( *pusChecksum ) ) );
+       }
+       #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+       return usChecksum;
+}
+/*-----------------------------------------------------------*/
+
+/**
+ * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
+ * The checksum algorithm is decribed as:
+ *   "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
+ *   header.  For purposes of computing the checksum, the value of the checksum field is zero."
+ *
+ * In a nutshell, that means that each 16-bit 'word' must be summed, after which
+ * the number of 'carries' (overflows) is added to the result. If that addition
+ * produces an overflow, that 'carry' must also be added to the final result. The final checksum
+ * should be the bitwise 'not' (ones-complement) of the result if the packet is
+ * meant to be transmitted, but this method simply returns the raw value, probably
+ * because when a packet is received, the checksum is verified by checking that
+ * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
+ *
+ * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
+ * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
+ * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
+ * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
+ * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
+ * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
+ * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
+ * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
+ *   union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
+ *
+ * Arguments:
+ *   ulSum: This argument provides a value to initialize the progressive summation
+ *      of the header's values to. It is often 0, but protocols like TCP or UDP
+ *      can have pseudo-header fields which need to be included in the checksum.
+ *   pucNextData: This argument contains the address of the first byte which this
+ *      method should process. The method's memory iterator is initialized to this value.
+ *   uxDataLengthBytes: This argument contains the number of bytes that this method
+ *      should process.
+ */
+uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )
+{
+xUnion32 xSum2, xSum, xTerm;
+xUnionPtr xSource;             /* Points to first byte */
+xUnionPtr xLastSource; /* Points to last byte plus one */
+uint32_t ulAlignBits, ulCarry = 0ul;
+
+       /* Small MCUs often spend up to 30% of the time doing checksum calculations
+       This function is optimised for 32-bit CPUs; Each time it will try to fetch
+       32-bits, sums it with an accumulator and counts the number of carries. */
+
+       /* Swap the input (little endian platform only). */
+       xSum.u32 = FreeRTOS_ntohs( ulSum );
+       xTerm.u32 = 0ul;
+
+       xSource.u8ptr = ( uint8_t * ) pucNextData;
+       ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */
+
+       /* If byte (8-bit) aligned... */
+       if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )
+       {
+               xTerm.u8[ 1 ] = *( xSource.u8ptr );
+               ( xSource.u8ptr )++;
+               uxDataLengthBytes--;
+               /* Now xSource is word (16-bit) aligned. */
+       }
+
+       /* If half-word (16-bit) aligned... */
+       if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) )
+       {
+               xSum.u32 += *(xSource.u16ptr);
+               ( xSource.u16ptr )++;
+               uxDataLengthBytes -= 2u;
+               /* Now xSource is word (32-bit) aligned. */
+       }
+
+       /* Word (32-bit) aligned, do the most part. */
+       xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u;
+
+       /* In this loop, four 32-bit additions will be done, in total 16 bytes.
+       Indexing with constants (0,1,2,3) gives faster code than using
+       post-increments. */
+       while( xSource.u32ptr < xLastSource.u32ptr )
+       {
+               /* Use a secondary Sum2, just to see if the addition produced an
+               overflow. */
+               xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
+               if( xSum2.u32 < xSum.u32 )
+               {
+                       ulCarry++;
+               }
+
+               /* Now add the secondary sum to the major sum, and remember if there was
+               a carry. */
+               xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
+               if( xSum2.u32 > xSum.u32 )
+               {
+                       ulCarry++;
+               }
+
+               /* And do the same trick once again for indexes 2 and 3 */
+               xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
+               if( xSum2.u32 < xSum.u32 )
+               {
+                       ulCarry++;
+               }
+
+               xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
+
+               if( xSum2.u32 > xSum.u32 )
+               {
+                       ulCarry++;
+               }
+
+               /* And finally advance the pointer 4 * 4 = 16 bytes. */
+               xSource.u32ptr += 4;
+       }
+
+       /* Now add all carries. */
+       xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
+
+       uxDataLengthBytes %= 16u;
+       xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );
+
+       /* Half-word aligned. */
+       while( xSource.u16ptr < xLastSource.u16ptr )
+       {
+               /* At least one more short. */
+               xSum.u32 += xSource.u16ptr[ 0 ];
+               xSource.u16ptr++;
+       }
+
+       if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u )        /* Maybe one more ? */
+       {
+               xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
+       }
+       xSum.u32 += xTerm.u32;
+
+       /* Now add all carries again. */
+       xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
+
+       /* The previous summation might have given a 16-bit carry. */
+       xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
+
+       if( ( ulAlignBits & 1u ) != 0u )
+       {
+               /* Quite unlikely, but pucNextData might be non-aligned, which would
+                mean that a checksum is calculated starting at an odd position. */
+               xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 );
+       }
+
+       /* swap the output (little endian platform only). */
+       return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) );
+}
+/*-----------------------------------------------------------*/
+
+void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend )
+{
+EthernetHeader_t *pxEthernetHeader;
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+       NetworkBufferDescriptor_t *pxNewBuffer;
+#endif
+
+       #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+       {
+               if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+               {
+               BaseType_t xIndex;
+
+                       FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )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( ipconfigZERO_COPY_TX_DRIVER != 0 )
+
+       if( xReleaseAfterSend == pdFALSE )
+       {
+               pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
+               xReleaseAfterSend = pdTRUE;
+               pxNetworkBuffer = pxNewBuffer;
+       }
+
+       if( pxNetworkBuffer != NULL )
+#endif
+       {
+               pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+
+               /* Swap source and destination MAC addresses. */
+               memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );
+               memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+               /* Send! */
+               xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
+       }
+}
+/*-----------------------------------------------------------*/
+
+uint32_t FreeRTOS_GetIPAddress( void )
+{
+       /* Returns the IP address of the NIC. */
+       return *ipLOCAL_IP_ADDRESS_POINTER;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
+{
+       /* Sets the IP address of the NIC. */
+       *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t FreeRTOS_GetGatewayAddress( void )
+{
+       return xNetworkAddressing.ulGatewayAddress;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t FreeRTOS_GetDNSServerAddress( void )
+{
+       return xNetworkAddressing.ulDNSServerAddress;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t FreeRTOS_GetNetmask( void )
+{
+       return xNetworkAddressing.ulNetMask;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )
+{
+       /* Copy the MAC address at the start of the default packet header fragment. */
+       memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );
+}
+/*-----------------------------------------------------------*/
+
+const uint8_t * FreeRTOS_GetMACAddress( void )
+{
+       return ipLOCAL_MAC_ADDRESS;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_SetNetmask ( uint32_t ulNetmask )
+{
+       xNetworkAddressing.ulNetMask = ulNetmask;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress )
+{
+       xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_DHCP == 1 )
+       void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
+       {
+               if( xEnableState != pdFALSE )
+               {
+                       xDHCPTimer.bActive = pdTRUE_UNSIGNED;
+               }
+               else
+               {
+                       xDHCPTimer.bActive = pdFALSE_UNSIGNED;
+               }
+       }
+#endif /* ipconfigUSE_DHCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_DHCP == 1 )
+       void vIPReloadDHCPTimer( uint32_t ulLeaseTime )
+       {
+               prvIPTimerReload( &xDHCPTimer, ulLeaseTime );
+       }
+#endif /* ipconfigUSE_DHCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDNS_USE_CALLBACKS == 1 )
+       void vIPSetDnsTimerEnableState( BaseType_t xEnableState )
+       {
+               if( xEnableState != 0 )
+               {
+                       xDNSTimer.bActive = pdTRUE;
+               }
+               else
+               {
+                       xDNSTimer.bActive = pdFALSE;
+               }
+       }
+#endif /* ipconfigUSE_DHCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDNS_USE_CALLBACKS != 0 )
+       void vIPReloadDNSTimer( uint32_t ulCheckTime )
+       {
+               prvIPTimerReload( &xDNSTimer, ulCheckTime );
+       }
+#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
+/*-----------------------------------------------------------*/
+
+BaseType_t xIPIsNetworkTaskReady( void )
+{
+       return xIPTaskInitialised;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t FreeRTOS_IsNetworkUp( void )
+{
+       return xNetworkUp;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+       UBaseType_t uxGetMinimumIPQueueSpace( void )
+       {
+               return uxQueueMinimumSpace;
+       }
+#endif
+/*-----------------------------------------------------------*/
+
+/* Provide access to private members for verification. */
+#ifdef FREERTOS_TCP_ENABLE_VERIFICATION
+       #include "aws_freertos_ip_verification_access_ip_define.h"
+#endif
+