]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_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_TCP_IP.c
index d26756589d64b65f6c459e028417063d6e02094a..849796508a8e37ad34236c8d20ad6de8ea726441 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
-/*\r
- * FreeRTOS_TCP_IP.c\r
- * Module which handles the TCP connections for FreeRTOS+TCP.\r
- * It depends on  FreeRTOS_TCP_WIN.c, which handles the TCP windowing\r
- * schemes.\r
- *\r
- * Endianness: in this module all ports and IP addresses are stored in\r
- * host byte-order, except fields in the IP-packets\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-#include <stdio.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_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_ARP.h"\r
-#include "FreeRTOS_TCP_WIN.h"\r
-\r
-\r
-/* Just make sure the contents doesn't get compiled if TCP is not enabled. */\r
-#if ipconfigUSE_TCP == 1\r
-\r
-/* This compile-time test was moved to here because some macro's\r
-were unknown within 'FreeRTOSIPConfigDefaults.h'.  It tests whether\r
-the defined MTU size can contain at least a complete TCP packet. */\r
-\r
-#if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )\r
-       #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.\r
-#endif\r
-\r
-/*\r
- * The meaning of the TCP flags:\r
- */\r
-#define ipTCP_FLAG_FIN                 0x0001u /* No more data from sender */\r
-#define ipTCP_FLAG_SYN                 0x0002u /* Synchronize sequence numbers */\r
-#define ipTCP_FLAG_RST                 0x0004u /* Reset the connection */\r
-#define ipTCP_FLAG_PSH                 0x0008u /* Push function: please push buffered data to the recv application */\r
-#define ipTCP_FLAG_ACK                 0x0010u /* Acknowledgment field is significant */\r
-#define ipTCP_FLAG_URG                 0x0020u /* Urgent pointer field is significant */\r
-#define ipTCP_FLAG_ECN                 0x0040u /* ECN-Echo */\r
-#define ipTCP_FLAG_CWR                 0x0080u /* Congestion Window Reduced */\r
-#define ipTCP_FLAG_NS                  0x0100u /* ECN-nonce concealment protection */\r
-#define ipTCP_FLAG_RSV                 0x0E00u /* Reserved, keep 0 */\r
-\r
-/* A mask to filter all protocol flags. */\r
-#define ipTCP_FLAG_CTRL                        0x001Fu\r
-\r
-/*\r
- * A few values of the TCP options:\r
- */\r
-#define TCP_OPT_END                            0u   /* End of TCP options list */\r
-#define TCP_OPT_NOOP                   1u   /* "No-operation" TCP option */\r
-#define TCP_OPT_MSS                            2u   /* Maximum segment size TCP option */\r
-#define TCP_OPT_WSOPT                  3u   /* TCP Window Scale Option (3-byte long) */\r
-#define TCP_OPT_SACK_P                 4u   /* Advertize that SACK is permitted */\r
-#define TCP_OPT_SACK_A                 5u   /* SACK option with first/last */\r
-#define TCP_OPT_TIMESTAMP              8u   /* Time-stamp option */\r
-\r
-#define TCP_OPT_MSS_LEN                        4u   /* Length of TCP MSS option. */\r
-#define TCP_OPT_WSOPT_LEN              3u   /* Length of TCP WSOPT option. */\r
-\r
-#define TCP_OPT_TIMESTAMP_LEN  10      /* fixed length of the time-stamp option */\r
-\r
-#ifndef ipconfigTCP_ACK_EARLIER_PACKET\r
-       #define ipconfigTCP_ACK_EARLIER_PACKET          1\r
-#endif\r
-\r
-/*\r
- * The macro NOW_CONNECTED() is use to determine if the connection makes a\r
- * transition from connected to non-connected and vice versa.\r
- * NOW_CONNECTED() returns true when the status has one of these values:\r
- * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT\r
- * Technically the connection status is closed earlier, but the library wants\r
- * to prevent that the socket will be deleted before the last ACK has been\r
- * and thus causing a 'RST' packet on either side.\r
- */\r
-#define NOW_CONNECTED( status )\\r
-       ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )\r
-\r
-/*\r
- * The highest 4 bits in the TCP offset byte indicate the total length of the\r
- * TCP header, divided by 4.\r
- */\r
-#define VALID_BITS_IN_TCP_OFFSET_BYTE          ( 0xF0u )\r
-\r
-/*\r
- * Acknowledgements to TCP data packets may be delayed as long as more is being expected.\r
- * A normal delay would be 200ms.  Here a much shorter delay of 20 ms is being used to\r
- * gain performance.\r
- */\r
-#define DELAYED_ACK_SHORT_DELAY_MS                     ( 2 )\r
-#define DELAYED_ACK_LONGER_DELAY_MS                    ( 20 )\r
-\r
-/*\r
- * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with\r
- * an MSS of 1460 bytes won't be transported through the internet.  The MSS will be reduced\r
- * to 1400 bytes.\r
- */\r
-#define REDUCED_MSS_THROUGH_INTERNET           ( 1400 )\r
-\r
-/*\r
- * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as\r
- * the number 5 (words) in the higher niblle of the TCP-offset byte.\r
- */\r
-#define TCP_OFFSET_LENGTH_BITS                 ( 0xf0u )\r
-#define TCP_OFFSET_STANDARD_LENGTH             ( 0x50u )\r
-\r
-/*\r
- * Each TCP socket is checked regularly to see if it can send data packets.\r
- * By default, the maximum number of packets sent during one check is limited to 8.\r
- * This amount may be further limited by setting the socket's TX window size.\r
- */\r
-#if( !defined( SEND_REPEATED_COUNT ) )\r
-       #define SEND_REPEATED_COUNT             ( 8 )\r
-#endif /* !defined( SEND_REPEATED_COUNT ) */\r
-\r
-/*\r
- * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.\r
- * When a TCP timer expires, retries and keep-alive messages will be checked.\r
- */\r
-#ifndef        tcpMAXIMUM_TCP_WAKEUP_TIME_MS\r
-       #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS           20000u\r
-#endif\r
-\r
-/*\r
- * The names of the different TCP states may be useful in logging.\r
- */\r
-#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
-       static const char *pcStateNames[] = {\r
-               "eCLOSED",\r
-               "eTCP_LISTEN",\r
-               "eCONNECT_SYN",\r
-               "eSYN_FIRST",\r
-               "eSYN_RECEIVED",\r
-               "eESTABLISHED",\r
-               "eFIN_WAIT_1",\r
-               "eFIN_WAIT_2",\r
-               "eCLOSE_WAIT",\r
-               "eCLOSING",\r
-               "eLAST_ACK",\r
-               "eTIME_WAIT",\r
-               "eUNKNOWN",\r
-};\r
-#endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */\r
-\r
-/*\r
- * Returns true if the socket must be checked.  Non-active sockets are waiting\r
- * for user action, either connect() or close().\r
- */\r
-static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );\r
-\r
-/*\r
- * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).\r
- */\r
-static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * Try to send a series of messages.\r
- */\r
-static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );\r
-\r
-/*\r
- * Return or send a packet to the other party.\r
- */\r
-static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
-       uint32_t ulLen, BaseType_t xReleaseAfterSend );\r
-\r
-/*\r
- * Initialise the data structures which keep track of the TCP windowing system.\r
- */\r
-static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * Let ARP look-up the MAC-address of the peer and initialise the first SYN\r
- * packet.\r
- */\r
-static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );\r
-\r
-#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-       /*\r
-        * For logging and debugging: make a string showing the TCP flags.\r
-        */\r
-       static const char *prvTCPFlagMeaning( UBaseType_t xFlags);\r
-#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-\r
-/*\r
- * Parse the TCP option(s) received, if present.\r
- */\r
-static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * Identify and deal with a single TCP header option, advancing the pointer to\r
- * the header. This function returns pdTRUE or pdFALSE depending on whether the\r
- * caller should continue to parse more header options or break the loop.\r
- */\r
-static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow);\r
-\r
-/*\r
- * Skip past TCP header options when doing Selective ACK, until there are no\r
- * more options left.\r
- */\r
-static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const ppucLen );\r
-\r
-/*\r
- * Set the initial properties in the options fields, like the preferred\r
- * value of MSS and whether SACK allowed.  Will be transmitted in the state\r
- * 'eCONNECT_SYN'.\r
- */\r
-static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );\r
-\r
-/*\r
- * For anti-hang protection and TCP keep-alive messages.  Called in two places:\r
- * after receiving a packet and after a state change.  The socket's alive timer\r
- * may be reset.\r
- */\r
-static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * Prepare an outgoing message, if anything has to be sent.\r
- */\r
-static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );\r
-\r
-/*\r
- * Calculate when this socket needs to be checked to do (re-)transmissions.\r
- */\r
-static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * The API FreeRTOS_send() adds data to the TX stream.  Add\r
- * this data to the windowing system to it can be transmitted.\r
- */\r
-static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- *  Called to handle the closure of a TCP connection.\r
- */\r
-static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * Called from prvTCPHandleState().  Find the TCP payload data and check and\r
- * return its length.\r
- */\r
-static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );\r
-\r
-/*\r
- * Called from prvTCPHandleState().  Check if the payload data may be accepted.\r
- * If so, it will be added to the socket's reception queue.\r
- */\r
-static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,\r
-       NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );\r
-\r
-/*\r
- * Set the TCP options (if any) for the outgoing packet.\r
- */\r
-static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to\r
- * eCONNECT_SYN.\r
- */\r
-static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );\r
-\r
-/*\r
- * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.\r
- */\r
-static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );\r
-\r
-/*\r
- * Called from prvTCPHandleState().  There is data to be sent.\r
- * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will\r
- * be checked if it would better be postponed for efficiency.\r
- */\r
-static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, BaseType_t xSendLength );\r
-\r
-/*\r
- * The heart of all: check incoming packet for valid data and acks and do what\r
- * is necessary in each state.\r
- */\r
-static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );\r
-\r
-/*\r
- * Common code for sending a TCP protocol control packet (i.e. no options, no\r
- * payload, just flags).\r
- */\r
-static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,\r
-                                                 uint8_t ucTCPFlags );\r
-\r
-/*\r
- * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,\r
- * case #3. In summary, an RST was received with a sequence number that is\r
- * unexpected but still within the window.\r
- */\r
-static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * Reply to a peer with the RST flag on, in case a packet can not be handled.\r
- */\r
-static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * Set the initial value for MSS (Maximum Segment Size) to be used.\r
- */\r
-static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * Return either a newly created socket, or the current socket in a connected\r
- * state (depends on the 'bReuseSocket' flag).\r
- */\r
-static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
-\r
-/*\r
- * After a listening socket receives a new connection, it may duplicate itself.\r
- * The copying takes place in prvTCPSocketCopy.\r
- */\r
-static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );\r
-\r
-/*\r
- * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected\r
- * state for too long.  If so, the socket will be closed, and -1 will be\r
- * returned.\r
- */\r
-#if( ipconfigTCP_HANG_PROTECTION == 1 )\r
-       static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );\r
-#endif\r
-\r
-static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
-       int32_t lDataLen, UBaseType_t uxOptionsLength );\r
-\r
-#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
-       const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );\r
-#endif\r
-\r
-#if( ipconfigUSE_TCP_WIN != 0 )\r
-       static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );\r
-#endif\r
-\r
-/*\r
- * Generate a randomized TCP Initial Sequence Number per RFC.\r
- */\r
-extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,\r
-                                                                                                       uint16_t usSourcePort,\r
-                                                                                                       uint32_t ulDestinationAddress,\r
-                                                                                                       uint16_t usDestinationPort );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* prvTCPSocketIsActive() returns true if the socket must be checked.\r
- * Non-active sockets are waiting for user action, either connect()\r
- * or close(). */\r
-static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )\r
-{\r
-       switch( uxStatus )\r
-       {\r
-       case eCLOSED:\r
-       case eCLOSE_WAIT:\r
-       case eFIN_WAIT_2:\r
-       case eCLOSING:\r
-       case eTIME_WAIT:\r
-               return pdFALSE;\r
-       default:\r
-               return pdTRUE;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigTCP_HANG_PROTECTION == 1 )\r
-\r
-       static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )\r
-       {\r
-       BaseType_t xResult;\r
-               switch( pxSocket->u.xTCP.ucTCPState )\r
-               {\r
-               case eESTABLISHED:\r
-                       /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in\r
-                       state ESTABLISHED can be protected using keep-alive messages. */\r
-                       xResult = pdFALSE;\r
-                       break;\r
-               case eCLOSED:\r
-               case eTCP_LISTEN:\r
-               case eCLOSE_WAIT:\r
-                       /* These 3 states may last for ever, up to the owner. */\r
-                       xResult = pdFALSE;\r
-                       break;\r
-               default:\r
-                       /* All other (non-connected) states will get anti-hanging\r
-                       protection. */\r
-                       xResult = pdTRUE;\r
-                       break;\r
-               }\r
-               if( xResult != pdFALSE )\r
-               {\r
-                       /* How much time has past since the last active moment which is\r
-                       defined as A) a state change or B) a packet has arrived. */\r
-                       TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;\r
-\r
-                       /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */\r
-                       if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )\r
-                       {\r
-                               #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",\r
-                                               pxSocket->usLocalPort,\r
-                                               pxSocket->u.xTCP.ulRemoteIP,\r
-                                               pxSocket->u.xTCP.usRemotePort,\r
-                                               FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );\r
-                               }\r
-                               #endif /* ipconfigHAS_DEBUG_PRINTF */\r
-\r
-                               /* Move to eCLOSE_WAIT, user may close the socket. */\r
-                               vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
-\r
-                               /* When 'bPassQueued' true, this socket is an orphan until it\r
-                               gets connected. */\r
-                               if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )\r
-                               {\r
-                                       if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )\r
-                                       {\r
-                                               /* As it did not get connected, and the user can never\r
-                                               accept() it anymore, it will be deleted now.  Called from\r
-                                               the IP-task, so it's safe to call the internal Close\r
-                                               function: vSocketClose(). */\r
-                                               vSocketClose( pxSocket );\r
-                                       }\r
-                                       /* Return a negative value to tell to inform the caller\r
-                                       xTCPTimerCheck()\r
-                                       that the socket got closed and may not be accessed anymore. */\r
-                                       xResult = -1;\r
-                               }\r
-                       }\r
-               }\r
-               return xResult;\r
-       }\r
-       /*-----------------------------------------------------------*/\r
-\r
-#endif\r
-\r
-/*\r
- * As soon as a TCP socket timer expires, this function xTCPSocketCheck\r
- * will be called (from xTCPTimerCheck)\r
- * It can send a delayed ACK or new data\r
- * Sequence of calling (normally) :\r
- * IP-Task:\r
- *             xTCPTimerCheck()                                // Check all sockets ( declared in FreeRTOS_Sockets.c )\r
- *             xTCPSocketCheck()                               // Either send a delayed ACK or call prvTCPSendPacket()\r
- *             prvTCPSendPacket()                              // Either send a SYN or call prvTCPSendRepeated ( regular messages )\r
- *             prvTCPSendRepeated()                    // Send at most 8 messages on a row\r
- *                     prvTCPReturnPacket()            // Prepare for returning\r
- *                     xNetworkInterfaceOutput()       // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )\r
- */\r
-BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-BaseType_t xResult = 0;\r
-BaseType_t xReady = pdFALSE;\r
-\r
-       if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )\r
-       {\r
-               /* The API FreeRTOS_send() might have added data to the TX stream.  Add\r
-               this data to the windowing system to it can be transmitted. */\r
-               prvTCPAddTxData( pxSocket );\r
-       }\r
-\r
-       #if ipconfigUSE_TCP_WIN == 1\r
-       {\r
-               if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
-               {\r
-                       /* The first task of this regular socket check is to send-out delayed\r
-                       ACK's. */\r
-                       if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* Earlier data was received but not yet acknowledged.  This\r
-                               function is called when the TCP timer for the socket expires, the\r
-                               ACK may be sent now. */\r
-                               if( pxSocket->u.xTCP.ucTCPState != eCLOSED )\r
-                               {\r
-                                       if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",\r
-                                                       pxSocket->usLocalPort,\r
-                                                       pxSocket->u.xTCP.usRemotePort,\r
-                                                       pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,\r
-                                                       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber   - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,\r
-                                                       ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );\r
-                                       }\r
-\r
-                                       prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );\r
-\r
-                                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-                                       {\r
-                                               /* The ownership has been passed to the SEND routine,\r
-                                               clear the pointer to it. */\r
-                                               pxSocket->u.xTCP.pxAckMessage = NULL;\r
-                                       }\r
-                                       #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-                               }\r
-                               if( prvTCPNextTimeout( pxSocket ) > 1 )\r
-                               {\r
-                                       /* Tell the code below that this function is ready. */\r
-                                       xReady = pdTRUE;\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The user wants to perform an active shutdown(), skip sending\r
-                               the     delayed ACK.  The function prvTCPSendPacket() will send the\r
-                               FIN     along with the ACK's. */\r
-                       }\r
-\r
-                       if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
-                       {\r
-                               vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
-                               pxSocket->u.xTCP.pxAckMessage = NULL;\r
-                       }\r
-               }\r
-       }\r
-       #endif /* ipconfigUSE_TCP_WIN */\r
-\r
-       if( xReady == pdFALSE )\r
-       {\r
-               /* The second task of this regular socket check is sending out data. */\r
-               if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||\r
-                       ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )\r
-               {\r
-                       prvTCPSendPacket( pxSocket );\r
-               }\r
-\r
-               /* Set the time-out for the next wakeup for this socket. */\r
-               prvTCPNextTimeout( pxSocket );\r
-\r
-               #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
-               {\r
-                       /* In all (non-connected) states in which keep-alive messages can not be sent\r
-                       the anti-hang protocol will close sockets that are 'hanging'. */\r
-                       xResult = prvTCPStatusAgeCheck( pxSocket );\r
-               }\r
-               #endif\r
-       }\r
-\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvTCPSendPacket() will be called when the socket time-out has been reached.\r
- * It is only called by xTCPSocketCheck().\r
- */\r
-static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-int32_t lResult = 0;\r
-UBaseType_t uxOptionsLength;\r
-TCPPacket_t *pxTCPPacket;\r
-NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-\r
-       if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )\r
-       {\r
-               /* The connection is in s state other than SYN. */\r
-               pxNetworkBuffer = NULL;\r
-\r
-               /* prvTCPSendRepeated() will only create a network buffer if necessary,\r
-               i.e. when data must be sent to the peer. */\r
-               lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );\r
-\r
-               if( pxNetworkBuffer != NULL )\r
-               {\r
-                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-               }\r
-       }\r
-       else\r
-       {\r
-               if( pxSocket->u.xTCP.ucRepCount >= 3u )\r
-               {\r
-                       /* The connection is in the SYN status. The packet will be repeated\r
-                       to most 3 times.  When there is no response, the socket get the\r
-                       status 'eCLOSE_WAIT'. */\r
-                       FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",\r
-                               pxSocket->u.xTCP.ulRemoteIP,            /* IP address of remote machine. */\r
-                               pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */\r
-                       vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
-               }\r
-               else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )\r
-               {\r
-                       /* Or else, if the connection has been prepared, or can be prepared\r
-                       now, proceed to send the packet with the SYN flag.\r
-                       prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if\r
-                       the Ethernet address of the peer or the gateway is found. */\r
-                       pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
-\r
-                       /* About to send a SYN packet.  Call prvSetSynAckOptions() to set\r
-                       the proper options: The size of MSS and whether SACK's are\r
-                       allowed. */\r
-                       uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );\r
-\r
-                       /* Return the number of bytes to be sent. */\r
-                       lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-\r
-                       /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and\r
-                       uxOptionsLength is always a multiple of 4.  The complete expression\r
-                       would be:\r
-                       ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */\r
-                       pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-\r
-                       /* Repeat Count is used for a connecting socket, to limit the number\r
-                       of tries. */\r
-                       pxSocket->u.xTCP.ucRepCount++;\r
-\r
-                       /* Send the SYN message to make a connection.  The messages is\r
-                       stored in the socket field 'xPacket'.  It will be wrapped in a\r
-                       pseudo network buffer descriptor before it will be sent. */\r
-                       prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );\r
-               }\r
-       }\r
-\r
-       /* Return the total number of bytes sent. */\r
-       return lResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvTCPSendRepeated will try to send a series of messages, as long as there is\r
- * data to be sent and as long as the transmit window isn't full.\r
- */\r
-static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )\r
-{\r
-UBaseType_t uxIndex;\r
-int32_t lResult = 0;\r
-UBaseType_t uxOptionsLength = 0u;\r
-int32_t xSendLength;\r
-\r
-       for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )\r
-       {\r
-               /* prvTCPPrepareSend() might allocate a network buffer if there is data\r
-               to be sent. */\r
-               xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );\r
-               if( xSendLength <= 0 )\r
-               {\r
-                       break;\r
-               }\r
-\r
-               /* And return the packet to the peer. */\r
-               prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );\r
-\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       *ppxNetworkBuffer = NULL;\r
-               }\r
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-\r
-               lResult += xSendLength;\r
-       }\r
-\r
-       /* Return the total number of bytes sent. */\r
-       return lResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Return (or send) a packet the the peer.  The data is stored in pxBuffer,\r
- * which may either point to a real network buffer or to a TCP socket field\r
- * called 'xTCP.xPacket'.   A temporary xNetworkBuffer will be used to pass\r
- * the data to the NIC.\r
- */\r
-static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )\r
-{\r
-TCPPacket_t * pxTCPPacket;\r
-IPHeader_t *pxIPHeader;\r
-EthernetHeader_t *pxEthernetHeader;\r
-uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;\r
-TCPWindow_t *pxTCPWindow;\r
-NetworkBufferDescriptor_t xTempBuffer;\r
-/* For sending, a pseudo network buffer will be used, as explained above. */\r
-\r
-       if( pxNetworkBuffer == NULL )\r
-       {\r
-               pxNetworkBuffer = &xTempBuffer;\r
-\r
-               #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
-               {\r
-                       xTempBuffer.pxNextBuffer = NULL;\r
-               }\r
-               #endif\r
-               xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
-               xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );\r
-               xReleaseAfterSend = pdFALSE;\r
-       }\r
-\r
-       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-       {\r
-               if( xReleaseAfterSend == pdFALSE )\r
-               {\r
-                       pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );\r
-                       if( pxNetworkBuffer == NULL )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );\r
-                       }\r
-                       xReleaseAfterSend = pdTRUE;\r
-               }\r
-       }\r
-       #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-\r
-       if( pxNetworkBuffer != NULL )\r
-       {\r
-               pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-               pxIPHeader = &pxTCPPacket->xIPHeader;\r
-               pxEthernetHeader = &pxTCPPacket->xEthernetHeader;\r
-\r
-               /* Fill the packet, using hton translations. */\r
-               if( pxSocket != NULL )\r
-               {\r
-                       /* Calculate the space in the RX buffer in order to advertise the\r
-                       size of this socket's reception window. */\r
-                       pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
-\r
-                       if( pxSocket->u.xTCP.rxStream != NULL )\r
-                       {\r
-                               /* An RX stream was created already, see how much space is\r
-                               available. */\r
-                               ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* No RX stream has been created, the full stream size is\r
-                               available. */\r
-                               ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;\r
-                       }\r
-\r
-                       /* Take the minimum of the RX buffer space and the RX window size. */\r
-                       ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace );\r
-\r
-                       if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )\r
-                       {\r
-                               /* The low-water mark was reached, meaning there was little\r
-                               space left.  The socket will wait until the application has read\r
-                               or flushed the incoming data, and 'zero-window' will be\r
-                               advertised. */\r
-                               ulSpace = 0u;\r
-                       }\r
-\r
-                       /* If possible, advertise an RX window size of at least 1 MSS, otherwise\r
-                       the peer might start 'zero window probing', i.e. sending small packets\r
-                       (1, 2, 4, 8... bytes). */\r
-                       if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )\r
-                       {\r
-                               ulSpace = pxSocket->u.xTCP.usCurMSS;\r
-                       }\r
-\r
-                       /* Avoid overflow of the 16-bit win field. */\r
-                       #if( ipconfigUSE_TCP_WIN != 0 )\r
-                       {\r
-                               ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );\r
-                       }\r
-                       #else\r
-                       {\r
-                               ulWinSize = ulSpace;\r
-                       }\r
-                       #endif\r
-                       if( ulWinSize > 0xfffcUL )\r
-                       {\r
-                               ulWinSize = 0xfffcUL;\r
-                       }\r
-\r
-                       pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );\r
-\r
-                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-                       {\r
-                               if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )\r
-                               {\r
-                                       if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )\r
-                                       {\r
-                                       size_t uxFrontSpace;\r
-\r
-                                               if(pxSocket->u.xTCP.rxStream != NULL)\r
-                                               {\r
-                                                       uxFrontSpace =  uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       uxFrontSpace = 0u;\r
-                                               }\r
-\r
-                                               FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",\r
-                                               pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",\r
-                                                       pxSocket->u.xTCP.ulRemoteIP,\r
-                                                       pxSocket->u.xTCP.usRemotePort,\r
-                                                       pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,\r
-                                                       (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );\r
-                                       }\r
-                               }\r
-                       }\r
-                       #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
-\r
-                       /* The new window size has been advertised, switch off the flag. */\r
-                       pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;\r
-\r
-                       /* Later on, when deciding to delay an ACK, a precise estimate is needed\r
-                       of the free RX space.  At this moment, 'ulHighestRxAllowed' would be the\r
-                       highest sequence number minus 1 that the socket will accept. */\r
-                       pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;\r
-\r
-                       #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
-                               if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )\r
-                               {\r
-                                       /* Sending a keep-alive packet, send the current sequence number\r
-                                       minus 1, which will     be recognised as a keep-alive packet an\r
-                                       responded to by acknowledging the last byte. */\r
-                                       pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
-                                       pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;\r
-\r
-                                       pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;\r
-                                       pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
-                               }\r
-                               else\r
-                       #endif\r
-                       {\r
-                               pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );\r
-\r
-                               if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )\r
-                               {\r
-                                       /* Suppress FIN in case this packet carries earlier data to be\r
-                                       retransmitted. */\r
-                                       uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );\r
-                                       if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )\r
-                                       {\r
-                                               pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );\r
-                                               FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",\r
-                                                       pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                                                       ulDataLen,\r
-                                                       pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       /* Tell which sequence number is expected next time */\r
-                       pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );\r
-               }\r
-               else\r
-               {\r
-                       /* Sending data without a socket, probably replying with a RST flag\r
-                       Just swap the two sequence numbers. */\r
-                       vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );\r
-               }\r
-\r
-               pxIPHeader->ucTimeToLive                   = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
-               pxIPHeader->usLength                       = FreeRTOS_htons( ulLen );\r
-               if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )\r
-               {\r
-                       /* When pxSocket is NULL, this function is called by prvTCPSendReset()\r
-                       and the IP-addresses must be swapped.\r
-                       Also swap the IP-addresses in case the IP-tack doesn't have an\r
-                       IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */\r
-                       ulSourceAddress = pxIPHeader->ulDestinationIPAddress;\r
-               }\r
-               else\r
-               {\r
-                       ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
-               }\r
-               pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
-               pxIPHeader->ulSourceIPAddress = ulSourceAddress;\r
-               vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );\r
-\r
-               /* Just an increasing number. */\r
-               pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );\r
-               usPacketIdentifier++;\r
-               pxIPHeader->usFragmentOffset = 0u;\r
-\r
-               #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )\r
-               {\r
-                       /* calculate the IP header checksum, in case the driver won't do that. */\r
-                       pxIPHeader->usHeaderChecksum = 0x00u;\r
-                       pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
-                       pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
-\r
-                       /* calculate the TCP checksum for an outgoing packet. */\r
-                       usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );\r
-\r
-                       /* A calculated checksum of 0 must be inverted as 0 means the checksum\r
-                       is disabled. */\r
-                       if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )\r
-                       {\r
-                               pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;\r
-                       }\r
-               }\r
-               #endif\r
-\r
-       #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
-               pxNetworkBuffer->pxNextBuffer = NULL;\r
-       #endif\r
-\r
-               /* Important: tell NIC driver how many bytes must be sent. */\r
-               pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;\r
-\r
-               /* Fill in the destination MAC addresses. */\r
-               memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),\r
-                       sizeof( pxEthernetHeader->xDestinationAddress ) );\r
-\r
-               /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */\r
-               memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\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
-                               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
-               /* Send! */\r
-               xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );\r
-\r
-               if( xReleaseAfterSend == pdFALSE )\r
-               {\r
-                       /* Swap-back some fields, as pxBuffer probably points to a socket field\r
-                       containing the packet header. */\r
-                       vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);\r
-                       pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;\r
-                       memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
-               }\r
-               else\r
-               {\r
-                       /* Nothing to do: the buffer has been passed to DMA and will be released after use */\r
-               }\r
-       } /* if( pxNetworkBuffer != NULL ) */\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * The SYN event is very important: the sequence numbers, which have a kind of\r
- * random starting value, are being synchronised.  The sliding window manager\r
- * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment\r
- * Size (MSS) in use.\r
- */\r
-static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-       if( xTCPWindowLoggingLevel )\r
-               FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",\r
-                       pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,\r
-                       pxSocket->u.xTCP.uxLittleSpace ,\r
-                       pxSocket->u.xTCP.uxEnoughSpace,\r
-                       pxSocket->u.xTCP.uxRxStreamSize ) );\r
-       vTCPWindowCreate(\r
-               &pxSocket->u.xTCP.xTCPWindow,\r
-               ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,\r
-               ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,\r
-               pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,\r
-               pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,\r
-               ( uint32_t ) pxSocket->u.xTCP.usInitMSS );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Connecting sockets have a special state: eCONNECT_SYN.  In this phase,\r
- * the Ethernet address of the target will be found using ARP.  In case the\r
- * target IP address is not within the netmask, the hardware address of the\r
- * gateway will be used.\r
- */\r
-static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-TCPPacket_t *pxTCPPacket;\r
-IPHeader_t *pxIPHeader;\r
-eARPLookupResult_t eReturned;\r
-uint32_t ulRemoteIP;\r
-MACAddress_t xEthAddress;\r
-BaseType_t xReturn = pdTRUE;\r
-uint32_t ulInitialSequenceNumber = 0;\r
-\r
-       #if( ipconfigHAS_PRINTF != 0 )\r
-       {\r
-               /* Only necessary for nicer logging. */\r
-               memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );\r
-       }\r
-       #endif /* ipconfigHAS_PRINTF != 0 */\r
-\r
-       ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
-\r
-       /* Determine the ARP cache status for the requested IP address. */\r
-       eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );\r
-\r
-       switch( eReturned )\r
-       {\r
-       case eARPCacheHit:              /* An ARP table lookup found a valid entry. */\r
-               break;                          /* We can now prepare the SYN packet. */\r
-       case eARPCacheMiss:             /* An ARP table lookup did not find a valid entry. */\r
-       case eCantSendPacket:   /* There is no IP address, or an ARP is still in progress. */\r
-       default:\r
-               /* Count the number of times it couldn't find the ARP address. */\r
-               pxSocket->u.xTCP.ucRepCount++;\r
-\r
-               FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",\r
-                       pxSocket->u.xTCP.ulRemoteIP,\r
-                       FreeRTOS_htonl( ulRemoteIP ),\r
-                       eReturned,\r
-                       xEthAddress.ucBytes[ 0 ],\r
-                       xEthAddress.ucBytes[ 1 ],\r
-                       xEthAddress.ucBytes[ 2 ],\r
-                       xEthAddress.ucBytes[ 3 ],\r
-                       xEthAddress.ucBytes[ 4 ],\r
-                       xEthAddress.ucBytes[ 5 ] ) );\r
-\r
-               /* And issue a (new) ARP request */\r
-               FreeRTOS_OutputARPRequest( ulRemoteIP );\r
-\r
-               xReturn = pdFALSE;\r
-       }\r
-\r
-       if( xReturn != pdFALSE )\r
-       {\r
-               /* Get a difficult-to-predict initial sequence number for this 4-tuple. */\r
-               ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,\r
-                                                                                                                                         pxSocket->usLocalPort,\r
-                                                                                                                                         pxSocket->u.xTCP.ulRemoteIP,\r
-                                                                                                                                         pxSocket->u.xTCP.usRemotePort );\r
-\r
-               /* Check for a random number generation error. */\r
-               if( 0 == ulInitialSequenceNumber )\r
-               {\r
-                       xReturn = pdFALSE;\r
-               }\r
-       }\r
-\r
-       if( xReturn != pdFALSE )\r
-       {\r
-               /* The MAC-address of the peer (or gateway) has been found,\r
-               now prepare the initial TCP packet and some fields in the socket. */\r
-               pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
-               pxIPHeader = &pxTCPPacket->xIPHeader;\r
-\r
-               /* reset the retry counter to zero. */\r
-               pxSocket->u.xTCP.ucRepCount = 0u;\r
-\r
-               /* And remember that the connect/SYN data are prepared. */\r
-               pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;\r
-\r
-               /* Now that the Ethernet address is known, the initial packet can be\r
-               prepared. */\r
-               memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
-\r
-               /* Write the Ethernet address in Source, because it will be swapped by\r
-               prvTCPReturnPacket(). */\r
-               memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );\r
-\r
-               /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */\r
-               pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;\r
-\r
-               pxIPHeader->ucVersionHeaderLength = 0x45u;\r
-               pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );\r
-               pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
-\r
-               pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;\r
-\r
-               /* Addresses and ports will be stored swapped because prvTCPReturnPacket\r
-               will swap them back while replying. */\r
-               pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
-               pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
-\r
-               pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );\r
-               pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
-\r
-               /* We are actively connecting, so the peer's Initial Sequence Number (ISN)\r
-               isn't known yet. */\r
-               pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;\r
-\r
-               /* Start with ISN (Initial Sequence Number). */\r
-               pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;\r
-\r
-               /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in\r
-               the high nibble of the TCP offset field. */\r
-               pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;\r
-\r
-               /* Only set the SYN flag. */\r
-               pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;\r
-\r
-               /* Set the values of usInitMSS / usCurMSS for this socket. */\r
-               prvSocketSetMSS( pxSocket );\r
-\r
-               /* The initial sequence numbers at our side are known.  Later\r
-               vTCPWindowInit() will be called to fill in the peer's sequence numbers, but\r
-               first wait for a SYN+ACK reply. */\r
-               prvTCPCreateWindow( pxSocket );\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* For logging and debugging: make a string showing the TCP flags\r
-*/\r
-#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-\r
-       static const char *prvTCPFlagMeaning( UBaseType_t xFlags)\r
-       {\r
-               static char retString[10];\r
-               snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",\r
-                       ( xFlags & ipTCP_FLAG_FIN )  ? 'F' : '.',       /* 0x0001: No more data from sender */\r
-                       ( xFlags & ipTCP_FLAG_SYN )  ? 'S' : '.',       /* 0x0002: Synchronize sequence numbers */\r
-                       ( xFlags & ipTCP_FLAG_RST )  ? 'R' : '.',       /* 0x0004: Reset the connection */\r
-                       ( xFlags & ipTCP_FLAG_PSH )  ? 'P' : '.',       /* 0x0008: Push function: please push buffered data to the recv application */\r
-                       ( xFlags & ipTCP_FLAG_ACK )  ? 'A' : '.',       /* 0x0010: Acknowledgment field is significant */\r
-                       ( xFlags & ipTCP_FLAG_URG )  ? 'U' : '.',       /* 0x0020: Urgent pointer field is significant */\r
-                       ( xFlags & ipTCP_FLAG_ECN )  ? 'E' : '.',       /* 0x0040: ECN-Echo */\r
-                       ( xFlags & ipTCP_FLAG_CWR )  ? 'C' : '.',       /* 0x0080: Congestion Window Reduced */\r
-                       ( xFlags & ipTCP_FLAG_NS )   ? 'N' : '.');      /* 0x0100: ECN-nonce concealment protection */\r
-               return retString;\r
-       }\r
-       /*-----------------------------------------------------------*/\r
-\r
-#endif /* ipconfigHAS_DEBUG_PRINTF */\r
-\r
-/*\r
- * Parse the TCP option(s) received, if present.  It has already been verified\r
- * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header\r
- * is longer than the usual 20 (5 x 4) bytes.\r
- */\r
-static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-TCPPacket_t * pxTCPPacket;\r
-TCPHeader_t * pxTCPHeader;\r
-const unsigned char *pucPtr;\r
-const unsigned char *pucLast;\r
-TCPWindow_t *pxTCPWindow;\r
-BaseType_t xShouldContinueLoop;\r
-\r
-       pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-       pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-\r
-       /* A character pointer to iterate through the option data */\r
-       pucPtr = pxTCPHeader->ucOptdata;\r
-       pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);\r
-       pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-\r
-       /* Validate options size calculation. */\r
-       if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )\r
-       {\r
-               return;\r
-       }\r
-\r
-       /* The comparison with pucLast is only necessary in case the option data are\r
-       corrupted, we don't like to run into invalid memory and crash. */\r
-       xShouldContinueLoop = pdTRUE;\r
-       while( ( pucPtr < pucLast ) && ( xShouldContinueLoop == pdTRUE ) )\r
-       {\r
-               xShouldContinueLoop = prvSingleStepTCPHeaderOptions( &pucPtr, &pucLast, &pxSocket, &pxTCPWindow );\r
-       }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow)\r
-{\r
-       UBaseType_t uxNewMSS;\r
-       UBaseType_t xRemainingOptionsBytes = ( *ppucLast ) - ( *ppucPtr );\r
-       unsigned char ucLen;\r
-\r
-       if( ( *ppucPtr )[ 0 ] == TCP_OPT_END )\r
-       {\r
-               /* End of options. */\r
-               return pdFALSE;\r
-       }\r
-       if( ( *ppucPtr )[ 0 ] == TCP_OPT_NOOP)\r
-       {\r
-               /* NOP option, inserted to make the length a multiple of 4. */\r
-               ( *ppucPtr )++;\r
-               return pdTRUE;\r
-       }\r
-\r
-       /* Any other well-formed option must be at least two bytes: the option\r
-       type byte followed by a length byte. */\r
-       if( xRemainingOptionsBytes < 2 )\r
-       {\r
-               return pdFALSE;\r
-       }\r
-#if( ipconfigUSE_TCP_WIN != 0 )\r
-       else if( ( *ppucPtr )[ 0 ] == TCP_OPT_WSOPT )\r
-       {\r
-               /* Confirm that the option fits in the remaining buffer space. */\r
-               if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( ( *ppucPtr )[ 1 ] != TCP_OPT_WSOPT_LEN ) )\r
-               {\r
-                       return pdFALSE;\r
-               }\r
-\r
-               ( *ppxSocket )->u.xTCP.ucPeerWinScaleFactor = ( *ppucPtr )[ 2 ];\r
-               ( *ppxSocket )->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;\r
-               ( *ppucPtr ) += TCP_OPT_WSOPT_LEN;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN */\r
-       else if( ( *ppucPtr )[ 0 ] == TCP_OPT_MSS )\r
-       {\r
-               /* Confirm that the option fits in the remaining buffer space. */\r
-               if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( ( *ppucPtr )[ 1 ] != TCP_OPT_MSS_LEN ) )\r
-               {\r
-                       return pdFALSE;\r
-               }\r
-\r
-               /* An MSS option with the correct option length.  FreeRTOS_htons()\r
-               is not needed here because usChar2u16() already returns a host\r
-               endian number. */\r
-               uxNewMSS = usChar2u16( ( *ppucPtr ) + 2 );\r
-\r
-               if( ( *ppxSocket )->u.xTCP.usInitMSS != uxNewMSS )\r
-               {\r
-                       /* Perform a basic check on the the new MSS. */\r
-                       if( uxNewMSS == 0 )\r
-                       {\r
-                               return pdFALSE;\r
-                       }\r
-\r
-                       FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", ( *ppxSocket )->u.xTCP.usInitMSS, uxNewMSS ) );\r
-               }\r
-\r
-               if( ( *ppxSocket )->u.xTCP.usInitMSS > uxNewMSS )\r
-               {\r
-                       /* our MSS was bigger than the MSS of the other party: adapt it. */\r
-                       ( *ppxSocket )->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;\r
-                       if( ( ( *ppxTCPWindow ) != NULL ) && ( ( *ppxSocket )->u.xTCP.usCurMSS > uxNewMSS ) )\r
-                       {\r
-                               /* The peer advertises a smaller MSS than this socket was\r
-                               using.  Use that as well. */\r
-                               FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", ( *ppxSocket )->u.xTCP.usCurMSS, uxNewMSS ) );\r
-                               ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
-                       }\r
-                       ( *ppxTCPWindow )->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( ( *ppxTCPWindow )->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );\r
-                       ( *ppxTCPWindow )->usMSSInit = ( uint16_t ) uxNewMSS;\r
-                       ( *ppxTCPWindow )->usMSS = ( uint16_t ) uxNewMSS;\r
-                       ( *ppxSocket )->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;\r
-                       ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
-               }\r
-\r
-               #if( ipconfigUSE_TCP_WIN != 1 )\r
-                       /* Without scaled windows, MSS is the only interesting option. */\r
-                       return pdFALSE;\r
-               #else\r
-                       /* Or else we continue to check another option: selective ACK. */\r
-                       ( *ppucPtr ) += TCP_OPT_MSS_LEN;\r
-               #endif  /* ipconfigUSE_TCP_WIN != 1 */\r
-       }\r
-       else\r
-       {\r
-               /* All other options have a length field, so that we easily\r
-               can skip past them. */\r
-               ucLen = ( *ppucPtr )[ 1 ];\r
-               if( ( ucLen < 2 ) || ( ucLen > xRemainingOptionsBytes ) )\r
-               {\r
-                       /* If the length field is too small or too big, the options are\r
-                        * malformed, don't process them further.\r
-                        */\r
-                       return pdFALSE;\r
-               }\r
-\r
-               #if( ipconfigUSE_TCP_WIN == 1 )\r
-               {\r
-                       /* Selective ACK: the peer has received a packet but it is missing\r
-                        * earlier packets. At least this packet does not need retransmission\r
-                        * anymore. ulTCPWindowTxSack( ) takes care of this administration.\r
-                        */\r
-                       if( ( *ppucPtr )[0] == TCP_OPT_SACK_A )\r
-                       {\r
-                               ucLen -= 2;\r
-                               ( *ppucPtr ) += 2;\r
-\r
-                               while( ucLen >= 8 )\r
-                               {\r
-                                       prvSkipPastRemainingOptions( ppucPtr, ppxSocket, &ucLen );\r
-                               }\r
-                               /* ucLen should be 0 by now. */\r
-                       }\r
-               }\r
-               #endif  /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-               ( *ppucPtr ) += ucLen;\r
-       }\r
-       return pdTRUE;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const pucLen )\r
-{\r
-uint32_t ulFirst = ulChar2u32( ( *ppucPtr ) );\r
-uint32_t ulLast  = ulChar2u32( ( *ppucPtr ) + 4 );\r
-uint32_t ulCount = ulTCPWindowTxSack( &( *ppxSocket )->u.xTCP.xTCPWindow, ulFirst, ulLast );\r
-       /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked\r
-        * starting from the head position.  Advance the tail pointer in txStream.\r
-        */\r
-       if( ( ( *ppxSocket )->u.xTCP.txStream  != NULL ) && ( ulCount > 0 ) )\r
-       {\r
-               /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */\r
-               uxStreamBufferGet( ( *ppxSocket )->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );\r
-               ( *ppxSocket )->xEventBits |= eSOCKET_SEND;\r
-\r
-               #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
-               {\r
-                       if( ( *ppxSocket )->xSelectBits & eSELECT_WRITE )\r
-                       {\r
-                               /* The field 'xEventBits' is used to store regular socket events\r
-                                * (at most 8), as well as 'select events', which will be left-shifted.\r
-                                */\r
-                               ( *ppxSocket )->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
-                       }\r
-               }\r
-               #endif\r
-\r
-               /* In case the socket owner has installed an OnSent handler, call it now.\r
-                */\r
-               #if( ipconfigUSE_CALLBACKS == 1 )\r
-               {\r
-                       if( ipconfigIS_VALID_PROG_ADDRESS( ( *ppxSocket )->u.xTCP.pxHandleSent ) )\r
-                       {\r
-                               ( *ppxSocket )->u.xTCP.pxHandleSent( (Socket_t )( *ppxSocket ), ulCount );\r
-                       }\r
-               }\r
-               #endif /* ipconfigUSE_CALLBACKS == 1  */\r
-       }\r
-       ( *ppucPtr ) += 8;\r
-       ( *pucLen ) -= 8;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN != 0 )\r
-\r
-       static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )\r
-       {\r
-       size_t uxWinSize;\r
-       uint8_t ucFactor;\r
-\r
-               /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */\r
-               uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;\r
-               ucFactor = 0u;\r
-               while( uxWinSize > 0xfffful )\r
-               {\r
-                       /* Divide by two and increase the binary factor by 1. */\r
-                       uxWinSize >>= 1;\r
-                       ucFactor++;\r
-               }\r
-\r
-               FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",\r
-                       pxSocket->u.xTCP.uxRxWinSize,\r
-                       pxSocket->u.xTCP.usInitMSS,\r
-                       ucFactor ) );\r
-\r
-               return ucFactor;\r
-       }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * When opening a TCP connection, while SYN's are being sent, the  parties may\r
- * communicate what MSS (Maximum Segment Size) they intend to use.   MSS is the\r
- * nett size of the payload, always smaller than MTU.\r
-*/\r
-static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )\r
-{\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;\r
-UBaseType_t uxOptionsLength;\r
-\r
-       /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */\r
-\r
-       pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;\r
-       pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;\r
-       pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );\r
-       pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );\r
-\r
-       #if( ipconfigUSE_TCP_WIN != 0 )\r
-       {\r
-               pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );\r
-\r
-               pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;\r
-               pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );\r
-               pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );\r
-               pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;\r
-               uxOptionsLength = 8u;\r
-       }\r
-       #else\r
-       {\r
-               uxOptionsLength = 4u;\r
-       }\r
-       #endif\r
-\r
-       #if( ipconfigUSE_TCP_WIN == 0 )\r
-       {\r
-               return uxOptionsLength;\r
-       }\r
-       #else\r
-       {\r
-               pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;\r
-               pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;\r
-               pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */\r
-               pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2;      /* 2: length of this option. */\r
-               uxOptionsLength += 4u;\r
-\r
-               return uxOptionsLength; /* bytes, not words. */\r
-       }\r
-       #endif  /* ipconfigUSE_TCP_WIN == 0 */\r
-}\r
-\r
-/*\r
- * For anti-hanging protection and TCP keep-alive messages.  Called in two\r
- * places: after receiving a packet and after a state change.  The socket's\r
- * alive timer may be reset.\r
- */\r
-static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-       #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
-       {\r
-               pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );\r
-       }\r
-       #endif\r
-\r
-       #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
-       {\r
-               pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;\r
-               pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
-               pxSocket->u.xTCP.ucKeepRepCount = 0u;\r
-               pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();\r
-       }\r
-       #endif\r
-\r
-       ( void ) pxSocket;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Changing to a new state. Centralised here to do specific actions such as\r
- * resetting the alive timer, calling the user's OnConnect handler to notify\r
- * that a socket has got (dis)connected, and setting bit to unblock a call to\r
- * FreeRTOS_select()\r
- */\r
-void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )\r
-{\r
-FreeRTOS_Socket_t *xParent = NULL;\r
-BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState );      /* Was it connected ? */\r
-BaseType_t bAfter  = ( BaseType_t ) NOW_CONNECTED( eTCPState );                                                /* Is it connected now ? */\r
-#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-       BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;\r
-#endif\r
-#if( ipconfigUSE_CALLBACKS == 1 )\r
-       FreeRTOS_Socket_t *xConnected = NULL;\r
-#endif\r
-\r
-       /* Has the connected status changed? */\r
-       if( bBefore != bAfter )\r
-       {\r
-               /* Is the socket connected now ? */\r
-               if( bAfter != pdFALSE )\r
-               {\r
-                       /* if bPassQueued is true, this socket is an orphan until it gets connected. */\r
-                       if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* Now that it is connected, find it's parent. */\r
-                               if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
-                               {\r
-                                       xParent = pxSocket;\r
-                               }\r
-                               else\r
-                               {\r
-                                       xParent = pxSocket->u.xTCP.pxPeerSocket;\r
-                                       configASSERT( xParent != NULL );\r
-                               }\r
-                               if( xParent != NULL )\r
-                               {\r
-                                       if( xParent->u.xTCP.pxPeerSocket == NULL )\r
-                                       {\r
-                                               xParent->u.xTCP.pxPeerSocket = pxSocket;\r
-                                       }\r
-\r
-                                       xParent->xEventBits |= eSOCKET_ACCEPT;\r
-\r
-                                       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
-                                       {\r
-                                               /* Library support FreeRTOS_select().  Receiving a new\r
-                                               connection is being translated as a READ event. */\r
-                                               if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )\r
-                                               {\r
-                                                       xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );\r
-                                               }\r
-                                       }\r
-                                       #endif\r
-\r
-                                       #if( ipconfigUSE_CALLBACKS == 1 )\r
-                                       {\r
-                                               if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&\r
-                                                       ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )\r
-                                               {\r
-                                                       /* The listening socket does not become connected itself, in stead\r
-                                                       a child socket is created.\r
-                                                       Postpone a call the OnConnect event until the end of this function. */\r
-                                                       xConnected = xParent;\r
-                                               }\r
-                                       }\r
-                                       #endif\r
-                               }\r
-\r
-                               /* Don't need to access the parent socket anymore, so the\r
-                               reference 'pxPeerSocket' may be cleared. */\r
-                               pxSocket->u.xTCP.pxPeerSocket = NULL;\r
-                               pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;\r
-\r
-                               /* When true, this socket may be returned in a call to accept(). */\r
-                               pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
-                       }\r
-                       else\r
-                       {\r
-                               pxSocket->xEventBits |= eSOCKET_CONNECT;\r
-\r
-                               #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
-                               {\r
-                                       if( pxSocket->xSelectBits & eSELECT_WRITE )\r
-                                       {\r
-                                               pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
-                                       }\r
-                               }\r
-                               #endif\r
-                       }\r
-               }\r
-               else  /* bAfter == pdFALSE, connection is closed. */\r
-               {\r
-                       /* Notify/wake-up the socket-owner by setting a semaphore. */\r
-                       pxSocket->xEventBits |= eSOCKET_CLOSED;\r
-\r
-                       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
-                       {\r
-                               if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )\r
-                               {\r
-                                       pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );\r
-                               }\r
-                       }\r
-                       #endif\r
-               }\r
-               #if( ipconfigUSE_CALLBACKS == 1 )\r
-               {\r
-                       if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )\r
-                       {\r
-                               /* The 'connected' state has changed, call the user handler. */\r
-                               xConnected = pxSocket;\r
-                       }\r
-               }\r
-               #endif /* ipconfigUSE_CALLBACKS */\r
-\r
-               if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )\r
-               {\r
-                       /* Now the socket isn't in an active state anymore so it\r
-                       won't need further attention of the IP-task.\r
-                       Setting time-out to zero means that the socket won't get checked during\r
-                       timer events. */\r
-                       pxSocket->u.xTCP.usTimeout = 0u;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               if( eTCPState == eCLOSED )\r
-               {\r
-                       /* Socket goes to status eCLOSED because of a RST.\r
-                       When nobody owns the socket yet, delete it. */\r
-                       if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||\r
-                               ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );\r
-                               if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )\r
-                               {\r
-                                       FreeRTOS_closesocket( pxSocket );\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       /* Fill in the new state. */\r
-       pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;\r
-\r
-       /* touch the alive timers because moving to another state. */\r
-       prvTCPTouchSocket( pxSocket );\r
-\r
-       #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
-       {\r
-       if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
-               FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",\r
-                       pxSocket->usLocalPort,\r
-                       pxSocket->u.xTCP.ulRemoteIP,\r
-                       pxSocket->u.xTCP.usRemotePort,\r
-                       FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),\r
-                       FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );\r
-       }\r
-       #endif /* ipconfigHAS_DEBUG_PRINTF */\r
-\r
-       #if( ipconfigUSE_CALLBACKS == 1 )\r
-       {\r
-               if( xConnected != NULL )\r
-               {\r
-                       /* The 'connected' state has changed, call the OnConnect handler of the parent. */\r
-                       xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter );\r
-               }\r
-       }\r
-       #endif\r
-       if( xParent != NULL )\r
-       {\r
-               vSocketWakeUpUser( xParent );\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
-       int32_t lDataLen, UBaseType_t uxOptionsLength )\r
-{\r
-NetworkBufferDescriptor_t *pxReturn;\r
-int32_t lNeeded;\r
-BaseType_t xResize;\r
-\r
-       if( xBufferAllocFixedSize != pdFALSE )\r
-       {\r
-               /* Network buffers are created with a fixed size and can hold the largest\r
-               MTU. */\r
-               lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;\r
-               /* and therefore, the buffer won't be too small.\r
-               Only ask for a new network buffer in case none was supplied. */\r
-               xResize = ( pxNetworkBuffer == NULL );\r
-       }\r
-       else\r
-       {\r
-               /* Network buffers are created with a variable size. See if it must\r
-               grow. */\r
-               lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),\r
-                       ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );\r
-               /* In case we were called from a TCP timer event, a buffer must be\r
-               created.  Otherwise, test 'xDataLength' of the provided buffer. */\r
-               xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );\r
-       }\r
-\r
-       if( xResize != pdFALSE )\r
-       {\r
-               /* The caller didn't provide a network buffer or the provided buffer is\r
-               too small.  As we must send-out a data packet, a buffer will be created\r
-               here. */\r
-               pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );\r
-\r
-               if( pxReturn != NULL )\r
-               {\r
-                       /* Set the actual packet size, in case the returned buffer is larger. */\r
-                       pxReturn->xDataLength = lNeeded;\r
-\r
-                       /* Copy the existing data to the new created buffer. */\r
-                       if( pxNetworkBuffer )\r
-                       {\r
-                               /* Either from the previous buffer... */\r
-                               memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );\r
-\r
-                               /* ...and release it. */\r
-                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Or from the socket field 'xTCP.xPacket'. */\r
-                               memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               /* xResize is false, the network buffer provided was big enough. */\r
-               pxReturn = pxNetworkBuffer;\r
-\r
-               /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the\r
-               xDataLength member must get the correct length too! */\r
-               pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;\r
-       }\r
-\r
-       return pxReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Prepare an outgoing message, in case anything has to be sent.\r
- */\r
-static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )\r
-{\r
-int32_t lDataLen;\r
-uint8_t *pucEthernetBuffer, *pucSendData;\r
-TCPPacket_t *pxTCPPacket;\r
-size_t uxOffset;\r
-uint32_t ulDataGot, ulDistance;\r
-TCPWindow_t *pxTCPWindow;\r
-NetworkBufferDescriptor_t *pxNewBuffer;\r
-int32_t lStreamPos;\r
-\r
-       if( ( *ppxNetworkBuffer ) != NULL )\r
-       {\r
-               /* A network buffer descriptor was already supplied */\r
-               pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;\r
-       }\r
-       else\r
-       {\r
-               /* For now let it point to the last packet header */\r
-               pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
-       }\r
-\r
-       pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
-       pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-       lDataLen = 0;\r
-       lStreamPos = 0;\r
-       pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;\r
-\r
-       if( pxSocket->u.xTCP.txStream != NULL )\r
-       {\r
-               /* ulTCPWindowTxGet will return the amount of data which may be sent\r
-               along with the position in the txStream.\r
-               Why check for MSS > 1 ?\r
-               Because some TCP-stacks (like uIP) use it for flow-control. */\r
-               if( pxSocket->u.xTCP.usCurMSS > 1u )\r
-               {\r
-                       lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );\r
-               }\r
-\r
-               if( lDataLen > 0 )\r
-               {\r
-                       /* Check if the current network buffer is big enough, if not,\r
-                       resize it. */\r
-                       pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );\r
-\r
-                       if( pxNewBuffer != NULL )\r
-                       {\r
-                               *ppxNetworkBuffer = pxNewBuffer;\r
-                               pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;\r
-                               pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
-\r
-                               pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;\r
-\r
-                               /* Translate the position in txStream to an offset from the tail\r
-                               marker. */\r
-                               uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );\r
-\r
-                               /* Here data is copied from the txStream in 'peek' mode.  Only\r
-                               when the packets are acked, the tail marker will be updated. */\r
-                               ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );\r
-\r
-                               #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-                               {\r
-                                       if( ulDataGot != ( uint32_t ) lDataLen )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",\r
-                                                       lStreamPos, uxOffset, ulDataGot, lDataLen ) );\r
-                                       }\r
-                               }\r
-                               #endif\r
-\r
-                               /* If the owner of the socket requests a closure, add the FIN\r
-                               flag to the last packet. */\r
-                               if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )\r
-                               {\r
-                                       ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );\r
-\r
-                                       if( ulDistance == ulDataGot )\r
-                                       {\r
-                                               #if (ipconfigHAS_DEBUG_PRINTF == 1)\r
-                                               {\r
-                                               /* the order of volatile accesses is undefined\r
-                                                       so such workaround */\r
-                                                       size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;\r
-                                                       size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;\r
-                                                       size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;\r
-\r
-                                                       FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,\r
-                                                               uxTail, uxMid, uxHead ) );\r
-                                               }\r
-                                               #endif\r
-                                               /* Although the socket sends a FIN, it will stay in\r
-                                               ESTABLISHED until all current data has been received or\r
-                                               delivered. */\r
-                                               pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
-                                               pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;\r
-                                               pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               lDataLen = -1;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )\r
-       {\r
-               /* See if the socket owner wants to shutdown this connection. */\r
-               if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&\r
-                       ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )\r
-               {\r
-                       pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;\r
-                       pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
-                       pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
-                       pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
-                       pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
-                       vTCPStateChange( pxSocket, eFIN_WAIT_1 );\r
-               }\r
-\r
-               #if( ipconfigTCP_KEEP_ALIVE != 0 )\r
-               {\r
-                       if( pxSocket->u.xTCP.ucKeepRepCount > 3u )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",\r
-                                       pxSocket->u.xTCP.ulRemoteIP,                    /* IP address of remote machine. */\r
-                                       pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */\r
-                               vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
-                               lDataLen = -1;\r
-                       }\r
-                       if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )\r
-                       {\r
-                               /* If there is no data to be sent, and no window-update message,\r
-                               we might want to send a keep-alive message. */\r
-                               TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;\r
-                               TickType_t xMax;\r
-                               xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );\r
-                               if( pxSocket->u.xTCP.ucKeepRepCount )\r
-                               {\r
-                                       xMax = ( 3u * configTICK_RATE_HZ );\r
-                               }\r
-                               if( xAge > xMax )\r
-                               {\r
-                                       pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );\r
-                                       if( xTCPWindowLoggingLevel )\r
-                                               FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",\r
-                                                       pxSocket->u.xTCP.ulRemoteIP,\r
-                                                       pxSocket->u.xTCP.usRemotePort,\r
-                                                       pxSocket->u.xTCP.ucKeepRepCount ) );\r
-                                       pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;\r
-                                       pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );\r
-                                       pxSocket->u.xTCP.ucKeepRepCount++;\r
-                               }\r
-                       }\r
-               }\r
-               #endif /* ipconfigTCP_KEEP_ALIVE */\r
-       }\r
-\r
-       /* Anything to send, a change of the advertised window size, or maybe send a\r
-       keep-alive message? */\r
-       if( ( lDataLen > 0 ) ||\r
-               ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||\r
-               ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )\r
-       {\r
-               pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );\r
-               pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-\r
-               pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;\r
-\r
-               if( lDataLen != 0l )\r
-               {\r
-                       pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;\r
-               }\r
-\r
-               lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-       }\r
-\r
-       return lDataLen;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Calculate after how much time this socket needs to be checked again.\r
- */\r
-static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
-\r
-       if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
-       {\r
-               /* The socket is actively connecting to a peer. */\r
-               if( pxSocket->u.xTCP.bits.bConnPrepared )\r
-               {\r
-                       /* Ethernet address has been found, use progressive timeout for\r
-                       active connect(). */\r
-                       if( pxSocket->u.xTCP.ucRepCount < 3u )\r
-                       {\r
-                               ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );\r
-                       }\r
-                       else\r
-                       {\r
-                               ulDelayMs = 11000UL;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* Still in the ARP phase: check every half second. */\r
-                       ulDelayMs = 500UL;\r
-               }\r
-\r
-               FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",\r
-                       pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,\r
-                       pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );\r
-               pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
-       }\r
-       else if( pxSocket->u.xTCP.usTimeout == 0u )\r
-       {\r
-               /* Let the sliding window mechanism decide what time-out is appropriate. */\r
-               BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );\r
-               if( ulDelayMs == 0u )\r
-               {\r
-                       if( xResult != ( BaseType_t )0 )\r
-                       {\r
-                               ulDelayMs = 1UL;\r
-                       }\r
-                       else\r
-                       {\r
-                               ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* ulDelayMs contains the time to wait before a re-transmission. */\r
-               }\r
-               pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
-       }\r
-       else\r
-       {\r
-               /* field '.usTimeout' has already been set (by the\r
-               keep-alive/delayed-ACK mechanism). */\r
-       }\r
-\r
-       /* Return the number of clock ticks before the timer expires. */\r
-       return ( TickType_t ) pxSocket->u.xTCP.usTimeout;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-int32_t lCount, lLength;\r
-\r
-       /* A txStream has been created already, see if the socket has new data for\r
-       the sliding window.\r
-\r
-       uxStreamBufferMidSpace() returns the distance between rxHead and rxMid.  It contains new\r
-       Tx data which has not been passed to the sliding window yet.  The oldest\r
-       data not-yet-confirmed can be found at rxTail. */\r
-       lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );\r
-\r
-       if( lLength > 0 )\r
-       {\r
-               /* All data between txMid and rxHead will now be passed to the sliding\r
-               window manager, so it can start transmitting them.\r
-\r
-               Hand over the new data to the sliding window handler.  It will be\r
-               split-up in chunks of 1460 bytes each (or less, depending on\r
-               ipconfigTCP_MSS). */\r
-               lCount = lTCPWindowTxAdd(       &pxSocket->u.xTCP.xTCPWindow,\r
-                                                               ( uint32_t ) lLength,\r
-                                                               ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,\r
-                                                               ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );\r
-\r
-               /* Move the rxMid pointer forward up to rxHead. */\r
-               if( lCount > 0 )\r
-               {\r
-                       vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvTCPHandleFin() will be called to handle socket closure\r
- * The Closure starts when either a FIN has been received and accepted,\r
- * Or when the socket has sent a FIN flag to the peer\r
- * Before being called, it has been checked that both reception and transmission\r
- * are complete.\r
- */\r
-static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-BaseType_t xSendLength = 0;\r
-uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );\r
-\r
-       if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )\r
-       {\r
-               pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;\r
-       }\r
-       if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
-       {\r
-               /* We haven't yet replied with a FIN, do so now. */\r
-               pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
-               pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
-       }\r
-       else\r
-       {\r
-               /* We did send a FIN already, see if it's ACK'd. */\r
-               if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )\r
-               {\r
-                       pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;\r
-               }\r
-       }\r
-\r
-       if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )\r
-       {\r
-               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
-               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;\r
-\r
-               /* And wait for the final ACK. */\r
-               vTCPStateChange( pxSocket, eLAST_ACK );\r
-       }\r
-       else\r
-       {\r
-               /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */\r
-               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;\r
-               if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )\r
-               {\r
-                       /* We have sent out a FIN but the peer hasn't replied with a FIN\r
-                       yet. Do nothing for the moment. */\r
-                       pxTCPHeader->ucTCPFlags = 0u;\r
-               }\r
-               else\r
-               {\r
-                       if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* This is the third of the three-way hand shake: the last\r
-                               ACK. */\r
-                               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The other party started the closure, so we just wait for the\r
-                               last ACK. */\r
-                               pxTCPHeader->ucTCPFlags = 0u;\r
-                       }\r
-\r
-                       /* And wait for the user to close this socket. */\r
-                       vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
-               }\r
-       }\r
-\r
-       pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
-\r
-       if( pxTCPHeader->ucTCPFlags != 0u )\r
-       {\r
-               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );\r
-       }\r
-\r
-       pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );\r
-\r
-       if( xTCPWindowLoggingLevel != 0 )\r
-       {\r
-               FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",\r
-                       ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                       pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                       pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                       pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                       pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
-       }\r
-\r
-       return xSendLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvCheckRxData(): called from prvTCPHandleState()\r
- *\r
- * The first thing that will be done is find the TCP payload data\r
- * and check the length of this data.\r
- */\r
-static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
-int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;\r
-\r
-       /* Determine the length and the offset of the user-data sent to this\r
-       node.\r
-\r
-       The size of the TCP header is given in a multiple of 4-byte words (single\r
-       byte, needs no ntoh() translation).  A shift-right 2: is the same as\r
-       (offset >> 4) * 4. */\r
-       lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );\r
-\r
-       /* Let pucRecvData point to the first byte received. */\r
-       *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;\r
-\r
-       /* Calculate lReceiveLength - the length of the TCP data received.  This is\r
-       equal to the total packet length minus:\r
-       ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/\r
-       lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;\r
-       lLength =  ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );\r
-\r
-       if( lReceiveLength > lLength )\r
-       {\r
-               /* More bytes were received than the reported length, often because of\r
-               padding bytes at the end. */\r
-               lReceiveLength = lLength;\r
-       }\r
-\r
-       /* Subtract the size of the TCP and IP headers and the actual data size is\r
-       known. */\r
-       if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )\r
-       {\r
-               lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );\r
-       }\r
-       else\r
-       {\r
-               lReceiveLength = 0;\r
-       }\r
-\r
-       /* Urgent Pointer:\r
-       This field communicates the current value of the urgent pointer as a\r
-       positive offset from the sequence number in this segment.  The urgent\r
-       pointer points to the sequence number of the octet following the urgent\r
-       data.  This field is only be interpreted in segments with the URG control\r
-       bit set. */\r
-       if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )\r
-       {\r
-               /* Although we ignore the urgent data, we have to skip it. */\r
-               lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );\r
-               *ppucRecvData += lUrgentLength;\r
-               lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );\r
-       }\r
-\r
-       return ( BaseType_t ) lReceiveLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvStoreRxData(): called from prvTCPHandleState()\r
- *\r
- * The second thing is to do is check if the payload data may be accepted\r
- * If so, they will be added to the reception queue.\r
- */\r
-static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,\r
-       NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-uint32_t ulSequenceNumber, ulSpace;\r
-int32_t lOffset, lStored;\r
-BaseType_t xResult = 0;\r
-\r
-       ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
-\r
-       if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )\r
-       {\r
-               /* See if way may accept the data contents and forward it to the socket\r
-               owner.\r
-\r
-               If it can't be "accept"ed it may have to be stored and send a selective\r
-               ack (SACK) option to confirm it.  In that case, xTCPWindowRxStore() will be\r
-               called later to store an out-of-order packet (in case lOffset is\r
-               negative). */\r
-               if ( pxSocket->u.xTCP.rxStream )\r
-               {\r
-                       ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );\r
-               }\r
-               else\r
-               {\r
-                       ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;\r
-               }\r
-\r
-               lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );\r
-\r
-               if( lOffset >= 0 )\r
-               {\r
-                       /* New data has arrived and may be made available to the user.  See\r
-                       if the head marker in rxStream may be advanced, only if lOffset == 0.\r
-                       In case the low-water mark is reached, bLowWater will be set\r
-                       "low-water" here stands for "little space". */\r
-                       lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );\r
-\r
-                       if( lStored != ( int32_t ) ulReceiveLength )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );\r
-\r
-                               /* Received data could not be stored.  The socket's flag\r
-                               bMallocError has been set.  The socket now has the status\r
-                               eCLOSE_WAIT and a RST packet will be sent back. */\r
-                               prvTCPSendReset( pxNetworkBuffer );\r
-                               xResult = -1;\r
-                       }\r
-               }\r
-\r
-               /* After a missing packet has come in, higher packets may be passed to\r
-               the user. */\r
-               #if( ipconfigUSE_TCP_WIN == 1 )\r
-               {\r
-                       /* Now lTCPAddRxdata() will move the rxHead pointer forward\r
-                       so data becomes available to the user immediately\r
-                       In case the low-water mark is reached, bLowWater will be set. */\r
-                       if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )\r
-                       {\r
-                               lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );\r
-                               pxTCPWindow->ulUserDataLength = 0;\r
-                       }\r
-               }\r
-               #endif /* ipconfigUSE_TCP_WIN */\r
-       }\r
-       else\r
-       {\r
-               pxTCPWindow->ucOptionLength = 0u;\r
-       }\r
-\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Set the TCP options (if any) for the outgoing packet. */\r
-static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;\r
-\r
-       #if(    ipconfigUSE_TCP_WIN == 1 )\r
-               if( uxOptionsLength != 0u )\r
-               {\r
-                       /* TCP options must be sent because a packet which is out-of-order\r
-                       was received. */\r
-                       if( xTCPWindowLoggingLevel >= 0 )\r
-                               FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",\r
-                                       pxSocket->usLocalPort,\r
-                                       pxSocket->u.xTCP.usRemotePort,\r
-                                       uxOptionsLength,\r
-                                       FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,\r
-                                       FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );\r
-                       memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );\r
-\r
-                       /* The header length divided by 4, goes into the higher nibble,\r
-                       effectively a shift-left 2. */\r
-                       pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-               }\r
-               else\r
-       #endif  /* ipconfigUSE_TCP_WIN */\r
-       if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )\r
-       {\r
-               /* TCP options must be sent because the MSS has changed. */\r
-               pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;\r
-               if( xTCPWindowLoggingLevel >= 0 )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );\r
-               }\r
-\r
-               pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;\r
-               pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;\r
-               pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );\r
-               pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );\r
-               uxOptionsLength = 4u;\r
-               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-       }\r
-\r
-       return uxOptionsLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvHandleSynReceived(): called from prvTCPHandleState()\r
- *\r
- * Called from the states: eSYN_RECEIVED and eCONNECT_SYN\r
- * If the flags received are correct, the socket will move to eESTABLISHED.\r
- */\r
-static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
-uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
-BaseType_t xSendLength = 0;\r
-\r
-       /* Either expect a ACK or a SYN+ACK. */\r
-       uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;\r
-       if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
-       {\r
-               usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;\r
-       }\r
-\r
-       if( ( ucTCPFlags & 0x17u ) != usExpect )\r
-       {\r
-               /* eSYN_RECEIVED: flags 0010 expected, not 0002. */\r
-               /* eSYN_RECEIVED: flags ACK  expected, not SYN. */\r
-               FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",\r
-                       pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",\r
-                       usExpect, ucTCPFlags ) );\r
-               vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
-               pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;\r
-               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-       }\r
-       else\r
-       {\r
-               pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;\r
-               pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;\r
-\r
-               if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
-               {\r
-                       TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );\r
-\r
-                       /* Clear the SYN flag in lastPacket. */\r
-                       pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;\r
-\r
-                       /* This socket was the one connecting actively so now perofmr the\r
-                       synchronisation. */\r
-                       vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,\r
-                               ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );\r
-                       pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
-                       pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */\r
-                       pxTCPWindow->ulNextTxSequenceNumber++;\r
-               }\r
-               else if( ulReceiveLength == 0u )\r
-               {\r
-                       pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;\r
-               }\r
-\r
-               /* The SYN+ACK has been confirmed, increase the next sequence number by\r
-               1. */\r
-               pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;\r
-\r
-               #if( ipconfigUSE_TCP_WIN == 1 )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",\r
-                               pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",\r
-                               pxSocket->usLocalPort,\r
-                               pxSocket->u.xTCP.ulRemoteIP,\r
-                               pxSocket->u.xTCP.usRemotePort,\r
-                               ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );\r
-               }\r
-               #endif /* ipconfigUSE_TCP_WIN */\r
-\r
-               if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )\r
-               {\r
-                       pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
-                       xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-                       pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-               }\r
-               #if( ipconfigUSE_TCP_WIN != 0 )\r
-               {\r
-                       if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* The other party did not send a scaling factor.\r
-                               A shifting factor in this side must be canceled. */\r
-                               pxSocket->u.xTCP.ucMyWinScaleFactor = 0;\r
-                               pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;\r
-                       }\r
-               }\r
-               #endif /* ipconfigUSE_TCP_WIN */\r
-               /* This was the third step of connecting: SYN, SYN+ACK, ACK     so now the\r
-               connection is established. */\r
-               vTCPStateChange( pxSocket, eESTABLISHED );\r
-       }\r
-\r
-       return xSendLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvHandleEstablished(): called from prvTCPHandleState()\r
- *\r
- * Called if the status is eESTABLISHED.  Data reception has been handled\r
- * earlier.  Here the ACK's from peer will be checked, and if a FIN is received,\r
- * the code will check if it may be accepted, i.e. if all expected data has been\r
- * completely received.\r
- */\r
-static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
-uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;\r
-BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;\r
-int32_t lDistance, lSendResult;\r
-\r
-       /* Remember the window size the peer is advertising. */\r
-       pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );\r
-       #if( ipconfigUSE_TCP_WIN != 0 )\r
-       {\r
-               pxSocket->u.xTCP.ulWindowSize =\r
-                       ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
-       }\r
-       #endif\r
-\r
-       if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )\r
-       {\r
-               ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );\r
-\r
-               /* ulTCPWindowTxAck() returns the number of bytes which have been acked,\r
-               starting at 'tx.ulCurrentSequenceNumber'.  Advance the tail pointer in\r
-               txStream. */\r
-               if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )\r
-               {\r
-                       /* Just advancing the tail index, 'ulCount' bytes have been\r
-                       confirmed, and because there is new space in the txStream, the\r
-                       user/owner should be woken up. */\r
-                       /* _HT_ : only in case the socket's waiting? */\r
-                       if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )\r
-                       {\r
-                               pxSocket->xEventBits |= eSOCKET_SEND;\r
-\r
-                               #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
-                               {\r
-                                       if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )\r
-                                       {\r
-                                               pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
-                                       }\r
-                               }\r
-                               #endif\r
-                               /* In case the socket owner has installed an OnSent handler,\r
-                               call it now. */\r
-                               #if( ipconfigUSE_CALLBACKS == 1 )\r
-                               {\r
-                                       if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )\r
-                                       {\r
-                                               pxSocket->u.xTCP.pxHandleSent( ( Socket_t )pxSocket, ulCount );\r
-                                       }\r
-                               }\r
-                               #endif /* ipconfigUSE_CALLBACKS == 1  */\r
-                       }\r
-               }\r
-       }\r
-\r
-       /* If this socket has a stream for transmission, add the data to the\r
-       outgoing segment(s). */\r
-       if( pxSocket->u.xTCP.txStream != NULL )\r
-       {\r
-               prvTCPAddTxData( pxSocket );\r
-       }\r
-\r
-       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
-\r
-       if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )\r
-       {\r
-               /* Peer is requesting to stop, see if we're really finished. */\r
-               xMayClose = pdTRUE;\r
-\r
-               /* Checks are only necessary if we haven't sent a FIN yet. */\r
-               if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
-               {\r
-                       /* xTCPWindowTxDone returns true when all Tx queues are empty. */\r
-                       bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );\r
-                       bTxDone  = xTCPWindowTxDone( pxTCPWindow );\r
-\r
-                       if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )\r
-                       {\r
-                               /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */\r
-                               FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",\r
-                                       pxSocket->usLocalPort,\r
-                                       pxSocket->u.xTCP.usRemotePort,\r
-                                       bRxComplete, bTxDone ) );\r
-                               xMayClose = pdFALSE;\r
-                       }\r
-                       else\r
-                       {\r
-                               lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
-\r
-                               if( lDistance > 1 )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",\r
-                                               lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
-                                               pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
-\r
-                                       xMayClose = pdFALSE;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if( xTCPWindowLoggingLevel > 0 )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",\r
-                               xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,\r
-                               pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );\r
-               }\r
-\r
-               if( xMayClose != pdFALSE )\r
-               {\r
-                       pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;\r
-                       xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
-               }\r
-       }\r
-\r
-       if( xMayClose == pdFALSE )\r
-       {\r
-               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
-\r
-               if( ulReceiveLength != 0u )\r
-               {\r
-                       xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-                       /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */\r
-                       pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-\r
-                       if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )\r
-                       {\r
-                               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
-                       }\r
-               }\r
-\r
-               /* Now get data to be transmitted. */\r
-               /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP\r
-               can not send-out both TCP options and also a full packet. Sending\r
-               options (SACK) is always more urgent than sending data, which can be\r
-               sent later. */\r
-               if( uxOptionsLength == 0u )\r
-               {\r
-                       /* prvTCPPrepareSend might allocate a bigger network buffer, if\r
-                       necessary. */\r
-                       lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );\r
-                       if( lSendResult > 0 )\r
-                       {\r
-                               xSendLength = ( BaseType_t ) lSendResult;\r
-                       }\r
-               }\r
-       }\r
-\r
-       return xSendLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Called from prvTCPHandleState().  There is data to be sent.  If\r
- * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be\r
- * checked if it would better be postponed for efficiency.\r
- */\r
-static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
-       uint32_t ulReceiveLength, BaseType_t xSendLength )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
-TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
-/* Find out what window size we may advertised. */\r
-int32_t lRxSpace;\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )\r
-               const int32_t lMinLength = 0;\r
-       #else\r
-               int32_t lMinLength;\r
-       #endif\r
-#endif\r
-\r
-       /* Set the time-out field, so that we'll be called by the IP-task in case no\r
-       next message will be received. */\r
-       lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
-       #if ipconfigUSE_TCP_WIN == 1\r
-       {\r
-\r
-               #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )\r
-               {\r
-                       lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );\r
-               }\r
-               #endif /* ipconfigTCP_ACK_EARLIER_PACKET */\r
-\r
-               /* In case we're receiving data continuously, we might postpone sending\r
-               an ACK to gain performance. */\r
-               if( ( ulReceiveLength > 0 ) &&                                                  /* Data was sent to this socket. */\r
-                       ( lRxSpace >= lMinLength ) &&                                           /* There is Rx space for more data. */\r
-                       ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) &&       /* Not in a closure phase. */\r
-                       ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */\r
-                       ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) &&      /* Connection established. */\r
-                       ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) )         /* There are no other flags than an ACK. */\r
-               {\r
-                       if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
-                       {\r
-                               /* There was still a delayed in queue, delete it. */\r
-                               if( pxSocket->u.xTCP.pxAckMessage != 0 )\r
-                               {\r
-                                       vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
-                               }\r
-\r
-                               pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;\r
-                       }\r
-                       if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) ||     /* Received a small message. */\r
-                               ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */\r
-                       {\r
-                               pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Normally a delayed ACK should wait 200 ms for a next incoming\r
-                               packet.  Only wait 20 ms here to gain performance.  A slow ACK\r
-                               for full-size message. */\r
-                               pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );\r
-                       }\r
-\r
-                       if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",\r
-                                       pxSocket->usLocalPort,\r
-                                       pxSocket->u.xTCP.usRemotePort,\r
-                                       pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
-                                       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                                       xSendLength,\r
-                                       pxSocket->u.xTCP.usTimeout, lRxSpace ) );\r
-                       }\r
-\r
-                       *ppxNetworkBuffer = NULL;\r
-                       xSendLength = 0;\r
-               }\r
-               else if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
-               {\r
-                       /* As an ACK is not being delayed, remove any earlier delayed ACK\r
-                       message. */\r
-                       if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
-                       {\r
-                               vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
-                       }\r
-\r
-                       pxSocket->u.xTCP.pxAckMessage = NULL;\r
-               }\r
-       }\r
-       #else\r
-       {\r
-               /* Remove compiler warnings. */\r
-               ( void ) ulReceiveLength;\r
-               ( void ) pxTCPHeader;\r
-               ( void ) lRxSpace;\r
-       }\r
-       #endif /* ipconfigUSE_TCP_WIN */\r
-\r
-       if( xSendLength != 0 )\r
-       {\r
-               if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",\r
-                               pxSocket->usLocalPort,\r
-                               pxSocket->u.xTCP.usRemotePort,\r
-                               pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
-                               pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
-                               xSendLength ) );\r
-               }\r
-\r
-               /* Set the parameter 'xReleaseAfterSend' to the value of\r
-               ipconfigZERO_COPY_TX_DRIVER. */\r
-               prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       /* The driver has taken ownership of the Network Buffer. */\r
-                       *ppxNetworkBuffer = NULL;\r
-               }\r
-               #endif\r
-       }\r
-\r
-       return xSendLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * prvTCPHandleState()\r
- * is the most important function of this TCP stack\r
- * We've tried to keep it (relatively short) by putting a lot of code in\r
- * the static functions above:\r
- *\r
- *             prvCheckRxData()\r
- *             prvStoreRxData()\r
- *             prvSetOptions()\r
- *             prvHandleSynReceived()\r
- *             prvHandleEstablished()\r
- *             prvSendData()\r
- *\r
- * As these functions are declared static, and they're called from one location\r
- * only, most compilers will inline them, thus avoiding a call and return.\r
- */\r
-static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )\r
-{\r
-TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
-TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
-BaseType_t xSendLength = 0;\r
-uint32_t ulReceiveLength;      /* Number of bytes contained in the TCP message. */\r
-uint8_t *pucRecvData;\r
-uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);\r
-\r
-       /* uxOptionsLength: the size of the options to be sent (always a multiple of\r
-       4 bytes)\r
-       1. in the SYN phase, we shall communicate the MSS\r
-       2. in case of a SACK, Selective ACK, ack a segment which comes in\r
-       out-of-order. */\r
-UBaseType_t uxOptionsLength = 0u;\r
-uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
-TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
-\r
-       /* First get the length and the position of the received data, if any.\r
-       pucRecvData will point to the first byte of the TCP payload. */\r
-       ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );\r
-\r
-       if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )\r
-       {\r
-               if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )\r
-               {\r
-                       /* This is most probably a keep-alive message from peer.  Setting\r
-                       'bWinChange' doesn't cause a window-size-change, the flag is used\r
-                       here to force sending an immediate ACK. */\r
-                       pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
-               }\r
-       }\r
-\r
-       /* Keep track of the highest sequence number that might be expected within\r
-       this connection. */\r
-       if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )\r
-       {\r
-               pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
-       }\r
-\r
-       /* Storing data may result in a fatal error if malloc() fails. */\r
-       if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )\r
-       {\r
-               xSendLength = -1;\r
-       }\r
-       else\r
-       {\r
-               uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );\r
-\r
-               if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );\r
-\r
-                       /* In eSYN_RECEIVED a simple ACK is expected, but apparently the\r
-                       'SYN+ACK' didn't arrive.  Step back to the previous state in which\r
-                       a first incoming SYN is handled.  The SYN was counted already so\r
-                       decrease it first. */\r
-                       vTCPStateChange( pxSocket, eSYN_FIRST );\r
-               }\r
-\r
-               if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )\r
-               {\r
-                       /* It's the first time a FIN has been received, remember its\r
-                       sequence number. */\r
-                       pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
-                       pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;\r
-\r
-                       /* Was peer the first one to send a FIN? */\r
-                       if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* If so, don't send the-last-ACK. */\r
-                               pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;\r
-                       }\r
-               }\r
-\r
-               switch (pxSocket->u.xTCP.ucTCPState)\r
-               {\r
-               case eCLOSED:           /* (server + client) no connection state at all. */\r
-                       /* Nothing to do for a closed socket, except waiting for the\r
-                       owner. */\r
-                       break;\r
-\r
-               case eTCP_LISTEN:       /* (server) waiting for a connection request from\r
-                                                       any remote TCP and port. */\r
-                       /* The listen state was handled in xProcessReceivedTCPPacket().\r
-                       Should not come here. */\r
-                       break;\r
-\r
-               case eSYN_FIRST:        /* (server) Just received a SYN request for a server\r
-                                                       socket. */\r
-                       {\r
-                               /* A new socket has been created, reply with a SYN+ACK.\r
-                               Acknowledge with seq+1 because the SYN is seen as pseudo data\r
-                               with len = 1. */\r
-                               uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );\r
-                               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;\r
-\r
-                               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
-\r
-                               /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and\r
-                               uxOptionsLength is a multiple of 4.  The complete expression is:\r
-                               ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */\r
-                               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
-                               vTCPStateChange( pxSocket, eSYN_RECEIVED );\r
-\r
-                               pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
-                               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */\r
-                       }\r
-                       break;\r
-\r
-               case eCONNECT_SYN:      /* (client) also called SYN_SENT: we've just send a\r
-                                                       SYN, expect     a SYN+ACK and send a ACK now. */\r
-                       /* Fall through */\r
-               case eSYN_RECEIVED:     /* (server) we've had a SYN, replied with SYN+SCK\r
-                                                       expect a ACK and do nothing. */\r
-                       xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
-                       break;\r
-\r
-               case eESTABLISHED:      /* (server + client) an open connection, data\r
-                                                       received can be delivered to the user. The normal\r
-                                                       state for the data transfer phase of the connection\r
-                                                       The closing states are also handled here with the\r
-                                                       use of some flags. */\r
-                       xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
-                       break;\r
-\r
-               case eLAST_ACK:         /* (server + client) waiting for an acknowledgement\r
-                                                       of the connection termination request previously\r
-                                                       sent to the remote TCP (which includes an\r
-                                                       acknowledgement of its connection termination\r
-                                                       request). */\r
-                       /* Fall through */\r
-               case eFIN_WAIT_1:       /* (server + client) waiting for a connection termination request from the remote TCP,\r
-                                                        * or an acknowledgement of the connection termination request previously sent. */\r
-                       /* Fall through */\r
-               case eFIN_WAIT_2:       /* (server + client) waiting for a connection termination request from the remote TCP. */\r
-                       xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
-                       break;\r
-\r
-               case eCLOSE_WAIT:       /* (server + client) waiting for a connection\r
-                                                       termination request from the local user.  Nothing to\r
-                                                       do, connection is closed, wait for owner to close\r
-                                                       this socket. */\r
-                       break;\r
-\r
-               case eCLOSING:          /* (server + client) waiting for a connection\r
-                                                       termination request acknowledgement from the remote\r
-                                                       TCP. */\r
-                       break;\r
-\r
-               case eTIME_WAIT:        /* (either server or client) waiting for enough time\r
-                                                       to pass to be sure the remote TCP received the\r
-                                                       acknowledgement of its connection termination\r
-                                                       request. [According to RFC 793 a connection can stay\r
-                                                       in TIME-WAIT for a maximum of four minutes known as\r
-                                                       a MSL (maximum segment lifetime).]  These states are\r
-                                                       implemented implicitly by settings flags like\r
-                                                       'bFinSent', 'bFinRecv', and 'bFinAcked'. */\r
-                       break;\r
-               default:\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if( xSendLength > 0 )\r
-       {\r
-               xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );\r
-       }\r
-\r
-       return xSendLength;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,\r
-                                                 uint8_t ucTCPFlags )\r
-{\r
-#if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )\r
-    {\r
-        TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
-        const BaseType_t xSendLength = ( BaseType_t )\r
-            ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */\r
-\r
-        pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;\r
-        pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;\r
-\r
-        prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE );\r
-    }\r
-#endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */\r
-\r
-    /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */\r
-    ( void )pxNetworkBuffer;\r
-    ( void )ucTCPFlags;\r
-\r
-    /* The packet was not consumed. */\r
-    return pdFAIL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-    return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-    return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,\r
-                                          ipTCP_FLAG_ACK | ipTCP_FLAG_RST );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-uint32_t ulMSS = ipconfigTCP_MSS;\r
-\r
-       if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )\r
-       {\r
-               /* Data for this peer will pass through a router, and maybe through\r
-               the internet.  Limit the MSS to 1400 bytes or less. */\r
-               ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );\r
-       }\r
-\r
-       FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );\r
-\r
-       pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- *     FreeRTOS_TCP_IP has only 2 public functions, this is the second one:\r
- *     xProcessReceivedTCPPacket()\r
- *             prvTCPHandleState()\r
- *                     prvTCPPrepareSend()\r
- *                             prvTCPReturnPacket()\r
- *                             xNetworkInterfaceOutput()       // Sends data to the NIC\r
- *             prvTCPSendRepeated()\r
- *                     prvTCPReturnPacket()            // Prepare for returning\r
- *                     xNetworkInterfaceOutput()       // Sends data to the NIC\r
-*/\r
-BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-FreeRTOS_Socket_t *pxSocket;\r
-TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-uint16_t ucTCPFlags;\r
-uint32_t ulLocalIP;\r
-uint16_t xLocalPort;\r
-uint32_t ulRemoteIP;\r
-uint16_t xRemotePort;\r
-uint32_t ulSequenceNumber;\r
-uint32_t ulAckNumber;\r
-BaseType_t xResult = pdPASS;\r
-configASSERT(pxNetworkBuffer);\r
-configASSERT(pxNetworkBuffer->pucEthernetBuffer);\r
-\r
-       /* Check for a minimum packet size. */\r
-       if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )\r
-       {\r
-               ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;\r
-               ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );\r
-               xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );\r
-               ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
-               xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
-        ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
-        ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr );\r
-\r
-               /* Find the destination socket, and if not found: return a socket listing to\r
-               the destination PORT. */\r
-               pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );\r
-       }\r
-       else\r
-       {\r
-               return pdFAIL;\r
-       }\r
-\r
-       if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )\r
-       {\r
-               /* A TCP messages is received but either there is no socket with the\r
-               given port number or the there is a socket, but it is in one of these\r
-               non-active states:  eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or\r
-               eTIME_WAIT. */\r
-\r
-               FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );\r
-\r
-               /* Send a RST to all packets that can not be handled.  As a result\r
-               the other party will get a ECONN error.  There are two exceptions:\r
-               1) A packet that already has the RST flag set.\r
-               2) A packet that only has the ACK flag set.\r
-               A packet with only the ACK flag set might be the last ACK in\r
-               a three-way hand-shake that closes a connection. */\r
-               if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&\r
-                       ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )\r
-               {\r
-                       prvTCPSendReset( pxNetworkBuffer );\r
-               }\r
-\r
-               /* The packet can't be handled. */\r
-               xResult = pdFAIL;\r
-       }\r
-       else\r
-       {\r
-               pxSocket->u.xTCP.ucRepCount = 0u;\r
-\r
-               if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )\r
-               {\r
-                       /* The matching socket is in a listening state.  Test if the peer\r
-                       has set the SYN flag. */\r
-                       if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )\r
-                       {\r
-                               /* What happens: maybe after a reboot, a client doesn't know the\r
-                               connection had gone.  Send a RST in order to get a new connect\r
-                               request. */\r
-                               #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
-                               {\r
-                               FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",\r
-                                       prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );\r
-                               }\r
-                               #endif /* ipconfigHAS_DEBUG_PRINTF */\r
-\r
-                               if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )\r
-                               {\r
-                                       prvTCPSendReset( pxNetworkBuffer );\r
-                               }\r
-                               xResult = pdFAIL;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* prvHandleListen() will either return a newly created socket\r
-                               (if bReuseSocket is false), otherwise it returns the current\r
-                               socket which will later get connected. */\r
-                               pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );\r
-\r
-                               if( pxSocket == NULL )\r
-                               {\r
-                                       xResult = pdFAIL;\r
-                               }\r
-                       }\r
-               }       /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */\r
-               else\r
-               {\r
-                       /* This is not a socket in listening mode. Check for the RST\r
-                       flag. */\r
-                       if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )\r
-                       {\r
-                FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );\r
-\r
-                /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */\r
-                if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
-                {\r
-                    /* Per the above RFC, "In the SYN-SENT state ... the RST is\r
-                    acceptable if the ACK field acknowledges the SYN." */\r
-                    if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 )\r
-                    {\r
-                        vTCPStateChange( pxSocket, eCLOSED );\r
-                    }\r
-                }\r
-                else\r
-                {\r
-                    /* Check whether the packet matches the next expected sequence number. */\r
-                    if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber )\r
-                    {\r
-                        vTCPStateChange( pxSocket, eCLOSED );\r
-                    }\r
-                    /* Otherwise, check whether the packet is within the receive window. */\r
-                    else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber &&\r
-                             ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber +\r
-                                                  pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) )\r
-                    {\r
-                        /* Send a challenge ACK. */\r
-                        prvTCPSendChallengeAck( pxNetworkBuffer );\r
-                    }\r
-                }\r
-\r
-                /* Otherwise, do nothing. In any case, the packet cannot be handled. */\r
-                               xResult = pdFAIL;\r
-                       }\r
-                       else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )\r
-                       {\r
-                               /* SYN flag while this socket is already connected. */\r
-                               FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );\r
-\r
-                               /* The packet cannot be handled. */\r
-                               xResult = pdFAIL;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Update the copy of the TCP header only (skipping eth and IP\r
-                               headers).  It might be used later on, whenever data must be sent\r
-                               to the peer. */\r
-                               const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );\r
-                               memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );\r
-                       }\r
-               }\r
-       }\r
-\r
-       if( xResult != pdFAIL )\r
-       {\r
-               /* Touch the alive timers because we received a message for this\r
-               socket. */\r
-               prvTCPTouchSocket( pxSocket );\r
-\r
-               /* Parse the TCP option(s), if present. */\r
-               /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,\r
-               then we MUST assume an MSS size of 536 bytes for backward compatibility. */\r
-\r
-               /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as\r
-               the number 5 (words) in the higher niblle of the TCP-offset byte. */\r
-               if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )\r
-               {\r
-                       prvCheckOptions( pxSocket, pxNetworkBuffer );\r
-               }\r
-\r
-\r
-               #if( ipconfigUSE_TCP_WIN == 1 )\r
-               {\r
-                       pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );\r
-                       pxSocket->u.xTCP.ulWindowSize =\r
-                               ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
-               }\r
-               #endif\r
-\r
-               /* In prvTCPHandleState() the incoming messages will be handled\r
-               depending on the current state of the connection. */\r
-               if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )\r
-               {\r
-                       /* prvTCPHandleState() has sent a message, see if there are more to\r
-                       be transmitted. */\r
-                       #if( ipconfigUSE_TCP_WIN == 1 )\r
-                       {\r
-                               prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );\r
-                       }\r
-                       #endif /* ipconfigUSE_TCP_WIN */\r
-               }\r
-\r
-               if( pxNetworkBuffer != NULL )\r
-               {\r
-                       /* We must check if the buffer is unequal to NULL, because the\r
-                       socket might keep a reference to it in case a delayed ACK must be\r
-                       sent. */\r
-                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-                       pxNetworkBuffer = NULL;\r
-               }\r
-\r
-               /* And finally, calculate when this socket wants to be woken up. */\r
-               prvTCPNextTimeout ( pxSocket );\r
-               /* Return pdPASS to tell that the network buffer is 'consumed'. */\r
-               xResult = pdPASS;\r
-       }\r
-\r
-       /* pdPASS being returned means the buffer has been consumed. */\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
-{\r
-TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-FreeRTOS_Socket_t *pxReturn = NULL;\r
-uint32_t ulInitialSequenceNumber;\r
-\r
-       /* Assume that a new Initial Sequence Number will be required. Request\r
-       it now in order to fail out if necessary. */\r
-       ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,\r
-                                                                                                                                 pxSocket->usLocalPort,\r
-                                                                                                                                 pxTCPPacket->xIPHeader.ulSourceIPAddress,\r
-                                                                                                                                 pxTCPPacket->xTCPHeader.usSourcePort );\r
-\r
-       /* A pure SYN (without ACK) has come in, create a new socket to answer\r
-       it. */\r
-       if( 0 != ulInitialSequenceNumber )\r
-       {\r
-               if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
-               {\r
-                       /* The flag bReuseSocket indicates that the same instance of the\r
-                       listening socket should be used for the connection. */\r
-                       pxReturn = pxSocket;\r
-                       pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
-                       pxSocket->u.xTCP.pxPeerSocket = pxSocket;\r
-               }\r
-               else\r
-               {\r
-                       /* The socket does not have the bReuseSocket flag set meaning create a\r
-                       new socket when a connection comes in. */\r
-                       pxReturn = NULL;\r
-\r
-                       if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )\r
-                       {\r
-                               FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",\r
-                                       pxSocket->usLocalPort,\r
-                                       pxSocket->u.xTCP.usChildCount,\r
-                                       pxSocket->u.xTCP.usBacklog,\r
-                                       pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );\r
-                               prvTCPSendReset( pxNetworkBuffer );\r
-                       }\r
-                       else\r
-                       {\r
-                               FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )\r
-                                       FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );\r
-\r
-                               if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );\r
-                                       prvTCPSendReset( pxNetworkBuffer );\r
-                               }\r
-                               else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )\r
-                               {\r
-                                       /* The socket will be connected immediately, no time for the\r
-                                       owner to setsockopt's, therefore copy properties of the server\r
-                                       socket to the new socket.  Only the binding might fail (due to\r
-                                       lack of resources). */\r
-                                       pxReturn = pxNewSocket;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) )\r
-       {\r
-               pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
-               pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
-               pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;\r
-\r
-               /* Here is the SYN action. */\r
-               pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
-               prvSocketSetMSS( pxReturn );\r
-\r
-               prvTCPCreateWindow( pxReturn );\r
-\r
-               vTCPStateChange( pxReturn, eSYN_FIRST );\r
-\r
-               /* Make a copy of the header up to the TCP header.  It is needed later\r
-               on, whenever data must be sent to the peer. */\r
-               memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );\r
-       }\r
-       return pxReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Duplicates a socket after a listening socket receives a connection.\r
- */\r
-static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )\r
-{\r
-struct freertos_sockaddr xAddress;\r
-\r
-       pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;\r
-       pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;\r
-       pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;\r
-       pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;\r
-       pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;\r
-       pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;\r
-       pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;\r
-       pxNewSocket->u.xTCP.uxRxWinSize  = pxSocket->u.xTCP.uxRxWinSize;\r
-       pxNewSocket->u.xTCP.uxTxWinSize  = pxSocket->u.xTCP.uxTxWinSize;\r
-\r
-       #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )\r
-       {\r
-               pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;\r
-       }\r
-       #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */\r
-\r
-       #if( ipconfigUSE_CALLBACKS == 1 )\r
-       {\r
-               /* In case call-backs are used, copy them from parent to child. */\r
-               pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;\r
-               pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;\r
-               pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;\r
-       }\r
-       #endif /* ipconfigUSE_CALLBACKS */\r
-\r
-       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
-       {\r
-               /* Child socket of listening sockets will inherit the Socket Set\r
-               Otherwise the owner has no chance of including it into the set. */\r
-               if( pxSocket->pxSocketSet )\r
-               {\r
-                       pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;\r
-                       pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;\r
-               }\r
-       }\r
-       #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
-\r
-       /* And bind it to the same local port as its parent. */\r
-       xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;\r
-       xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );\r
-\r
-       #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
-       {\r
-               /* Only when there is anti-hanging protection, a socket may become an\r
-               orphan temporarily.  Once this socket is really connected, the owner of\r
-               the server socket will be notified. */\r
-\r
-               /* When bPassQueued is true, the socket is an orphan until it gets\r
-               connected. */\r
-               pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
-               pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;\r
-       }\r
-       #else\r
-       {\r
-               /* A reference to the new socket may be stored and the socket is marked\r
-               as 'passable'. */\r
-\r
-               /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to\r
-               accept(). */\r
-               pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
-               if(pxSocket->u.xTCP.pxPeerSocket == NULL )\r
-               {\r
-                       pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;\r
-               }\r
-       }\r
-       #endif\r
-\r
-       pxSocket->u.xTCP.usChildCount++;\r
-\r
-       FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",\r
-               pxSocket->usLocalPort,\r
-               pxSocket->u.xTCP.usChildCount,\r
-               pxSocket->u.xTCP.usBacklog,\r
-               pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );\r
-\r
-       /* Now bind the child socket to the same port as the listening socket. */\r
-       if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )\r
-       {\r
-               FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );\r
-               vSocketClose( pxNewSocket );\r
-               return pdFALSE;\r
-       }\r
-\r
-       return pdTRUE;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
-\r
-       const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )\r
-       {\r
-               if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )\r
-               {\r
-                       ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;\r
-               }\r
-               return pcStateNames[ ulState ];\r
-       }\r
-\r
-#endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * In the API accept(), the user asks is there is a new client?  As API's can\r
- * not walk through the xBoundTCPSocketsList the IP-task will do this.\r
- */\r
-BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )\r
-{\r
-TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
-ListItem_t *pxIterator;\r
-FreeRTOS_Socket_t *pxFound;\r
-BaseType_t xResult = pdFALSE;\r
-\r
-       /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one\r
-       who has access. */\r
-       for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );\r
-               pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );\r
-               pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )\r
-       {\r
-               if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )\r
-               {\r
-                       pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
-                       if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
-                       {\r
-                               pxSocket->u.xTCP.pxPeerSocket = pxFound;\r
-                               FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );\r
-                               xResult = pdTRUE;\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#endif /* ipconfigUSE_TCP == 1 */\r
-\r
-/* Provide access to private members for testing. */\r
-#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS\r
-       #include "iot_freertos_tcp_test_access_tcp_define.h"\r
-#endif\r
-\r
-/* Provide access to private members for verification. */\r
-#ifdef FREERTOS_TCP_ENABLE_VERIFICATION\r
-       #include "aws_freertos_tcp_verification_access_tcp_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
+ */
+
+/*
+ * FreeRTOS_TCP_IP.c
+ * Module which handles the TCP connections for FreeRTOS+TCP.
+ * It depends on  FreeRTOS_TCP_WIN.c, which handles the TCP windowing
+ * schemes.
+ *
+ * Endianness: in this module all ports and IP addresses are stored in
+ * host byte-order, except fields in the IP-packets
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.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_UDP_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_TCP_WIN.h"
+
+
+/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
+#if ipconfigUSE_TCP == 1
+
+/* This compile-time test was moved to here because some macro's
+were unknown within 'FreeRTOSIPConfigDefaults.h'.  It tests whether
+the defined MTU size can contain at least a complete TCP packet. */
+
+#if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
+       #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
+#endif
+
+/*
+ * The meaning of the TCP flags:
+ */
+#define ipTCP_FLAG_FIN                 0x0001u /* No more data from sender */
+#define ipTCP_FLAG_SYN                 0x0002u /* Synchronize sequence numbers */
+#define ipTCP_FLAG_RST                 0x0004u /* Reset the connection */
+#define ipTCP_FLAG_PSH                 0x0008u /* Push function: please push buffered data to the recv application */
+#define ipTCP_FLAG_ACK                 0x0010u /* Acknowledgment field is significant */
+#define ipTCP_FLAG_URG                 0x0020u /* Urgent pointer field is significant */
+#define ipTCP_FLAG_ECN                 0x0040u /* ECN-Echo */
+#define ipTCP_FLAG_CWR                 0x0080u /* Congestion Window Reduced */
+#define ipTCP_FLAG_NS                  0x0100u /* ECN-nonce concealment protection */
+#define ipTCP_FLAG_RSV                 0x0E00u /* Reserved, keep 0 */
+
+/* A mask to filter all protocol flags. */
+#define ipTCP_FLAG_CTRL                        0x001Fu
+
+/*
+ * A few values of the TCP options:
+ */
+#define TCP_OPT_END                            0u   /* End of TCP options list */
+#define TCP_OPT_NOOP                   1u   /* "No-operation" TCP option */
+#define TCP_OPT_MSS                            2u   /* Maximum segment size TCP option */
+#define TCP_OPT_WSOPT                  3u   /* TCP Window Scale Option (3-byte long) */
+#define TCP_OPT_SACK_P                 4u   /* Advertize that SACK is permitted */
+#define TCP_OPT_SACK_A                 5u   /* SACK option with first/last */
+#define TCP_OPT_TIMESTAMP              8u   /* Time-stamp option */
+
+#define TCP_OPT_MSS_LEN                        4u   /* Length of TCP MSS option. */
+#define TCP_OPT_WSOPT_LEN              3u   /* Length of TCP WSOPT option. */
+
+#define TCP_OPT_TIMESTAMP_LEN  10      /* fixed length of the time-stamp option */
+
+#ifndef ipconfigTCP_ACK_EARLIER_PACKET
+       #define ipconfigTCP_ACK_EARLIER_PACKET          1
+#endif
+
+/*
+ * The macro NOW_CONNECTED() is use to determine if the connection makes a
+ * transition from connected to non-connected and vice versa.
+ * NOW_CONNECTED() returns true when the status has one of these values:
+ * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
+ * Technically the connection status is closed earlier, but the library wants
+ * to prevent that the socket will be deleted before the last ACK has been
+ * and thus causing a 'RST' packet on either side.
+ */
+#define NOW_CONNECTED( status )\
+       ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
+
+/*
+ * The highest 4 bits in the TCP offset byte indicate the total length of the
+ * TCP header, divided by 4.
+ */
+#define VALID_BITS_IN_TCP_OFFSET_BYTE          ( 0xF0u )
+
+/*
+ * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
+ * A normal delay would be 200ms.  Here a much shorter delay of 20 ms is being used to
+ * gain performance.
+ */
+#define DELAYED_ACK_SHORT_DELAY_MS                     ( 2 )
+#define DELAYED_ACK_LONGER_DELAY_MS                    ( 20 )
+
+/*
+ * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
+ * an MSS of 1460 bytes won't be transported through the internet.  The MSS will be reduced
+ * to 1400 bytes.
+ */
+#define REDUCED_MSS_THROUGH_INTERNET           ( 1400 )
+
+/*
+ * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
+ * the number 5 (words) in the higher niblle of the TCP-offset byte.
+ */
+#define TCP_OFFSET_LENGTH_BITS                 ( 0xf0u )
+#define TCP_OFFSET_STANDARD_LENGTH             ( 0x50u )
+
+/*
+ * Each TCP socket is checked regularly to see if it can send data packets.
+ * By default, the maximum number of packets sent during one check is limited to 8.
+ * This amount may be further limited by setting the socket's TX window size.
+ */
+#if( !defined( SEND_REPEATED_COUNT ) )
+       #define SEND_REPEATED_COUNT             ( 8 )
+#endif /* !defined( SEND_REPEATED_COUNT ) */
+
+/*
+ * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
+ * When a TCP timer expires, retries and keep-alive messages will be checked.
+ */
+#ifndef        tcpMAXIMUM_TCP_WAKEUP_TIME_MS
+       #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS           20000u
+#endif
+
+/*
+ * The names of the different TCP states may be useful in logging.
+ */
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+       static const char *pcStateNames[] = {
+               "eCLOSED",
+               "eTCP_LISTEN",
+               "eCONNECT_SYN",
+               "eSYN_FIRST",
+               "eSYN_RECEIVED",
+               "eESTABLISHED",
+               "eFIN_WAIT_1",
+               "eFIN_WAIT_2",
+               "eCLOSE_WAIT",
+               "eCLOSING",
+               "eLAST_ACK",
+               "eTIME_WAIT",
+               "eUNKNOWN",
+};
+#endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
+
+/*
+ * Returns true if the socket must be checked.  Non-active sockets are waiting
+ * for user action, either connect() or close().
+ */
+static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
+
+/*
+ * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
+ */
+static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Try to send a series of messages.
+ */
+static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
+
+/*
+ * Return or send a packet to the other party.
+ */
+static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+       uint32_t ulLen, BaseType_t xReleaseAfterSend );
+
+/*
+ * Initialise the data structures which keep track of the TCP windowing system.
+ */
+static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Let ARP look-up the MAC-address of the peer and initialise the first SYN
+ * packet.
+ */
+static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
+
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+       /*
+        * For logging and debugging: make a string showing the TCP flags.
+        */
+       static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
+#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+/*
+ * Parse the TCP option(s) received, if present.
+ */
+static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Identify and deal with a single TCP header option, advancing the pointer to
+ * the header. This function returns pdTRUE or pdFALSE depending on whether the
+ * caller should continue to parse more header options or break the loop.
+ */
+static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow);
+
+/*
+ * Skip past TCP header options when doing Selective ACK, until there are no
+ * more options left.
+ */
+static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const ppucLen );
+
+/*
+ * Set the initial properties in the options fields, like the preferred
+ * value of MSS and whether SACK allowed.  Will be transmitted in the state
+ * 'eCONNECT_SYN'.
+ */
+static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
+
+/*
+ * For anti-hang protection and TCP keep-alive messages.  Called in two places:
+ * after receiving a packet and after a state change.  The socket's alive timer
+ * may be reset.
+ */
+static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Prepare an outgoing message, if anything has to be sent.
+ */
+static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
+
+/*
+ * Calculate when this socket needs to be checked to do (re-)transmissions.
+ */
+static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * The API FreeRTOS_send() adds data to the TX stream.  Add
+ * this data to the windowing system to it can be transmitted.
+ */
+static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ *  Called to handle the closure of a TCP connection.
+ */
+static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Called from prvTCPHandleState().  Find the TCP payload data and check and
+ * return its length.
+ */
+static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
+
+/*
+ * Called from prvTCPHandleState().  Check if the payload data may be accepted.
+ * If so, it will be added to the socket's reception queue.
+ */
+static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
+       NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
+
+/*
+ * Set the TCP options (if any) for the outgoing packet.
+ */
+static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
+ * eCONNECT_SYN.
+ */
+static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
+
+/*
+ * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
+ */
+static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
+
+/*
+ * Called from prvTCPHandleState().  There is data to be sent.
+ * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
+ * be checked if it would better be postponed for efficiency.
+ */
+static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, BaseType_t xSendLength );
+
+/*
+ * The heart of all: check incoming packet for valid data and acks and do what
+ * is necessary in each state.
+ */
+static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
+
+/*
+ * Common code for sending a TCP protocol control packet (i.e. no options, no
+ * payload, just flags).
+ */
+static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
+                                                 uint8_t ucTCPFlags );
+
+/*
+ * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2,
+ * case #3. In summary, an RST was received with a sequence number that is
+ * unexpected but still within the window.
+ */
+static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Reply to a peer with the RST flag on, in case a packet can not be handled.
+ */
+static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Set the initial value for MSS (Maximum Segment Size) to be used.
+ */
+static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Return either a newly created socket, or the current socket in a connected
+ * state (depends on the 'bReuseSocket' flag).
+ */
+static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * After a listening socket receives a new connection, it may duplicate itself.
+ * The copying takes place in prvTCPSocketCopy.
+ */
+static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
+ * state for too long.  If so, the socket will be closed, and -1 will be
+ * returned.
+ */
+#if( ipconfigTCP_HANG_PROTECTION == 1 )
+       static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
+#endif
+
+static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+       int32_t lDataLen, UBaseType_t uxOptionsLength );
+
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+       const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
+#endif
+
+#if( ipconfigUSE_TCP_WIN != 0 )
+       static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
+#endif
+
+/*
+ * Generate a randomized TCP Initial Sequence Number per RFC.
+ */
+extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
+                                                                                                       uint16_t usSourcePort,
+                                                                                                       uint32_t ulDestinationAddress,
+                                                                                                       uint16_t usDestinationPort );
+
+/*-----------------------------------------------------------*/
+
+/* prvTCPSocketIsActive() returns true if the socket must be checked.
+ * Non-active sockets are waiting for user action, either connect()
+ * or close(). */
+static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
+{
+       switch( uxStatus )
+       {
+       case eCLOSED:
+       case eCLOSE_WAIT:
+       case eFIN_WAIT_2:
+       case eCLOSING:
+       case eTIME_WAIT:
+               return pdFALSE;
+       default:
+               return pdTRUE;
+       }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigTCP_HANG_PROTECTION == 1 )
+
+       static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
+       {
+       BaseType_t xResult;
+               switch( pxSocket->u.xTCP.ucTCPState )
+               {
+               case eESTABLISHED:
+                       /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
+                       state ESTABLISHED can be protected using keep-alive messages. */
+                       xResult = pdFALSE;
+                       break;
+               case eCLOSED:
+               case eTCP_LISTEN:
+               case eCLOSE_WAIT:
+                       /* These 3 states may last for ever, up to the owner. */
+                       xResult = pdFALSE;
+                       break;
+               default:
+                       /* All other (non-connected) states will get anti-hanging
+                       protection. */
+                       xResult = pdTRUE;
+                       break;
+               }
+               if( xResult != pdFALSE )
+               {
+                       /* How much time has past since the last active moment which is
+                       defined as A) a state change or B) a packet has arrived. */
+                       TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
+
+                       /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
+                       if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
+                       {
+                               #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+                               {
+                                       FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
+                                               pxSocket->usLocalPort,
+                                               pxSocket->u.xTCP.ulRemoteIP,
+                                               pxSocket->u.xTCP.usRemotePort,
+                                               FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
+                               }
+                               #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+                               /* Move to eCLOSE_WAIT, user may close the socket. */
+                               vTCPStateChange( pxSocket, eCLOSE_WAIT );
+
+                               /* When 'bPassQueued' true, this socket is an orphan until it
+                               gets connected. */
+                               if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
+                               {
+                                       if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+                                       {
+                                               /* As it did not get connected, and the user can never
+                                               accept() it anymore, it will be deleted now.  Called from
+                                               the IP-task, so it's safe to call the internal Close
+                                               function: vSocketClose(). */
+                                               vSocketClose( pxSocket );
+                                       }
+                                       /* Return a negative value to tell to inform the caller
+                                       xTCPTimerCheck()
+                                       that the socket got closed and may not be accessed anymore. */
+                                       xResult = -1;
+                               }
+                       }
+               }
+               return xResult;
+       }
+       /*-----------------------------------------------------------*/
+
+#endif
+
+/*
+ * As soon as a TCP socket timer expires, this function xTCPSocketCheck
+ * will be called (from xTCPTimerCheck)
+ * It can send a delayed ACK or new data
+ * Sequence of calling (normally) :
+ * IP-Task:
+ *             xTCPTimerCheck()                                // Check all sockets ( declared in FreeRTOS_Sockets.c )
+ *             xTCPSocketCheck()                               // Either send a delayed ACK or call prvTCPSendPacket()
+ *             prvTCPSendPacket()                              // Either send a SYN or call prvTCPSendRepeated ( regular messages )
+ *             prvTCPSendRepeated()                    // Send at most 8 messages on a row
+ *                     prvTCPReturnPacket()            // Prepare for returning
+ *                     xNetworkInterfaceOutput()       // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
+ */
+BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
+{
+BaseType_t xResult = 0;
+BaseType_t xReady = pdFALSE;
+
+       if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
+       {
+               /* The API FreeRTOS_send() might have added data to the TX stream.  Add
+               this data to the windowing system to it can be transmitted. */
+               prvTCPAddTxData( pxSocket );
+       }
+
+       #if ipconfigUSE_TCP_WIN == 1
+       {
+               if( pxSocket->u.xTCP.pxAckMessage != NULL )
+               {
+                       /* The first task of this regular socket check is to send-out delayed
+                       ACK's. */
+                       if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
+                       {
+                               /* Earlier data was received but not yet acknowledged.  This
+                               function is called when the TCP timer for the socket expires, the
+                               ACK may be sent now. */
+                               if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
+                               {
+                                       if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
+                                       {
+                                               FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
+                                                       pxSocket->usLocalPort,
+                                                       pxSocket->u.xTCP.usRemotePort,
+                                                       pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
+                                                       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber   - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
+                                                       ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
+                                       }
+
+                                       prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
+
+                                       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+                                       {
+                                               /* The ownership has been passed to the SEND routine,
+                                               clear the pointer to it. */
+                                               pxSocket->u.xTCP.pxAckMessage = NULL;
+                                       }
+                                       #endif /* ipconfigZERO_COPY_TX_DRIVER */
+                               }
+                               if( prvTCPNextTimeout( pxSocket ) > 1 )
+                               {
+                                       /* Tell the code below that this function is ready. */
+                                       xReady = pdTRUE;
+                               }
+                       }
+                       else
+                       {
+                               /* The user wants to perform an active shutdown(), skip sending
+                               the     delayed ACK.  The function prvTCPSendPacket() will send the
+                               FIN     along with the ACK's. */
+                       }
+
+                       if( pxSocket->u.xTCP.pxAckMessage != NULL )
+                       {
+                               vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+                               pxSocket->u.xTCP.pxAckMessage = NULL;
+                       }
+               }
+       }
+       #endif /* ipconfigUSE_TCP_WIN */
+
+       if( xReady == pdFALSE )
+       {
+               /* The second task of this regular socket check is sending out data. */
+               if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
+                       ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
+               {
+                       prvTCPSendPacket( pxSocket );
+               }
+
+               /* Set the time-out for the next wakeup for this socket. */
+               prvTCPNextTimeout( pxSocket );
+
+               #if( ipconfigTCP_HANG_PROTECTION == 1 )
+               {
+                       /* In all (non-connected) states in which keep-alive messages can not be sent
+                       the anti-hang protocol will close sockets that are 'hanging'. */
+                       xResult = prvTCPStatusAgeCheck( pxSocket );
+               }
+               #endif
+       }
+
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPSendPacket() will be called when the socket time-out has been reached.
+ * It is only called by xTCPSocketCheck().
+ */
+static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
+{
+int32_t lResult = 0;
+UBaseType_t uxOptionsLength;
+TCPPacket_t *pxTCPPacket;
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+       if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
+       {
+               /* The connection is in s state other than SYN. */
+               pxNetworkBuffer = NULL;
+
+               /* prvTCPSendRepeated() will only create a network buffer if necessary,
+               i.e. when data must be sent to the peer. */
+               lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
+
+               if( pxNetworkBuffer != NULL )
+               {
+                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+               }
+       }
+       else
+       {
+               if( pxSocket->u.xTCP.ucRepCount >= 3u )
+               {
+                       /* The connection is in the SYN status. The packet will be repeated
+                       to most 3 times.  When there is no response, the socket get the
+                       status 'eCLOSE_WAIT'. */
+                       FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
+                               pxSocket->u.xTCP.ulRemoteIP,            /* IP address of remote machine. */
+                               pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */
+                       vTCPStateChange( pxSocket, eCLOSE_WAIT );
+               }
+               else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
+               {
+                       /* Or else, if the connection has been prepared, or can be prepared
+                       now, proceed to send the packet with the SYN flag.
+                       prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
+                       the Ethernet address of the peer or the gateway is found. */
+                       pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+
+                       /* About to send a SYN packet.  Call prvSetSynAckOptions() to set
+                       the proper options: The size of MSS and whether SACK's are
+                       allowed. */
+                       uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
+
+                       /* Return the number of bytes to be sent. */
+                       lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+
+                       /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and
+                       uxOptionsLength is always a multiple of 4.  The complete expression
+                       would be:
+                       ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
+                       pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+                       /* Repeat Count is used for a connecting socket, to limit the number
+                       of tries. */
+                       pxSocket->u.xTCP.ucRepCount++;
+
+                       /* Send the SYN message to make a connection.  The messages is
+                       stored in the socket field 'xPacket'.  It will be wrapped in a
+                       pseudo network buffer descriptor before it will be sent. */
+                       prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
+               }
+       }
+
+       /* Return the total number of bytes sent. */
+       return lResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPSendRepeated will try to send a series of messages, as long as there is
+ * data to be sent and as long as the transmit window isn't full.
+ */
+static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
+{
+UBaseType_t uxIndex;
+int32_t lResult = 0;
+UBaseType_t uxOptionsLength = 0u;
+int32_t xSendLength;
+
+       for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
+       {
+               /* prvTCPPrepareSend() might allocate a network buffer if there is data
+               to be sent. */
+               xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
+               if( xSendLength <= 0 )
+               {
+                       break;
+               }
+
+               /* And return the packet to the peer. */
+               prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
+
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       *ppxNetworkBuffer = NULL;
+               }
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+               lResult += xSendLength;
+       }
+
+       /* Return the total number of bytes sent. */
+       return lResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Return (or send) a packet the the peer.  The data is stored in pxBuffer,
+ * which may either point to a real network buffer or to a TCP socket field
+ * called 'xTCP.xPacket'.   A temporary xNetworkBuffer will be used to pass
+ * the data to the NIC.
+ */
+static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
+{
+TCPPacket_t * pxTCPPacket;
+IPHeader_t *pxIPHeader;
+EthernetHeader_t *pxEthernetHeader;
+uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
+TCPWindow_t *pxTCPWindow;
+NetworkBufferDescriptor_t xTempBuffer;
+/* For sending, a pseudo network buffer will be used, as explained above. */
+
+       if( pxNetworkBuffer == NULL )
+       {
+               pxNetworkBuffer = &xTempBuffer;
+
+               #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+               {
+                       xTempBuffer.pxNextBuffer = NULL;
+               }
+               #endif
+               xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+               xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
+               xReleaseAfterSend = pdFALSE;
+       }
+
+       #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+       {
+               if( xReleaseAfterSend == pdFALSE )
+               {
+                       pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
+                       if( pxNetworkBuffer == NULL )
+                       {
+                               FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
+                       }
+                       xReleaseAfterSend = pdTRUE;
+               }
+       }
+       #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+       if( pxNetworkBuffer != NULL )
+       {
+               pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+               pxIPHeader = &pxTCPPacket->xIPHeader;
+               pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
+
+               /* Fill the packet, using hton translations. */
+               if( pxSocket != NULL )
+               {
+                       /* Calculate the space in the RX buffer in order to advertise the
+                       size of this socket's reception window. */
+                       pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
+
+                       if( pxSocket->u.xTCP.rxStream != NULL )
+                       {
+                               /* An RX stream was created already, see how much space is
+                               available. */
+                               ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
+                       }
+                       else
+                       {
+                               /* No RX stream has been created, the full stream size is
+                               available. */
+                               ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
+                       }
+
+                       /* Take the minimum of the RX buffer space and the RX window size. */
+                       ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace );
+
+                       if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
+                       {
+                               /* The low-water mark was reached, meaning there was little
+                               space left.  The socket will wait until the application has read
+                               or flushed the incoming data, and 'zero-window' will be
+                               advertised. */
+                               ulSpace = 0u;
+                       }
+
+                       /* If possible, advertise an RX window size of at least 1 MSS, otherwise
+                       the peer might start 'zero window probing', i.e. sending small packets
+                       (1, 2, 4, 8... bytes). */
+                       if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
+                       {
+                               ulSpace = pxSocket->u.xTCP.usCurMSS;
+                       }
+
+                       /* Avoid overflow of the 16-bit win field. */
+                       #if( ipconfigUSE_TCP_WIN != 0 )
+                       {
+                               ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
+                       }
+                       #else
+                       {
+                               ulWinSize = ulSpace;
+                       }
+                       #endif
+                       if( ulWinSize > 0xfffcUL )
+                       {
+                               ulWinSize = 0xfffcUL;
+                       }
+
+                       pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
+
+                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+                       {
+                               if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
+                               {
+                                       if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
+                                       {
+                                       size_t uxFrontSpace;
+
+                                               if(pxSocket->u.xTCP.rxStream != NULL)
+                                               {
+                                                       uxFrontSpace =  uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
+                                               }
+                                               else
+                                               {
+                                                       uxFrontSpace = 0u;
+                                               }
+
+                                               FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
+                                               pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
+                                                       pxSocket->u.xTCP.ulRemoteIP,
+                                                       pxSocket->u.xTCP.usRemotePort,
+                                                       pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
+                                                       (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
+                                       }
+                               }
+                       }
+                       #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+                       /* The new window size has been advertised, switch off the flag. */
+                       pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
+
+                       /* Later on, when deciding to delay an ACK, a precise estimate is needed
+                       of the free RX space.  At this moment, 'ulHighestRxAllowed' would be the
+                       highest sequence number minus 1 that the socket will accept. */
+                       pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
+
+                       #if( ipconfigTCP_KEEP_ALIVE == 1 )
+                               if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
+                               {
+                                       /* Sending a keep-alive packet, send the current sequence number
+                                       minus 1, which will     be recognised as a keep-alive packet an
+                                       responded to by acknowledging the last byte. */
+                                       pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
+                                       pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
+
+                                       pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
+                                       pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
+                               }
+                               else
+                       #endif
+                       {
+                               pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
+
+                               if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
+                               {
+                                       /* Suppress FIN in case this packet carries earlier data to be
+                                       retransmitted. */
+                                       uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
+                                       if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
+                                       {
+                                               pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
+                                               FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
+                                                       pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                                                       ulDataLen,
+                                                       pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
+                                       }
+                               }
+                       }
+
+                       /* Tell which sequence number is expected next time */
+                       pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
+               }
+               else
+               {
+                       /* Sending data without a socket, probably replying with a RST flag
+                       Just swap the two sequence numbers. */
+                       vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
+               }
+
+               pxIPHeader->ucTimeToLive                   = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
+               pxIPHeader->usLength                       = FreeRTOS_htons( ulLen );
+               if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
+               {
+                       /* When pxSocket is NULL, this function is called by prvTCPSendReset()
+                       and the IP-addresses must be swapped.
+                       Also swap the IP-addresses in case the IP-tack doesn't have an
+                       IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
+                       ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
+               }
+               else
+               {
+                       ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+               }
+               pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
+               pxIPHeader->ulSourceIPAddress = ulSourceAddress;
+               vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
+
+               /* Just an increasing number. */
+               pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
+               usPacketIdentifier++;
+               pxIPHeader->usFragmentOffset = 0u;
+
+               #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+               {
+                       /* calculate the IP header checksum, in case the driver won't do that. */
+                       pxIPHeader->usHeaderChecksum = 0x00u;
+                       pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+                       pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+                       /* calculate the TCP checksum for an outgoing packet. */
+                       usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
+
+                       /* A calculated checksum of 0 must be inverted as 0 means the checksum
+                       is disabled. */
+                       if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
+                       {
+                               pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
+                       }
+               }
+               #endif
+
+       #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+               pxNetworkBuffer->pxNextBuffer = NULL;
+       #endif
+
+               /* Important: tell NIC driver how many bytes must be sent. */
+               pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
+
+               /* Fill in the destination MAC addresses. */
+               memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
+                       sizeof( pxEthernetHeader->xDestinationAddress ) );
+
+               /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
+               memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+               #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+               {
+                       if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+                       {
+                       BaseType_t xIndex;
+
+                               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
+
+               /* Send! */
+               xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
+
+               if( xReleaseAfterSend == pdFALSE )
+               {
+                       /* Swap-back some fields, as pxBuffer probably points to a socket field
+                       containing the packet header. */
+                       vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
+                       pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
+                       memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+               }
+               else
+               {
+                       /* Nothing to do: the buffer has been passed to DMA and will be released after use */
+               }
+       } /* if( pxNetworkBuffer != NULL ) */
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * The SYN event is very important: the sequence numbers, which have a kind of
+ * random starting value, are being synchronised.  The sliding window manager
+ * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
+ * Size (MSS) in use.
+ */
+static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
+{
+       if( xTCPWindowLoggingLevel )
+               FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
+                       pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
+                       pxSocket->u.xTCP.uxLittleSpace ,
+                       pxSocket->u.xTCP.uxEnoughSpace,
+                       pxSocket->u.xTCP.uxRxStreamSize ) );
+       vTCPWindowCreate(
+               &pxSocket->u.xTCP.xTCPWindow,
+               ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
+               ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
+               pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
+               pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
+               ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Connecting sockets have a special state: eCONNECT_SYN.  In this phase,
+ * the Ethernet address of the target will be found using ARP.  In case the
+ * target IP address is not within the netmask, the hardware address of the
+ * gateway will be used.
+ */
+static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
+{
+TCPPacket_t *pxTCPPacket;
+IPHeader_t *pxIPHeader;
+eARPLookupResult_t eReturned;
+uint32_t ulRemoteIP;
+MACAddress_t xEthAddress;
+BaseType_t xReturn = pdTRUE;
+uint32_t ulInitialSequenceNumber = 0;
+
+       #if( ipconfigHAS_PRINTF != 0 )
+       {
+               /* Only necessary for nicer logging. */
+               memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
+       }
+       #endif /* ipconfigHAS_PRINTF != 0 */
+
+       ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
+
+       /* Determine the ARP cache status for the requested IP address. */
+       eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
+
+       switch( eReturned )
+       {
+       case eARPCacheHit:              /* An ARP table lookup found a valid entry. */
+               break;                          /* We can now prepare the SYN packet. */
+       case eARPCacheMiss:             /* An ARP table lookup did not find a valid entry. */
+       case eCantSendPacket:   /* There is no IP address, or an ARP is still in progress. */
+       default:
+               /* Count the number of times it couldn't find the ARP address. */
+               pxSocket->u.xTCP.ucRepCount++;
+
+               FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
+                       pxSocket->u.xTCP.ulRemoteIP,
+                       FreeRTOS_htonl( ulRemoteIP ),
+                       eReturned,
+                       xEthAddress.ucBytes[ 0 ],
+                       xEthAddress.ucBytes[ 1 ],
+                       xEthAddress.ucBytes[ 2 ],
+                       xEthAddress.ucBytes[ 3 ],
+                       xEthAddress.ucBytes[ 4 ],
+                       xEthAddress.ucBytes[ 5 ] ) );
+
+               /* And issue a (new) ARP request */
+               FreeRTOS_OutputARPRequest( ulRemoteIP );
+
+               xReturn = pdFALSE;
+       }
+
+       if( xReturn != pdFALSE )
+       {
+               /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
+               ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
+                                                                                                                                         pxSocket->usLocalPort,
+                                                                                                                                         pxSocket->u.xTCP.ulRemoteIP,
+                                                                                                                                         pxSocket->u.xTCP.usRemotePort );
+
+               /* Check for a random number generation error. */
+               if( 0 == ulInitialSequenceNumber )
+               {
+                       xReturn = pdFALSE;
+               }
+       }
+
+       if( xReturn != pdFALSE )
+       {
+               /* The MAC-address of the peer (or gateway) has been found,
+               now prepare the initial TCP packet and some fields in the socket. */
+               pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+               pxIPHeader = &pxTCPPacket->xIPHeader;
+
+               /* reset the retry counter to zero. */
+               pxSocket->u.xTCP.ucRepCount = 0u;
+
+               /* And remember that the connect/SYN data are prepared. */
+               pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
+
+               /* Now that the Ethernet address is known, the initial packet can be
+               prepared. */
+               memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
+
+               /* Write the Ethernet address in Source, because it will be swapped by
+               prvTCPReturnPacket(). */
+               memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
+
+               /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
+               pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
+
+               pxIPHeader->ucVersionHeaderLength = 0x45u;
+               pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
+               pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
+
+               pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
+
+               /* Addresses and ports will be stored swapped because prvTCPReturnPacket
+               will swap them back while replying. */
+               pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+               pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
+
+               pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
+               pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
+
+               /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
+               isn't known yet. */
+               pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
+
+               /* Start with ISN (Initial Sequence Number). */
+               pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
+
+               /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
+               the high nibble of the TCP offset field. */
+               pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
+
+               /* Only set the SYN flag. */
+               pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
+
+               /* Set the values of usInitMSS / usCurMSS for this socket. */
+               prvSocketSetMSS( pxSocket );
+
+               /* The initial sequence numbers at our side are known.  Later
+               vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
+               first wait for a SYN+ACK reply. */
+               prvTCPCreateWindow( pxSocket );
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+/* For logging and debugging: make a string showing the TCP flags
+*/
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+
+       static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
+       {
+               static char retString[10];
+               snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
+                       ( xFlags & ipTCP_FLAG_FIN )  ? 'F' : '.',       /* 0x0001: No more data from sender */
+                       ( xFlags & ipTCP_FLAG_SYN )  ? 'S' : '.',       /* 0x0002: Synchronize sequence numbers */
+                       ( xFlags & ipTCP_FLAG_RST )  ? 'R' : '.',       /* 0x0004: Reset the connection */
+                       ( xFlags & ipTCP_FLAG_PSH )  ? 'P' : '.',       /* 0x0008: Push function: please push buffered data to the recv application */
+                       ( xFlags & ipTCP_FLAG_ACK )  ? 'A' : '.',       /* 0x0010: Acknowledgment field is significant */
+                       ( xFlags & ipTCP_FLAG_URG )  ? 'U' : '.',       /* 0x0020: Urgent pointer field is significant */
+                       ( xFlags & ipTCP_FLAG_ECN )  ? 'E' : '.',       /* 0x0040: ECN-Echo */
+                       ( xFlags & ipTCP_FLAG_CWR )  ? 'C' : '.',       /* 0x0080: Congestion Window Reduced */
+                       ( xFlags & ipTCP_FLAG_NS )   ? 'N' : '.');      /* 0x0100: ECN-nonce concealment protection */
+               return retString;
+       }
+       /*-----------------------------------------------------------*/
+
+#endif /* ipconfigHAS_DEBUG_PRINTF */
+
+/*
+ * Parse the TCP option(s) received, if present.  It has already been verified
+ * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
+ * is longer than the usual 20 (5 x 4) bytes.
+ */
+static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t * pxTCPPacket;
+TCPHeader_t * pxTCPHeader;
+const unsigned char *pucPtr;
+const unsigned char *pucLast;
+TCPWindow_t *pxTCPWindow;
+BaseType_t xShouldContinueLoop;
+
+       pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+       pxTCPHeader = &pxTCPPacket->xTCPHeader;
+
+       /* A character pointer to iterate through the option data */
+       pucPtr = pxTCPHeader->ucOptdata;
+       pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
+       pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+
+       /* Validate options size calculation. */
+       if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) )
+       {
+               return;
+       }
+
+       /* The comparison with pucLast is only necessary in case the option data are
+       corrupted, we don't like to run into invalid memory and crash. */
+       xShouldContinueLoop = pdTRUE;
+       while( ( pucPtr < pucLast ) && ( xShouldContinueLoop == pdTRUE ) )
+       {
+               xShouldContinueLoop = prvSingleStepTCPHeaderOptions( &pucPtr, &pucLast, &pxSocket, &pxTCPWindow );
+       }
+}
+
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvSingleStepTCPHeaderOptions( const unsigned char ** const ppucPtr, const unsigned char ** const ppucLast, FreeRTOS_Socket_t ** const ppxSocket, TCPWindow_t ** const ppxTCPWindow)
+{
+       UBaseType_t uxNewMSS;
+       UBaseType_t xRemainingOptionsBytes = ( *ppucLast ) - ( *ppucPtr );
+       unsigned char ucLen;
+
+       if( ( *ppucPtr )[ 0 ] == TCP_OPT_END )
+       {
+               /* End of options. */
+               return pdFALSE;
+       }
+       if( ( *ppucPtr )[ 0 ] == TCP_OPT_NOOP)
+       {
+               /* NOP option, inserted to make the length a multiple of 4. */
+               ( *ppucPtr )++;
+               return pdTRUE;
+       }
+
+       /* Any other well-formed option must be at least two bytes: the option
+       type byte followed by a length byte. */
+       if( xRemainingOptionsBytes < 2 )
+       {
+               return pdFALSE;
+       }
+#if( ipconfigUSE_TCP_WIN != 0 )
+       else if( ( *ppucPtr )[ 0 ] == TCP_OPT_WSOPT )
+       {
+               /* Confirm that the option fits in the remaining buffer space. */
+               if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( ( *ppucPtr )[ 1 ] != TCP_OPT_WSOPT_LEN ) )
+               {
+                       return pdFALSE;
+               }
+
+               ( *ppxSocket )->u.xTCP.ucPeerWinScaleFactor = ( *ppucPtr )[ 2 ];
+               ( *ppxSocket )->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
+               ( *ppucPtr ) += TCP_OPT_WSOPT_LEN;
+       }
+#endif /* ipconfigUSE_TCP_WIN */
+       else if( ( *ppucPtr )[ 0 ] == TCP_OPT_MSS )
+       {
+               /* Confirm that the option fits in the remaining buffer space. */
+               if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( ( *ppucPtr )[ 1 ] != TCP_OPT_MSS_LEN ) )
+               {
+                       return pdFALSE;
+               }
+
+               /* An MSS option with the correct option length.  FreeRTOS_htons()
+               is not needed here because usChar2u16() already returns a host
+               endian number. */
+               uxNewMSS = usChar2u16( ( *ppucPtr ) + 2 );
+
+               if( ( *ppxSocket )->u.xTCP.usInitMSS != uxNewMSS )
+               {
+                       /* Perform a basic check on the the new MSS. */
+                       if( uxNewMSS == 0 )
+                       {
+                               return pdFALSE;
+                       }
+
+                       FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", ( *ppxSocket )->u.xTCP.usInitMSS, uxNewMSS ) );
+               }
+
+               if( ( *ppxSocket )->u.xTCP.usInitMSS > uxNewMSS )
+               {
+                       /* our MSS was bigger than the MSS of the other party: adapt it. */
+                       ( *ppxSocket )->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
+                       if( ( ( *ppxTCPWindow ) != NULL ) && ( ( *ppxSocket )->u.xTCP.usCurMSS > uxNewMSS ) )
+                       {
+                               /* The peer advertises a smaller MSS than this socket was
+                               using.  Use that as well. */
+                               FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", ( *ppxSocket )->u.xTCP.usCurMSS, uxNewMSS ) );
+                               ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
+                       }
+                       ( *ppxTCPWindow )->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( ( *ppxTCPWindow )->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
+                       ( *ppxTCPWindow )->usMSSInit = ( uint16_t ) uxNewMSS;
+                       ( *ppxTCPWindow )->usMSS = ( uint16_t ) uxNewMSS;
+                       ( *ppxSocket )->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
+                       ( *ppxSocket )->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
+               }
+
+               #if( ipconfigUSE_TCP_WIN != 1 )
+                       /* Without scaled windows, MSS is the only interesting option. */
+                       return pdFALSE;
+               #else
+                       /* Or else we continue to check another option: selective ACK. */
+                       ( *ppucPtr ) += TCP_OPT_MSS_LEN;
+               #endif  /* ipconfigUSE_TCP_WIN != 1 */
+       }
+       else
+       {
+               /* All other options have a length field, so that we easily
+               can skip past them. */
+               ucLen = ( *ppucPtr )[ 1 ];
+               if( ( ucLen < 2 ) || ( ucLen > xRemainingOptionsBytes ) )
+               {
+                       /* If the length field is too small or too big, the options are
+                        * malformed, don't process them further.
+                        */
+                       return pdFALSE;
+               }
+
+               #if( ipconfigUSE_TCP_WIN == 1 )
+               {
+                       /* Selective ACK: the peer has received a packet but it is missing
+                        * earlier packets. At least this packet does not need retransmission
+                        * anymore. ulTCPWindowTxSack( ) takes care of this administration.
+                        */
+                       if( ( *ppucPtr )[0] == TCP_OPT_SACK_A )
+                       {
+                               ucLen -= 2;
+                               ( *ppucPtr ) += 2;
+
+                               while( ucLen >= 8 )
+                               {
+                                       prvSkipPastRemainingOptions( ppucPtr, ppxSocket, &ucLen );
+                               }
+                               /* ucLen should be 0 by now. */
+                       }
+               }
+               #endif  /* ipconfigUSE_TCP_WIN == 1 */
+
+               ( *ppucPtr ) += ucLen;
+       }
+       return pdTRUE;
+}
+
+/*-----------------------------------------------------------*/
+
+static void prvSkipPastRemainingOptions( const unsigned char ** const ppucPtr, FreeRTOS_Socket_t ** const ppxSocket, unsigned char * const pucLen )
+{
+uint32_t ulFirst = ulChar2u32( ( *ppucPtr ) );
+uint32_t ulLast  = ulChar2u32( ( *ppucPtr ) + 4 );
+uint32_t ulCount = ulTCPWindowTxSack( &( *ppxSocket )->u.xTCP.xTCPWindow, ulFirst, ulLast );
+       /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
+        * starting from the head position.  Advance the tail pointer in txStream.
+        */
+       if( ( ( *ppxSocket )->u.xTCP.txStream  != NULL ) && ( ulCount > 0 ) )
+       {
+               /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
+               uxStreamBufferGet( ( *ppxSocket )->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
+               ( *ppxSocket )->xEventBits |= eSOCKET_SEND;
+
+               #if ipconfigSUPPORT_SELECT_FUNCTION == 1
+               {
+                       if( ( *ppxSocket )->xSelectBits & eSELECT_WRITE )
+                       {
+                               /* The field 'xEventBits' is used to store regular socket events
+                                * (at most 8), as well as 'select events', which will be left-shifted.
+                                */
+                               ( *ppxSocket )->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+                       }
+               }
+               #endif
+
+               /* In case the socket owner has installed an OnSent handler, call it now.
+                */
+               #if( ipconfigUSE_CALLBACKS == 1 )
+               {
+                       if( ipconfigIS_VALID_PROG_ADDRESS( ( *ppxSocket )->u.xTCP.pxHandleSent ) )
+                       {
+                               ( *ppxSocket )->u.xTCP.pxHandleSent( (Socket_t )( *ppxSocket ), ulCount );
+                       }
+               }
+               #endif /* ipconfigUSE_CALLBACKS == 1  */
+       }
+       ( *ppucPtr ) += 8;
+       ( *pucLen ) -= 8;
+}
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN != 0 )
+
+       static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
+       {
+       size_t uxWinSize;
+       uint8_t ucFactor;
+
+               /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
+               uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
+               ucFactor = 0u;
+               while( uxWinSize > 0xfffful )
+               {
+                       /* Divide by two and increase the binary factor by 1. */
+                       uxWinSize >>= 1;
+                       ucFactor++;
+               }
+
+               FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
+                       pxSocket->u.xTCP.uxRxWinSize,
+                       pxSocket->u.xTCP.usInitMSS,
+                       ucFactor ) );
+
+               return ucFactor;
+       }
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * When opening a TCP connection, while SYN's are being sent, the  parties may
+ * communicate what MSS (Maximum Segment Size) they intend to use.   MSS is the
+ * nett size of the payload, always smaller than MTU.
+*/
+static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
+{
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
+UBaseType_t uxOptionsLength;
+
+       /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
+
+       pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
+       pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
+       pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
+       pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
+
+       #if( ipconfigUSE_TCP_WIN != 0 )
+       {
+               pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
+
+               pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
+               pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
+               pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
+               pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
+               uxOptionsLength = 8u;
+       }
+       #else
+       {
+               uxOptionsLength = 4u;
+       }
+       #endif
+
+       #if( ipconfigUSE_TCP_WIN == 0 )
+       {
+               return uxOptionsLength;
+       }
+       #else
+       {
+               pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
+               pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
+               pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
+               pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2;      /* 2: length of this option. */
+               uxOptionsLength += 4u;
+
+               return uxOptionsLength; /* bytes, not words. */
+       }
+       #endif  /* ipconfigUSE_TCP_WIN == 0 */
+}
+
+/*
+ * For anti-hanging protection and TCP keep-alive messages.  Called in two
+ * places: after receiving a packet and after a state change.  The socket's
+ * alive timer may be reset.
+ */
+static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
+{
+       #if( ipconfigTCP_HANG_PROTECTION == 1 )
+       {
+               pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
+       }
+       #endif
+
+       #if( ipconfigTCP_KEEP_ALIVE == 1 )
+       {
+               pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
+               pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
+               pxSocket->u.xTCP.ucKeepRepCount = 0u;
+               pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
+       }
+       #endif
+
+       ( void ) pxSocket;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Changing to a new state. Centralised here to do specific actions such as
+ * resetting the alive timer, calling the user's OnConnect handler to notify
+ * that a socket has got (dis)connected, and setting bit to unblock a call to
+ * FreeRTOS_select()
+ */
+void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
+{
+FreeRTOS_Socket_t *xParent = NULL;
+BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState );      /* Was it connected ? */
+BaseType_t bAfter  = ( BaseType_t ) NOW_CONNECTED( eTCPState );                                                /* Is it connected now ? */
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+       BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
+#endif
+#if( ipconfigUSE_CALLBACKS == 1 )
+       FreeRTOS_Socket_t *xConnected = NULL;
+#endif
+
+       /* Has the connected status changed? */
+       if( bBefore != bAfter )
+       {
+               /* Is the socket connected now ? */
+               if( bAfter != pdFALSE )
+               {
+                       /* if bPassQueued is true, this socket is an orphan until it gets connected. */
+                       if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
+                       {
+                               /* Now that it is connected, find it's parent. */
+                               if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
+                               {
+                                       xParent = pxSocket;
+                               }
+                               else
+                               {
+                                       xParent = pxSocket->u.xTCP.pxPeerSocket;
+                                       configASSERT( xParent != NULL );
+                               }
+                               if( xParent != NULL )
+                               {
+                                       if( xParent->u.xTCP.pxPeerSocket == NULL )
+                                       {
+                                               xParent->u.xTCP.pxPeerSocket = pxSocket;
+                                       }
+
+                                       xParent->xEventBits |= eSOCKET_ACCEPT;
+
+                                       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+                                       {
+                                               /* Library support FreeRTOS_select().  Receiving a new
+                                               connection is being translated as a READ event. */
+                                               if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
+                                               {
+                                                       xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
+                                               }
+                                       }
+                                       #endif
+
+                                       #if( ipconfigUSE_CALLBACKS == 1 )
+                                       {
+                                               if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
+                                                       ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
+                                               {
+                                                       /* The listening socket does not become connected itself, in stead
+                                                       a child socket is created.
+                                                       Postpone a call the OnConnect event until the end of this function. */
+                                                       xConnected = xParent;
+                                               }
+                                       }
+                                       #endif
+                               }
+
+                               /* Don't need to access the parent socket anymore, so the
+                               reference 'pxPeerSocket' may be cleared. */
+                               pxSocket->u.xTCP.pxPeerSocket = NULL;
+                               pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
+
+                               /* When true, this socket may be returned in a call to accept(). */
+                               pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
+                       }
+                       else
+                       {
+                               pxSocket->xEventBits |= eSOCKET_CONNECT;
+
+                               #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+                               {
+                                       if( pxSocket->xSelectBits & eSELECT_WRITE )
+                                       {
+                                               pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+                                       }
+                               }
+                               #endif
+                       }
+               }
+               else  /* bAfter == pdFALSE, connection is closed. */
+               {
+                       /* Notify/wake-up the socket-owner by setting a semaphore. */
+                       pxSocket->xEventBits |= eSOCKET_CLOSED;
+
+                       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+                       {
+                               if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
+                               {
+                                       pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
+                               }
+                       }
+                       #endif
+               }
+               #if( ipconfigUSE_CALLBACKS == 1 )
+               {
+                       if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
+                       {
+                               /* The 'connected' state has changed, call the user handler. */
+                               xConnected = pxSocket;
+                       }
+               }
+               #endif /* ipconfigUSE_CALLBACKS */
+
+               if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
+               {
+                       /* Now the socket isn't in an active state anymore so it
+                       won't need further attention of the IP-task.
+                       Setting time-out to zero means that the socket won't get checked during
+                       timer events. */
+                       pxSocket->u.xTCP.usTimeout = 0u;
+               }
+       }
+       else
+       {
+               if( eTCPState == eCLOSED )
+               {
+                       /* Socket goes to status eCLOSED because of a RST.
+                       When nobody owns the socket yet, delete it. */
+                       if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
+                               ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
+                       {
+                               FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
+                               if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+                               {
+                                       FreeRTOS_closesocket( pxSocket );
+                               }
+                       }
+               }
+       }
+
+       /* Fill in the new state. */
+       pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
+
+       /* touch the alive timers because moving to another state. */
+       prvTCPTouchSocket( pxSocket );
+
+       #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+       {
+       if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+               FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
+                       pxSocket->usLocalPort,
+                       pxSocket->u.xTCP.ulRemoteIP,
+                       pxSocket->u.xTCP.usRemotePort,
+                       FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
+                       FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
+       }
+       #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+       #if( ipconfigUSE_CALLBACKS == 1 )
+       {
+               if( xConnected != NULL )
+               {
+                       /* The 'connected' state has changed, call the OnConnect handler of the parent. */
+                       xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter );
+               }
+       }
+       #endif
+       if( xParent != NULL )
+       {
+               vSocketWakeUpUser( xParent );
+       }
+}
+/*-----------------------------------------------------------*/
+
+static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+       int32_t lDataLen, UBaseType_t uxOptionsLength )
+{
+NetworkBufferDescriptor_t *pxReturn;
+int32_t lNeeded;
+BaseType_t xResize;
+
+       if( xBufferAllocFixedSize != pdFALSE )
+       {
+               /* Network buffers are created with a fixed size and can hold the largest
+               MTU. */
+               lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
+               /* and therefore, the buffer won't be too small.
+               Only ask for a new network buffer in case none was supplied. */
+               xResize = ( pxNetworkBuffer == NULL );
+       }
+       else
+       {
+               /* Network buffers are created with a variable size. See if it must
+               grow. */
+               lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
+                       ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
+               /* In case we were called from a TCP timer event, a buffer must be
+               created.  Otherwise, test 'xDataLength' of the provided buffer. */
+               xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded );
+       }
+
+       if( xResize != pdFALSE )
+       {
+               /* The caller didn't provide a network buffer or the provided buffer is
+               too small.  As we must send-out a data packet, a buffer will be created
+               here. */
+               pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
+
+               if( pxReturn != NULL )
+               {
+                       /* Set the actual packet size, in case the returned buffer is larger. */
+                       pxReturn->xDataLength = lNeeded;
+
+                       /* Copy the existing data to the new created buffer. */
+                       if( pxNetworkBuffer )
+                       {
+                               /* Either from the previous buffer... */
+                               memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
+
+                               /* ...and release it. */
+                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+                       }
+                       else
+                       {
+                               /* Or from the socket field 'xTCP.xPacket'. */
+                               memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
+                       }
+               }
+       }
+       else
+       {
+               /* xResize is false, the network buffer provided was big enough. */
+               pxReturn = pxNetworkBuffer;
+
+               /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
+               xDataLength member must get the correct length too! */
+               pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
+       }
+
+       return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Prepare an outgoing message, in case anything has to be sent.
+ */
+static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
+{
+int32_t lDataLen;
+uint8_t *pucEthernetBuffer, *pucSendData;
+TCPPacket_t *pxTCPPacket;
+size_t uxOffset;
+uint32_t ulDataGot, ulDistance;
+TCPWindow_t *pxTCPWindow;
+NetworkBufferDescriptor_t *pxNewBuffer;
+int32_t lStreamPos;
+
+       if( ( *ppxNetworkBuffer ) != NULL )
+       {
+               /* A network buffer descriptor was already supplied */
+               pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
+       }
+       else
+       {
+               /* For now let it point to the last packet header */
+               pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+       }
+
+       pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
+       pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+       lDataLen = 0;
+       lStreamPos = 0;
+       pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
+
+       if( pxSocket->u.xTCP.txStream != NULL )
+       {
+               /* ulTCPWindowTxGet will return the amount of data which may be sent
+               along with the position in the txStream.
+               Why check for MSS > 1 ?
+               Because some TCP-stacks (like uIP) use it for flow-control. */
+               if( pxSocket->u.xTCP.usCurMSS > 1u )
+               {
+                       lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
+               }
+
+               if( lDataLen > 0 )
+               {
+                       /* Check if the current network buffer is big enough, if not,
+                       resize it. */
+                       pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
+
+                       if( pxNewBuffer != NULL )
+                       {
+                               *ppxNetworkBuffer = pxNewBuffer;
+                               pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
+                               pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
+
+                               pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
+
+                               /* Translate the position in txStream to an offset from the tail
+                               marker. */
+                               uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
+
+                               /* Here data is copied from the txStream in 'peek' mode.  Only
+                               when the packets are acked, the tail marker will be updated. */
+                               ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
+
+                               #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+                               {
+                                       if( ulDataGot != ( uint32_t ) lDataLen )
+                                       {
+                                               FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
+                                                       lStreamPos, uxOffset, ulDataGot, lDataLen ) );
+                                       }
+                               }
+                               #endif
+
+                               /* If the owner of the socket requests a closure, add the FIN
+                               flag to the last packet. */
+                               if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
+                               {
+                                       ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
+
+                                       if( ulDistance == ulDataGot )
+                                       {
+                                               #if (ipconfigHAS_DEBUG_PRINTF == 1)
+                                               {
+                                               /* the order of volatile accesses is undefined
+                                                       so such workaround */
+                                                       size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
+                                                       size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
+                                                       size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
+
+                                                       FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
+                                                               uxTail, uxMid, uxHead ) );
+                                               }
+                                               #endif
+                                               /* Although the socket sends a FIN, it will stay in
+                                               ESTABLISHED until all current data has been received or
+                                               delivered. */
+                                               pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
+                                               pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
+                                               pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               lDataLen = -1;
+                       }
+               }
+       }
+
+       if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
+       {
+               /* See if the socket owner wants to shutdown this connection. */
+               if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
+                       ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
+               {
+                       pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
+                       pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
+                       pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+                       pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+                       pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+                       vTCPStateChange( pxSocket, eFIN_WAIT_1 );
+               }
+
+               #if( ipconfigTCP_KEEP_ALIVE != 0 )
+               {
+                       if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
+                       {
+                               FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
+                                       pxSocket->u.xTCP.ulRemoteIP,                    /* IP address of remote machine. */
+                                       pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */
+                               vTCPStateChange( pxSocket, eCLOSE_WAIT );
+                               lDataLen = -1;
+                       }
+                       if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
+                       {
+                               /* If there is no data to be sent, and no window-update message,
+                               we might want to send a keep-alive message. */
+                               TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
+                               TickType_t xMax;
+                               xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
+                               if( pxSocket->u.xTCP.ucKeepRepCount )
+                               {
+                                       xMax = ( 3u * configTICK_RATE_HZ );
+                               }
+                               if( xAge > xMax )
+                               {
+                                       pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
+                                       if( xTCPWindowLoggingLevel )
+                                               FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
+                                                       pxSocket->u.xTCP.ulRemoteIP,
+                                                       pxSocket->u.xTCP.usRemotePort,
+                                                       pxSocket->u.xTCP.ucKeepRepCount ) );
+                                       pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
+                                       pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
+                                       pxSocket->u.xTCP.ucKeepRepCount++;
+                               }
+                       }
+               }
+               #endif /* ipconfigTCP_KEEP_ALIVE */
+       }
+
+       /* Anything to send, a change of the advertised window size, or maybe send a
+       keep-alive message? */
+       if( ( lDataLen > 0 ) ||
+               ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
+               ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
+       {
+               pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
+               pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+               pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
+
+               if( lDataLen != 0l )
+               {
+                       pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
+               }
+
+               lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+       }
+
+       return lDataLen;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Calculate after how much time this socket needs to be checked again.
+ */
+static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
+{
+TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
+
+       if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+       {
+               /* The socket is actively connecting to a peer. */
+               if( pxSocket->u.xTCP.bits.bConnPrepared )
+               {
+                       /* Ethernet address has been found, use progressive timeout for
+                       active connect(). */
+                       if( pxSocket->u.xTCP.ucRepCount < 3u )
+                       {
+                               ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
+                       }
+                       else
+                       {
+                               ulDelayMs = 11000UL;
+                       }
+               }
+               else
+               {
+                       /* Still in the ARP phase: check every half second. */
+                       ulDelayMs = 500UL;
+               }
+
+               FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
+                       pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
+                       pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
+               pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
+       }
+       else if( pxSocket->u.xTCP.usTimeout == 0u )
+       {
+               /* Let the sliding window mechanism decide what time-out is appropriate. */
+               BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
+               if( ulDelayMs == 0u )
+               {
+                       if( xResult != ( BaseType_t )0 )
+                       {
+                               ulDelayMs = 1UL;
+                       }
+                       else
+                       {
+                               ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
+                       }
+               }
+               else
+               {
+                       /* ulDelayMs contains the time to wait before a re-transmission. */
+               }
+               pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
+       }
+       else
+       {
+               /* field '.usTimeout' has already been set (by the
+               keep-alive/delayed-ACK mechanism). */
+       }
+
+       /* Return the number of clock ticks before the timer expires. */
+       return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
+{
+int32_t lCount, lLength;
+
+       /* A txStream has been created already, see if the socket has new data for
+       the sliding window.
+
+       uxStreamBufferMidSpace() returns the distance between rxHead and rxMid.  It contains new
+       Tx data which has not been passed to the sliding window yet.  The oldest
+       data not-yet-confirmed can be found at rxTail. */
+       lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
+
+       if( lLength > 0 )
+       {
+               /* All data between txMid and rxHead will now be passed to the sliding
+               window manager, so it can start transmitting them.
+
+               Hand over the new data to the sliding window handler.  It will be
+               split-up in chunks of 1460 bytes each (or less, depending on
+               ipconfigTCP_MSS). */
+               lCount = lTCPWindowTxAdd(       &pxSocket->u.xTCP.xTCPWindow,
+                                                               ( uint32_t ) lLength,
+                                                               ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
+                                                               ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
+
+               /* Move the rxMid pointer forward up to rxHead. */
+               if( lCount > 0 )
+               {
+                       vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPHandleFin() will be called to handle socket closure
+ * The Closure starts when either a FIN has been received and accepted,
+ * Or when the socket has sent a FIN flag to the peer
+ * Before being called, it has been checked that both reception and transmission
+ * are complete.
+ */
+static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+BaseType_t xSendLength = 0;
+uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
+
+       if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
+       {
+               pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
+       }
+       if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+       {
+               /* We haven't yet replied with a FIN, do so now. */
+               pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+               pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+       }
+       else
+       {
+               /* We did send a FIN already, see if it's ACK'd. */
+               if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
+               {
+                       pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
+               }
+       }
+
+       if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
+       {
+               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
+               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
+
+               /* And wait for the final ACK. */
+               vTCPStateChange( pxSocket, eLAST_ACK );
+       }
+       else
+       {
+               /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
+               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
+               if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
+               {
+                       /* We have sent out a FIN but the peer hasn't replied with a FIN
+                       yet. Do nothing for the moment. */
+                       pxTCPHeader->ucTCPFlags = 0u;
+               }
+               else
+               {
+                       if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
+                       {
+                               /* This is the third of the three-way hand shake: the last
+                               ACK. */
+                               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+                       }
+                       else
+                       {
+                               /* The other party started the closure, so we just wait for the
+                               last ACK. */
+                               pxTCPHeader->ucTCPFlags = 0u;
+                       }
+
+                       /* And wait for the user to close this socket. */
+                       vTCPStateChange( pxSocket, eCLOSE_WAIT );
+               }
+       }
+
+       pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+
+       if( pxTCPHeader->ucTCPFlags != 0u )
+       {
+               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
+       }
+
+       pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
+
+       if( xTCPWindowLoggingLevel != 0 )
+       {
+               FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
+                       ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
+                       pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                       pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                       pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                       pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
+       }
+
+       return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvCheckRxData(): called from prvTCPHandleState()
+ *
+ * The first thing that will be done is find the TCP payload data
+ * and check the length of this data.
+ */
+static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
+int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
+
+       /* Determine the length and the offset of the user-data sent to this
+       node.
+
+       The size of the TCP header is given in a multiple of 4-byte words (single
+       byte, needs no ntoh() translation).  A shift-right 2: is the same as
+       (offset >> 4) * 4. */
+       lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
+
+       /* Let pucRecvData point to the first byte received. */
+       *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
+
+       /* Calculate lReceiveLength - the length of the TCP data received.  This is
+       equal to the total packet length minus:
+       ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
+       lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
+       lLength =  ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
+
+       if( lReceiveLength > lLength )
+       {
+               /* More bytes were received than the reported length, often because of
+               padding bytes at the end. */
+               lReceiveLength = lLength;
+       }
+
+       /* Subtract the size of the TCP and IP headers and the actual data size is
+       known. */
+       if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
+       {
+               lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
+       }
+       else
+       {
+               lReceiveLength = 0;
+       }
+
+       /* Urgent Pointer:
+       This field communicates the current value of the urgent pointer as a
+       positive offset from the sequence number in this segment.  The urgent
+       pointer points to the sequence number of the octet following the urgent
+       data.  This field is only be interpreted in segments with the URG control
+       bit set. */
+       if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
+       {
+               /* Although we ignore the urgent data, we have to skip it. */
+               lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
+               *ppucRecvData += lUrgentLength;
+               lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
+       }
+
+       return ( BaseType_t ) lReceiveLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvStoreRxData(): called from prvTCPHandleState()
+ *
+ * The second thing is to do is check if the payload data may be accepted
+ * If so, they will be added to the reception queue.
+ */
+static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
+       NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint32_t ulSequenceNumber, ulSpace;
+int32_t lOffset, lStored;
+BaseType_t xResult = 0;
+
+       ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
+
+       if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
+       {
+               /* See if way may accept the data contents and forward it to the socket
+               owner.
+
+               If it can't be "accept"ed it may have to be stored and send a selective
+               ack (SACK) option to confirm it.  In that case, xTCPWindowRxStore() will be
+               called later to store an out-of-order packet (in case lOffset is
+               negative). */
+               if ( pxSocket->u.xTCP.rxStream )
+               {
+                       ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
+               }
+               else
+               {
+                       ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
+               }
+
+               lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
+
+               if( lOffset >= 0 )
+               {
+                       /* New data has arrived and may be made available to the user.  See
+                       if the head marker in rxStream may be advanced, only if lOffset == 0.
+                       In case the low-water mark is reached, bLowWater will be set
+                       "low-water" here stands for "little space". */
+                       lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
+
+                       if( lStored != ( int32_t ) ulReceiveLength )
+                       {
+                               FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
+
+                               /* Received data could not be stored.  The socket's flag
+                               bMallocError has been set.  The socket now has the status
+                               eCLOSE_WAIT and a RST packet will be sent back. */
+                               prvTCPSendReset( pxNetworkBuffer );
+                               xResult = -1;
+                       }
+               }
+
+               /* After a missing packet has come in, higher packets may be passed to
+               the user. */
+               #if( ipconfigUSE_TCP_WIN == 1 )
+               {
+                       /* Now lTCPAddRxdata() will move the rxHead pointer forward
+                       so data becomes available to the user immediately
+                       In case the low-water mark is reached, bLowWater will be set. */
+                       if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
+                       {
+                               lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
+                               pxTCPWindow->ulUserDataLength = 0;
+                       }
+               }
+               #endif /* ipconfigUSE_TCP_WIN */
+       }
+       else
+       {
+               pxTCPWindow->ucOptionLength = 0u;
+       }
+
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/* Set the TCP options (if any) for the outgoing packet. */
+static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
+
+       #if(    ipconfigUSE_TCP_WIN == 1 )
+               if( uxOptionsLength != 0u )
+               {
+                       /* TCP options must be sent because a packet which is out-of-order
+                       was received. */
+                       if( xTCPWindowLoggingLevel >= 0 )
+                               FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
+                                       pxSocket->usLocalPort,
+                                       pxSocket->u.xTCP.usRemotePort,
+                                       uxOptionsLength,
+                                       FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
+                                       FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
+                       memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
+
+                       /* The header length divided by 4, goes into the higher nibble,
+                       effectively a shift-left 2. */
+                       pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+               }
+               else
+       #endif  /* ipconfigUSE_TCP_WIN */
+       if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
+       {
+               /* TCP options must be sent because the MSS has changed. */
+               pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
+               if( xTCPWindowLoggingLevel >= 0 )
+               {
+                       FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
+               }
+
+               pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
+               pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
+               pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
+               pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
+               uxOptionsLength = 4u;
+               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+       }
+
+       return uxOptionsLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvHandleSynReceived(): called from prvTCPHandleState()
+ *
+ * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
+ * If the flags received are correct, the socket will move to eESTABLISHED.
+ */
+static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
+BaseType_t xSendLength = 0;
+
+       /* Either expect a ACK or a SYN+ACK. */
+       uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
+       if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+       {
+               usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
+       }
+
+       if( ( ucTCPFlags & 0x17u ) != usExpect )
+       {
+               /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
+               /* eSYN_RECEIVED: flags ACK  expected, not SYN. */
+               FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
+                       pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
+                       usExpect, ucTCPFlags ) );
+               vTCPStateChange( pxSocket, eCLOSE_WAIT );
+               pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
+               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+       }
+       else
+       {
+               pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
+               pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
+
+               if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+               {
+                       TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
+
+                       /* Clear the SYN flag in lastPacket. */
+                       pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
+
+                       /* This socket was the one connecting actively so now perofmr the
+                       synchronisation. */
+                       vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
+                               ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
+                       pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
+                       pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
+                       pxTCPWindow->ulNextTxSequenceNumber++;
+               }
+               else if( ulReceiveLength == 0u )
+               {
+                       pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
+               }
+
+               /* The SYN+ACK has been confirmed, increase the next sequence number by
+               1. */
+               pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
+
+               #if( ipconfigUSE_TCP_WIN == 1 )
+               {
+                       FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
+                               pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
+                               pxSocket->usLocalPort,
+                               pxSocket->u.xTCP.ulRemoteIP,
+                               pxSocket->u.xTCP.usRemotePort,
+                               ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
+               }
+               #endif /* ipconfigUSE_TCP_WIN */
+
+               if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
+               {
+                       pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+                       xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+                       pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+               }
+               #if( ipconfigUSE_TCP_WIN != 0 )
+               {
+                       if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
+                       {
+                               /* The other party did not send a scaling factor.
+                               A shifting factor in this side must be canceled. */
+                               pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
+                               pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
+                       }
+               }
+               #endif /* ipconfigUSE_TCP_WIN */
+               /* This was the third step of connecting: SYN, SYN+ACK, ACK     so now the
+               connection is established. */
+               vTCPStateChange( pxSocket, eESTABLISHED );
+       }
+
+       return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvHandleEstablished(): called from prvTCPHandleState()
+ *
+ * Called if the status is eESTABLISHED.  Data reception has been handled
+ * earlier.  Here the ACK's from peer will be checked, and if a FIN is received,
+ * the code will check if it may be accepted, i.e. if all expected data has been
+ * completely received.
+ */
+static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
+BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
+int32_t lDistance, lSendResult;
+
+       /* Remember the window size the peer is advertising. */
+       pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
+       #if( ipconfigUSE_TCP_WIN != 0 )
+       {
+               pxSocket->u.xTCP.ulWindowSize =
+                       ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
+       }
+       #endif
+
+       if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
+       {
+               ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
+
+               /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
+               starting at 'tx.ulCurrentSequenceNumber'.  Advance the tail pointer in
+               txStream. */
+               if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
+               {
+                       /* Just advancing the tail index, 'ulCount' bytes have been
+                       confirmed, and because there is new space in the txStream, the
+                       user/owner should be woken up. */
+                       /* _HT_ : only in case the socket's waiting? */
+                       if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
+                       {
+                               pxSocket->xEventBits |= eSOCKET_SEND;
+
+                               #if ipconfigSUPPORT_SELECT_FUNCTION == 1
+                               {
+                                       if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
+                                       {
+                                               pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+                                       }
+                               }
+                               #endif
+                               /* In case the socket owner has installed an OnSent handler,
+                               call it now. */
+                               #if( ipconfigUSE_CALLBACKS == 1 )
+                               {
+                                       if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
+                                       {
+                                               pxSocket->u.xTCP.pxHandleSent( ( Socket_t )pxSocket, ulCount );
+                                       }
+                               }
+                               #endif /* ipconfigUSE_CALLBACKS == 1  */
+                       }
+               }
+       }
+
+       /* If this socket has a stream for transmission, add the data to the
+       outgoing segment(s). */
+       if( pxSocket->u.xTCP.txStream != NULL )
+       {
+               prvTCPAddTxData( pxSocket );
+       }
+
+       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+
+       if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
+       {
+               /* Peer is requesting to stop, see if we're really finished. */
+               xMayClose = pdTRUE;
+
+               /* Checks are only necessary if we haven't sent a FIN yet. */
+               if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+               {
+                       /* xTCPWindowTxDone returns true when all Tx queues are empty. */
+                       bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
+                       bTxDone  = xTCPWindowTxDone( pxTCPWindow );
+
+                       if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
+                       {
+                               /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
+                               FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
+                                       pxSocket->usLocalPort,
+                                       pxSocket->u.xTCP.usRemotePort,
+                                       bRxComplete, bTxDone ) );
+                               xMayClose = pdFALSE;
+                       }
+                       else
+                       {
+                               lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
+
+                               if( lDistance > 1 )
+                               {
+                                       FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
+                                               lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+                                               pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
+
+                                       xMayClose = pdFALSE;
+                               }
+                       }
+               }
+
+               if( xTCPWindowLoggingLevel > 0 )
+               {
+                       FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
+                               xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
+                               pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
+               }
+
+               if( xMayClose != pdFALSE )
+               {
+                       pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
+                       xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
+               }
+       }
+
+       if( xMayClose == pdFALSE )
+       {
+               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+
+               if( ulReceiveLength != 0u )
+               {
+                       xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+                       /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
+                       pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+                       if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
+                       {
+                               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
+                       }
+               }
+
+               /* Now get data to be transmitted. */
+               /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
+               can not send-out both TCP options and also a full packet. Sending
+               options (SACK) is always more urgent than sending data, which can be
+               sent later. */
+               if( uxOptionsLength == 0u )
+               {
+                       /* prvTCPPrepareSend might allocate a bigger network buffer, if
+                       necessary. */
+                       lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
+                       if( lSendResult > 0 )
+                       {
+                               xSendLength = ( BaseType_t ) lSendResult;
+                       }
+               }
+       }
+
+       return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Called from prvTCPHandleState().  There is data to be sent.  If
+ * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
+ * checked if it would better be postponed for efficiency.
+ */
+static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+       uint32_t ulReceiveLength, BaseType_t xSendLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+/* Find out what window size we may advertised. */
+int32_t lRxSpace;
+#if( ipconfigUSE_TCP_WIN == 1 )
+       #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
+               const int32_t lMinLength = 0;
+       #else
+               int32_t lMinLength;
+       #endif
+#endif
+
+       /* Set the time-out field, so that we'll be called by the IP-task in case no
+       next message will be received. */
+       lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
+       #if ipconfigUSE_TCP_WIN == 1
+       {
+
+               #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
+               {
+                       lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
+               }
+               #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
+
+               /* In case we're receiving data continuously, we might postpone sending
+               an ACK to gain performance. */
+               if( ( ulReceiveLength > 0 ) &&                                                  /* Data was sent to this socket. */
+                       ( lRxSpace >= lMinLength ) &&                                           /* There is Rx space for more data. */
+                       ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) &&       /* Not in a closure phase. */
+                       ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
+                       ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) &&      /* Connection established. */
+                       ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) )         /* There are no other flags than an ACK. */
+               {
+                       if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
+                       {
+                               /* There was still a delayed in queue, delete it. */
+                               if( pxSocket->u.xTCP.pxAckMessage != 0 )
+                               {
+                                       vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+                               }
+
+                               pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
+                       }
+                       if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) ||     /* Received a small message. */
+                               ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
+                       {
+                               pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
+                       }
+                       else
+                       {
+                               /* Normally a delayed ACK should wait 200 ms for a next incoming
+                               packet.  Only wait 20 ms here to gain performance.  A slow ACK
+                               for full-size message. */
+                               pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
+                       }
+
+                       if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+                       {
+                               FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
+                                       pxSocket->usLocalPort,
+                                       pxSocket->u.xTCP.usRemotePort,
+                                       pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+                                       pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                                       xSendLength,
+                                       pxSocket->u.xTCP.usTimeout, lRxSpace ) );
+                       }
+
+                       *ppxNetworkBuffer = NULL;
+                       xSendLength = 0;
+               }
+               else if( pxSocket->u.xTCP.pxAckMessage != NULL )
+               {
+                       /* As an ACK is not being delayed, remove any earlier delayed ACK
+                       message. */
+                       if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
+                       {
+                               vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+                       }
+
+                       pxSocket->u.xTCP.pxAckMessage = NULL;
+               }
+       }
+       #else
+       {
+               /* Remove compiler warnings. */
+               ( void ) ulReceiveLength;
+               ( void ) pxTCPHeader;
+               ( void ) lRxSpace;
+       }
+       #endif /* ipconfigUSE_TCP_WIN */
+
+       if( xSendLength != 0 )
+       {
+               if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+               {
+                       FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
+                               pxSocket->usLocalPort,
+                               pxSocket->u.xTCP.usRemotePort,
+                               pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+                               pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+                               xSendLength ) );
+               }
+
+               /* Set the parameter 'xReleaseAfterSend' to the value of
+               ipconfigZERO_COPY_TX_DRIVER. */
+               prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       /* The driver has taken ownership of the Network Buffer. */
+                       *ppxNetworkBuffer = NULL;
+               }
+               #endif
+       }
+
+       return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPHandleState()
+ * is the most important function of this TCP stack
+ * We've tried to keep it (relatively short) by putting a lot of code in
+ * the static functions above:
+ *
+ *             prvCheckRxData()
+ *             prvStoreRxData()
+ *             prvSetOptions()
+ *             prvHandleSynReceived()
+ *             prvHandleEstablished()
+ *             prvSendData()
+ *
+ * As these functions are declared static, and they're called from one location
+ * only, most compilers will inline them, thus avoiding a call and return.
+ */
+static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
+BaseType_t xSendLength = 0;
+uint32_t ulReceiveLength;      /* Number of bytes contained in the TCP message. */
+uint8_t *pucRecvData;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
+
+       /* uxOptionsLength: the size of the options to be sent (always a multiple of
+       4 bytes)
+       1. in the SYN phase, we shall communicate the MSS
+       2. in case of a SACK, Selective ACK, ack a segment which comes in
+       out-of-order. */
+UBaseType_t uxOptionsLength = 0u;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
+
+       /* First get the length and the position of the received data, if any.
+       pucRecvData will point to the first byte of the TCP payload. */
+       ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
+
+       if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
+       {
+               if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
+               {
+                       /* This is most probably a keep-alive message from peer.  Setting
+                       'bWinChange' doesn't cause a window-size-change, the flag is used
+                       here to force sending an immediate ACK. */
+                       pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+               }
+       }
+
+       /* Keep track of the highest sequence number that might be expected within
+       this connection. */
+       if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
+       {
+               pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
+       }
+
+       /* Storing data may result in a fatal error if malloc() fails. */
+       if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
+       {
+               xSendLength = -1;
+       }
+       else
+       {
+               uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
+
+               if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
+               {
+                       FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
+
+                       /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
+                       'SYN+ACK' didn't arrive.  Step back to the previous state in which
+                       a first incoming SYN is handled.  The SYN was counted already so
+                       decrease it first. */
+                       vTCPStateChange( pxSocket, eSYN_FIRST );
+               }
+
+               if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
+               {
+                       /* It's the first time a FIN has been received, remember its
+                       sequence number. */
+                       pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
+                       pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
+
+                       /* Was peer the first one to send a FIN? */
+                       if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+                       {
+                               /* If so, don't send the-last-ACK. */
+                               pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
+                       }
+               }
+
+               switch (pxSocket->u.xTCP.ucTCPState)
+               {
+               case eCLOSED:           /* (server + client) no connection state at all. */
+                       /* Nothing to do for a closed socket, except waiting for the
+                       owner. */
+                       break;
+
+               case eTCP_LISTEN:       /* (server) waiting for a connection request from
+                                                       any remote TCP and port. */
+                       /* The listen state was handled in xProcessReceivedTCPPacket().
+                       Should not come here. */
+                       break;
+
+               case eSYN_FIRST:        /* (server) Just received a SYN request for a server
+                                                       socket. */
+                       {
+                               /* A new socket has been created, reply with a SYN+ACK.
+                               Acknowledge with seq+1 because the SYN is seen as pseudo data
+                               with len = 1. */
+                               uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
+                               pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
+
+                               xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+
+                               /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and
+                               uxOptionsLength is a multiple of 4.  The complete expression is:
+                               ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
+                               pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+                               vTCPStateChange( pxSocket, eSYN_RECEIVED );
+
+                               pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
+                               pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
+                       }
+                       break;
+
+               case eCONNECT_SYN:      /* (client) also called SYN_SENT: we've just send a
+                                                       SYN, expect     a SYN+ACK and send a ACK now. */
+                       /* Fall through */
+               case eSYN_RECEIVED:     /* (server) we've had a SYN, replied with SYN+SCK
+                                                       expect a ACK and do nothing. */
+                       xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
+                       break;
+
+               case eESTABLISHED:      /* (server + client) an open connection, data
+                                                       received can be delivered to the user. The normal
+                                                       state for the data transfer phase of the connection
+                                                       The closing states are also handled here with the
+                                                       use of some flags. */
+                       xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
+                       break;
+
+               case eLAST_ACK:         /* (server + client) waiting for an acknowledgement
+                                                       of the connection termination request previously
+                                                       sent to the remote TCP (which includes an
+                                                       acknowledgement of its connection termination
+                                                       request). */
+                       /* Fall through */
+               case eFIN_WAIT_1:       /* (server + client) waiting for a connection termination request from the remote TCP,
+                                                        * or an acknowledgement of the connection termination request previously sent. */
+                       /* Fall through */
+               case eFIN_WAIT_2:       /* (server + client) waiting for a connection termination request from the remote TCP. */
+                       xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
+                       break;
+
+               case eCLOSE_WAIT:       /* (server + client) waiting for a connection
+                                                       termination request from the local user.  Nothing to
+                                                       do, connection is closed, wait for owner to close
+                                                       this socket. */
+                       break;
+
+               case eCLOSING:          /* (server + client) waiting for a connection
+                                                       termination request acknowledgement from the remote
+                                                       TCP. */
+                       break;
+
+               case eTIME_WAIT:        /* (either server or client) waiting for enough time
+                                                       to pass to be sure the remote TCP received the
+                                                       acknowledgement of its connection termination
+                                                       request. [According to RFC 793 a connection can stay
+                                                       in TIME-WAIT for a maximum of four minutes known as
+                                                       a MSL (maximum segment lifetime).]  These states are
+                                                       implemented implicitly by settings flags like
+                                                       'bFinSent', 'bFinRecv', and 'bFinAcked'. */
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if( xSendLength > 0 )
+       {
+               xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
+       }
+
+       return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer,
+                                                 uint8_t ucTCPFlags )
+{
+#if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
+    {
+        TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
+        const BaseType_t xSendLength = ( BaseType_t )
+            ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
+
+        pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;
+        pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
+
+        prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE );
+    }
+#endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
+
+    /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
+    ( void )pxNetworkBuffer;
+    ( void )ucTCPFlags;
+
+    /* The packet was not consumed. */
+    return pdFAIL;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+    return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+    return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,
+                                          ipTCP_FLAG_ACK | ipTCP_FLAG_RST );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
+{
+uint32_t ulMSS = ipconfigTCP_MSS;
+
+       if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
+       {
+               /* Data for this peer will pass through a router, and maybe through
+               the internet.  Limit the MSS to 1400 bytes or less. */
+               ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
+       }
+
+       FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
+
+       pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ *     FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
+ *     xProcessReceivedTCPPacket()
+ *             prvTCPHandleState()
+ *                     prvTCPPrepareSend()
+ *                             prvTCPReturnPacket()
+ *                             xNetworkInterfaceOutput()       // Sends data to the NIC
+ *             prvTCPSendRepeated()
+ *                     prvTCPReturnPacket()            // Prepare for returning
+ *                     xNetworkInterfaceOutput()       // Sends data to the NIC
+*/
+BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+FreeRTOS_Socket_t *pxSocket;
+TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+uint16_t ucTCPFlags;
+uint32_t ulLocalIP;
+uint16_t xLocalPort;
+uint32_t ulRemoteIP;
+uint16_t xRemotePort;
+uint32_t ulSequenceNumber;
+uint32_t ulAckNumber;
+BaseType_t xResult = pdPASS;
+configASSERT(pxNetworkBuffer);
+configASSERT(pxNetworkBuffer->pucEthernetBuffer);
+
+       /* Check for a minimum packet size. */
+       if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )
+       {
+               ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
+               ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
+               xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
+               ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
+               xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
+        ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
+        ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr );
+
+               /* Find the destination socket, and if not found: return a socket listing to
+               the destination PORT. */
+               pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
+       }
+       else
+       {
+               return pdFAIL;
+       }
+
+       if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
+       {
+               /* A TCP messages is received but either there is no socket with the
+               given port number or the there is a socket, but it is in one of these
+               non-active states:  eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
+               eTIME_WAIT. */
+
+               FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
+
+               /* Send a RST to all packets that can not be handled.  As a result
+               the other party will get a ECONN error.  There are two exceptions:
+               1) A packet that already has the RST flag set.
+               2) A packet that only has the ACK flag set.
+               A packet with only the ACK flag set might be the last ACK in
+               a three-way hand-shake that closes a connection. */
+               if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
+                       ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
+               {
+                       prvTCPSendReset( pxNetworkBuffer );
+               }
+
+               /* The packet can't be handled. */
+               xResult = pdFAIL;
+       }
+       else
+       {
+               pxSocket->u.xTCP.ucRepCount = 0u;
+
+               if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
+               {
+                       /* The matching socket is in a listening state.  Test if the peer
+                       has set the SYN flag. */
+                       if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
+                       {
+                               /* What happens: maybe after a reboot, a client doesn't know the
+                               connection had gone.  Send a RST in order to get a new connect
+                               request. */
+                               #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+                               {
+                               FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
+                                       prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
+                               }
+                               #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+                               if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
+                               {
+                                       prvTCPSendReset( pxNetworkBuffer );
+                               }
+                               xResult = pdFAIL;
+                       }
+                       else
+                       {
+                               /* prvHandleListen() will either return a newly created socket
+                               (if bReuseSocket is false), otherwise it returns the current
+                               socket which will later get connected. */
+                               pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
+
+                               if( pxSocket == NULL )
+                               {
+                                       xResult = pdFAIL;
+                               }
+                       }
+               }       /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
+               else
+               {
+                       /* This is not a socket in listening mode. Check for the RST
+                       flag. */
+                       if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
+                       {
+                FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
+
+                /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */
+                if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+                {
+                    /* Per the above RFC, "In the SYN-SENT state ... the RST is
+                    acceptable if the ACK field acknowledges the SYN." */
+                    if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 )
+                    {
+                        vTCPStateChange( pxSocket, eCLOSED );
+                    }
+                }
+                else
+                {
+                    /* Check whether the packet matches the next expected sequence number. */
+                    if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber )
+                    {
+                        vTCPStateChange( pxSocket, eCLOSED );
+                    }
+                    /* Otherwise, check whether the packet is within the receive window. */
+                    else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber &&
+                             ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber +
+                                                  pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) )
+                    {
+                        /* Send a challenge ACK. */
+                        prvTCPSendChallengeAck( pxNetworkBuffer );
+                    }
+                }
+
+                /* Otherwise, do nothing. In any case, the packet cannot be handled. */
+                               xResult = pdFAIL;
+                       }
+                       else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
+                       {
+                               /* SYN flag while this socket is already connected. */
+                               FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
+
+                               /* The packet cannot be handled. */
+                               xResult = pdFAIL;
+                       }
+                       else
+                       {
+                               /* Update the copy of the TCP header only (skipping eth and IP
+                               headers).  It might be used later on, whenever data must be sent
+                               to the peer. */
+                               const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
+                               memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
+                       }
+               }
+       }
+
+       if( xResult != pdFAIL )
+       {
+               /* Touch the alive timers because we received a message for this
+               socket. */
+               prvTCPTouchSocket( pxSocket );
+
+               /* Parse the TCP option(s), if present. */
+               /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
+               then we MUST assume an MSS size of 536 bytes for backward compatibility. */
+
+               /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
+               the number 5 (words) in the higher niblle of the TCP-offset byte. */
+               if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
+               {
+                       prvCheckOptions( pxSocket, pxNetworkBuffer );
+               }
+
+
+               #if( ipconfigUSE_TCP_WIN == 1 )
+               {
+                       pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
+                       pxSocket->u.xTCP.ulWindowSize =
+                               ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
+               }
+               #endif
+
+               /* In prvTCPHandleState() the incoming messages will be handled
+               depending on the current state of the connection. */
+               if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
+               {
+                       /* prvTCPHandleState() has sent a message, see if there are more to
+                       be transmitted. */
+                       #if( ipconfigUSE_TCP_WIN == 1 )
+                       {
+                               prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
+                       }
+                       #endif /* ipconfigUSE_TCP_WIN */
+               }
+
+               if( pxNetworkBuffer != NULL )
+               {
+                       /* We must check if the buffer is unequal to NULL, because the
+                       socket might keep a reference to it in case a delayed ACK must be
+                       sent. */
+                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+                       pxNetworkBuffer = NULL;
+               }
+
+               /* And finally, calculate when this socket wants to be woken up. */
+               prvTCPNextTimeout ( pxSocket );
+               /* Return pdPASS to tell that the network buffer is 'consumed'. */
+               xResult = pdPASS;
+       }
+
+       /* pdPASS being returned means the buffer has been consumed. */
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+FreeRTOS_Socket_t *pxReturn = NULL;
+uint32_t ulInitialSequenceNumber;
+
+       /* Assume that a new Initial Sequence Number will be required. Request
+       it now in order to fail out if necessary. */
+       ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER,
+                                                                                                                                 pxSocket->usLocalPort,
+                                                                                                                                 pxTCPPacket->xIPHeader.ulSourceIPAddress,
+                                                                                                                                 pxTCPPacket->xTCPHeader.usSourcePort );
+
+       /* A pure SYN (without ACK) has come in, create a new socket to answer
+       it. */
+       if( 0 != ulInitialSequenceNumber )
+       {
+               if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
+               {
+                       /* The flag bReuseSocket indicates that the same instance of the
+                       listening socket should be used for the connection. */
+                       pxReturn = pxSocket;
+                       pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
+                       pxSocket->u.xTCP.pxPeerSocket = pxSocket;
+               }
+               else
+               {
+                       /* The socket does not have the bReuseSocket flag set meaning create a
+                       new socket when a connection comes in. */
+                       pxReturn = NULL;
+
+                       if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
+                       {
+                               FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
+                                       pxSocket->usLocalPort,
+                                       pxSocket->u.xTCP.usChildCount,
+                                       pxSocket->u.xTCP.usBacklog,
+                                       pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
+                               prvTCPSendReset( pxNetworkBuffer );
+                       }
+                       else
+                       {
+                               FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * )
+                                       FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
+
+                               if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
+                                       prvTCPSendReset( pxNetworkBuffer );
+                               }
+                               else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
+                               {
+                                       /* The socket will be connected immediately, no time for the
+                                       owner to setsockopt's, therefore copy properties of the server
+                                       socket to the new socket.  Only the binding might fail (due to
+                                       lack of resources). */
+                                       pxReturn = pxNewSocket;
+                               }
+                       }
+               }
+       }
+
+       if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) )
+       {
+               pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
+               pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
+               pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
+
+               /* Here is the SYN action. */
+               pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
+               prvSocketSetMSS( pxReturn );
+
+               prvTCPCreateWindow( pxReturn );
+
+               vTCPStateChange( pxReturn, eSYN_FIRST );
+
+               /* Make a copy of the header up to the TCP header.  It is needed later
+               on, whenever data must be sent to the peer. */
+               memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
+       }
+       return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Duplicates a socket after a listening socket receives a connection.
+ */
+static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
+{
+struct freertos_sockaddr xAddress;
+
+       pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
+       pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
+       pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
+       pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
+       pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
+       pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
+       pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
+       pxNewSocket->u.xTCP.uxRxWinSize  = pxSocket->u.xTCP.uxRxWinSize;
+       pxNewSocket->u.xTCP.uxTxWinSize  = pxSocket->u.xTCP.uxTxWinSize;
+
+       #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+       {
+               pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
+       }
+       #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
+
+       #if( ipconfigUSE_CALLBACKS == 1 )
+       {
+               /* In case call-backs are used, copy them from parent to child. */
+               pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
+               pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
+               pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
+       }
+       #endif /* ipconfigUSE_CALLBACKS */
+
+       #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+       {
+               /* Child socket of listening sockets will inherit the Socket Set
+               Otherwise the owner has no chance of including it into the set. */
+               if( pxSocket->pxSocketSet )
+               {
+                       pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
+                       pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
+               }
+       }
+       #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+
+       /* And bind it to the same local port as its parent. */
+       xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
+       xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
+
+       #if( ipconfigTCP_HANG_PROTECTION == 1 )
+       {
+               /* Only when there is anti-hanging protection, a socket may become an
+               orphan temporarily.  Once this socket is really connected, the owner of
+               the server socket will be notified. */
+
+               /* When bPassQueued is true, the socket is an orphan until it gets
+               connected. */
+               pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
+               pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
+       }
+       #else
+       {
+               /* A reference to the new socket may be stored and the socket is marked
+               as 'passable'. */
+
+               /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to
+               accept(). */
+               pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
+               if(pxSocket->u.xTCP.pxPeerSocket == NULL )
+               {
+                       pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
+               }
+       }
+       #endif
+
+       pxSocket->u.xTCP.usChildCount++;
+
+       FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
+               pxSocket->usLocalPort,
+               pxSocket->u.xTCP.usChildCount,
+               pxSocket->u.xTCP.usBacklog,
+               pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
+
+       /* Now bind the child socket to the same port as the listening socket. */
+       if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
+       {
+               FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
+               vSocketClose( pxNewSocket );
+               return pdFALSE;
+       }
+
+       return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+
+       const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
+       {
+               if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
+               {
+                       ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
+               }
+               return pcStateNames[ ulState ];
+       }
+
+#endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
+/*-----------------------------------------------------------*/
+
+/*
+ * In the API accept(), the user asks is there is a new client?  As API's can
+ * not walk through the xBoundTCPSocketsList the IP-task will do this.
+ */
+BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
+{
+TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
+ListItem_t *pxIterator;
+FreeRTOS_Socket_t *pxFound;
+BaseType_t xResult = pdFALSE;
+
+       /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
+       who has access. */
+       for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
+               pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
+               pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
+       {
+               if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
+               {
+                       pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+                       if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
+                       {
+                               pxSocket->u.xTCP.pxPeerSocket = pxFound;
+                               FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
+                               xResult = pdTRUE;
+                               break;
+                       }
+               }
+       }
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_TCP == 1 */
+
+/* Provide access to private members for testing. */
+#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
+       #include "iot_freertos_tcp_test_access_tcp_define.h"
+#endif
+
+/* Provide access to private members for verification. */
+#ifdef FREERTOS_TCP_ENABLE_VERIFICATION
+       #include "aws_freertos_tcp_verification_access_tcp_define.h"
+#endif
+