3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://aws.amazon.com/freertos
23 * http://www.FreeRTOS.org
28 * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
29 * functions have two versions - one for FreeRTOS+TCP (full) and one for
30 * FreeRTOS+TCP (lite).
32 * In this module all ports and IP addresses and sequence numbers are
33 * being stored in host byte-order.
36 /* Standard includes. */
39 /* FreeRTOS includes. */
45 /* FreeRTOS+TCP includes. */
46 #include "FreeRTOS_UDP_IP.h"
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "NetworkBufferManagement.h"
51 #include "FreeRTOS_TCP_WIN.h"
53 /* Constants used for Smoothed Round Trip Time (SRTT). */
54 #define winSRTT_INCREMENT_NEW 2
55 #define winSRTT_INCREMENT_CURRENT 6
56 #define winSRTT_DECREMENT_NEW 1
57 #define winSRTT_DECREMENT_CURRENT 7
58 #define winSRTT_CAP_mS 50
60 #if( ipconfigUSE_TCP_WIN == 1 )
62 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
64 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
66 /* The code to send a single Selective ACK (SACK):
67 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
68 * followed by a lower and a higher sequence number,
69 * where LEN is 2 + 2*4 = 10 bytes. */
70 #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
71 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
73 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
76 /* Normal retransmission:
77 * A packet will be retransmitted after a Retransmit Time-Out (RTO).
78 * Fast retransmission:
79 * When 3 packets with a higher sequence number have been acknowledged
80 * by the peer, it is very unlikely a current packet will ever arrive.
81 * It will be retransmitted far before the RTO.
83 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
85 /* If there have been several retransmissions (4), decrease the
86 * size of the transmission window to at most 2 times MSS.
88 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
90 #endif /* configUSE_TCP_WIN */
91 /*-----------------------------------------------------------*/
93 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
96 * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
97 * Available descriptors are stored in the 'xSegmentList'
98 * When a socket owns a descriptor, it will either be stored in
99 * 'xTxSegments' or 'xRxSegments'
100 * As soon as a package has been confirmed, the descriptor will be returned
101 * to the segment pool
103 #if( ipconfigUSE_TCP_WIN == 1 )
104 static BaseType_t prvCreateSectors( void );
105 #endif /* ipconfigUSE_TCP_WIN == 1 */
108 * Find a segment with a given sequence number in the list of received
109 * segments: 'pxWindow->xRxSegments'.
111 #if( ipconfigUSE_TCP_WIN == 1 )
112 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
113 #endif /* ipconfigUSE_TCP_WIN == 1 */
116 * Allocate a new segment
117 * The socket will borrow all segments from a common pool: 'xSegmentList',
118 * which is a list of 'TCPSegment_t'
120 #if( ipconfigUSE_TCP_WIN == 1 )
121 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
122 #endif /* ipconfigUSE_TCP_WIN == 1 */
124 /* When the peer has a close request (FIN flag), the driver will check if
125 * there are missing packets in the Rx-queue
126 * It will accept the closure of the connection if both conditions are true:
127 * - the Rx-queue is empty
128 * - we've ACK'd the highest Rx sequence number seen
130 #if( ipconfigUSE_TCP_WIN == 1 )
131 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
132 #endif /* ipconfigUSE_TCP_WIN == 1 */
135 * Detaches and returns the head of a queue
137 #if( ipconfigUSE_TCP_WIN == 1 )
138 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
139 #endif /* ipconfigUSE_TCP_WIN == 1 */
142 * Returns the head of a queue but it won't be detached
144 #if( ipconfigUSE_TCP_WIN == 1 )
145 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
146 #endif /* ipconfigUSE_TCP_WIN == 1 */
149 * Free entry pxSegment because it's not used anymore
150 * The ownership will be passed back to the segment pool
152 #if( ipconfigUSE_TCP_WIN == 1 )
153 static void vTCPWindowFree( TCPSegment_t *pxSegment );
154 #endif /* ipconfigUSE_TCP_WIN == 1 */
157 * A segment has been received with sequence number 'ulSequenceNumber', where
158 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
159 * segment was expected. xTCPWindowRxConfirm() will check if there is already
160 * another segment with a sequence number between (ulSequenceNumber) and
161 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
162 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
164 #if( ipconfigUSE_TCP_WIN == 1 )
165 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
166 #endif /* ipconfigUSE_TCP_WIN == 1 */
169 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
172 #if( ipconfigUSE_TCP_WIN == 1 )
173 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
174 #endif /* ipconfigUSE_TCP_WIN == 1 */
177 * This function will look if there is new transmission data. It will return
178 * true if there is data to be sent.
180 #if( ipconfigUSE_TCP_WIN == 1 )
181 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
182 #endif /* ipconfigUSE_TCP_WIN == 1 */
185 * An acknowledge was received. See if some outstanding data may be removed
186 * from the transmission queue(s).
188 #if( ipconfigUSE_TCP_WIN == 1 )
189 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
190 #endif /* ipconfigUSE_TCP_WIN == 1 */
193 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
194 * to find a possible condition for a FAST retransmission.
196 #if( ipconfigUSE_TCP_WIN == 1 )
197 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
198 #endif /* ipconfigUSE_TCP_WIN == 1 */
200 /*-----------------------------------------------------------*/
202 /* TCP segment pool. */
203 #if( ipconfigUSE_TCP_WIN == 1 )
204 static TCPSegment_t *xTCPSegments = NULL;
205 #endif /* ipconfigUSE_TCP_WIN == 1 */
207 /* List of free TCP segments. */
208 #if( ipconfigUSE_TCP_WIN == 1 )
209 static List_t xSegmentList;
212 /* Logging verbosity level. */
213 BaseType_t xTCPWindowLoggingLevel = 0;
215 #if( ipconfigUSE_TCP_WIN == 1 )
216 /* Some 32-bit arithmetic: comparing sequence numbers */
217 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
218 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
221 Return true if the unsigned subtraction of (b-a) doesn't generate an
222 arithmetic overflow. */
223 return ( ( b - a ) & 0x80000000UL ) == 0UL;
225 #endif /* ipconfigUSE_TCP_WIN */
226 /*-----------------------------------------------------------*/
228 #if( ipconfigUSE_TCP_WIN == 1 )
229 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
230 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
233 return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
235 #endif /* ipconfigUSE_TCP_WIN */
236 /*-----------------------------------------------------------*/
238 #if( ipconfigUSE_TCP_WIN == 1 )
239 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
240 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
243 return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
245 #endif /* ipconfigUSE_TCP_WIN */
247 /*-----------------------------------------------------------*/
248 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
249 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
252 return ( ( a - b ) & 0x80000000UL ) == 0UL;
254 /*-----------------------------------------------------------*/
256 #if( ipconfigUSE_TCP_WIN == 1 )
257 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
258 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
260 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
263 /*-----------------------------------------------------------*/
265 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
266 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
268 pxTimer->ulBorn = xTaskGetTickCount ( );
270 /*-----------------------------------------------------------*/
272 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
273 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
275 return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
277 /*-----------------------------------------------------------*/
279 /* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
280 preceded by a prototype. Later this prototype will be located in list.h? */
282 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
284 void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
286 /* Insert a new list item into pxList, it does not sort the list,
287 but it puts the item just before xListEnd, so it will be the last item
288 returned by listGET_HEAD_ENTRY() */
289 pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
290 pxNewListItem->pxPrevious = pxWhere->pxPrevious;
291 pxWhere->pxPrevious->pxNext = pxNewListItem;
292 pxWhere->pxPrevious = pxNewListItem;
294 /* Remember which list the item is in. */
295 listLIST_ITEM_CONTAINER( pxNewListItem ) = ( void * ) pxList;
297 ( pxList->uxNumberOfItems )++;
299 /*-----------------------------------------------------------*/
301 #if( ipconfigUSE_TCP_WIN == 1 )
303 static BaseType_t prvCreateSectors( void )
305 BaseType_t xIndex, xReturn;
307 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
309 vListInitialise( &xSegmentList );
310 xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
312 if( xTCPSegments == NULL )
314 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
315 ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
321 /* Clear the allocated space. */
322 memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
324 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
326 /* Could call vListInitialiseItem here but all data has been
327 nulled already. Set the owner to a segment descriptor. */
328 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
329 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
331 /* And add it to the pool of available segments */
332 vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
341 #endif /* ipconfigUSE_TCP_WIN == 1 */
342 /*-----------------------------------------------------------*/
344 #if( ipconfigUSE_TCP_WIN == 1 )
346 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
348 const ListItem_t *pxIterator;
349 const MiniListItem_t* pxEnd;
350 TCPSegment_t *pxSegment, *pxReturn = NULL;
352 /* Find a segment with a given sequence number in the list of received
355 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
357 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
358 pxIterator != ( const ListItem_t * ) pxEnd;
359 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
361 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
363 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
365 pxReturn = pxSegment;
373 #endif /* ipconfigUSE_TCP_WIN == 1 */
374 /*-----------------------------------------------------------*/
376 #if( ipconfigUSE_TCP_WIN == 1 )
378 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
380 TCPSegment_t *pxSegment;
383 /* Allocate a new segment. The socket will borrow all segments from a
384 common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
385 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
387 /* If the TCP-stack runs out of segments, you might consider
388 increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
389 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
394 /* Pop the item at the head of the list. Semaphore protection is
395 not required as only the IP task will call these functions. */
396 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
397 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
399 configASSERT( pxItem != NULL );
400 configASSERT( pxSegment != NULL );
402 /* Remove the item from xSegmentList. */
403 uxListRemove( pxItem );
405 /* Add it to either the connections' Rx or Tx queue. */
406 vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
408 /* And set the segment's timer to zero */
409 vTCPTimerSet( &pxSegment->xTransmitTimer );
411 pxSegment->u.ulFlags = 0;
412 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
413 pxSegment->lMaxLength = lCount;
414 pxSegment->lDataLength = lCount;
415 pxSegment->ulSequenceNumber = ulSequenceNumber;
416 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
418 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
419 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
421 if( xLowestLength > xLength )
423 xLowestLength = xLength;
426 #endif /* ipconfigHAS_DEBUG_PRINTF */
432 #endif /* ipconfigUSE_TCP_WIN == 1 */
433 /*-----------------------------------------------------------*/
435 #if( ipconfigUSE_TCP_WIN == 1 )
437 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
441 /* When the peer has a close request (FIN flag), the driver will check
442 if there are missing packets in the Rx-queue. It will accept the
443 closure of the connection if both conditions are true:
444 - the Rx-queue is empty
445 - the highest Rx sequence number has been ACK'ed */
446 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
448 /* Rx data has been stored while earlier packets were missing. */
451 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
453 /* No Rx packets are being stored and the highest sequence number
454 that has been received has been ACKed. */
459 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
460 ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
461 ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
468 #endif /* ipconfigUSE_TCP_WIN == 1 */
469 /*-----------------------------------------------------------*/
471 #if( ipconfigUSE_TCP_WIN == 1 )
473 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
475 TCPSegment_t *pxSegment;
478 /* Detaches and returns the head of a queue. */
479 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
485 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
486 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
488 uxListRemove( pxItem );
494 #endif /* ipconfigUSE_TCP_WIN == 1 */
495 /*-----------------------------------------------------------*/
497 #if( ipconfigUSE_TCP_WIN == 1 )
499 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
502 TCPSegment_t *pxReturn;
504 /* Returns the head of a queue but it won't be detached. */
505 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
511 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
512 pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
518 #endif /* ipconfigUSE_TCP_WIN == 1 */
519 /*-----------------------------------------------------------*/
521 #if( ipconfigUSE_TCP_WIN == 1 )
523 static void vTCPWindowFree( TCPSegment_t *pxSegment )
525 /* Free entry pxSegment because it's not used any more. The ownership
526 will be passed back to the segment pool.
528 Unlink it from one of the queues, if any. */
529 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
531 uxListRemove( &( pxSegment->xQueueItem ) );
534 pxSegment->ulSequenceNumber = 0u;
535 pxSegment->lDataLength = 0l;
536 pxSegment->u.ulFlags = 0u;
538 /* Take it out of xRxSegments/xTxSegments */
539 if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
541 uxListRemove( &( pxSegment->xListItem ) );
544 /* Return it to xSegmentList */
545 vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
548 #endif /* ipconfigUSE_TCP_WIN == 1 */
549 /*-----------------------------------------------------------*/
551 #if( ipconfigUSE_TCP_WIN == 1 )
553 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
557 TCPSegment_t *pxSegment;
559 /* Destroy a window. A TCP window doesn't serve any more. Return all
560 owned segments to the pool. In order to save code, it will make 2 rounds,
561 one to remove the segments from xRxSegments, and a second round to clear
563 for( xRound = 0; xRound < 2; xRound++ )
567 pxSegments = &( pxWindow->xRxSegments );
571 pxSegments = &( pxWindow->xTxSegments );
574 if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
576 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
578 pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
579 vTCPWindowFree( pxSegment );
585 #endif /* ipconfigUSE_TCP_WIN == 1 */
586 /*-----------------------------------------------------------*/
588 void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
589 uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
591 /* Create and initialize a window. */
593 #if( ipconfigUSE_TCP_WIN == 1 )
595 if( xTCPSegments == NULL )
600 vListInitialise( &pxWindow->xTxSegments );
601 vListInitialise( &pxWindow->xRxSegments );
603 vListInitialise( &pxWindow->xPriorityQueue ); /* Priority queue: segments which must be sent immediately */
604 vListInitialise( &pxWindow->xTxQueue ); /* Transmit queue: segments queued for transmission */
605 vListInitialise( &pxWindow->xWaitQueue ); /* Waiting queue: outstanding segments */
607 #endif /* ipconfigUSE_TCP_WIN == 1 */
609 if( xTCPWindowLoggingLevel != 0 )
611 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
612 ulRxWindowLength, ulTxWindowLength ) );
615 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
616 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
618 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
620 /*-----------------------------------------------------------*/
622 void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
624 const int32_t l500ms = 500;
626 pxWindow->u.ulFlags = 0ul;
627 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
631 if( pxWindow->usMSSInit != 0u )
633 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
636 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
638 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
639 pxWindow->usMSS = ( uint16_t ) ulMSS;
643 #if( ipconfigUSE_TCP_WIN == 0 )
645 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
647 #endif /* ipconfigUSE_TCP_WIN == 1 */
649 /*Start with a timeout of 2 * 500 ms (1 sec). */
650 pxWindow->lSRTT = l500ms;
652 /* Just for logging, to print relative sequence numbers. */
653 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
655 /* The segment asked for in the next transmission. */
656 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
658 /* The right-hand side of the receive window. */
659 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
661 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
663 /* The segment asked for in next transmission. */
664 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
666 /* The sequence number given to the next outgoing byte to be added is
667 maintained by lTCPWindowTxAdd(). */
668 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
670 /* The right-hand side of the transmit window. */
671 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
672 pxWindow->ulOurSequenceNumber = ulSequenceNumber;
674 /*-----------------------------------------------------------*/
676 #if( ipconfigUSE_TCP_WIN == 1 )
678 void vTCPSegmentCleanup( void )
680 /* Free and clear the TCP segments pointer. This function should only be called
681 * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this
683 if( xTCPSegments != NULL )
685 vPortFreeLarge( xTCPSegments );
690 #endif /* ipconfgiUSE_TCP_WIN == 1 */
691 /*-----------------------------------------------------------*/
693 /*=============================================================================
706 *=============================================================================*/
708 #if( ipconfigUSE_TCP_WIN == 1 )
710 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
712 TCPSegment_t *pxBest = NULL;
713 const ListItem_t *pxIterator;
714 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
715 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
716 TCPSegment_t *pxSegment;
718 /* A segment has been received with sequence number 'ulSequenceNumber',
719 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
720 exactly this segment was expected. xTCPWindowRxConfirm() will check if
721 there is already another segment with a sequence number between (ulSequenceNumber)
722 and (ulSequenceNumber+ulLength). Normally none will be found, because
723 the next RX segment should have a sequence number equal to
724 '(ulSequenceNumber+ulLength)'. */
726 /* Iterate through all RX segments that are stored: */
727 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
728 pxIterator != ( const ListItem_t * ) pxEnd;
729 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
731 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
732 /* And see if there is a segment for which:
733 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
734 If there are more matching segments, the one with the lowest sequence number
736 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
737 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
739 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
746 if( ( pxBest != NULL ) &&
747 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
749 FreeRTOS_flush_logging();
750 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
751 pxWindow->usPeerPortNumber,
752 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
754 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
755 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
757 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
763 #endif /* ipconfgiUSE_TCP_WIN == 1 */
764 /*-----------------------------------------------------------*/
766 #if( ipconfigUSE_TCP_WIN == 1 )
768 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
770 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
771 int32_t lReturn, lDistance;
772 TCPSegment_t *pxFound;
774 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
775 directly to user (segment is expected). If it returns a positive
776 number, an earlier packet is missing, but this packet may be stored.
777 If negative, the packet has already been stored, or it is out-of-order,
778 or there is not enough space.
780 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
781 if more Rx data may be passed to the user after this packet. */
783 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
785 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
786 pxWindow->ucOptionLength = 0u;
788 /* Non-zero if TCP-windows contains data which must be popped. */
789 pxWindow->ulUserDataLength = 0ul;
791 if( ulCurrentSequenceNumber == ulSequenceNumber )
793 /* This is the packet with the lowest sequence number we're waiting
794 for. It can be passed directly to the rx stream. */
795 if( ulLength > ulSpace )
797 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
802 ulCurrentSequenceNumber += ulLength;
804 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
806 ulSavedSequenceNumber = ulCurrentSequenceNumber;
808 /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
809 If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
810 So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
814 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
816 if ( pxFound != NULL )
818 /* Remove it because it will be passed to user directly. */
819 vTCPWindowFree( pxFound );
823 /* Check for following segments that are already in the
824 queue and increment ulCurrentSequenceNumber. */
825 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
827 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
829 /* As all packet below this one have been passed to the
830 user it can be discarded. */
831 vTCPWindowFree( pxFound );
834 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
836 /* After the current data-package, there is more data
838 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
840 if( xTCPWindowLoggingLevel >= 1 )
842 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
843 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
844 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
845 pxWindow->ulUserDataLength,
846 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
847 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
852 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
854 /* Packet was expected, may be passed directly to the socket
855 buffer or application. Store the packet at offset 0. */
859 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
861 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
862 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
867 /* The packet is not the one expected. See if it falls within the Rx
868 window so it can be stored. */
870 /* An "out-of-sequence" segment was received, must have missed one.
871 Prepare a SACK (Selective ACK). */
872 ulLast = ulSequenceNumber + ulLength;
873 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
877 /* An earlier has been received, must be a retransmission of a
878 packet that has been accepted already. No need to send out a
879 Selective ACK (SACK). */
882 else if( lDistance > ( int32_t ) ulSpace )
884 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
885 sequence number of this packet is too far ahead, ignore it. */
886 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
891 /* See if there is more data in a contiguous block to make the
892 SACK describe a longer range of data. */
894 /* TODO: SACK's may also be delayed for a short period
895 * This is useful because subsequent packets will be SACK'd with
898 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
900 ulLast += ( uint32_t ) pxFound->lDataLength;
903 if( xTCPWindowLoggingLevel >= 1 )
905 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
906 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
907 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
908 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
909 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
910 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
913 /* Now prepare the SACK message.
914 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
915 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
917 /* First sequence number that we received. */
918 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
921 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
923 /* Which make 12 (3*4) option bytes. */
924 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
926 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
928 if( pxFound != NULL )
930 /* This out-of-sequence packet has been received for a
931 second time. It is already stored but do send a SACK
937 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
939 if( pxFound == NULL )
941 /* Can not send a SACK, because the segment cannot be
943 pxWindow->ucOptionLength = 0u;
945 /* Needs to be stored but there is no segment
951 if( xTCPWindowLoggingLevel != 0 )
953 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
954 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
955 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
956 FreeRTOS_flush_logging( );
959 /* Return a positive value. The packet may be accepted
960 and stored but an earlier packet is still missing. */
961 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
970 #endif /* ipconfgiUSE_TCP_WIN == 1 */
971 /*-----------------------------------------------------------*/
973 /*=============================================================================
987 *=============================================================================*/
989 #if( ipconfigUSE_TCP_WIN == 1 )
991 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
993 /* +TCP stores data in circular buffers. Calculate the next position to
996 if( lPosition >= lMax )
1004 #endif /* ipconfigUSE_TCP_WIN == 1 */
1005 /*-----------------------------------------------------------*/
1007 #if( ipconfigUSE_TCP_WIN == 1 )
1009 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
1011 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
1013 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
1015 /* Puts a message in the Tx-window (after buffer size has been
1017 if( pxSegment != NULL )
1019 if( pxSegment->lDataLength < pxSegment->lMaxLength )
1021 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
1023 /* Adding data to a segment that was already in the TX queue. It
1024 will be filled-up to a maximum of MSS (maximum segment size). */
1025 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
1027 pxSegment->lDataLength += lToWrite;
1029 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
1031 /* This segment is full, don't add more bytes. */
1032 pxWindow->pxHeadSegment = NULL;
1035 lBytesLeft -= lToWrite;
1037 /* ulNextTxSequenceNumber is the sequence number of the next byte to
1038 be stored for transmission. */
1039 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
1041 /* Increased the return value. */
1044 /* Some detailed logging, for those who're interested. */
1045 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
1047 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
1049 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1050 pxSegment->lDataLength,
1051 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1052 pxSegment->lStreamPos ) );
1053 FreeRTOS_flush_logging( );
1056 /* Calculate the next position in the circular data buffer, knowing
1057 its maximum length 'lMax'. */
1058 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
1063 while( lBytesLeft > 0 )
1065 /* The current transmission segment is full, create new segments as
1067 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
1069 if( pxSegment != NULL )
1071 /* Store as many as needed, but no more than the maximum
1073 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
1075 pxSegment->lDataLength = lToWrite;
1076 pxSegment->lStreamPos = lPosition;
1077 lBytesLeft -= lToWrite;
1078 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
1079 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
1082 /* Link this segment in the Tx-Queue. */
1083 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
1085 /* Let 'pxHeadSegment' point to this segment if there is still
1087 if( pxSegment->lDataLength < pxSegment->lMaxLength )
1089 pxWindow->pxHeadSegment = pxSegment;
1093 pxWindow->pxHeadSegment = NULL;
1096 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
1098 if( ( xTCPWindowLoggingLevel >= 3 ) ||
1099 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
1101 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
1103 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1104 pxSegment->lDataLength,
1105 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1106 pxSegment->lStreamPos ) );
1107 FreeRTOS_flush_logging( );
1113 /* A sever situation: running out of segments for transmission.
1114 No more data can be sent at the moment. */
1117 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
1126 #endif /* ipconfigUSE_TCP_WIN == 1 */
1127 /*-----------------------------------------------------------*/
1129 #if( ipconfigUSE_TCP_WIN == 1 )
1131 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
1133 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
1136 #endif /* ipconfigUSE_TCP_WIN == 1 */
1137 /*-----------------------------------------------------------*/
1139 #if( ipconfigUSE_TCP_WIN == 1 )
1141 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
1143 uint32_t ulTxOutstanding;
1144 BaseType_t xHasSpace;
1145 TCPSegment_t *pxSegment;
1147 /* This function will look if there is new transmission data. It will
1148 return true if there is data to be sent. */
1150 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
1152 if( pxSegment == NULL )
1154 xHasSpace = pdFALSE;
1158 /* How much data is outstanding, i.e. how much data has been sent
1159 but not yet acknowledged ? */
1160 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
1162 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
1166 ulTxOutstanding = 0UL;
1169 /* Subtract this from the peer's space. */
1170 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
1172 /* See if the next segment may be sent. */
1173 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
1179 xHasSpace = pdFALSE;
1182 /* If 'xHasSpace', it looks like the peer has at least space for 1
1183 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
1184 limitation of the transmission window (in case of many resends it
1185 may be decreased). */
1186 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
1188 xHasSpace = pdFALSE;
1195 #endif /* ipconfigUSE_TCP_WIN == 1 */
1196 /*-----------------------------------------------------------*/
1198 #if( ipconfigUSE_TCP_WIN == 1 )
1200 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
1202 TCPSegment_t *pxSegment;
1204 TickType_t ulAge, ulMaxAge;
1208 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
1210 /* No need to look at retransmissions or new transmission as long as
1211 there are priority segments. *pulDelay equals zero, meaning it must
1212 be sent out immediately. */
1217 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
1219 if( pxSegment != NULL )
1221 /* There is an outstanding segment, see if it is time to resend
1223 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
1225 /* After a packet has been sent for the first time, it will wait
1226 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
1227 each time doubling the time-out */
1228 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
1230 if( ulMaxAge > ulAge )
1232 /* A segment must be sent after this amount of msecs */
1233 *pulDelay = ulMaxAge - ulAge;
1240 /* No priority segment, no outstanding data, see if there is new
1241 transmission data. */
1242 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
1244 /* See if it fits in the peer's reception window. */
1245 if( pxSegment == NULL )
1249 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
1251 /* Too many outstanding messages. */
1254 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
1256 /* 'bSendFullSize' is a special optimisation. If true, the
1257 driver will only sent completely filled packets (of MSS
1271 #endif /* ipconfigUSE_TCP_WIN == 1 */
1272 /*-----------------------------------------------------------*/
1274 #if( ipconfigUSE_TCP_WIN == 1 )
1276 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
1278 TCPSegment_t *pxSegment;
1280 uint32_t ulReturn = ~0UL;
1283 /* Fetches data to be sent-out now.
1285 Priority messages: segments with a resend need no check current sliding
1287 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
1288 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
1290 if( pxSegment == NULL )
1292 /* Waiting messages: outstanding messages with a running timer
1293 neither check peer's reception window size because these packets
1294 have been sent earlier. */
1295 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
1297 if( pxSegment != NULL )
1299 /* Do check the timing. */
1300 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
1302 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
1304 /* A normal (non-fast) retransmission. Move it from the
1305 head of the waiting queue. */
1306 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
1307 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
1309 /* Some detailed logging. */
1310 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
1312 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
1313 pxWindow->usPeerPortNumber,
1314 pxWindow->usOurPortNumber,
1315 pxSegment->lDataLength,
1316 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1317 pxSegment->ulSequenceNumber ) );
1318 FreeRTOS_flush_logging( );
1327 if( pxSegment == NULL )
1329 /* New messages: sent-out for the first time. Check current
1330 sliding window size of peer. */
1331 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
1333 if( pxSegment == NULL )
1335 /* No segments queued. */
1338 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
1340 /* A segment has been queued but the driver waits until it
1341 has a full size of MSS. */
1344 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
1346 /* Peer has no more space at this moment. */
1351 /* Move it out of the Tx queue. */
1352 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
1354 /* Don't let pxHeadSegment point to this segment any more,
1355 so no more data will be added. */
1356 if( pxWindow->pxHeadSegment == pxSegment )
1358 pxWindow->pxHeadSegment = NULL;
1361 /* pxWindow->tx.highest registers the highest sequence
1362 number in our transmission window. */
1363 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
1365 /* ...and more detailed logging */
1366 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1368 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
1369 pxWindow->usPeerPortNumber,
1370 pxWindow->usOurPortNumber,
1371 pxSegment->lDataLength,
1372 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1374 FreeRTOS_flush_logging( );
1381 /* There is a priority segment. It doesn't need any checking for
1382 space or timeouts. */
1383 if( xTCPWindowLoggingLevel != 0 )
1385 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
1386 pxWindow->usPeerPortNumber,
1387 pxWindow->usOurPortNumber,
1388 pxSegment->lDataLength,
1389 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1391 FreeRTOS_flush_logging( );
1395 /* See if it has already been determined to return 0. */
1396 if( ulReturn != 0UL )
1398 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
1400 /* Now that the segment will be transmitted, add it to the tail of
1401 the waiting queue. */
1402 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
1404 /* And mark it as outstanding. */
1405 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
1407 /* Administer the transmit count, needed for fast
1409 ( pxSegment->u.bits.ucTransmitCount )++;
1411 /* If there have been several retransmissions (4), decrease the
1412 size of the transmission window to at most 2 times MSS. */
1413 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
1415 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
1417 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
1418 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
1419 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
1420 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
1424 /* Clear the transmit timer. */
1425 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
1427 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
1429 /* Inform the caller where to find the data within the queue. */
1430 *plPosition = pxSegment->lStreamPos;
1432 /* And return the length of the data segment */
1433 ulReturn = ( uint32_t ) pxSegment->lDataLength;
1439 #endif /* ipconfigUSE_TCP_WIN == 1 */
1440 /*-----------------------------------------------------------*/
1442 #if( ipconfigUSE_TCP_WIN == 1 )
1444 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
1446 uint32_t ulBytesConfirmed = 0u;
1447 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
1448 const ListItem_t *pxIterator;
1449 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
1450 BaseType_t xDoUnlink;
1451 TCPSegment_t *pxSegment;
1452 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
1453 may be removed from the transmission queue(s).
1454 All TX segments for which
1455 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
1456 contiguous block. Note that the segments are stored in xTxSegments in a
1457 strict sequential order. */
1459 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
1461 0 < a < 1; usually a = 1/8
1466 RTT is Round Trip Time
1467 SRTT is Smoothed RTT
1468 RTO is Retransmit timeout
1470 A Smoothed RTT will increase quickly, but it is conservative when
1471 becoming smaller. */
1474 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
1475 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
1478 xDoUnlink = pdFALSE;
1479 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
1481 /* Move to the next item because the current item might get
1483 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
1485 /* Continue if this segment does not fall within the ACK'd range. */
1486 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
1492 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
1497 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
1499 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
1501 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
1503 /* What happens? Only part of this segment was accepted,
1504 probably due to WND limits
1506 AAAAAAA BBBBBBB << acked
1507 aaaaaaa aaaa << sent */
1508 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1510 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
1511 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
1512 pxWindow->usPeerPortNumber,
1513 pxWindow->usOurPortNumber,
1514 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
1515 ulLast - pxWindow->tx.ulFirstSequenceNumber,
1516 ulFirstSeq, ulFirstSeq + ulDataLength ) );
1518 #endif /* ipconfigHAS_DEBUG_PRINTF */
1522 /* This segment is fully ACK'd, set the flag. */
1523 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
1525 /* Calculate the RTT only if the segment was sent-out for the
1526 first time and if this is the last ACK'd segment in a range. */
1527 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
1529 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
1531 if( pxWindow->lSRTT >= mS )
1533 /* RTT becomes smaller: adapt slowly. */
1534 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
1538 /* RTT becomes larger: adapt quicker */
1539 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
1542 /* Cap to the minimum of 50ms. */
1543 if( pxWindow->lSRTT < winSRTT_CAP_mS )
1545 pxWindow->lSRTT = winSRTT_CAP_mS;
1549 /* Unlink it from the 3 queues, but do not destroy it (yet). */
1553 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
1554 side of the transmission queue? If so, it may be freed. */
1555 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
1557 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1559 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
1560 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
1561 ulLast - pxWindow->tx.ulFirstSequenceNumber,
1562 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
1565 /* Increase the left-hand value of the transmission window. */
1566 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
1568 /* This function will return the number of bytes that the tail
1569 of txStream may be advanced. */
1570 ulBytesConfirmed += ulDataLength;
1572 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
1573 vTCPWindowFree( pxSegment );
1575 /* No need to unlink it any more. */
1576 xDoUnlink = pdFALSE;
1579 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
1581 /* Remove item from its queues. */
1582 uxListRemove( &pxSegment->xQueueItem );
1585 ulSequenceNumber += ulDataLength;
1588 return ulBytesConfirmed;
1590 #endif /* ipconfigUSE_TCP_WIN == 1 */
1591 /*-----------------------------------------------------------*/
1593 #if( ipconfigUSE_TCP_WIN == 1 )
1595 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
1597 const ListItem_t *pxIterator;
1598 const MiniListItem_t* pxEnd;
1599 TCPSegment_t *pxSegment;
1600 uint32_t ulCount = 0UL;
1602 /* A higher Tx block has been acknowledged. Now iterate through the
1603 xWaitQueue to find a possible condition for a FAST retransmission. */
1605 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
1607 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
1608 pxIterator != ( const ListItem_t * ) pxEnd; )
1610 /* Get the owner, which is a TCP segment. */
1611 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
1613 /* Hop to the next item before the current gets unlinked. */
1614 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
1616 /* Fast retransmission:
1617 When 3 packets with a higher sequence number have been acknowledged
1618 by the peer, it is very unlikely a current packet will ever arrive.
1619 It will be retransmitted far before the RTO. */
1620 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
1621 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
1622 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
1624 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
1626 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
1627 which might lead to a second fast rexmit. */
1628 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1630 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
1631 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1632 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
1633 FreeRTOS_flush_logging( );
1636 /* Remove it from xWaitQueue. */
1637 uxListRemove( &pxSegment->xQueueItem );
1639 /* Add this segment to the priority queue so it gets
1640 retransmitted immediately. */
1641 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
1648 #endif /* ipconfigUSE_TCP_WIN == 1 */
1649 /*-----------------------------------------------------------*/
1651 #if( ipconfigUSE_TCP_WIN == 1 )
1653 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
1655 uint32_t ulFirstSequence, ulReturn;
1657 /* Receive a normal ACK. */
1659 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
1661 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
1667 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
1673 #endif /* ipconfigUSE_TCP_WIN == 1 */
1674 /*-----------------------------------------------------------*/
1676 #if( ipconfigUSE_TCP_WIN == 1 )
1678 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
1680 uint32_t ulAckCount = 0UL;
1681 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
1683 /* Receive a SACK option. */
1684 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
1685 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
1687 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
1689 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
1690 pxWindow->usPeerPortNumber,
1691 pxWindow->usOurPortNumber,
1692 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
1693 ulLast - pxWindow->tx.ulFirstSequenceNumber,
1694 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
1695 FreeRTOS_flush_logging( );
1701 #endif /* ipconfigUSE_TCP_WIN == 1 */
1702 /*-----------------------------------------------------------*/
1705 ##### # ##### #### ######
1706 # # # # # # # # # # #
1708 # ### ##### # # # # # #
1709 # # # # # # # # #####
1710 # # # # # # #### # # #
1712 # # # # #### # # # #
1713 #### ##### # # # #### #### ####
1717 #if( ipconfigUSE_TCP_WIN == 0 )
1719 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
1723 /* Data was received at 'ulSequenceNumber'. See if it was expected
1724 and if there is enough space to store the new data. */
1725 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
1731 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
1738 #endif /* ipconfigUSE_TCP_WIN == 0 */
1739 /*-----------------------------------------------------------*/
1741 #if( ipconfigUSE_TCP_WIN == 0 )
1743 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
1745 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
1748 /* Data is being scheduled for transmission. */
1750 /* lMax would indicate the size of the txStream. */
1752 /* This is tiny TCP: there is only 1 segment for outgoing data.
1753 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
1754 if( pxSegment->lDataLength > 0 )
1760 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
1762 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1764 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
1767 ulLength = ( uint32_t ) pxSegment->lMaxLength;
1770 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1772 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
1773 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1774 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1778 /* The sequence number of the first byte in this packet. */
1779 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
1780 pxSegment->lDataLength = ( int32_t ) ulLength;
1781 pxSegment->lStreamPos = lPosition;
1782 pxSegment->u.ulFlags = 0UL;
1783 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
1785 /* Increase the sequence number of the next data to be stored for
1787 pxWindow->ulNextTxSequenceNumber += ulLength;
1788 lResult = ( int32_t )ulLength;
1794 #endif /* ipconfigUSE_TCP_WIN == 0 */
1795 /*-----------------------------------------------------------*/
1797 #if( ipconfigUSE_TCP_WIN == 0 )
1799 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
1801 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
1802 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
1805 if( ulLength != 0UL )
1807 /* _HT_ Still under investigation */
1808 ( void ) ulWindowSize;
1810 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
1812 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
1813 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
1815 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
1821 if( ulLength != 0ul )
1823 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
1824 pxSegment->u.bits.ucTransmitCount++;
1825 vTCPTimerSet (&pxSegment->xTransmitTimer);
1826 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
1827 *plPosition = pxSegment->lStreamPos;
1834 #endif /* ipconfigUSE_TCP_WIN == 0 */
1835 /*-----------------------------------------------------------*/
1837 #if( ipconfigUSE_TCP_WIN == 0 )
1839 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
1843 /* Has the outstanding data been sent because user wants to shutdown? */
1844 if( pxWindow->xTxSegment.lDataLength == 0 )
1856 #endif /* ipconfigUSE_TCP_WIN == 0 */
1857 /*-----------------------------------------------------------*/
1859 #if( ipconfigUSE_TCP_WIN == 0 )
1861 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
1862 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
1866 if( ulWindowSize >= pxWindow->usMSSInit )
1878 #endif /* ipconfigUSE_TCP_WIN == 0 */
1879 /*-----------------------------------------------------------*/
1881 #if( ipconfigUSE_TCP_WIN == 0 )
1883 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
1885 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
1887 TickType_t ulAge, ulMaxAge;
1889 /* Check data to be sent. */
1890 *pulDelay = ( TickType_t ) 0;
1891 if( pxSegment->lDataLength == 0 )
1893 /* Got nothing to send right now. */
1898 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
1900 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
1901 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
1903 if( ulMaxAge > ulAge )
1905 *pulDelay = ulMaxAge - ulAge;
1910 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
1912 /* Too many outstanding messages. */
1924 #endif /* ipconfigUSE_TCP_WIN == 0 */
1925 /*-----------------------------------------------------------*/
1927 #if( ipconfigUSE_TCP_WIN == 0 )
1929 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
1931 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
1932 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
1934 /* Receive a normal ACK */
1936 if( ulDataLength != 0ul )
1938 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
1940 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
1942 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
1943 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1944 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1948 /* Nothing to send right now. */
1953 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
1955 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
1957 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
1958 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
1962 pxSegment->lDataLength = 0;
1966 return ulDataLength;
1969 #endif /* ipconfigUSE_TCP_WIN == 0 */
1970 /*-----------------------------------------------------------*/
1972 #if( ipconfigUSE_TCP_WIN == 0 )
1974 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
1976 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
1977 'ulCurrentSequenceNumber' is the highest sequence number stored,
1978 'ulHighestSequenceNumber' is the highest sequence number seen. */
1979 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
1982 #endif /* ipconfigUSE_TCP_WIN == 0 */
1983 /*-----------------------------------------------------------*/
1985 #if( ipconfigUSE_TCP_WIN == 0 )
1987 /* Destroy a window (always returns NULL) */
1988 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
1990 /* As in tiny TCP there are no shared segments descriptors, there is
1991 nothing to release. */
1995 #endif /* ipconfigUSE_TCP_WIN == 0 */
1996 /*-----------------------------------------------------------*/