]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_TCP_WIN.c
index cda8acd1cea63bc755ede7e0ee4e223ab5a901d7..8040880092d4a3cfbccb8a132a65ffbf0d5223d1 100644 (file)
-/*\r
- * FreeRTOS+TCP V2.2.0\r
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/*\r
- * FreeRTOS_TCP_WIN.c\r
- * Module which handles the TCP windowing schemes for FreeRTOS+TCP.  Many\r
- * functions have two versions - one for FreeRTOS+TCP (full) and one for\r
- * FreeRTOS+TCP (lite).\r
- *\r
- * In this module all ports and IP addresses and sequence numbers are\r
- * being stored in host byte-order.\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_UDP_IP.h"\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "NetworkBufferManagement.h"\r
-#include "FreeRTOS_TCP_WIN.h"\r
-\r
-/* Constants used for Smoothed Round Trip Time (SRTT). */\r
-#define        winSRTT_INCREMENT_NEW           2\r
-#define winSRTT_INCREMENT_CURRENT      6\r
-#define        winSRTT_DECREMENT_NEW           1\r
-#define winSRTT_DECREMENT_CURRENT      7\r
-#define winSRTT_CAP_mS                         50\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )\r
-\r
-       #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )\r
-\r
-       /* The code to send a single Selective ACK (SACK):\r
-        * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),\r
-        * followed by a lower and a higher sequence number,\r
-        * where LEN is 2 + 2*4 = 10 bytes. */\r
-       #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )\r
-               #define OPTION_CODE_SINGLE_SACK         ( 0x0101050aUL )\r
-       #else\r
-               #define OPTION_CODE_SINGLE_SACK         ( 0x0a050101UL )\r
-       #endif\r
-\r
-       /* Normal retransmission:\r
-        * A packet will be retransmitted after a Retransmit Time-Out (RTO).\r
-        * Fast retransmission:\r
-        * When 3 packets with a higher sequence number have been acknowledged\r
-        * by the peer, it is very unlikely a current packet will ever arrive.\r
-        * It will be retransmitted far before the RTO.\r
-        */\r
-       #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT           ( 3u )\r
-\r
-       /* If there have been several retransmissions (4), decrease the\r
-        * size of the transmission window to at most 2 times MSS.\r
-        */\r
-       #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW           ( 4u )\r
-\r
-#endif /* configUSE_TCP_WIN */\r
-/*-----------------------------------------------------------*/\r
-\r
-extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );\r
-\r
-/*\r
- * All TCP sockets share a pool of segment descriptors (TCPSegment_t)\r
- * Available descriptors are stored in the 'xSegmentList'\r
- * When a socket owns a descriptor, it will either be stored in\r
- * 'xTxSegments' or 'xRxSegments'\r
- * As soon as a package has been confirmed, the descriptor will be returned\r
- * to the segment pool\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static BaseType_t prvCreateSectors( void );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * Find a segment with a given sequence number in the list of received\r
- * segments: 'pxWindow->xRxSegments'.\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * Allocate a new segment\r
- * The socket will borrow all segments from a common pool: 'xSegmentList',\r
- * which is a list of 'TCPSegment_t'\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/* When the peer has a close request (FIN flag), the driver will check if\r
- * there are missing packets in the Rx-queue\r
- * It will accept the closure of the connection if both conditions are true:\r
- * - the Rx-queue is empty\r
- * - we've ACK'd the highest Rx sequence number seen\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * Detaches and returns the head of a queue\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * Returns the head of a queue but it won't be detached\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- *  Free entry pxSegment because it's not used anymore\r
- *     The ownership will be passed back to the segment pool\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static void vTCPWindowFree( TCPSegment_t *pxSegment );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * A segment has been received with sequence number 'ulSequenceNumber', where\r
- * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this\r
- * segment was expected.  xTCPWindowRxConfirm() will check if there is already\r
- * another segment with a sequence number between (ulSequenceNumber) and\r
- * (ulSequenceNumber+xLength).  Normally none will be found, because the next Rx\r
- * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * FreeRTOS+TCP stores data in circular buffers.  Calculate the next position to\r
- * store.\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * This function will look if there is new transmission data.  It will return\r
- * true if there is data to be sent.\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * An acknowledge was received.  See if some outstanding data may be removed\r
- * from the transmission queue(s).\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*\r
- * A higher Tx block has been acknowledged.  Now iterate through the xWaitQueue\r
- * to find a possible condition for a FAST retransmission.\r
- */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* TCP segment pool. */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static TCPSegment_t *xTCPSegments = NULL;\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-/* List of free TCP segments. */\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static List_t xSegmentList;\r
-#endif\r
-\r
-/* Logging verbosity level. */\r
-BaseType_t xTCPWindowLoggingLevel = 0;\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       /* Some 32-bit arithmetic: comparing sequence numbers */\r
-       static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );\r
-       static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )\r
-       {\r
-               /* Test if a <= b\r
-               Return true if the unsigned subtraction of (b-a) doesn't generate an\r
-               arithmetic overflow. */\r
-               return ( ( b - a ) & 0x80000000UL ) == 0UL;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );\r
-       static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )\r
-       {\r
-               /* Test if a < b */\r
-               return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );\r
-       static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )\r
-       {\r
-               /* Test if a > b */\r
-               return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN */\r
-\r
-/*-----------------------------------------------------------*/\r
-static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );\r
-static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )\r
-{\r
-       /* Test if a >= b */\r
-       return ( ( a - b ) & 0x80000000UL ) == 0UL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-       static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );\r
-       static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )\r
-       {\r
-               vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );\r
-       }\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );\r
-static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )\r
-{\r
-       pxTimer->ulBorn = xTaskGetTickCount ( );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );\r
-static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )\r
-{\r
-       return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* _HT_ GCC (using the settings that I'm using) checks for every public function if it is\r
-preceded by a prototype. Later this prototype will be located in list.h? */\r
-\r
-extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );\r
-\r
-void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )\r
-{\r
-       /* Insert a new list item into pxList, it does not sort the list,\r
-       but it puts the item just before xListEnd, so it will be the last item\r
-       returned by listGET_HEAD_ENTRY() */\r
-       pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;\r
-       pxNewListItem->pxPrevious = pxWhere->pxPrevious;\r
-       pxWhere->pxPrevious->pxNext = pxNewListItem;\r
-       pxWhere->pxPrevious = pxNewListItem;\r
-\r
-       /* Remember which list the item is in. */\r
-       listLIST_ITEM_CONTAINER( pxNewListItem ) = ( void * ) pxList;\r
-\r
-       ( pxList->uxNumberOfItems )++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static BaseType_t prvCreateSectors( void )\r
-       {\r
-       BaseType_t xIndex, xReturn;\r
-\r
-               /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */\r
-\r
-               vListInitialise( &xSegmentList );\r
-               xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );\r
-\r
-               if( xTCPSegments == NULL )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",\r
-                               ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );\r
-\r
-                       xReturn = pdFAIL;\r
-               }\r
-               else\r
-               {\r
-                       /* Clear the allocated space. */\r
-                       memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );\r
-\r
-                       for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )\r
-                       {\r
-                               /* Could call vListInitialiseItem here but all data has been\r
-                               nulled already.  Set the owner to a segment descriptor. */\r
-                               listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );\r
-                               listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );\r
-\r
-                               /* And add it to the pool of available segments */\r
-                               vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );\r
-                       }\r
-\r
-                       xReturn = pdPASS;\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )\r
-       {\r
-       const ListItem_t *pxIterator;\r
-       const MiniListItem_t* pxEnd;\r
-       TCPSegment_t *pxSegment, *pxReturn = NULL;\r
-\r
-               /* Find a segment with a given sequence number in the list of received\r
-               segments. */\r
-\r
-               pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );\r
-\r
-               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );\r
-                        pxIterator != ( const ListItem_t * ) pxEnd;\r
-                        pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )\r
-               {\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
-\r
-                       if( pxSegment->ulSequenceNumber == ulSequenceNumber )\r
-                       {\r
-                               pxReturn = pxSegment;\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               return pxReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )\r
-       {\r
-       TCPSegment_t *pxSegment;\r
-       ListItem_t * pxItem;\r
-\r
-               /* Allocate a new segment.  The socket will borrow all segments from a\r
-               common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */\r
-               if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )\r
-               {\r
-                       /* If the TCP-stack runs out of segments, you might consider\r
-                       increasing 'ipconfigTCP_WIN_SEG_COUNT'. */\r
-                       FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );\r
-                       pxSegment = NULL;\r
-               }\r
-               else\r
-               {\r
-                       /* Pop the item at the head of the list.  Semaphore protection is\r
-                       not required as only the IP task will call these functions.  */\r
-                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );\r
-\r
-                       configASSERT( pxItem != NULL );\r
-                       configASSERT( pxSegment != NULL );\r
-\r
-                       /* Remove the item from xSegmentList. */\r
-                       uxListRemove( pxItem );\r
-\r
-                       /* Add it to either the connections' Rx or Tx queue. */\r
-                       vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );\r
-\r
-                       /* And set the segment's timer to zero */\r
-                       vTCPTimerSet( &pxSegment->xTransmitTimer );\r
-\r
-                       pxSegment->u.ulFlags = 0;\r
-                       pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );\r
-                       pxSegment->lMaxLength = lCount;\r
-                       pxSegment->lDataLength = lCount;\r
-                       pxSegment->ulSequenceNumber = ulSequenceNumber;\r
-                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-                       {\r
-                       static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;\r
-                       UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );\r
-\r
-                               if( xLowestLength > xLength )\r
-                               {\r
-                                       xLowestLength = xLength;\r
-                               }\r
-                       }\r
-                       #endif /* ipconfigHAS_DEBUG_PRINTF */\r
-               }\r
-\r
-               return pxSegment;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )\r
-       {\r
-       BaseType_t xReturn;\r
-\r
-               /* When the peer has a close request (FIN flag), the driver will check\r
-               if there are missing packets in the Rx-queue.  It will accept the\r
-               closure of the connection if both conditions are true:\r
-                 - the Rx-queue is empty\r
-                 - the highest Rx sequence number has been ACK'ed */\r
-               if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )\r
-               {\r
-                       /* Rx data has been stored while earlier packets were missing. */\r
-                       xReturn = pdFALSE;\r
-               }\r
-               else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )\r
-               {\r
-                       /* No Rx packets are being stored and the highest sequence number\r
-                       that has been received has been ACKed. */\r
-                       xReturn = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",\r
-                               ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),\r
-                               ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );\r
-                       xReturn = pdFALSE;\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )\r
-       {\r
-       TCPSegment_t *pxSegment;\r
-       ListItem_t * pxItem;\r
-\r
-               /* Detaches and returns the head of a queue. */\r
-               if( listLIST_IS_EMPTY( pxList ) != pdFALSE )\r
-               {\r
-                       pxSegment = NULL;\r
-               }\r
-               else\r
-               {\r
-                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );\r
-\r
-                       uxListRemove( pxItem );\r
-               }\r
-\r
-               return pxSegment;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )\r
-       {\r
-       ListItem_t *pxItem;\r
-       TCPSegment_t *pxReturn;\r
-\r
-               /* Returns the head of a queue but it won't be detached. */\r
-               if( listLIST_IS_EMPTY( pxList ) != pdFALSE )\r
-               {\r
-                       pxReturn = NULL;\r
-               }\r
-               else\r
-               {\r
-                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );\r
-                       pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );\r
-               }\r
-\r
-               return pxReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static void vTCPWindowFree( TCPSegment_t *pxSegment )\r
-       {\r
-               /*  Free entry pxSegment because it's not used any more.  The ownership\r
-               will be passed back to the segment pool.\r
-\r
-               Unlink it from one of the queues, if any. */\r
-               if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )\r
-               {\r
-                       uxListRemove( &( pxSegment->xQueueItem ) );\r
-               }\r
-\r
-               pxSegment->ulSequenceNumber = 0u;\r
-               pxSegment->lDataLength = 0l;\r
-               pxSegment->u.ulFlags = 0u;\r
-\r
-               /* Take it out of xRxSegments/xTxSegments */\r
-               if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )\r
-               {\r
-                       uxListRemove( &( pxSegment->xListItem ) );\r
-               }\r
-\r
-               /* Return it to xSegmentList */\r
-               vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       void vTCPWindowDestroy( TCPWindow_t *pxWindow )\r
-       {\r
-       List_t * pxSegments;\r
-       BaseType_t xRound;\r
-       TCPSegment_t *pxSegment;\r
-\r
-               /*  Destroy a window.  A TCP window doesn't serve any more.  Return all\r
-               owned segments to the pool.  In order to save code, it will make 2 rounds,\r
-               one to remove the segments from xRxSegments, and a second round to clear\r
-               xTxSegments*/\r
-               for( xRound = 0; xRound < 2; xRound++ )\r
-               {\r
-                       if( xRound != 0 )\r
-                       {\r
-                               pxSegments = &( pxWindow->xRxSegments );\r
-                       }\r
-                       else\r
-                       {\r
-                               pxSegments = &( pxWindow->xTxSegments );\r
-                       }\r
-\r
-                       if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )\r
-                       {\r
-                               while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )\r
-                               {\r
-                                       pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );\r
-                                       vTCPWindowFree( pxSegment );\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,\r
-       uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )\r
-{\r
-       /* Create and initialize a window. */\r
-\r
-       #if( ipconfigUSE_TCP_WIN == 1 )\r
-       {\r
-               if( xTCPSegments == NULL )\r
-               {\r
-                       prvCreateSectors();\r
-               }\r
-\r
-               vListInitialise( &pxWindow->xTxSegments );\r
-               vListInitialise( &pxWindow->xRxSegments );\r
-\r
-               vListInitialise( &pxWindow->xPriorityQueue );                   /* Priority queue: segments which must be sent immediately */\r
-               vListInitialise( &pxWindow->xTxQueue   );                       /* Transmit queue: segments queued for transmission */\r
-               vListInitialise( &pxWindow->xWaitQueue );                       /* Waiting queue:  outstanding segments */\r
-       }\r
-       #endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-       if( xTCPWindowLoggingLevel != 0 )\r
-       {\r
-               FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",\r
-                       ulRxWindowLength, ulTxWindowLength ) );\r
-       }\r
-\r
-       pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;\r
-       pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;\r
-\r
-       vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )\r
-{\r
-const int32_t l500ms = 500;\r
-\r
-       pxWindow->u.ulFlags = 0ul;\r
-       pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;\r
-\r
-       if( ulMSS != 0ul )\r
-       {\r
-               if( pxWindow->usMSSInit != 0u )\r
-               {\r
-                       pxWindow->usMSSInit = ( uint16_t ) ulMSS;\r
-               }\r
-\r
-               if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )\r
-               {\r
-                       pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;\r
-                       pxWindow->usMSS = ( uint16_t ) ulMSS;\r
-               }\r
-       }\r
-\r
-       #if( ipconfigUSE_TCP_WIN == 0 )\r
-       {\r
-               pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;\r
-       }\r
-       #endif /* ipconfigUSE_TCP_WIN == 1 */\r
-\r
-       /*Start with a timeout of 2 * 500 ms (1 sec). */\r
-       pxWindow->lSRTT = l500ms;\r
-\r
-       /* Just for logging, to print relative sequence numbers. */\r
-       pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;\r
-\r
-       /* The segment asked for in the next transmission. */\r
-       pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;\r
-\r
-       /* The right-hand side of the receive window. */\r
-       pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;\r
-\r
-       pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;\r
-\r
-       /* The segment asked for in next transmission. */\r
-       pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;\r
-\r
-       /* The sequence number given to the next outgoing byte to be added is\r
-       maintained by lTCPWindowTxAdd(). */\r
-       pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;\r
-\r
-       /* The right-hand side of the transmit window. */\r
-       pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;\r
-       pxWindow->ulOurSequenceNumber = ulSequenceNumber;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-    void vTCPSegmentCleanup( void )\r
-    {\r
-        /* Free and clear the TCP segments pointer. This function should only be called\r
-         * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this\r
-         * function. */\r
-        if( xTCPSegments != NULL )\r
-        {\r
-            vPortFreeLarge( xTCPSegments );\r
-            xTCPSegments = NULL;\r
-        }\r
-    }\r
-\r
-#endif /* ipconfgiUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-/*=============================================================================\r
- *\r
- *                ######        #    #\r
- *                 #    #       #    #\r
- *                 #    #       #    #\r
- *                 #    #        ####\r
- *                 ######         ##\r
- *                 #  ##         ####\r
- *                 #   #        #    #\r
- *                 #    #       #    #\r
- *                ###  ##       #    #\r
- * Rx functions\r
- *\r
- *=============================================================================*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )\r
-       {\r
-       TCPSegment_t *pxBest = NULL;\r
-       const ListItem_t *pxIterator;\r
-       uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;\r
-       const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );\r
-       TCPSegment_t *pxSegment;\r
-\r
-               /* A segment has been received with sequence number 'ulSequenceNumber',\r
-               where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that\r
-               exactly this segment was expected.  xTCPWindowRxConfirm() will check if\r
-               there is already another segment with a sequence number between (ulSequenceNumber)\r
-               and (ulSequenceNumber+ulLength).  Normally none will be found, because\r
-               the next RX segment should have a sequence number equal to\r
-               '(ulSequenceNumber+ulLength)'. */\r
-\r
-               /* Iterate through all RX segments that are stored: */\r
-               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );\r
-                        pxIterator != ( const ListItem_t * ) pxEnd;\r
-                        pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )\r
-               {\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
-                       /* And see if there is a segment for which:\r
-                       'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'\r
-                       If there are more matching segments, the one with the lowest sequence number\r
-                       shall be taken */\r
-                       if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&\r
-                               ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )\r
-                       {\r
-                               if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )\r
-                               {\r
-                                       pxBest = pxSegment;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if( ( pxBest != NULL ) &&\r
-                       ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )\r
-               {\r
-                       FreeRTOS_flush_logging();\r
-                       FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",\r
-                               pxWindow->usPeerPortNumber,\r
-                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                               ulLength,\r
-                               ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,\r
-                               pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                               pxBest->lDataLength,\r
-                               pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );\r
-               }\r
-\r
-               return pxBest;\r
-       }\r
-\r
-#endif /* ipconfgiUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )\r
-       {\r
-       uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;\r
-       int32_t lReturn, lDistance;\r
-       TCPSegment_t *pxFound;\r
-\r
-               /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed\r
-               directly to user (segment is expected).  If it returns a positive\r
-               number, an earlier packet is missing, but this packet may be stored.\r
-               If negative, the packet has already been stored, or it is out-of-order,\r
-               or there is not enough space.\r
-\r
-               As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,\r
-               if more Rx data may be passed to the user after this packet. */\r
-\r
-               ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;\r
-\r
-               /* For Selective Ack (SACK), used when out-of-sequence data come in. */\r
-               pxWindow->ucOptionLength = 0u;\r
-\r
-               /* Non-zero if TCP-windows contains data which must be popped. */\r
-               pxWindow->ulUserDataLength = 0ul;\r
-\r
-               if( ulCurrentSequenceNumber == ulSequenceNumber )\r
-               {\r
-                       /* This is the packet with the lowest sequence number we're waiting\r
-                       for.  It can be passed directly to the rx stream. */\r
-                       if( ulLength > ulSpace )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );\r
-                               lReturn = -1;\r
-                       }\r
-                       else\r
-                       {\r
-                               ulCurrentSequenceNumber += ulLength;\r
-\r
-                               if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )\r
-                               {\r
-                                       ulSavedSequenceNumber = ulCurrentSequenceNumber;\r
-\r
-                    /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.\r
-                    If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.\r
-                    So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just\r
-                    clean them out. */\r
-                    do\r
-                    {\r
-                        pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );\r
-\r
-                        if ( pxFound != NULL )\r
-                        {\r
-                            /* Remove it because it will be passed to user directly. */\r
-                            vTCPWindowFree( pxFound );\r
-                        }\r
-                    } while ( pxFound );\r
-\r
-                                       /*  Check for following segments that are already in the\r
-                                       queue and increment ulCurrentSequenceNumber. */\r
-                                       while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )\r
-                                       {\r
-                                               ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;\r
-\r
-                                               /* As all packet below this one have been passed to the\r
-                                               user it can be discarded. */\r
-                                               vTCPWindowFree( pxFound );\r
-                                       }\r
-\r
-                                       if( ulSavedSequenceNumber != ulCurrentSequenceNumber )\r
-                                       {\r
-                                               /*  After the current data-package, there is more data\r
-                                               to be popped. */\r
-                                               pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;\r
-\r
-                                               if( xTCPWindowLoggingLevel >= 1 )\r
-                                               {\r
-                                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",\r
-                                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,\r
-                                                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                                                               pxWindow->ulUserDataLength,\r
-                                                               ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                                                               listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;\r
-\r
-                               /* Packet was expected, may be passed directly to the socket\r
-                               buffer or application.  Store the packet at offset 0. */\r
-                               lReturn = 0;\r
-                       }\r
-               }\r
-               else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )\r
-               {\r
-                       /* Looks like a TCP keep-alive message.  Do not accept/store Rx data\r
-                       ulUserDataLength = 0. Not packet out-of-sync.  Just reply to it. */\r
-                       lReturn = -1;\r
-               }\r
-               else\r
-               {\r
-                       /* The packet is not the one expected.  See if it falls within the Rx\r
-                       window so it can be stored. */\r
-\r
-                       /*  An "out-of-sequence" segment was received, must have missed one.\r
-                       Prepare a SACK (Selective ACK). */\r
-                       ulLast = ulSequenceNumber + ulLength;\r
-                       lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );\r
-\r
-                       if( lDistance <= 0 )\r
-                       {\r
-                               /* An earlier has been received, must be a retransmission of a\r
-                               packet that has been accepted already.  No need to send out a\r
-                               Selective ACK (SACK). */\r
-                               lReturn = -1;\r
-                       }\r
-                       else if( lDistance > ( int32_t ) ulSpace )\r
-                       {\r
-                               /* The new segment is ahead of rx.ulCurrentSequenceNumber.  The\r
-                               sequence number of this packet is too far ahead, ignore it. */\r
-                               FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );\r
-                               lReturn = -1;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* See if there is more data in a contiguous block to make the\r
-                               SACK describe a longer range of data. */\r
-\r
-                               /* TODO: SACK's may also be delayed for a short period\r
-                                * This is useful because subsequent packets will be SACK'd with\r
-                                * single one message\r
-                                */\r
-                               while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )\r
-                               {\r
-                                       ulLast += ( uint32_t ) pxFound->lDataLength;\r
-                               }\r
-\r
-                               if( xTCPWindowLoggingLevel >= 1 )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",\r
-                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,\r
-                                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                                               ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                                               ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ),  /* want this signed */\r
-                                               ulLast - pxWindow->rx.ulFirstSequenceNumber ) );\r
-                               }\r
-\r
-                               /* Now prepare the SACK message.\r
-                               Code OPTION_CODE_SINGLE_SACK already in network byte order. */\r
-                               pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;\r
-\r
-                               /* First sequence number that we received. */\r
-                               pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );\r
-\r
-                               /* Last + 1 */\r
-                               pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );\r
-\r
-                               /* Which make 12 (3*4) option bytes. */\r
-                               pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );\r
-\r
-                               pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );\r
-\r
-                               if( pxFound != NULL )\r
-                               {\r
-                                       /* This out-of-sequence packet has been received for a\r
-                                       second time.  It is already stored but do send a SACK\r
-                                       again. */\r
-                                       lReturn = -1;\r
-                               }\r
-                               else\r
-                               {\r
-                                       pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );\r
-\r
-                                       if( pxFound == NULL )\r
-                                       {\r
-                                               /* Can not send a SACK, because the segment cannot be\r
-                                               stored. */\r
-                                               pxWindow->ucOptionLength = 0u;\r
-\r
-                                               /* Needs to be stored but there is no segment\r
-                                               available. */\r
-                                               lReturn = -1;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               if( xTCPWindowLoggingLevel != 0 )\r
-                                               {\r
-                                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",\r
-                                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,\r
-                                                               listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );\r
-                                                       FreeRTOS_flush_logging( );\r
-                                               }\r
-\r
-                                               /* Return a positive value.  The packet may be accepted\r
-                                               and stored but an earlier packet is still missing. */\r
-                                               lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return lReturn;\r
-       }\r
-\r
-#endif /* ipconfgiUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-/*=============================================================================\r
- *\r
- *                    #########   #    #\r
- *                    #   #   #   #    #\r
- *                        #       #    #\r
- *                        #        ####\r
- *                        #         ##\r
- *                        #        ####\r
- *                        #       #    #\r
- *                        #       #    #\r
- *                      #####     #    #\r
- *\r
- * Tx functions\r
- *\r
- *=============================================================================*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )\r
-       {\r
-               /* +TCP stores data in circular buffers.  Calculate the next position to\r
-               store. */\r
-               lPosition += lCount;\r
-               if( lPosition >= lMax )\r
-               {\r
-                       lPosition -= lMax;\r
-               }\r
-\r
-               return lPosition;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )\r
-       {\r
-       int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;\r
-       int32_t lDone = 0;\r
-       TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;\r
-\r
-               /* Puts a message in the Tx-window (after buffer size has been\r
-               verified). */\r
-               if( pxSegment != NULL )\r
-               {\r
-                       if( pxSegment->lDataLength < pxSegment->lMaxLength )\r
-                       {\r
-                               if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )\r
-                               {\r
-                                       /* Adding data to a segment that was already in the TX queue.  It\r
-                                       will be filled-up to a maximum of MSS (maximum segment size). */\r
-                                       lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );\r
-\r
-                                       pxSegment->lDataLength += lToWrite;\r
-\r
-                                       if( pxSegment->lDataLength >= pxSegment->lMaxLength )\r
-                                       {\r
-                                               /* This segment is full, don't add more bytes. */\r
-                                               pxWindow->pxHeadSegment = NULL;\r
-                                       }\r
-\r
-                                       lBytesLeft -= lToWrite;\r
-\r
-                                       /* ulNextTxSequenceNumber is the sequence number of the next byte to\r
-                                       be stored for transmission. */\r
-                                       pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;\r
-\r
-                                       /* Increased the return value. */\r
-                                       lDone += lToWrite;\r
-\r
-                                       /* Some detailed logging, for those who're interested. */\r
-                                       if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",\r
-                                                       ulLength,\r
-                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       pxSegment->lDataLength,\r
-                                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       pxSegment->lStreamPos ) );\r
-                                               FreeRTOS_flush_logging( );\r
-                                       }\r
-\r
-                                       /* Calculate the next position in the circular data buffer, knowing\r
-                                       its maximum length 'lMax'. */\r
-                                       lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );\r
-                               }\r
-                       }\r
-               }\r
-\r
-               while( lBytesLeft > 0 )\r
-               {\r
-                       /* The current transmission segment is full, create new segments as\r
-                       needed. */\r
-                       pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );\r
-\r
-                       if( pxSegment != NULL )\r
-                       {\r
-                               /* Store as many as needed, but no more than the maximum\r
-                               (MSS). */\r
-                               lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );\r
-\r
-                               pxSegment->lDataLength = lToWrite;\r
-                               pxSegment->lStreamPos = lPosition;\r
-                               lBytesLeft -= lToWrite;\r
-                               lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );\r
-                               pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;\r
-                               lDone += lToWrite;\r
-\r
-                               /* Link this segment in the Tx-Queue. */\r
-                               vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );\r
-\r
-                               /* Let 'pxHeadSegment' point to this segment if there is still\r
-                               space. */\r
-                               if( pxSegment->lDataLength < pxSegment->lMaxLength )\r
-                               {\r
-                                       pxWindow->pxHeadSegment = pxSegment;\r
-                               }\r
-                               else\r
-                               {\r
-                                       pxWindow->pxHeadSegment = NULL;\r
-                               }\r
-\r
-                               if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )\r
-                               {\r
-                                       if( ( xTCPWindowLoggingLevel >= 3 ) ||\r
-                                               ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",\r
-                                                       ulLength,\r
-                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       pxSegment->lDataLength,\r
-                                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       pxSegment->lStreamPos ) );\r
-                                               FreeRTOS_flush_logging( );\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               /* A sever situation: running out of segments for transmission.\r
-                               No more data can be sent at the moment. */\r
-                               if( lDone != 0 )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );\r
-                               }\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               return lDone;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )\r
-       {\r
-               return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )\r
-       {\r
-       uint32_t ulTxOutstanding;\r
-       BaseType_t xHasSpace;\r
-       TCPSegment_t *pxSegment;\r
-\r
-               /* This function will look if there is new transmission data.  It will\r
-               return true if there is data to be sent. */\r
-\r
-               pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );\r
-\r
-               if( pxSegment == NULL )\r
-               {\r
-                       xHasSpace = pdFALSE;\r
-               }\r
-               else\r
-               {\r
-                       /* How much data is outstanding, i.e. how much data has been sent\r
-                       but not yet acknowledged ? */\r
-                       if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )\r
-                       {\r
-                               ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;\r
-                       }\r
-                       else\r
-                       {\r
-                               ulTxOutstanding = 0UL;\r
-                       }\r
-\r
-                       /* Subtract this from the peer's space. */\r
-                       ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );\r
-\r
-                       /* See if the next segment may be sent. */\r
-                       if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )\r
-                       {\r
-                               xHasSpace = pdTRUE;\r
-                       }\r
-                       else\r
-                       {\r
-                               xHasSpace = pdFALSE;\r
-                       }\r
-\r
-                       /* If 'xHasSpace', it looks like the peer has at least space for 1\r
-                       more new segment of size MSS.  xSize.ulTxWindowLength is the self-imposed\r
-                       limitation of the transmission window (in case of many resends it\r
-                       may be decreased). */\r
-                       if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )\r
-                       {\r
-                               xHasSpace = pdFALSE;\r
-                       }\r
-               }\r
-\r
-               return xHasSpace;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )\r
-       {\r
-       TCPSegment_t *pxSegment;\r
-       BaseType_t xReturn;\r
-       TickType_t ulAge, ulMaxAge;\r
-\r
-               *pulDelay = 0u;\r
-\r
-               if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )\r
-               {\r
-                       /* No need to look at retransmissions or new transmission as long as\r
-                       there are priority segments.  *pulDelay equals zero, meaning it must\r
-                       be sent out immediately. */\r
-                       xReturn = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );\r
-\r
-                       if( pxSegment != NULL )\r
-                       {\r
-                               /* There is an outstanding segment, see if it is time to resend\r
-                               it. */\r
-                               ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );\r
-\r
-                               /* After a packet has been sent for the first time, it will wait\r
-                               '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,\r
-                               each time doubling the time-out */\r
-                               ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );\r
-\r
-                               if( ulMaxAge > ulAge )\r
-                               {\r
-                                       /* A segment must be sent after this amount of msecs */\r
-                                       *pulDelay = ulMaxAge - ulAge;\r
-                               }\r
-\r
-                               xReturn = pdTRUE;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* No priority segment, no outstanding data, see if there is new\r
-                               transmission data. */\r
-                               pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );\r
-\r
-                               /* See if it fits in the peer's reception window. */\r
-                               if( pxSegment == NULL )\r
-                               {\r
-                                       xReturn = pdFALSE;\r
-                               }\r
-                               else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )\r
-                               {\r
-                                       /* Too many outstanding messages. */\r
-                                       xReturn = pdFALSE;\r
-                               }\r
-                               else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )\r
-                               {\r
-                                       /* 'bSendFullSize' is a special optimisation.  If true, the\r
-                                       driver will only sent completely filled packets (of MSS\r
-                                       bytes). */\r
-                                       xReturn = pdFALSE;\r
-                               }\r
-                               else\r
-                               {\r
-                                       xReturn = pdTRUE;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )\r
-       {\r
-       TCPSegment_t *pxSegment;\r
-       uint32_t ulMaxTime;\r
-       uint32_t ulReturn  = ~0UL;\r
-\r
-\r
-               /* Fetches data to be sent-out now.\r
-\r
-               Priority messages: segments with a resend need no check current sliding\r
-               window size. */\r
-               pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );\r
-               pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;\r
-\r
-               if( pxSegment == NULL )\r
-               {\r
-                       /* Waiting messages: outstanding messages with a running timer\r
-                       neither check peer's reception window size because these packets\r
-                       have been sent earlier. */\r
-                       pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );\r
-\r
-                       if( pxSegment != NULL )\r
-                       {\r
-                               /* Do check the timing. */\r
-                               ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );\r
-\r
-                               if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )\r
-                               {\r
-                                       /* A normal (non-fast) retransmission.  Move it from the\r
-                                       head of the waiting queue. */\r
-                                       pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );\r
-                                       pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;\r
-\r
-                                       /* Some detailed logging. */\r
-                                       if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",\r
-                                                       pxWindow->usPeerPortNumber,\r
-                                                       pxWindow->usOurPortNumber,\r
-                                                       pxSegment->lDataLength,\r
-                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       pxSegment->ulSequenceNumber ) );\r
-                                               FreeRTOS_flush_logging( );\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       pxSegment = NULL;\r
-                               }\r
-                       }\r
-\r
-                       if( pxSegment == NULL )\r
-                       {\r
-                               /* New messages: sent-out for the first time.  Check current\r
-                               sliding window size of peer. */\r
-                               pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );\r
-\r
-                               if( pxSegment == NULL )\r
-                               {\r
-                                       /* No segments queued. */\r
-                                       ulReturn = 0UL;\r
-                               }\r
-                               else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )\r
-                               {\r
-                                       /* A segment has been queued but the driver waits until it\r
-                                       has a full size of MSS. */\r
-                                       ulReturn = 0;\r
-                               }\r
-                               else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )\r
-                               {\r
-                                       /* Peer has no more space at this moment. */\r
-                                       ulReturn = 0;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* Move it out of the Tx queue. */\r
-                                       pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );\r
-\r
-                                       /* Don't let pxHeadSegment point to this segment any more,\r
-                                       so no more data will be added. */\r
-                                       if( pxWindow->pxHeadSegment == pxSegment )\r
-                                       {\r
-                                               pxWindow->pxHeadSegment = NULL;\r
-                                       }\r
-\r
-                                       /* pxWindow->tx.highest registers the highest sequence\r
-                                       number in our transmission window. */\r
-                                       pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );\r
-\r
-                                       /* ...and more detailed logging */\r
-                                       if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",\r
-                                                       pxWindow->usPeerPortNumber,\r
-                                                       pxWindow->usOurPortNumber,\r
-                                                       pxSegment->lDataLength,\r
-                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       ulWindowSize ) );\r
-                                               FreeRTOS_flush_logging( );\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* There is a priority segment. It doesn't need any checking for\r
-                       space or timeouts. */\r
-                       if( xTCPWindowLoggingLevel != 0 )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",\r
-                                       pxWindow->usPeerPortNumber,\r
-                                       pxWindow->usOurPortNumber,\r
-                                       pxSegment->lDataLength,\r
-                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                       ulWindowSize ) );\r
-                               FreeRTOS_flush_logging( );\r
-                       }\r
-               }\r
-\r
-               /* See if it has already been determined to return 0. */\r
-               if( ulReturn != 0UL )\r
-               {\r
-                       configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );\r
-\r
-                       /* Now that the segment will be transmitted, add it to the tail of\r
-                       the waiting queue. */\r
-                       vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );\r
-\r
-                       /* And mark it as outstanding. */\r
-                       pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;\r
-\r
-                       /* Administer the transmit count, needed for fast\r
-                       retransmissions. */\r
-                       ( pxSegment->u.bits.ucTransmitCount )++;\r
-\r
-                       /* If there have been several retransmissions (4), decrease the\r
-                       size of the transmission window to at most 2 times MSS. */\r
-                       if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )\r
-                       {\r
-                               if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",\r
-                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,\r
-                                               pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );\r
-                                       pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );\r
-                               }\r
-                       }\r
-\r
-                       /* Clear the transmit timer. */\r
-                       vTCPTimerSet( &( pxSegment->xTransmitTimer ) );\r
-\r
-                       pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;\r
-\r
-                       /* Inform the caller where to find the data within the queue. */\r
-                       *plPosition = pxSegment->lStreamPos;\r
-\r
-                       /* And return the length of the data segment */\r
-                       ulReturn = ( uint32_t ) pxSegment->lDataLength;\r
-               }\r
-\r
-               return ulReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )\r
-       {\r
-       uint32_t ulBytesConfirmed = 0u;\r
-       uint32_t ulSequenceNumber = ulFirst, ulDataLength;\r
-       const ListItem_t *pxIterator;\r
-       const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );\r
-       BaseType_t xDoUnlink;\r
-       TCPSegment_t *pxSegment;\r
-               /* An acknowledgement or a selective ACK (SACK) was received.  See if some outstanding data\r
-               may be removed from the transmission queue(s).\r
-               All TX segments for which\r
-               ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a\r
-               contiguous block.  Note that the segments are stored in xTxSegments in a\r
-               strict sequential order. */\r
-\r
-               /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT\r
-\r
-               0 < a < 1; usually a = 1/8\r
-\r
-               RTO = 2 * SRTT\r
-\r
-               where:\r
-                 RTT is Round Trip Time\r
-                 SRTT is Smoothed RTT\r
-                 RTO is Retransmit timeout\r
-\r
-                A Smoothed RTT will increase quickly, but it is conservative when\r
-                becoming smaller. */\r
-\r
-               for(\r
-                               pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );\r
-                               ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );\r
-                       )\r
-               {\r
-                       xDoUnlink = pdFALSE;\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
-\r
-                       /* Move to the next item because the current item might get\r
-                       removed. */\r
-                       pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );\r
-\r
-                       /* Continue if this segment does not fall within the ACK'd range. */\r
-                       if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )\r
-                       {\r
-                               continue;\r
-                       }\r
-\r
-                       /* Is it ready? */\r
-                       if( ulSequenceNumber != pxSegment->ulSequenceNumber )\r
-                       {\r
-                               break;\r
-                       }\r
-\r
-                       ulDataLength = ( uint32_t ) pxSegment->lDataLength;\r
-\r
-                       if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )\r
-                       {\r
-                               if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )\r
-                               {\r
-                                       /* What happens?  Only part of this segment was accepted,\r
-                                       probably due to WND limits\r
-\r
-                                         AAAAAAA BBBBBBB << acked\r
-                                         aaaaaaa aaaa    << sent */\r
-                                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-                                       {\r
-                                               uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;\r
-                                               FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",\r
-                                                       pxWindow->usPeerPortNumber,\r
-                                                       pxWindow->usOurPortNumber,\r
-                                                       ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       ulLast - pxWindow->tx.ulFirstSequenceNumber,\r
-                                                       ulFirstSeq, ulFirstSeq + ulDataLength ) );\r
-                                       }\r
-                                       #endif /* ipconfigHAS_DEBUG_PRINTF */\r
-                                       break;\r
-                               }\r
-\r
-                               /* This segment is fully ACK'd, set the flag. */\r
-                               pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;\r
-\r
-                               /* Calculate the RTT only if the segment was sent-out for the\r
-                               first time and if this is the last ACK'd segment in a range. */\r
-                               if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )\r
-                               {\r
-                                       int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );\r
-\r
-                                       if( pxWindow->lSRTT >= mS )\r
-                                       {\r
-                                               /* RTT becomes smaller: adapt slowly. */\r
-                                               pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               /* RTT becomes larger: adapt quicker */\r
-                                               pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );\r
-                                       }\r
-\r
-                                       /* Cap to the minimum of 50ms. */\r
-                                       if( pxWindow->lSRTT < winSRTT_CAP_mS )\r
-                                       {\r
-                                               pxWindow->lSRTT = winSRTT_CAP_mS;\r
-                                       }\r
-                               }\r
-\r
-                               /* Unlink it from the 3 queues, but do not destroy it (yet). */\r
-                               xDoUnlink = pdTRUE;\r
-                       }\r
-\r
-                       /* pxSegment->u.bits.bAcked is now true.  Is it located at the left\r
-                       side of the transmission queue?  If so, it may be freed. */\r
-                       if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )\r
-                       {\r
-                               if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",\r
-                                               ulFirst - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               ulLast - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );\r
-                               }\r
-\r
-                               /* Increase the left-hand value of the transmission window. */\r
-                               pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;\r
-\r
-                               /* This function will return the number of bytes that the tail\r
-                               of txStream may be advanced. */\r
-                               ulBytesConfirmed += ulDataLength;\r
-\r
-                               /* All segments below tx.ulCurrentSequenceNumber may be freed. */\r
-                               vTCPWindowFree( pxSegment );\r
-\r
-                               /* No need to unlink it any more. */\r
-                               xDoUnlink = pdFALSE;\r
-                       }\r
-\r
-                       if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )\r
-                       {\r
-                               /* Remove item from its queues. */\r
-                               uxListRemove( &pxSegment->xQueueItem );\r
-                       }\r
-\r
-                       ulSequenceNumber += ulDataLength;\r
-               }\r
-\r
-               return ulBytesConfirmed;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )\r
-       {\r
-       const ListItem_t *pxIterator;\r
-       const MiniListItem_t* pxEnd;\r
-       TCPSegment_t *pxSegment;\r
-       uint32_t ulCount = 0UL;\r
-\r
-               /* A higher Tx block has been acknowledged.  Now iterate through the\r
-                xWaitQueue to find a possible condition for a FAST retransmission. */\r
-\r
-               pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );\r
-\r
-               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );\r
-                        pxIterator != ( const ListItem_t * ) pxEnd; )\r
-               {\r
-                       /* Get the owner, which is a TCP segment. */\r
-                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
-\r
-                       /* Hop to the next item before the current gets unlinked. */\r
-                       pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator );\r
-\r
-                       /* Fast retransmission:\r
-                       When 3 packets with a higher sequence number have been acknowledged\r
-                       by the peer, it is very unlikely a current packet will ever arrive.\r
-                       It will be retransmitted far before the RTO. */\r
-                       if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&\r
-                               ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&\r
-                               ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )\r
-                       {\r
-                               pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;\r
-\r
-                               /* Not clearing 'ucDupAckCount' yet as more SACK's might come in\r
-                               which might lead to a second fast rexmit. */\r
-                               if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",\r
-                                               pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );\r
-                                       FreeRTOS_flush_logging( );\r
-                               }\r
-\r
-                               /* Remove it from xWaitQueue. */\r
-                               uxListRemove( &pxSegment->xQueueItem );\r
-\r
-                               /* Add this segment to the priority queue so it gets\r
-                               retransmitted immediately. */\r
-                               vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );\r
-                               ulCount++;\r
-                       }\r
-               }\r
-\r
-               return ulCount;\r
-       }\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )\r
-       {\r
-       uint32_t ulFirstSequence, ulReturn;\r
-\r
-               /* Receive a normal ACK. */\r
-\r
-               ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;\r
-\r
-               if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )\r
-               {\r
-                       ulReturn = 0UL;\r
-               }\r
-               else\r
-               {\r
-                       ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );\r
-               }\r
-\r
-               return ulReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 1 )\r
-\r
-       uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )\r
-       {\r
-       uint32_t ulAckCount = 0UL;\r
-       uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;\r
-\r
-               /* Receive a SACK option. */\r
-               ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );\r
-               prvTCPWindowFastRetransmit( pxWindow, ulFirst );\r
-\r
-               if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )\r
-               {\r
-                       FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",\r
-                               pxWindow->usPeerPortNumber,\r
-                               pxWindow->usOurPortNumber,\r
-                               ulFirst - pxWindow->tx.ulFirstSequenceNumber,\r
-                               ulLast - pxWindow->tx.ulFirstSequenceNumber,\r
-                               pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );\r
-                       FreeRTOS_flush_logging( );\r
-               }\r
-\r
-               return ulAckCount;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
-#####   #                      #####   ####  ######\r
-# # #   #                      # # #  #    #  #    #\r
-  #                              #   #     #  #    #\r
-  #   ###   #####  #    #        #   #        #    #\r
-  #     #   #    # #    #        #   #        #####\r
-  #     #   #    # #    # ####   #   #        #\r
-  #     #   #    # #    #        #   #     #  #\r
-  #     #   #    #  ####         #    #    #  #\r
- #### ##### #    #     #        ####   ####  ####\r
-                      #\r
-                   ###\r
-*/\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )\r
-       {\r
-       int32_t iReturn;\r
-\r
-               /* Data was received at 'ulSequenceNumber'.  See if it was expected\r
-               and if there is enough space to store the new data. */\r
-               if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )\r
-               {\r
-                       iReturn = -1;\r
-               }\r
-               else\r
-               {\r
-                       pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;\r
-                       iReturn = 0;\r
-               }\r
-\r
-               return iReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )\r
-       {\r
-       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );\r
-       int32_t lResult;\r
-\r
-               /* Data is being scheduled for transmission. */\r
-\r
-               /* lMax would indicate the size of the txStream. */\r
-               ( void ) lMax;\r
-               /* This is tiny TCP: there is only 1 segment for outgoing data.\r
-               As long as 'lDataLength' is unequal to zero, the segment is still occupied. */\r
-               if( pxSegment->lDataLength > 0 )\r
-               {\r
-                       lResult = 0L;\r
-               }\r
-               else\r
-               {\r
-                       if( ulLength > ( uint32_t ) pxSegment->lMaxLength )\r
-                       {\r
-                               if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );\r
-                               }\r
-\r
-                               ulLength = ( uint32_t ) pxSegment->lMaxLength;\r
-                       }\r
-\r
-                       if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",\r
-                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                       pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                       ulLength ) );\r
-                       }\r
-\r
-                       /* The sequence number of the first byte in this packet. */\r
-                       pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;\r
-                       pxSegment->lDataLength = ( int32_t ) ulLength;\r
-                       pxSegment->lStreamPos = lPosition;\r
-                       pxSegment->u.ulFlags = 0UL;\r
-                       vTCPTimerSet( &( pxSegment->xTransmitTimer ) );\r
-\r
-                       /* Increase the sequence number of the next data to be stored for\r
-                       transmission. */\r
-                       pxWindow->ulNextTxSequenceNumber += ulLength;\r
-                       lResult = ( int32_t )ulLength;\r
-               }\r
-\r
-               return lResult;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )\r
-       {\r
-       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );\r
-       uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;\r
-       uint32_t ulMaxTime;\r
-\r
-               if( ulLength != 0UL )\r
-               {\r
-                       /* _HT_ Still under investigation */\r
-                       ( void ) ulWindowSize;\r
-\r
-                       if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )\r
-                       {\r
-                               /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */\r
-                               ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );\r
-\r
-                               if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )\r
-                               {\r
-                                       ulLength = 0ul;\r
-                               }\r
-                       }\r
-\r
-                       if( ulLength != 0ul )\r
-                       {\r
-                               pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;\r
-                               pxSegment->u.bits.ucTransmitCount++;\r
-                               vTCPTimerSet (&pxSegment->xTransmitTimer);\r
-                               pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;\r
-                               *plPosition = pxSegment->lStreamPos;\r
-                       }\r
-               }\r
-\r
-               return ulLength;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )\r
-       {\r
-       BaseType_t xReturn;\r
-\r
-               /* Has the outstanding data been sent because user wants to shutdown? */\r
-               if( pxWindow->xTxSegment.lDataLength == 0 )\r
-               {\r
-                       xReturn = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       xReturn = pdFALSE;\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );\r
-       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )\r
-       {\r
-       BaseType_t xReturn;\r
-\r
-               if( ulWindowSize >= pxWindow->usMSSInit )\r
-               {\r
-                       xReturn = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       xReturn = pdFALSE;\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )\r
-       {\r
-       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );\r
-       BaseType_t xReturn;\r
-       TickType_t ulAge, ulMaxAge;\r
-\r
-               /* Check data to be sent. */\r
-               *pulDelay = ( TickType_t ) 0;\r
-               if( pxSegment->lDataLength == 0 )\r
-               {\r
-                       /* Got nothing to send right now. */\r
-                       xReturn = pdFALSE;\r
-               }\r
-               else\r
-               {\r
-                       if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )\r
-                       {\r
-                               ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );\r
-                               ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );\r
-\r
-                               if( ulMaxAge > ulAge )\r
-                               {\r
-                                       *pulDelay = ulMaxAge - ulAge;\r
-                               }\r
-\r
-                               xReturn = pdTRUE;\r
-                       }\r
-                       else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )\r
-                       {\r
-                               /* Too many outstanding messages. */\r
-                               xReturn = pdFALSE;\r
-                       }\r
-                       else\r
-                       {\r
-                               xReturn = pdTRUE;\r
-                       }\r
-               }\r
-\r
-               return xReturn;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )\r
-       {\r
-       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );\r
-       uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;\r
-\r
-               /* Receive a normal ACK */\r
-\r
-               if( ulDataLength != 0ul )\r
-               {\r
-                       if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )\r
-                       {\r
-                               if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",\r
-                                               ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               ulDataLength ) );\r
-                               }\r
-\r
-                               /* Nothing to send right now. */\r
-                               ulDataLength = 0ul;\r
-                       }\r
-                       else\r
-                       {\r
-                               pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;\r
-\r
-                               if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",\r
-                                               ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,\r
-                                               ulDataLength ) );\r
-                               }\r
-\r
-                               pxSegment->lDataLength = 0;\r
-                       }\r
-               }\r
-\r
-               return ulDataLength;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )\r
-       {\r
-               /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'\r
-               'ulCurrentSequenceNumber' is the highest sequence number stored,\r
-               'ulHighestSequenceNumber' is the highest sequence number seen. */\r
-               return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_TCP_WIN == 0 )\r
-\r
-       /* Destroy a window (always returns NULL) */\r
-       void vTCPWindowDestroy( TCPWindow_t *pxWindow )\r
-       {\r
-               /* As in tiny TCP there are no shared segments descriptors, there is\r
-               nothing to release. */\r
-               ( void ) pxWindow;\r
-       }\r
-\r
-#endif /* ipconfigUSE_TCP_WIN == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
+/*
+ * FreeRTOS+TCP V2.2.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/*
+ * FreeRTOS_TCP_WIN.c
+ * Module which handles the TCP windowing schemes for FreeRTOS+TCP.  Many
+ * functions have two versions - one for FreeRTOS+TCP (full) and one for
+ * FreeRTOS+TCP (lite).
+ *
+ * In this module all ports and IP addresses and sequence numbers are
+ * being stored in host byte-order.
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+#include "FreeRTOS_TCP_WIN.h"
+
+/* Constants used for Smoothed Round Trip Time (SRTT). */
+#define        winSRTT_INCREMENT_NEW           2
+#define winSRTT_INCREMENT_CURRENT      6
+#define        winSRTT_DECREMENT_NEW           1
+#define winSRTT_DECREMENT_CURRENT      7
+#define winSRTT_CAP_mS                         50
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
+
+       #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
+
+       /* The code to send a single Selective ACK (SACK):
+        * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
+        * followed by a lower and a higher sequence number,
+        * where LEN is 2 + 2*4 = 10 bytes. */
+       #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
+               #define OPTION_CODE_SINGLE_SACK         ( 0x0101050aUL )
+       #else
+               #define OPTION_CODE_SINGLE_SACK         ( 0x0a050101UL )
+       #endif
+
+       /* Normal retransmission:
+        * A packet will be retransmitted after a Retransmit Time-Out (RTO).
+        * Fast retransmission:
+        * When 3 packets with a higher sequence number have been acknowledged
+        * by the peer, it is very unlikely a current packet will ever arrive.
+        * It will be retransmitted far before the RTO.
+        */
+       #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT           ( 3u )
+
+       /* If there have been several retransmissions (4), decrease the
+        * size of the transmission window to at most 2 times MSS.
+        */
+       #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW           ( 4u )
+
+#endif /* configUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
+
+/*
+ * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
+ * Available descriptors are stored in the 'xSegmentList'
+ * When a socket owns a descriptor, it will either be stored in
+ * 'xTxSegments' or 'xRxSegments'
+ * As soon as a package has been confirmed, the descriptor will be returned
+ * to the segment pool
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static BaseType_t prvCreateSectors( void );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Find a segment with a given sequence number in the list of received
+ * segments: 'pxWindow->xRxSegments'.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Allocate a new segment
+ * The socket will borrow all segments from a common pool: 'xSegmentList',
+ * which is a list of 'TCPSegment_t'
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/* When the peer has a close request (FIN flag), the driver will check if
+ * there are missing packets in the Rx-queue
+ * It will accept the closure of the connection if both conditions are true:
+ * - the Rx-queue is empty
+ * - we've ACK'd the highest Rx sequence number seen
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Detaches and returns the head of a queue
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Returns the head of a queue but it won't be detached
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ *  Free entry pxSegment because it's not used anymore
+ *     The ownership will be passed back to the segment pool
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static void vTCPWindowFree( TCPSegment_t *pxSegment );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * A segment has been received with sequence number 'ulSequenceNumber', where
+ * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
+ * segment was expected.  xTCPWindowRxConfirm() will check if there is already
+ * another segment with a sequence number between (ulSequenceNumber) and
+ * (ulSequenceNumber+xLength).  Normally none will be found, because the next Rx
+ * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * FreeRTOS+TCP stores data in circular buffers.  Calculate the next position to
+ * store.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * This function will look if there is new transmission data.  It will return
+ * true if there is data to be sent.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * An acknowledge was received.  See if some outstanding data may be removed
+ * from the transmission queue(s).
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * A higher Tx block has been acknowledged.  Now iterate through the xWaitQueue
+ * to find a possible condition for a FAST retransmission.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*-----------------------------------------------------------*/
+
+/* TCP segment pool. */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static TCPSegment_t *xTCPSegments = NULL;
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/* List of free TCP segments. */
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static List_t xSegmentList;
+#endif
+
+/* Logging verbosity level. */
+BaseType_t xTCPWindowLoggingLevel = 0;
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+       /* Some 32-bit arithmetic: comparing sequence numbers */
+       static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
+       static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
+       {
+               /* Test if a <= b
+               Return true if the unsigned subtraction of (b-a) doesn't generate an
+               arithmetic overflow. */
+               return ( ( b - a ) & 0x80000000UL ) == 0UL;
+       }
+#endif /* ipconfigUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
+       static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
+       {
+               /* Test if a < b */
+               return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
+       }
+#endif /* ipconfigUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
+       static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
+       {
+               /* Test if a > b */
+               return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
+       }
+#endif /* ipconfigUSE_TCP_WIN */
+
+/*-----------------------------------------------------------*/
+static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
+static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
+{
+       /* Test if a >= b */
+       return ( ( a - b ) & 0x80000000UL ) == 0UL;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+       static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
+       static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
+       {
+               vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
+       }
+#endif
+/*-----------------------------------------------------------*/
+
+static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
+static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
+{
+       pxTimer->ulBorn = xTaskGetTickCount ( );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
+static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
+{
+       return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
+}
+/*-----------------------------------------------------------*/
+
+/* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
+preceded by a prototype. Later this prototype will be located in list.h? */
+
+extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
+
+void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
+{
+       /* Insert a new list item into pxList, it does not sort the list,
+       but it puts the item just before xListEnd, so it will be the last item
+       returned by listGET_HEAD_ENTRY() */
+       pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
+       pxNewListItem->pxPrevious = pxWhere->pxPrevious;
+       pxWhere->pxPrevious->pxNext = pxNewListItem;
+       pxWhere->pxPrevious = pxNewListItem;
+
+       /* Remember which list the item is in. */
+       listLIST_ITEM_CONTAINER( pxNewListItem ) = ( void * ) pxList;
+
+       ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static BaseType_t prvCreateSectors( void )
+       {
+       BaseType_t xIndex, xReturn;
+
+               /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
+
+               vListInitialise( &xSegmentList );
+               xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
+
+               if( xTCPSegments == NULL )
+               {
+                       FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
+                               ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
+
+                       xReturn = pdFAIL;
+               }
+               else
+               {
+                       /* Clear the allocated space. */
+                       memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
+
+                       for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
+                       {
+                               /* Could call vListInitialiseItem here but all data has been
+                               nulled already.  Set the owner to a segment descriptor. */
+                               listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
+                               listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
+
+                               /* And add it to the pool of available segments */
+                               vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
+                       }
+
+                       xReturn = pdPASS;
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+       {
+       const ListItem_t *pxIterator;
+       const MiniListItem_t* pxEnd;
+       TCPSegment_t *pxSegment, *pxReturn = NULL;
+
+               /* Find a segment with a given sequence number in the list of received
+               segments. */
+
+               pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
+
+               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+                        pxIterator != ( const ListItem_t * ) pxEnd;
+                        pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+               {
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+                       if( pxSegment->ulSequenceNumber == ulSequenceNumber )
+                       {
+                               pxReturn = pxSegment;
+                               break;
+                       }
+               }
+
+               return pxReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
+       {
+       TCPSegment_t *pxSegment;
+       ListItem_t * pxItem;
+
+               /* Allocate a new segment.  The socket will borrow all segments from a
+               common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
+               if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
+               {
+                       /* If the TCP-stack runs out of segments, you might consider
+                       increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
+                       FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
+                       pxSegment = NULL;
+               }
+               else
+               {
+                       /* Pop the item at the head of the list.  Semaphore protection is
+                       not required as only the IP task will call these functions.  */
+                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+
+                       configASSERT( pxItem != NULL );
+                       configASSERT( pxSegment != NULL );
+
+                       /* Remove the item from xSegmentList. */
+                       uxListRemove( pxItem );
+
+                       /* Add it to either the connections' Rx or Tx queue. */
+                       vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
+
+                       /* And set the segment's timer to zero */
+                       vTCPTimerSet( &pxSegment->xTransmitTimer );
+
+                       pxSegment->u.ulFlags = 0;
+                       pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
+                       pxSegment->lMaxLength = lCount;
+                       pxSegment->lDataLength = lCount;
+                       pxSegment->ulSequenceNumber = ulSequenceNumber;
+                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+                       {
+                       static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
+                       UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
+
+                               if( xLowestLength > xLength )
+                               {
+                                       xLowestLength = xLength;
+                               }
+                       }
+                       #endif /* ipconfigHAS_DEBUG_PRINTF */
+               }
+
+               return pxSegment;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
+       {
+       BaseType_t xReturn;
+
+               /* When the peer has a close request (FIN flag), the driver will check
+               if there are missing packets in the Rx-queue.  It will accept the
+               closure of the connection if both conditions are true:
+                 - the Rx-queue is empty
+                 - the highest Rx sequence number has been ACK'ed */
+               if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
+               {
+                       /* Rx data has been stored while earlier packets were missing. */
+                       xReturn = pdFALSE;
+               }
+               else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
+               {
+                       /* No Rx packets are being stored and the highest sequence number
+                       that has been received has been ACKed. */
+                       xReturn = pdTRUE;
+               }
+               else
+               {
+                       FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
+                               ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
+                               ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
+                       xReturn = pdFALSE;
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
+       {
+       TCPSegment_t *pxSegment;
+       ListItem_t * pxItem;
+
+               /* Detaches and returns the head of a queue. */
+               if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
+               {
+                       pxSegment = NULL;
+               }
+               else
+               {
+                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+
+                       uxListRemove( pxItem );
+               }
+
+               return pxSegment;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
+       {
+       ListItem_t *pxItem;
+       TCPSegment_t *pxReturn;
+
+               /* Returns the head of a queue but it won't be detached. */
+               if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
+               {
+                       pxReturn = NULL;
+               }
+               else
+               {
+                       pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
+                       pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+               }
+
+               return pxReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static void vTCPWindowFree( TCPSegment_t *pxSegment )
+       {
+               /*  Free entry pxSegment because it's not used any more.  The ownership
+               will be passed back to the segment pool.
+
+               Unlink it from one of the queues, if any. */
+               if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
+               {
+                       uxListRemove( &( pxSegment->xQueueItem ) );
+               }
+
+               pxSegment->ulSequenceNumber = 0u;
+               pxSegment->lDataLength = 0l;
+               pxSegment->u.ulFlags = 0u;
+
+               /* Take it out of xRxSegments/xTxSegments */
+               if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
+               {
+                       uxListRemove( &( pxSegment->xListItem ) );
+               }
+
+               /* Return it to xSegmentList */
+               vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       void vTCPWindowDestroy( TCPWindow_t *pxWindow )
+       {
+       List_t * pxSegments;
+       BaseType_t xRound;
+       TCPSegment_t *pxSegment;
+
+               /*  Destroy a window.  A TCP window doesn't serve any more.  Return all
+               owned segments to the pool.  In order to save code, it will make 2 rounds,
+               one to remove the segments from xRxSegments, and a second round to clear
+               xTxSegments*/
+               for( xRound = 0; xRound < 2; xRound++ )
+               {
+                       if( xRound != 0 )
+                       {
+                               pxSegments = &( pxWindow->xRxSegments );
+                       }
+                       else
+                       {
+                               pxSegments = &( pxWindow->xTxSegments );
+                       }
+
+                       if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
+                       {
+                               while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
+                               {
+                                       pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
+                                       vTCPWindowFree( pxSegment );
+                               }
+                       }
+               }
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
+       uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
+{
+       /* Create and initialize a window. */
+
+       #if( ipconfigUSE_TCP_WIN == 1 )
+       {
+               if( xTCPSegments == NULL )
+               {
+                       prvCreateSectors();
+               }
+
+               vListInitialise( &pxWindow->xTxSegments );
+               vListInitialise( &pxWindow->xRxSegments );
+
+               vListInitialise( &pxWindow->xPriorityQueue );                   /* Priority queue: segments which must be sent immediately */
+               vListInitialise( &pxWindow->xTxQueue   );                       /* Transmit queue: segments queued for transmission */
+               vListInitialise( &pxWindow->xWaitQueue );                       /* Waiting queue:  outstanding segments */
+       }
+       #endif /* ipconfigUSE_TCP_WIN == 1 */
+
+       if( xTCPWindowLoggingLevel != 0 )
+       {
+               FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
+                       ulRxWindowLength, ulTxWindowLength ) );
+       }
+
+       pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
+       pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
+
+       vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
+}
+/*-----------------------------------------------------------*/
+
+void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
+{
+const int32_t l500ms = 500;
+
+       pxWindow->u.ulFlags = 0ul;
+       pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
+
+       if( ulMSS != 0ul )
+       {
+               if( pxWindow->usMSSInit != 0u )
+               {
+                       pxWindow->usMSSInit = ( uint16_t ) ulMSS;
+               }
+
+               if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
+               {
+                       pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
+                       pxWindow->usMSS = ( uint16_t ) ulMSS;
+               }
+       }
+
+       #if( ipconfigUSE_TCP_WIN == 0 )
+       {
+               pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
+       }
+       #endif /* ipconfigUSE_TCP_WIN == 1 */
+
+       /*Start with a timeout of 2 * 500 ms (1 sec). */
+       pxWindow->lSRTT = l500ms;
+
+       /* Just for logging, to print relative sequence numbers. */
+       pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
+
+       /* The segment asked for in the next transmission. */
+       pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
+
+       /* The right-hand side of the receive window. */
+       pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
+
+       pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
+
+       /* The segment asked for in next transmission. */
+       pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
+
+       /* The sequence number given to the next outgoing byte to be added is
+       maintained by lTCPWindowTxAdd(). */
+       pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
+
+       /* The right-hand side of the transmit window. */
+       pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
+       pxWindow->ulOurSequenceNumber = ulSequenceNumber;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+    void vTCPSegmentCleanup( void )
+    {
+        /* Free and clear the TCP segments pointer. This function should only be called
+         * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this
+         * function. */
+        if( xTCPSegments != NULL )
+        {
+            vPortFreeLarge( xTCPSegments );
+            xTCPSegments = NULL;
+        }
+    }
+
+#endif /* ipconfgiUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+/*=============================================================================
+ *
+ *                ######        #    #
+ *                 #    #       #    #
+ *                 #    #       #    #
+ *                 #    #        ####
+ *                 ######         ##
+ *                 #  ##         ####
+ *                 #   #        #    #
+ *                 #    #       #    #
+ *                ###  ##       #    #
+ * Rx functions
+ *
+ *=============================================================================*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
+       {
+       TCPSegment_t *pxBest = NULL;
+       const ListItem_t *pxIterator;
+       uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
+       const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
+       TCPSegment_t *pxSegment;
+
+               /* A segment has been received with sequence number 'ulSequenceNumber',
+               where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
+               exactly this segment was expected.  xTCPWindowRxConfirm() will check if
+               there is already another segment with a sequence number between (ulSequenceNumber)
+               and (ulSequenceNumber+ulLength).  Normally none will be found, because
+               the next RX segment should have a sequence number equal to
+               '(ulSequenceNumber+ulLength)'. */
+
+               /* Iterate through all RX segments that are stored: */
+               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+                        pxIterator != ( const ListItem_t * ) pxEnd;
+                        pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+               {
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+                       /* And see if there is a segment for which:
+                       'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
+                       If there are more matching segments, the one with the lowest sequence number
+                       shall be taken */
+                       if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
+                               ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
+                       {
+                               if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
+                               {
+                                       pxBest = pxSegment;
+                               }
+                       }
+               }
+
+               if( ( pxBest != NULL ) &&
+                       ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
+               {
+                       FreeRTOS_flush_logging();
+                       FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
+                               pxWindow->usPeerPortNumber,
+                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                               ulLength,
+                               ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
+                               pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                               pxBest->lDataLength,
+                               pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
+               }
+
+               return pxBest;
+       }
+
+#endif /* ipconfgiUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
+       {
+       uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
+       int32_t lReturn, lDistance;
+       TCPSegment_t *pxFound;
+
+               /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
+               directly to user (segment is expected).  If it returns a positive
+               number, an earlier packet is missing, but this packet may be stored.
+               If negative, the packet has already been stored, or it is out-of-order,
+               or there is not enough space.
+
+               As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
+               if more Rx data may be passed to the user after this packet. */
+
+               ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
+
+               /* For Selective Ack (SACK), used when out-of-sequence data come in. */
+               pxWindow->ucOptionLength = 0u;
+
+               /* Non-zero if TCP-windows contains data which must be popped. */
+               pxWindow->ulUserDataLength = 0ul;
+
+               if( ulCurrentSequenceNumber == ulSequenceNumber )
+               {
+                       /* This is the packet with the lowest sequence number we're waiting
+                       for.  It can be passed directly to the rx stream. */
+                       if( ulLength > ulSpace )
+                       {
+                               FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
+                               lReturn = -1;
+                       }
+                       else
+                       {
+                               ulCurrentSequenceNumber += ulLength;
+
+                               if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
+                               {
+                                       ulSavedSequenceNumber = ulCurrentSequenceNumber;
+
+                    /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
+                    If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
+                    So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
+                    clean them out. */
+                    do
+                    {
+                        pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
+
+                        if ( pxFound != NULL )
+                        {
+                            /* Remove it because it will be passed to user directly. */
+                            vTCPWindowFree( pxFound );
+                        }
+                    } while ( pxFound );
+
+                                       /*  Check for following segments that are already in the
+                                       queue and increment ulCurrentSequenceNumber. */
+                                       while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
+                                       {
+                                               ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
+
+                                               /* As all packet below this one have been passed to the
+                                               user it can be discarded. */
+                                               vTCPWindowFree( pxFound );
+                                       }
+
+                                       if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
+                                       {
+                                               /*  After the current data-package, there is more data
+                                               to be popped. */
+                                               pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
+
+                                               if( xTCPWindowLoggingLevel >= 1 )
+                                               {
+                                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
+                                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+                                                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                                                               pxWindow->ulUserDataLength,
+                                                               ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                                                               listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
+                                               }
+                                       }
+                               }
+
+                               pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
+
+                               /* Packet was expected, may be passed directly to the socket
+                               buffer or application.  Store the packet at offset 0. */
+                               lReturn = 0;
+                       }
+               }
+               else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
+               {
+                       /* Looks like a TCP keep-alive message.  Do not accept/store Rx data
+                       ulUserDataLength = 0. Not packet out-of-sync.  Just reply to it. */
+                       lReturn = -1;
+               }
+               else
+               {
+                       /* The packet is not the one expected.  See if it falls within the Rx
+                       window so it can be stored. */
+
+                       /*  An "out-of-sequence" segment was received, must have missed one.
+                       Prepare a SACK (Selective ACK). */
+                       ulLast = ulSequenceNumber + ulLength;
+                       lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
+
+                       if( lDistance <= 0 )
+                       {
+                               /* An earlier has been received, must be a retransmission of a
+                               packet that has been accepted already.  No need to send out a
+                               Selective ACK (SACK). */
+                               lReturn = -1;
+                       }
+                       else if( lDistance > ( int32_t ) ulSpace )
+                       {
+                               /* The new segment is ahead of rx.ulCurrentSequenceNumber.  The
+                               sequence number of this packet is too far ahead, ignore it. */
+                               FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
+                               lReturn = -1;
+                       }
+                       else
+                       {
+                               /* See if there is more data in a contiguous block to make the
+                               SACK describe a longer range of data. */
+
+                               /* TODO: SACK's may also be delayed for a short period
+                                * This is useful because subsequent packets will be SACK'd with
+                                * single one message
+                                */
+                               while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
+                               {
+                                       ulLast += ( uint32_t ) pxFound->lDataLength;
+                               }
+
+                               if( xTCPWindowLoggingLevel >= 1 )
+                               {
+                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
+                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+                                               ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                                               ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                                               ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ),  /* want this signed */
+                                               ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
+                               }
+
+                               /* Now prepare the SACK message.
+                               Code OPTION_CODE_SINGLE_SACK already in network byte order. */
+                               pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
+
+                               /* First sequence number that we received. */
+                               pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
+
+                               /* Last + 1 */
+                               pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
+
+                               /* Which make 12 (3*4) option bytes. */
+                               pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
+
+                               pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
+
+                               if( pxFound != NULL )
+                               {
+                                       /* This out-of-sequence packet has been received for a
+                                       second time.  It is already stored but do send a SACK
+                                       again. */
+                                       lReturn = -1;
+                               }
+                               else
+                               {
+                                       pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
+
+                                       if( pxFound == NULL )
+                                       {
+                                               /* Can not send a SACK, because the segment cannot be
+                                               stored. */
+                                               pxWindow->ucOptionLength = 0u;
+
+                                               /* Needs to be stored but there is no segment
+                                               available. */
+                                               lReturn = -1;
+                                       }
+                                       else
+                                       {
+                                               if( xTCPWindowLoggingLevel != 0 )
+                                               {
+                                                       FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
+                                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+                                                               listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
+                                                       FreeRTOS_flush_logging( );
+                                               }
+
+                                               /* Return a positive value.  The packet may be accepted
+                                               and stored but an earlier packet is still missing. */
+                                               lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
+                                       }
+                               }
+                       }
+               }
+
+               return lReturn;
+       }
+
+#endif /* ipconfgiUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+/*=============================================================================
+ *
+ *                    #########   #    #
+ *                    #   #   #   #    #
+ *                        #       #    #
+ *                        #        ####
+ *                        #         ##
+ *                        #        ####
+ *                        #       #    #
+ *                        #       #    #
+ *                      #####     #    #
+ *
+ * Tx functions
+ *
+ *=============================================================================*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
+       {
+               /* +TCP stores data in circular buffers.  Calculate the next position to
+               store. */
+               lPosition += lCount;
+               if( lPosition >= lMax )
+               {
+                       lPosition -= lMax;
+               }
+
+               return lPosition;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
+       {
+       int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
+       int32_t lDone = 0;
+       TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
+
+               /* Puts a message in the Tx-window (after buffer size has been
+               verified). */
+               if( pxSegment != NULL )
+               {
+                       if( pxSegment->lDataLength < pxSegment->lMaxLength )
+                       {
+                               if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
+                               {
+                                       /* Adding data to a segment that was already in the TX queue.  It
+                                       will be filled-up to a maximum of MSS (maximum segment size). */
+                                       lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
+
+                                       pxSegment->lDataLength += lToWrite;
+
+                                       if( pxSegment->lDataLength >= pxSegment->lMaxLength )
+                                       {
+                                               /* This segment is full, don't add more bytes. */
+                                               pxWindow->pxHeadSegment = NULL;
+                                       }
+
+                                       lBytesLeft -= lToWrite;
+
+                                       /* ulNextTxSequenceNumber is the sequence number of the next byte to
+                                       be stored for transmission. */
+                                       pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
+
+                                       /* Increased the return value. */
+                                       lDone += lToWrite;
+
+                                       /* Some detailed logging, for those who're interested. */
+                                       if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
+                                       {
+                                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
+                                                       ulLength,
+                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       pxSegment->lDataLength,
+                                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       pxSegment->lStreamPos ) );
+                                               FreeRTOS_flush_logging( );
+                                       }
+
+                                       /* Calculate the next position in the circular data buffer, knowing
+                                       its maximum length 'lMax'. */
+                                       lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
+                               }
+                       }
+               }
+
+               while( lBytesLeft > 0 )
+               {
+                       /* The current transmission segment is full, create new segments as
+                       needed. */
+                       pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
+
+                       if( pxSegment != NULL )
+                       {
+                               /* Store as many as needed, but no more than the maximum
+                               (MSS). */
+                               lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
+
+                               pxSegment->lDataLength = lToWrite;
+                               pxSegment->lStreamPos = lPosition;
+                               lBytesLeft -= lToWrite;
+                               lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
+                               pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
+                               lDone += lToWrite;
+
+                               /* Link this segment in the Tx-Queue. */
+                               vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
+
+                               /* Let 'pxHeadSegment' point to this segment if there is still
+                               space. */
+                               if( pxSegment->lDataLength < pxSegment->lMaxLength )
+                               {
+                                       pxWindow->pxHeadSegment = pxSegment;
+                               }
+                               else
+                               {
+                                       pxWindow->pxHeadSegment = NULL;
+                               }
+
+                               if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
+                               {
+                                       if( ( xTCPWindowLoggingLevel >= 3 ) ||
+                                               ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
+                                       {
+                                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
+                                                       ulLength,
+                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       pxSegment->lDataLength,
+                                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       pxSegment->lStreamPos ) );
+                                               FreeRTOS_flush_logging( );
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* A sever situation: running out of segments for transmission.
+                               No more data can be sent at the moment. */
+                               if( lDone != 0 )
+                               {
+                                       FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
+                               }
+                               break;
+                       }
+               }
+
+               return lDone;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
+       {
+               return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
+       {
+       uint32_t ulTxOutstanding;
+       BaseType_t xHasSpace;
+       TCPSegment_t *pxSegment;
+
+               /* This function will look if there is new transmission data.  It will
+               return true if there is data to be sent. */
+
+               pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
+
+               if( pxSegment == NULL )
+               {
+                       xHasSpace = pdFALSE;
+               }
+               else
+               {
+                       /* How much data is outstanding, i.e. how much data has been sent
+                       but not yet acknowledged ? */
+                       if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
+                       {
+                               ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
+                       }
+                       else
+                       {
+                               ulTxOutstanding = 0UL;
+                       }
+
+                       /* Subtract this from the peer's space. */
+                       ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
+
+                       /* See if the next segment may be sent. */
+                       if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
+                       {
+                               xHasSpace = pdTRUE;
+                       }
+                       else
+                       {
+                               xHasSpace = pdFALSE;
+                       }
+
+                       /* If 'xHasSpace', it looks like the peer has at least space for 1
+                       more new segment of size MSS.  xSize.ulTxWindowLength is the self-imposed
+                       limitation of the transmission window (in case of many resends it
+                       may be decreased). */
+                       if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
+                       {
+                               xHasSpace = pdFALSE;
+                       }
+               }
+
+               return xHasSpace;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
+       {
+       TCPSegment_t *pxSegment;
+       BaseType_t xReturn;
+       TickType_t ulAge, ulMaxAge;
+
+               *pulDelay = 0u;
+
+               if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
+               {
+                       /* No need to look at retransmissions or new transmission as long as
+                       there are priority segments.  *pulDelay equals zero, meaning it must
+                       be sent out immediately. */
+                       xReturn = pdTRUE;
+               }
+               else
+               {
+                       pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
+
+                       if( pxSegment != NULL )
+                       {
+                               /* There is an outstanding segment, see if it is time to resend
+                               it. */
+                               ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
+
+                               /* After a packet has been sent for the first time, it will wait
+                               '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
+                               each time doubling the time-out */
+                               ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+                               if( ulMaxAge > ulAge )
+                               {
+                                       /* A segment must be sent after this amount of msecs */
+                                       *pulDelay = ulMaxAge - ulAge;
+                               }
+
+                               xReturn = pdTRUE;
+                       }
+                       else
+                       {
+                               /* No priority segment, no outstanding data, see if there is new
+                               transmission data. */
+                               pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
+
+                               /* See if it fits in the peer's reception window. */
+                               if( pxSegment == NULL )
+                               {
+                                       xReturn = pdFALSE;
+                               }
+                               else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+                               {
+                                       /* Too many outstanding messages. */
+                                       xReturn = pdFALSE;
+                               }
+                               else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
+                               {
+                                       /* 'bSendFullSize' is a special optimisation.  If true, the
+                                       driver will only sent completely filled packets (of MSS
+                                       bytes). */
+                                       xReturn = pdFALSE;
+                               }
+                               else
+                               {
+                                       xReturn = pdTRUE;
+                               }
+                       }
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
+       {
+       TCPSegment_t *pxSegment;
+       uint32_t ulMaxTime;
+       uint32_t ulReturn  = ~0UL;
+
+
+               /* Fetches data to be sent-out now.
+
+               Priority messages: segments with a resend need no check current sliding
+               window size. */
+               pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
+               pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
+
+               if( pxSegment == NULL )
+               {
+                       /* Waiting messages: outstanding messages with a running timer
+                       neither check peer's reception window size because these packets
+                       have been sent earlier. */
+                       pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
+
+                       if( pxSegment != NULL )
+                       {
+                               /* Do check the timing. */
+                               ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+                               if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
+                               {
+                                       /* A normal (non-fast) retransmission.  Move it from the
+                                       head of the waiting queue. */
+                                       pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
+                                       pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
+
+                                       /* Some detailed logging. */
+                                       if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
+                                       {
+                                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
+                                                       pxWindow->usPeerPortNumber,
+                                                       pxWindow->usOurPortNumber,
+                                                       pxSegment->lDataLength,
+                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       pxSegment->ulSequenceNumber ) );
+                                               FreeRTOS_flush_logging( );
+                                       }
+                               }
+                               else
+                               {
+                                       pxSegment = NULL;
+                               }
+                       }
+
+                       if( pxSegment == NULL )
+                       {
+                               /* New messages: sent-out for the first time.  Check current
+                               sliding window size of peer. */
+                               pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
+
+                               if( pxSegment == NULL )
+                               {
+                                       /* No segments queued. */
+                                       ulReturn = 0UL;
+                               }
+                               else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
+                               {
+                                       /* A segment has been queued but the driver waits until it
+                                       has a full size of MSS. */
+                                       ulReturn = 0;
+                               }
+                               else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+                               {
+                                       /* Peer has no more space at this moment. */
+                                       ulReturn = 0;
+                               }
+                               else
+                               {
+                                       /* Move it out of the Tx queue. */
+                                       pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
+
+                                       /* Don't let pxHeadSegment point to this segment any more,
+                                       so no more data will be added. */
+                                       if( pxWindow->pxHeadSegment == pxSegment )
+                                       {
+                                               pxWindow->pxHeadSegment = NULL;
+                                       }
+
+                                       /* pxWindow->tx.highest registers the highest sequence
+                                       number in our transmission window. */
+                                       pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
+
+                                       /* ...and more detailed logging */
+                                       if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                                       {
+                                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
+                                                       pxWindow->usPeerPortNumber,
+                                                       pxWindow->usOurPortNumber,
+                                                       pxSegment->lDataLength,
+                                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                                       ulWindowSize ) );
+                                               FreeRTOS_flush_logging( );
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       /* There is a priority segment. It doesn't need any checking for
+                       space or timeouts. */
+                       if( xTCPWindowLoggingLevel != 0 )
+                       {
+                               FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
+                                       pxWindow->usPeerPortNumber,
+                                       pxWindow->usOurPortNumber,
+                                       pxSegment->lDataLength,
+                                       pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                       ulWindowSize ) );
+                               FreeRTOS_flush_logging( );
+                       }
+               }
+
+               /* See if it has already been determined to return 0. */
+               if( ulReturn != 0UL )
+               {
+                       configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
+
+                       /* Now that the segment will be transmitted, add it to the tail of
+                       the waiting queue. */
+                       vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
+
+                       /* And mark it as outstanding. */
+                       pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
+
+                       /* Administer the transmit count, needed for fast
+                       retransmissions. */
+                       ( pxSegment->u.bits.ucTransmitCount )++;
+
+                       /* If there have been several retransmissions (4), decrease the
+                       size of the transmission window to at most 2 times MSS. */
+                       if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
+                       {
+                               if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
+                                               pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+                                               pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
+                                       pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
+                               }
+                       }
+
+                       /* Clear the transmit timer. */
+                       vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
+
+                       pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
+
+                       /* Inform the caller where to find the data within the queue. */
+                       *plPosition = pxSegment->lStreamPos;
+
+                       /* And return the length of the data segment */
+                       ulReturn = ( uint32_t ) pxSegment->lDataLength;
+               }
+
+               return ulReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
+       {
+       uint32_t ulBytesConfirmed = 0u;
+       uint32_t ulSequenceNumber = ulFirst, ulDataLength;
+       const ListItem_t *pxIterator;
+       const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
+       BaseType_t xDoUnlink;
+       TCPSegment_t *pxSegment;
+               /* An acknowledgement or a selective ACK (SACK) was received.  See if some outstanding data
+               may be removed from the transmission queue(s).
+               All TX segments for which
+               ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
+               contiguous block.  Note that the segments are stored in xTxSegments in a
+               strict sequential order. */
+
+               /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
+
+               0 < a < 1; usually a = 1/8
+
+               RTO = 2 * SRTT
+
+               where:
+                 RTT is Round Trip Time
+                 SRTT is Smoothed RTT
+                 RTO is Retransmit timeout
+
+                A Smoothed RTT will increase quickly, but it is conservative when
+                becoming smaller. */
+
+               for(
+                               pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+                               ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
+                       )
+               {
+                       xDoUnlink = pdFALSE;
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+                       /* Move to the next item because the current item might get
+                       removed. */
+                       pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
+
+                       /* Continue if this segment does not fall within the ACK'd range. */
+                       if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
+                       {
+                               continue;
+                       }
+
+                       /* Is it ready? */
+                       if( ulSequenceNumber != pxSegment->ulSequenceNumber )
+                       {
+                               break;
+                       }
+
+                       ulDataLength = ( uint32_t ) pxSegment->lDataLength;
+
+                       if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
+                       {
+                               if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
+                               {
+                                       /* What happens?  Only part of this segment was accepted,
+                                       probably due to WND limits
+
+                                         AAAAAAA BBBBBBB << acked
+                                         aaaaaaa aaaa    << sent */
+                                       #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+                                       {
+                                               uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
+                                               FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
+                                                       pxWindow->usPeerPortNumber,
+                                                       pxWindow->usOurPortNumber,
+                                                       ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
+                                                       ulLast - pxWindow->tx.ulFirstSequenceNumber,
+                                                       ulFirstSeq, ulFirstSeq + ulDataLength ) );
+                                       }
+                                       #endif /* ipconfigHAS_DEBUG_PRINTF */
+                                       break;
+                               }
+
+                               /* This segment is fully ACK'd, set the flag. */
+                               pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
+
+                               /* Calculate the RTT only if the segment was sent-out for the
+                               first time and if this is the last ACK'd segment in a range. */
+                               if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
+                               {
+                                       int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
+
+                                       if( pxWindow->lSRTT >= mS )
+                                       {
+                                               /* RTT becomes smaller: adapt slowly. */
+                                               pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
+                                       }
+                                       else
+                                       {
+                                               /* RTT becomes larger: adapt quicker */
+                                               pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
+                                       }
+
+                                       /* Cap to the minimum of 50ms. */
+                                       if( pxWindow->lSRTT < winSRTT_CAP_mS )
+                                       {
+                                               pxWindow->lSRTT = winSRTT_CAP_mS;
+                                       }
+                               }
+
+                               /* Unlink it from the 3 queues, but do not destroy it (yet). */
+                               xDoUnlink = pdTRUE;
+                       }
+
+                       /* pxSegment->u.bits.bAcked is now true.  Is it located at the left
+                       side of the transmission queue?  If so, it may be freed. */
+                       if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
+                       {
+                               if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
+                                               ulFirst - pxWindow->tx.ulFirstSequenceNumber,
+                                               ulLast - pxWindow->tx.ulFirstSequenceNumber,
+                                               pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
+                               }
+
+                               /* Increase the left-hand value of the transmission window. */
+                               pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
+
+                               /* This function will return the number of bytes that the tail
+                               of txStream may be advanced. */
+                               ulBytesConfirmed += ulDataLength;
+
+                               /* All segments below tx.ulCurrentSequenceNumber may be freed. */
+                               vTCPWindowFree( pxSegment );
+
+                               /* No need to unlink it any more. */
+                               xDoUnlink = pdFALSE;
+                       }
+
+                       if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
+                       {
+                               /* Remove item from its queues. */
+                               uxListRemove( &pxSegment->xQueueItem );
+                       }
+
+                       ulSequenceNumber += ulDataLength;
+               }
+
+               return ulBytesConfirmed;
+       }
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
+       {
+       const ListItem_t *pxIterator;
+       const MiniListItem_t* pxEnd;
+       TCPSegment_t *pxSegment;
+       uint32_t ulCount = 0UL;
+
+               /* A higher Tx block has been acknowledged.  Now iterate through the
+                xWaitQueue to find a possible condition for a FAST retransmission. */
+
+               pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
+
+               for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+                        pxIterator != ( const ListItem_t * ) pxEnd; )
+               {
+                       /* Get the owner, which is a TCP segment. */
+                       pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+                       /* Hop to the next item before the current gets unlinked. */
+                       pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator );
+
+                       /* Fast retransmission:
+                       When 3 packets with a higher sequence number have been acknowledged
+                       by the peer, it is very unlikely a current packet will ever arrive.
+                       It will be retransmitted far before the RTO. */
+                       if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
+                               ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
+                               ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
+                       {
+                               pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
+
+                               /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
+                               which might lead to a second fast rexmit. */
+                               if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
+                                               pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                               ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
+                                       FreeRTOS_flush_logging( );
+                               }
+
+                               /* Remove it from xWaitQueue. */
+                               uxListRemove( &pxSegment->xQueueItem );
+
+                               /* Add this segment to the priority queue so it gets
+                               retransmitted immediately. */
+                               vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
+                               ulCount++;
+                       }
+               }
+
+               return ulCount;
+       }
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+       {
+       uint32_t ulFirstSequence, ulReturn;
+
+               /* Receive a normal ACK. */
+
+               ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
+
+               if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
+               {
+                       ulReturn = 0UL;
+               }
+               else
+               {
+                       ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
+               }
+
+               return ulReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+       uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
+       {
+       uint32_t ulAckCount = 0UL;
+       uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
+
+               /* Receive a SACK option. */
+               ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
+               prvTCPWindowFastRetransmit( pxWindow, ulFirst );
+
+               if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
+               {
+                       FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
+                               pxWindow->usPeerPortNumber,
+                               pxWindow->usOurPortNumber,
+                               ulFirst - pxWindow->tx.ulFirstSequenceNumber,
+                               ulLast - pxWindow->tx.ulFirstSequenceNumber,
+                               pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
+                       FreeRTOS_flush_logging( );
+               }
+
+               return ulAckCount;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+/*
+#####   #                      #####   ####  ######
+# # #   #                      # # #  #    #  #    #
+  #                              #   #     #  #    #
+  #   ###   #####  #    #        #   #        #    #
+  #     #   #    # #    #        #   #        #####
+  #     #   #    # #    # ####   #   #        #
+  #     #   #    # #    #        #   #     #  #
+  #     #   #    #  ####         #    #    #  #
+ #### ##### #    #     #        ####   ####  ####
+                      #
+                   ###
+*/
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
+       {
+       int32_t iReturn;
+
+               /* Data was received at 'ulSequenceNumber'.  See if it was expected
+               and if there is enough space to store the new data. */
+               if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
+               {
+                       iReturn = -1;
+               }
+               else
+               {
+                       pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
+                       iReturn = 0;
+               }
+
+               return iReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
+       {
+       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+       int32_t lResult;
+
+               /* Data is being scheduled for transmission. */
+
+               /* lMax would indicate the size of the txStream. */
+               ( void ) lMax;
+               /* This is tiny TCP: there is only 1 segment for outgoing data.
+               As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
+               if( pxSegment->lDataLength > 0 )
+               {
+                       lResult = 0L;
+               }
+               else
+               {
+                       if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
+                       {
+                               if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
+                               }
+
+                               ulLength = ( uint32_t ) pxSegment->lMaxLength;
+                       }
+
+                       if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                       {
+                               FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
+                                       pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                       pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                       ulLength ) );
+                       }
+
+                       /* The sequence number of the first byte in this packet. */
+                       pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
+                       pxSegment->lDataLength = ( int32_t ) ulLength;
+                       pxSegment->lStreamPos = lPosition;
+                       pxSegment->u.ulFlags = 0UL;
+                       vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
+
+                       /* Increase the sequence number of the next data to be stored for
+                       transmission. */
+                       pxWindow->ulNextTxSequenceNumber += ulLength;
+                       lResult = ( int32_t )ulLength;
+               }
+
+               return lResult;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
+       {
+       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+       uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
+       uint32_t ulMaxTime;
+
+               if( ulLength != 0UL )
+               {
+                       /* _HT_ Still under investigation */
+                       ( void ) ulWindowSize;
+
+                       if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
+                       {
+                               /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
+                               ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+                               if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
+                               {
+                                       ulLength = 0ul;
+                               }
+                       }
+
+                       if( ulLength != 0ul )
+                       {
+                               pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
+                               pxSegment->u.bits.ucTransmitCount++;
+                               vTCPTimerSet (&pxSegment->xTransmitTimer);
+                               pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
+                               *plPosition = pxSegment->lStreamPos;
+                       }
+               }
+
+               return ulLength;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
+       {
+       BaseType_t xReturn;
+
+               /* Has the outstanding data been sent because user wants to shutdown? */
+               if( pxWindow->xTxSegment.lDataLength == 0 )
+               {
+                       xReturn = pdTRUE;
+               }
+               else
+               {
+                       xReturn = pdFALSE;
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
+       static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
+       {
+       BaseType_t xReturn;
+
+               if( ulWindowSize >= pxWindow->usMSSInit )
+               {
+                       xReturn = pdTRUE;
+               }
+               else
+               {
+                       xReturn = pdFALSE;
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
+       {
+       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+       BaseType_t xReturn;
+       TickType_t ulAge, ulMaxAge;
+
+               /* Check data to be sent. */
+               *pulDelay = ( TickType_t ) 0;
+               if( pxSegment->lDataLength == 0 )
+               {
+                       /* Got nothing to send right now. */
+                       xReturn = pdFALSE;
+               }
+               else
+               {
+                       if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
+                       {
+                               ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
+                               ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+                               if( ulMaxAge > ulAge )
+                               {
+                                       *pulDelay = ulMaxAge - ulAge;
+                               }
+
+                               xReturn = pdTRUE;
+                       }
+                       else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+                       {
+                               /* Too many outstanding messages. */
+                               xReturn = pdFALSE;
+                       }
+                       else
+                       {
+                               xReturn = pdTRUE;
+                       }
+               }
+
+               return xReturn;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+       {
+       TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+       uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
+
+               /* Receive a normal ACK */
+
+               if( ulDataLength != 0ul )
+               {
+                       if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
+                       {
+                               if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
+                               {
+                                       FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
+                                               ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                               pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                               ulDataLength ) );
+                               }
+
+                               /* Nothing to send right now. */
+                               ulDataLength = 0ul;
+                       }
+                       else
+                       {
+                               pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
+
+                               if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+                               {
+                                       FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
+                                               ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+                                               ulDataLength ) );
+                               }
+
+                               pxSegment->lDataLength = 0;
+                       }
+               }
+
+               return ulDataLength;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
+       {
+               /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
+               'ulCurrentSequenceNumber' is the highest sequence number stored,
+               'ulHighestSequenceNumber' is the highest sequence number seen. */
+               return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+       /* Destroy a window (always returns NULL) */
+       void vTCPWindowDestroy( TCPWindow_t *pxWindow )
+       {
+               /* As in tiny TCP there are no shared segments descriptors, there is
+               nothing to release. */
+               ( void ) pxWindow;
+       }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+