/*
 * FreeRTOS+TCP V2.2.1
 * 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_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_ARP.h"


/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
#if ipconfigUSE_TCP == 1

/*lint -e750  local macro not referenced [MISRA 2012 Rule 2.5, advisory] */

/*
 * The meaning of the TCP flags:
 */
#define tcpTCP_FLAG_FIN				( ( uint8_t ) 0x01U ) /* No more data from sender */
#define tcpTCP_FLAG_SYN				( ( uint8_t ) 0x02U ) /* Synchronize sequence numbers */
#define tcpTCP_FLAG_RST				( ( uint8_t ) 0x04U ) /* Reset the connection */
#define tcpTCP_FLAG_PSH				( ( uint8_t ) 0x08U ) /* Push function: please push buffered data to the recv application */
#define tcpTCP_FLAG_ACK				( ( uint8_t ) 0x10U ) /* Acknowledgment field is significant */
#define tcpTCP_FLAG_URG				( ( uint8_t ) 0x20U ) /* Urgent pointer field is significant */
#define tcpTCP_FLAG_ECN				( ( uint8_t ) 0x40U ) /* ECN-Echo */
#define tcpTCP_FLAG_CWR				( ( uint8_t ) 0x80U ) /* Congestion Window Reduced */

/* A mask to filter all protocol flags. */
#define tcpTCP_FLAG_CTRL			( ( uint8_t ) 0x1FU )

/*
 * A few values of the TCP options:
 */
#define tcpTCP_OPT_END				0U   /* End of TCP options list */
#define tcpTCP_OPT_NOOP				1U   /* "No-operation" TCP option */
#define tcpTCP_OPT_MSS				2U   /* Maximum segment size TCP option */
#define tcpTCP_OPT_WSOPT			3U   /* TCP Window Scale Option (3-byte long) */
#define tcpTCP_OPT_SACK_P			4U   /* Advertize that SACK is permitted */
#define tcpTCP_OPT_SACK_A			5U   /* SACK option with first/last */
#define tcpTCP_OPT_TIMESTAMP		8U   /* Time-stamp option */

#define tcpTCP_OPT_MSS_LEN			4U   /* Length of TCP MSS option. */
#define tcpTCP_OPT_WSOPT_LEN		3U   /* Length of TCP WSOPT option. */

#define tcpTCP_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 tcpNOW_CONNECTED() is use to determine if the connection makes a
 * transition from connected to non-connected and vice versa.
 * tcpNOW_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 tcpNOW_CONNECTED( status )\
	( ( ( ( status ) >= ( BaseType_t ) eESTABLISHED ) && ( ( status ) != ( BaseType_t ) eCLOSE_WAIT ) ) ? 1 : 0 )

/*
 * The highest 4 bits in the TCP offset byte indicate the total length of the
 * TCP header, divided by 4.
 */
#define tcpVALID_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 tcpDELAYED_ACK_SHORT_DELAY_MS			( 2 )	/* Should not become smaller than 1. */
#define tcpDELAYED_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 tcpREDUCED_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 tcpTCP_OFFSET_LENGTH_BITS			( 0xf0U )
#define tcpTCP_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

/* Two macro's that were introduced to work with both IPv4 and IPv6. */
#define xIPHeaderSize( pxNetworkBuffer )	( ipSIZE_OF_IPv4_HEADER )
#define uxIPHeaderSizeSocket( pxSocket )	( ipSIZE_OF_IPv4_HEADER )

/*
 * Returns true if the socket must be checked.  Non-active sockets are waiting
 * for user action, either connect() or close().
 */
static BaseType_t prvTCPSocketIsActive( eIPTCPState_t xStatus );

/*
 * 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 *pxDescriptor,
	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, const 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 size_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
											 size_t uxTotalLength,
											 FreeRTOS_Socket_t * const pxSocket,
											 BaseType_t xHasSYNFlag );

#if( ipconfigUSE_TCP_WIN == 1 )
	/*
	 * Skip past TCP header options when doing Selective ACK, until there are no
	 * more options left.
	 */
	static void prvReadSackOption( const uint8_t * const pucPtr,
								   size_t uxIndex,
								   FreeRTOS_Socket_t * const pxSocket );
#endif/* ( ipconfigUSE_TCP_WIN == 1 ) */


/*
 * 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, TCPHeader_t *pxTCPHeader );

/*
 * 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, const NetworkBufferDescriptor_t *pxNetworkBuffer );

/*
 * Called from prvTCPHandleState().  Find the TCP payload data and check and
 * return its length.
 */
static BaseType_t prvCheckRxData( const 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, const 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, const 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, const NetworkBufferDescriptor_t *pxNetworkBuffer,
	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 xByteCount );

/*
 * 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( const FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
	int32_t lDataLen, UBaseType_t uxOptionsLength );

#if( ipconfigUSE_TCP_WIN != 0 )
	static uint8_t prvWinScaleFactor( const FreeRTOS_Socket_t *pxSocket );
#endif

/*-----------------------------------------------------------*/

/* 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( eIPTCPState_t xStatus )
{
BaseType_t xResult;
	switch( xStatus )
	{
	case eCLOSED:
	case eCLOSE_WAIT:
	case eFIN_WAIT_2:
	case eCLOSING:
	case eTIME_WAIT:
		xResult = pdFALSE;
		break;
	case eTCP_LISTEN:
	case eCONNECT_SYN:
	case eSYN_FIRST:
	case eSYN_RECEIVED:
	case eESTABLISHED:
	case eFIN_WAIT_1:
	case eLAST_ACK:
	default:
		xResult = pdTRUE;
		break;
	}
	return xResult;
}
/*-----------------------------------------------------------*/

#if( ipconfigTCP_HANG_PROTECTION == 1 )

	static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
	{
	BaseType_t xResult;
	eIPTCPState_t eState = ipNUMERIC_CAST( eIPTCPState_t, pxSocket->u.xTCP.ucTCPState );

		switch( eState )
		{
		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;
		case eCONNECT_SYN:
		case eSYN_FIRST:
		case eSYN_RECEIVED:
		case eFIN_WAIT_1:
		case eFIN_WAIT_2:
		case eCLOSING:
		case eLAST_ACK:
		case eTIME_WAIT:
		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 > ( ( TickType_t ) ipconfigTCP_HANG_PROTECTION_TIME * ( TickType_t ) 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(). */
						( void ) 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 >= ( uint8_t ) 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 so 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 != ( uint8_t ) 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,
							( unsigned ) 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 ) > 1U )
				{
					/* 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 >= ( uint8_t ) eESTABLISHED ) ||
			( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCONNECT_SYN ) )
		{
			( void ) prvTCPSendPacket( pxSocket );
		}

		/* Set the time-out for the next wakeup for this socket. */
		( void ) 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;
NetworkBufferDescriptor_t *pxNetworkBuffer;

	if( pxSocket->u.xTCP.ucTCPState != ( uint8_t ) eCONNECT_SYN )
	{
		/* The connection is in a 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 ) )
		{
		ProtocolHeaders_t *pxProtocolHeaders;
		const UBaseType_t uxHeaderSize = ipSIZE_OF_IPv4_HEADER;
			/* 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. */
			pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *, &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ ipSIZE_OF_ETH_HEADER + uxHeaderSize ] ) );

			/* 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, &( pxProtocolHeaders->xTCPHeader ) );

			/* Return the number of bytes to be sent. */
			lResult = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + 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 */
			pxProtocolHeaders->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 );
		}
		else
		{
			/* Nothing to do. */
		}
	}

	/* 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 *pxDescriptor, uint32_t ulLen, BaseType_t xReleaseAfterSend )
{
TCPPacket_t * pxTCPPacket;
IPHeader_t *pxIPHeader;
BaseType_t xDoRelease = xReleaseAfterSend;
EthernetHeader_t *pxEthernetHeader;
uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
const TCPWindow_t *pxTCPWindow;
NetworkBufferDescriptor_t *pxNetworkBuffer = pxDescriptor;	/* To avoid error: "function parameter modified [MISRA 2012 Rule 17.8, advisory]" */
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 );
		xDoRelease = pdFALSE;
	}

	#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
	{
		if( xDoRelease == pdFALSE )
		{
			pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( size_t ) pxNetworkBuffer->xDataLength );
			if( pxNetworkBuffer == NULL )
			{
				FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
			}
			xDoRelease = pdTRUE;
		}
	}
	#endif /* ipconfigZERO_COPY_TX_DRIVER */

	#ifndef __COVERITY__
	if( pxNetworkBuffer != NULL )
	#endif
	{
		pxTCPPacket = ipPOINTER_CAST( 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 );

			/* 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 ) tcpTCP_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 ) ~tcpTCP_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( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
			pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );

			/* calculate the TCP checksum for an outgoing packet. */
			( void ) 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 == 0U )
			{
				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. */
		( void ) memcpy( &( pxEthernetHeader->xDestinationAddress ),
						 &( pxEthernetHeader->xSourceAddress ),
						 sizeof( pxEthernetHeader->xDestinationAddress ) );

		/* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
		( void ) memcpy( &( pxEthernetHeader->xSourceAddress ), 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! */
		( void ) xNetworkInterfaceOutput( pxNetworkBuffer, xDoRelease );

		if( xDoRelease == 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;
			( void ) 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 != 0 )
	{
		FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %u Water %u <= %u <= %u\n",
			( unsigned ) pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
			( unsigned ) pxSocket->u.xTCP.uxLittleSpace ,
			( unsigned ) pxSocket->u.xTCP.uxEnoughSpace,
			( unsigned ) pxSocket->u.xTCP.uxRxStreamSize ) );
	}
	vTCPWindowCreate(
		&pxSocket->u.xTCP.xTCPWindow,
		( ( size_t ) ipconfigTCP_MSS ) * pxSocket->u.xTCP.uxRxWinSize,
		( ( size_t ) 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. */
		( void ) 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;
		break;
	}

	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( ulInitialSequenceNumber == 0UL )
		{
			xReturn = pdFALSE;
		}
	}

	if( xReturn != pdFALSE )
	{
	uint16_t usLength;

		/* The MAC-address of the peer (or gateway) has been found,
		now prepare the initial TCP packet and some fields in the socket. */
		pxTCPPacket = ipPOINTER_CAST( 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. */
		( void ) 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(). */
		( void ) 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;
		usLength = ( uint16_t ) ( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
		pxIPHeader->usLength = FreeRTOS_htons( usLength );
		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 = tcpTCP_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];
		size_t uxFlags = ( size_t ) xFlags;
		( void ) snprintf(retString,
			sizeof( retString ), "%c%c%c%c%c%c%c%c",
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_FIN ) != 0 )   ? 'F' : '.',	/* 0x0001: No more data from sender */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_SYN ) != 0 )   ? 'S' : '.',	/* 0x0002: Synchronize sequence numbers */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_RST ) != 0 )   ? 'R' : '.',	/* 0x0004: Reset the connection */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_PSH ) != 0 )   ? 'P' : '.',	/* 0x0008: Push function: please push buffered data to the recv application */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_ACK ) != 0 )   ? 'A' : '.',	/* 0x0010: Acknowledgment field is significant */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_URG ) != 0 )   ? 'U' : '.',	/* 0x0020: Urgent pointer field is significant */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_ECN ) != 0 )   ? 'E' : '.',	/* 0x0040: ECN-Echo */
			( ( uxFlags & ( size_t ) tcpTCP_FLAG_CWR ) != 0 )   ? 'C' : '.');	/* 0x0080: Congestion Window Reduced */
		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, const NetworkBufferDescriptor_t *pxNetworkBuffer )
{
size_t uxTCPHeaderOffset = ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer );
const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ uxTCPHeaderOffset ] ) );
const TCPHeader_t * pxTCPHeader;
const uint8_t *pucPtr;
BaseType_t xHasSYNFlag;
/* Offset in the network packet where the first option byte is stored. */
size_t uxOptionOffset = uxTCPHeaderOffset + ( sizeof( TCPHeader_t ) - sizeof( pxTCPHeader->ucOptdata ) );
size_t uxOptionsLength;
size_t uxResult;
uint8_t ucLength;

	pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );


	/* A character pointer to iterate through the option data */
	pucPtr = pxTCPHeader->ucOptdata;
	if( pxTCPHeader->ucTCPOffset <= ( 5U << 4U ) )
	{
		/* Avoid integer underflow in computation of ucLength. */
		return;
	}
	ucLength = ( ( ( pxTCPHeader->ucTCPOffset >> 4U ) - 5U ) << 2U );
	uxOptionsLength = ( size_t ) ucLength;
	if( pxNetworkBuffer->xDataLength > uxOptionOffset )
	{
		/* Validate options size calculation. */
		if( ( pxNetworkBuffer->xDataLength > uxOptionOffset ) &&
			( uxOptionsLength <= ( pxNetworkBuffer->xDataLength - uxOptionOffset ) ) )
		{
			if( ( pxTCPHeader->ucTCPFlags & tcpTCP_FLAG_SYN ) != ( uint8_t ) 0U )
			{
				xHasSYNFlag = pdTRUE;
			}
			else
			{
				xHasSYNFlag = pdFALSE;
			}
			/* The length check is only necessary in case the option data are
			corrupted, we don't like to run into invalid memory and crash. */
			for( ;; )
			{
				if( uxOptionsLength == 0U )
				{
					/* coverity[break_stmt] : Break statement terminating the loop */
					break;
				}
				uxResult = prvSingleStepTCPHeaderOptions( pucPtr, uxOptionsLength, pxSocket, xHasSYNFlag );
				if( uxResult == 0UL )
				{
					break;
				}
				uxOptionsLength -= uxResult;
				pucPtr = &( pucPtr[ uxResult ] );
			}
		}
	}
}
/*-----------------------------------------------------------*/

static size_t prvSingleStepTCPHeaderOptions( const uint8_t * const pucPtr,
											 size_t uxTotalLength,
											 FreeRTOS_Socket_t * const pxSocket,
											 BaseType_t xHasSYNFlag )
{
UBaseType_t uxNewMSS;
size_t uxRemainingOptionsBytes = uxTotalLength;
uint8_t ucLen;
size_t uxIndex = 0U;
TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );

	if( pucPtr[ 0U ] == tcpTCP_OPT_END )
	{
		/* End of options. */
		return 0U;
	}
	if( pucPtr[ 0U ] == tcpTCP_OPT_NOOP )
	{
		/* NOP option, inserted to make the length a multiple of 4. */
		return 1U;
	}

	/* Any other well-formed option must be at least two bytes: the option
	type byte followed by a length byte. */
	if( uxRemainingOptionsBytes < 2U )
	{
		return 0U;
	}
#if( ipconfigUSE_TCP_WIN != 0 )
	else if( pucPtr[ 0 ] == tcpTCP_OPT_WSOPT )
	{
		/* The TCP Window Scale Option. */
		/* Confirm that the option fits in the remaining buffer space. */
		if( ( uxRemainingOptionsBytes < tcpTCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_WSOPT_LEN ) )
		{
			return 0U;
		}
		/* Option is only valid in SYN phase. */
		if( xHasSYNFlag != 0 )
		{
			pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
			pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
		}
		uxIndex = tcpTCP_OPT_WSOPT_LEN;
	}
#endif	/* ipconfigUSE_TCP_WIN */
	else if( pucPtr[ 0 ] == tcpTCP_OPT_MSS )
	{
		/* Confirm that the option fits in the remaining buffer space. */
		if( ( uxRemainingOptionsBytes < tcpTCP_OPT_MSS_LEN ) || ( pucPtr[ 1 ] != tcpTCP_OPT_MSS_LEN ) )
		{
			return 0U;
		}

		/* An MSS option with the correct option length.  FreeRTOS_htons()
		is not needed here because usChar2u16() already returns a host
		endian number. */
		uxNewMSS = usChar2u16( &( pucPtr[ 2 ] ) );

		if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
		{
			/* Perform a basic check on the the new MSS. */
			if( uxNewMSS == 0U )
			{
				return 0U;
			}

			FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
		}

		if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
		{
			/* our MSS was bigger than the MSS of the other party: adapt it. */
			pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
			if( pxSocket->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", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
				pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
			}
			pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
			pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
			pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
			pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
			pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
		}

		uxIndex = tcpTCP_OPT_MSS_LEN;
	}
	else
	{
		/* All other options have a length field, so that we easily
		can skip past them. */
		ucLen = pucPtr[ 1 ];
		if( ( ucLen < ( uint8_t ) 2U ) || ( uxRemainingOptionsBytes < ( size_t ) ucLen ) )
		{
			/* If the length field is too small or too big, the options are
			 * malformed, don't process them further.
			 */
			return 0U;
		}

		#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( pucPtr[ 0U ] == tcpTCP_OPT_SACK_A )
			{
				ucLen -= 2U;
				uxIndex += 2U;

				while( ucLen >= ( uint8_t ) 8U )
				{
					prvReadSackOption( pucPtr, uxIndex, pxSocket );
					uxIndex += 8U;
					ucLen -= 8U;
				}
				/* ucLen should be 0 by now. */
			}
		}
		#endif	/* ipconfigUSE_TCP_WIN == 1 */

		uxIndex += ( size_t ) ucLen;
	}
	return uxIndex;
}
/*-----------------------------------------------------------*/

#if( ipconfigUSE_TCP_WIN == 1 )
	static void prvReadSackOption( const uint8_t * const pucPtr,
								   size_t uxIndex,
								   FreeRTOS_Socket_t * const pxSocket )
	{
	uint32_t ulFirst = ulChar2u32( &( pucPtr[ uxIndex ] ) );
	uint32_t ulLast  = ulChar2u32( &( pucPtr[ uxIndex + 4U ] ) );
	uint32_t ulCount = ulTCPWindowTxSack( &( pxSocket->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( ( pxSocket->u.xTCP.txStream  != NULL ) && ( ulCount > 0U ) )
		{
			/* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
			( void ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
			pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_SEND;

			#if ipconfigSUPPORT_SELECT_FUNCTION == 1
			{
				if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
				{
					/* The field 'xEventBits' is used to store regular socket events
					 * (at most 8), as well as 'select events', which will be left-shifted.
					 */
					pxSocket->xEventBits |= ( ( EventBits_t ) 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( pxSocket, ulCount );
				}
			}
			#endif /* ipconfigUSE_CALLBACKS == 1  */
		}
	}

#endif	/* ( ipconfigUSE_TCP_WIN != 0 ) */
/*-----------------------------------------------------------*/

#if( ipconfigUSE_TCP_WIN != 0 )

	static uint8_t prvWinScaleFactor( const 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 %u MSS %u Factor %u\n",
			( unsigned ) pxSocket->u.xTCP.uxRxWinSize,
			( unsigned ) 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, TCPHeader_t * pxTCPHeader )
{
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 ) tcpTCP_OPT_MSS;
	pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) tcpTCP_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 ] = tcpTCP_OPT_NOOP;
		pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT );
		pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT_LEN );
		pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
		uxOptionsLength = 8U;
	}
	#else
	{
		uxOptionsLength = 4U;
	}
	#endif

	#if( ipconfigUSE_TCP_WIN != 0 )
	{
		pxTCPHeader->ucOptdata[ uxOptionsLength      ] = tcpTCP_OPT_NOOP;
		pxTCPHeader->ucOptdata[ uxOptionsLength + 1U ] = tcpTCP_OPT_NOOP;
		pxTCPHeader->ucOptdata[ uxOptionsLength + 2U ] = tcpTCP_OPT_SACK_P;	/* 4: Sack-Permitted Option. */
		pxTCPHeader->ucOptdata[ uxOptionsLength + 3U ] = 2U;	/* 2: length of this option. */
		uxOptionsLength += 4U;

	}
	#endif	/* ipconfigUSE_TCP_WIN == 0 */
	return uxOptionsLength; /* bytes, not words. */
}

/*
 * 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 = ipNUMERIC_CAST( BaseType_t, tcpNOW_CONNECTED( ( BaseType_t ) pxSocket->u.xTCP.ucTCPState ) );	/* Was it connected ? */
BaseType_t bAfter  = ipNUMERIC_CAST( BaseType_t, tcpNOW_CONNECTED( ( BaseType_t ) 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 |= ( EventBits_t ) 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 & ( ( EventBits_t ) eSELECT_READ ) ) != 0U )
						{
							xParent->xEventBits |= ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT;
						}
					}
					#endif

					#if( ipconfigUSE_CALLBACKS == 1 )
					{
						if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) ) &&
							( 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 |= ( EventBits_t ) eSOCKET_CONNECT;

				#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
				{
					if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U )
					{
						pxSocket->xEventBits |= ( ( EventBits_t ) 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 |= ( EventBits_t ) eSOCKET_CLOSED;

			#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
			{
				if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
				{
					pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT;
				}
			}
			#endif
		}
		#if( ipconfigUSE_CALLBACKS == 1 )
		{
			if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) ) && ( xConnected == NULL ) )
			{
				/* The 'connected' state has changed, call the user handler. */
				xConnected = pxSocket;
			}
		}
		#endif /* ipconfigUSE_CALLBACKS */

		if( prvTCPSocketIsActive( ipNUMERIC_CAST( eIPTCPState_t, pxSocket->u.xTCP.ucTCPState ) ) == 0 )
		{
			/* 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( ( ( BaseType_t ) eTCPState ) ==  ( ( BaseType_t ) 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 )
				{
					( void ) 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 ) ) )
		{
			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( const 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. */
		if( pxNetworkBuffer == NULL )
		{
			xResize = pdTRUE;
		}
		else
		{
			xResize = pdFALSE;
		}
	}
	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 ),
			ipNUMERIC_CAST( int32_t, ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + 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. */
		if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )
		{
			xResize = pdTRUE;
		}
		else
		{
			xResize = pdFALSE;
		}
	}

	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 = ( size_t ) lNeeded;

			/* Copy the existing data to the new created buffer. */
			if( pxNetworkBuffer != NULL )
			{
				/* Either from the previous buffer... */
				( void ) memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );

				/* ...and release it. */
				vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
			}
			else
			{
				/* Or from the socket field 'xTCP.xPacket'. */
				( void ) 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. */
		configASSERT( pxNetworkBuffer != NULL );	/* to tell lint: when xResize is false, pxNetworkBuffer is not NULL. */
		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 + uxIPHeaderSizeSocket( pxSocket ) + 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;
ProtocolHeaders_t *pxProtocolHeaders;
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;
	}

	pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *, &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
	pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
	lDataLen = 0;
	lStreamPos = 0;
	pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_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;
				pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *, &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );

				pucSendData = &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + 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 %d offs %u only %u != %d\n",
							( int ) lStreamPos, ( unsigned ) uxOffset, ( unsigned ) ulDataGot, ( int ) 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 %u <= %u (%u <= %u <= %u)\n",
								( unsigned ) ulDataGot, ( unsigned ) ulDistance,
								( unsigned ) uxTail, ( unsigned ) uxMid, ( unsigned ) uxHead ) );
						}
						#endif
						/* Although the socket sends a FIN, it will stay in
						ESTABLISHED until all current data has been received or
						delivered. */
						pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_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 == ( uint8_t ) 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;
			pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_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 ) /*_RB_ Magic number. */
			{
				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 * ( TickType_t ) configTICK_RATE_HZ );
				if( pxSocket->u.xTCP.ucKeepRepCount != ( uint8_t ) 0U )
				{
					xMax = ( TickType_t ) ( 3U * configTICK_RATE_HZ );
				}
				if( xAge > xMax )
				{
					pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
					if( xTCPWindowLoggingLevel != 0 )
					{
						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( 2500U ) );
					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 ) )
	{
		pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_FLAG_PSH );
		pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); /*_RB_ "2" needs comment. */

		pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_ACK;

		if( lDataLen != 0L )
		{
			pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_PSH;
		}

		lDataLen += ipNUMERIC_CAST( int32_t, uxIPHeaderSizeSocket( pxSocket ) + 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 == ( uint8_t ) eCONNECT_SYN )
	{
		/* The socket is actively connecting to a peer. */
		if( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED )
		{
			/* 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 )ipMS_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 ) ipMS_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, const NetworkBufferDescriptor_t *pxNetworkBuffer )
{
ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
TCPHeader_t *pxTCPHeader = &( pxProtocolHeaders->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 & tcpTCP_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 + 1UL ) )
		{
			pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
		}
	}

	if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
	{
		pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
		pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_ACK | ( uint8_t ) tcpTCP_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 = tcpTCP_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 = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + 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( const NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
{
const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
const TCPHeader_t *pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
const IPHeader_t *pxIPHeader = ipPOINTER_CAST( const IPHeader_t *, &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
const size_t xIPHeaderLength = ipSIZE_OF_IPv4_HEADER;
uint16_t usLength;

	/* 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 = ipNUMERIC_CAST( BaseType_t, ( pxTCPHeader->ucTCPOffset & tcpVALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );

	/* Let pucRecvData point to the first byte received. */
	*ppucRecvData = &( pxNetworkBuffer->pucEthernetBuffer[ ( size_t ) ipSIZE_OF_ETH_HEADER + xIPHeaderLength + ( size_t ) 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 = ipNUMERIC_CAST( int32_t, pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;

	usLength = FreeRTOS_htons( pxIPHeader->usLength );
	lLength =  ( int32_t ) 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 ) xIPHeaderLength ) )
	{
		lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) xIPHeaderLength );
	}
	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 & tcpTCP_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, const uint8_t *pucRecvData,
	NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
{
const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( const ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
const TCPHeader_t *pxTCPHeader = &pxProtocolHeaders->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 >= ( uint8_t ) 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, lTCPAddRxdata() will be
		called later to store an out-of-order packet (in case lOffset is
		negative). */
		if ( pxSocket->u.xTCP.rxStream != NULL )
		{
			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. */
				( void ) 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 > 0UL ) )
			{
				( void ) 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, const NetworkBufferDescriptor_t *pxNetworkBuffer )
{
ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
TCPHeader_t *pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
const 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 ) );
		}
		( void ) 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 >= ( EventBits_t ) 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 ] = tcpTCP_OPT_MSS;
		pxTCPHeader->ucOptdata[ 1 ] = tcpTCP_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 );
	}
	else
	{
		/* Nothing. */
	}

	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, const NetworkBufferDescriptor_t *pxNetworkBuffer,
	uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
{
ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
TCPHeader_t *pxTCPHeader = &pxProtocolHeaders->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 ) tcpTCP_FLAG_ACK;
	if( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eCONNECT_SYN )
	{
		usExpect |= ( uint16_t ) tcpTCP_FLAG_SYN;
	}

	if( ipNUMERIC_CAST( uint16_t, 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 == ( uint8_t ) eSYN_RECEIVED ) ? "eSYN_RECEIVED" : "eCONNECT_SYN",
			usExpect, ucTCPFlags ) );
		vTCPStateChange( pxSocket, eCLOSE_WAIT );
		/* Send RST with the expected sequence and ACK numbers,
		otherwise the packet will be ignored. */
		pxTCPWindow->ulOurSequenceNumber = FreeRTOS_htonl( pxTCPHeader->ulAckNr );
		pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;

		pxTCPHeader->ucTCPFlags |= tcpTCP_FLAG_RST;
		xSendLength = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + 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 == ( uint8_t ) eCONNECT_SYN )
		{
		ProtocolHeaders_t *pxLastHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
			&( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );

			/* Clear the SYN flag in lastPacket. */
			pxLastHeaders->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_ACK;
			pxProtocolHeaders->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_ACK;

			/* This socket was the one connecting actively so now perform the
			synchronisation. */
			vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
				ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
			pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1U;
			pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1U;
			pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
			pxTCPWindow->ulNextTxSequenceNumber++;
		}
		else if( ulReceiveLength == 0U )
		{
			pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
		}
		else
		{
			/* Nothing. */
		}

		/* 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 == ( uint8_t )  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 == ( EventBits_t ) eCONNECT_SYN ) || ( ulReceiveLength != 0UL ) )
		{
			pxTCPHeader->ucTCPFlags = tcpTCP_FLAG_ACK;
			xSendLength = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + ( size_t ) 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 )
{
ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
TCPHeader_t *pxTCPHeader = &pxProtocolHeaders->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;
uint16_t usWindow;

	/* Remember the window size the peer is advertising. */
	usWindow = FreeRTOS_ntohs( pxTCPHeader->usWindow );
	pxSocket->u.xTCP.ulWindowSize = ( uint32_t ) usWindow;
	#if( ipconfigUSE_TCP_WIN != 0 )
	{
		pxSocket->u.xTCP.ulWindowSize =
			( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
	}
	#endif /* ipconfigUSE_TCP_WIN */

	if( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_ACK ) != 0U )
	{
		ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPHeader->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 |= ( EventBits_t ) eSOCKET_SEND;

				#if ipconfigSUPPORT_SELECT_FUNCTION == 1
				{
					if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U )
					{
						pxSocket->xEventBits |= ( ( EventBits_t ) 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 ) tcpTCP_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 = ipNUMERIC_CAST( 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 = tcpTCP_FLAG_ACK;

		if( ulReceiveLength != 0U )
		{
			xSendLength = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + 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 xByteCount )
{
const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( *ppxNetworkBuffer ) ] ) );
const TCPHeader_t *pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
const TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
/* Find out what window size we may advertised. */
int32_t lRxSpace;
BaseType_t xSendLength = xByteCount;
#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 = ipNUMERIC_CAST( 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. */
		/* lint e9007 is OK because 'uxIPHeaderSizeSocket()' has no side-effects. */
		if( ( ulReceiveLength > 0U ) &&							/* 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 == ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
			( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eESTABLISHED ) &&	/* Connection established. */
			( pxTCPHeader->ucTCPFlags == tcpTCP_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 != NULL )
				{
					vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
				}

				pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
			}
			if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) ||	/* Received a small message. */
				( lRxSpace < ipNUMERIC_CAST( 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 ) tcpDELAYED_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 ) ipMS_TO_MIN_TICKS( tcpDELAYED_ACK_LONGER_DELAY_MS );
			}

			if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) )
			{
				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
		{
			/* The ack will not be postponed, and there was no stored ack ( in 'pxAckMessage' ). */
		}
	}
	#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 ) ) )
		{
			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 )
{
ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( ProtocolHeaders_t *,
	&( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( *ppxNetworkBuffer ) ] ) );
TCPHeader_t *pxTCPHeader = &( pxProtocolHeaders->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 >= ( uint8_t ) eESTABLISHED )
	{
		if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
		{
			/* 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( ( ipNUMERIC_CAST( int32_t, ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0L )
	{
		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 == ( uint8_t ) eSYN_RECEIVED ) && ( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_CTRL ) == ( uint8_t ) tcpTCP_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 & tcpTCP_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( ipNUMERIC_CAST( eIPTCPState_t, 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, pxTCPHeader );
				pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_SYN | ( uint8_t ) tcpTCP_FLAG_ACK;

				xSendLength = ipNUMERIC_CAST( BaseType_t, uxIPHeaderSizeSocket( pxSocket ) + 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.ulHighestSequenceNumber = ulSequenceNumber + 1UL;
				pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1UL;
				pxTCPWindow->ulNextTxSequenceNumber     = pxTCPWindow->tx.ulFirstSequenceNumber + 1UL;
				pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1UL; /* 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:
			/* No more known states. */
			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 == 1 )
	/* Configured to ignore unknown packets just suppress a compiler warning. */
	( void ) pxNetworkBuffer;
	( void ) ucTCPFlags;
#else
	{
		TCPPacket_t *pxTCPPacket = ipPOINTER_CAST( TCPPacket_t *, pxNetworkBuffer->pucEthernetBuffer );
		const BaseType_t xSendLength = ( BaseType_t )
			( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ); /* Plus 0 options. */

		pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;
		pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER ) << 2;

		prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE );
	}
#endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */

	/* The packet was not consumed. */
	return pdFAIL;
}
/*-----------------------------------------------------------*/

static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer )
{
	return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, tcpTCP_FLAG_ACK );
}
/*-----------------------------------------------------------*/

static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
{
	return prvTCPSendSpecialPacketHelper( pxNetworkBuffer,
										  ( uint8_t ) tcpTCP_FLAG_ACK | ( uint8_t ) tcpTCP_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 ) tcpREDUCED_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 = ( uint16_t ) ulMSS;
	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 *pxDescriptor )
{
/* Function might modify the parameter. */
NetworkBufferDescriptor_t *pxNetworkBuffer = pxDescriptor;
const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( const ProtocolHeaders_t *,
	&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );
FreeRTOS_Socket_t *pxSocket;
uint16_t ucTCPFlags = pxProtocolHeaders->xTCPHeader.ucTCPFlags;
uint32_t ulLocalIP;
uint16_t xLocalPort = FreeRTOS_htons( pxProtocolHeaders->xTCPHeader.usDestinationPort );
uint16_t xRemotePort = FreeRTOS_htons( pxProtocolHeaders->xTCPHeader.usSourcePort );
uint32_t ulRemoteIP;
uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxProtocolHeaders->xTCPHeader.ulSequenceNumber );
uint32_t ulAckNumber = FreeRTOS_ntohl( pxProtocolHeaders->xTCPHeader.ulAckNr );;
BaseType_t xResult = pdPASS;
configASSERT( pxNetworkBuffer != NULL );
configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
const IPHeader_t *pxIPHeader;

	/* Check for a minimum packet size. */
	if( pxNetworkBuffer->xDataLength < ( ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) + ipSIZE_OF_TCP_HEADER ) )
	{
		return pdFAIL;
	}

	pxIPHeader = ipPOINTER_CAST( const IPHeader_t *, &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
	ulLocalIP = FreeRTOS_htonl( pxIPHeader->ulDestinationIPAddress );
	ulRemoteIP = FreeRTOS_htonl( pxIPHeader->ulSourceIPAddress );

	/* 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 );

	if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ipNUMERIC_CAST( eIPTCPState_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 & tcpTCP_FLAG_CTRL ) != tcpTCP_FLAG_ACK ) &&
			( ( ucTCPFlags & tcpTCP_FLAG_RST ) == 0U ) )
		{
			( void ) prvTCPSendReset( pxNetworkBuffer );
		}

		/* The packet can't be handled. */
		xResult = pdFAIL;
	}
	else
	{
		pxSocket->u.xTCP.ucRepCount = 0U;

		if( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eTCP_LISTEN )
		{
			/* The matching socket is in a listening state.  Test if the peer
			has set the SYN flag. */
			if( ( ucTCPFlags & tcpTCP_FLAG_CTRL ) != tcpTCP_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 & tcpTCP_FLAG_RST ) == 0U )
				{
					( void ) 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 & tcpTCP_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 == ( uint8_t ) 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 + 1UL ) )
					{
						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. */
						( void ) prvTCPSendChallengeAck( pxNetworkBuffer );
					}
					else
					{
						/* Nothing. */
					}
				}

				/* Otherwise, do nothing. In any case, the packet cannot be handled. */
				xResult = pdFAIL;
			}
			else if( ( ( ucTCPFlags & tcpTCP_FLAG_CTRL ) == tcpTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) 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 = ipNUMERIC_CAST( BaseType_t, ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) );
				( void ) memcpy( &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ lOffset ] ),
								 &( pxNetworkBuffer->pucEthernetBuffer[ lOffset ] ),
								 ipSIZE_OF_TCP_HEADER );
			}
		}
	}

	if( xResult != pdFAIL )
	{
	uint16_t usWindow;

		/* pxSocket is not NULL when xResult != pdFAIL. */
		configASSERT( pxSocket != NULL );
		/* 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 nibble of the TCP-offset byte. */
		if( ( pxProtocolHeaders->xTCPHeader.ucTCPOffset & tcpTCP_OFFSET_LENGTH_BITS ) > tcpTCP_OFFSET_STANDARD_LENGTH )
		{
			prvCheckOptions( pxSocket, pxNetworkBuffer );
		}

		usWindow = FreeRTOS_ntohs( pxProtocolHeaders->xTCPHeader.usWindow );
		pxSocket->u.xTCP.ulWindowSize = (uint32_t ) usWindow;
		#if( ipconfigUSE_TCP_WIN == 1 )
		{
			/* rfc1323 : The Window field in a SYN (i.e., a <SYN> or <SYN,ACK>)
			segment itself is never scaled. */
			if( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_SYN ) == 0U )
			{
				pxSocket->u.xTCP.ulWindowSize =
					( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
			}
		}
		#endif /* ipconfigUSE_TCP_WIN */

		/* 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 )
			{
				( void ) 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 );
			#ifndef _lint
			/* Clear pointers that are freed. */
			pxNetworkBuffer = NULL;
			#endif
		}

		/* And finally, calculate when this socket wants to be woken up. */
		( void ) 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 )
{
const TCPPacket_t * pxTCPPacket = ipPOINTER_CAST( const 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( ulInitialSequenceNumber != 0UL )
	{
		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 == 1U ) ? "" : "ren" ) );
				( void ) 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" ) );
					( void ) 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;
				}
				else
				{
					/* Copying failed somehow. */
				}
			}
		}
	}

	if( ( ulInitialSequenceNumber != 0U ) && ( pxReturn != NULL ) )
	{
	const ProtocolHeaders_t *pxProtocolHeaders = ipPOINTER_CAST( const ProtocolHeaders_t *,
		&( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( pxNetworkBuffer ) ] ) );

		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( pxProtocolHeaders->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. */
		( void ) 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;
BaseType_t xResult;

	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 != NULL )
		{
			pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
			pxNewSocket->xSelectBits = pxSocket->xSelectBits | ( ( EventBits_t ) eSELECT_READ ) | ( ( EventBits_t ) 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 true, 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" ) );
		( void ) vSocketClose( pxNewSocket );
		xResult = pdFALSE;
	}
	else
	{
		xResult = pdTRUE;
	}

	return xResult;
}
/*-----------------------------------------------------------*/

#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )

	const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
	{
	static const char * const 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",
	};
	BaseType_t xIndex = ( BaseType_t ) ulState;

		if( ( xIndex < 0 ) || ( xIndex >= ARRAY_SIZE( pcStateNames ) ) )
		{
			/* The last item is called 'eUNKNOWN' */
			xIndex = ARRAY_SIZE( pcStateNames );
			xIndex--;
		}
		return pcStateNames[ xIndex ];
	}

#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 uxLocalPort = ( TickType_t ) FreeRTOS_htons( pxSocket->usLocalPort );
const ListItem_t *pxIterator;
FreeRTOS_Socket_t *pxFound;
BaseType_t xResult = pdFALSE;
const ListItem_t *pxEndTCP = ipPOINTER_CAST( const ListItem_t *, listGET_END_MARKER( &xBoundTCPSocketsList ) );

	/* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
	who has access. */
	for( pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
		pxIterator != pxEndTCP;
		pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
	{
		if( listGET_LIST_ITEM_VALUE( pxIterator ) == ( configLIST_VOLATILE TickType_t ) uxLocalPort )
		{
			pxFound = ipPOINTER_CAST( FreeRTOS_Socket_t *, listGET_LIST_ITEM_OWNER( pxIterator ) );
			if( ( pxFound->ucProtocol == ( uint8_t ) 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 FREERTOS_ENABLE_UNIT_TESTS
	#include "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
