xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_TCP_WIN.c (revision b23fa86ac476770d3224c07213bec32f5b1628bd)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 
29 /**
30  * @file FreeRTOS_TCP_WIN.c
31  * @brief Module which handles the TCP windowing schemes for FreeRTOS+TCP.  Many
32  * functions have two versions - one for FreeRTOS+TCP (full) and one for
33  * FreeRTOS+TCP (lite).
34  *
35  * In this module all ports and IP addresses and sequence numbers are
36  * being stored in host byte-order.
37  */
38 
39 /* Standard includes. */
40 #include <stdint.h>
41 
42 /* FreeRTOS includes. */
43 #include "FreeRTOS.h"
44 #include "task.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_UDP_IP.h"
49 #include "FreeRTOS_Sockets.h"
50 #include "FreeRTOS_IP_Private.h"
51 
52 #if ( ipconfigUSE_TCP == 1 )
53 
54 /* Constants used for Smoothed Round Trip Time (SRTT). */
55     #define winSRTT_INCREMENT_NEW        2                                     /**< New increment for the smoothed RTT. */
56     #define winSRTT_INCREMENT_CURRENT    6                                     /**< Current increment for the smoothed RTT. */
57     #define winSRTT_DECREMENT_NEW        1                                     /**< New decrement for the smoothed RTT. */
58     #define winSRTT_DECREMENT_CURRENT    7                                     /**< Current decrement for the smoothed RTT. */
59     #define winSRTT_CAP_mS               ( ipconfigTCP_SRTT_MINIMUM_VALUE_MS ) /**< Cap in milliseconds. */
60 
61     #if ( ipconfigUSE_TCP_WIN == 1 )
62 
63 /** @brief Create a new Rx window. */
64         #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount )    xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
65 
66 /** @brief Create a new Tx window. */
67         #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount )    xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
68 
69 /** @brief The code to send a single Selective ACK (SACK):
70  * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
71  * followed by a lower and a higher sequence number,
72  * where LEN is 2 + 2*4 = 10 bytes. */
73         #if ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
74             #define OPTION_CODE_SINGLE_SACK    ( 0x0101050aU )
75         #else
76             #define OPTION_CODE_SINGLE_SACK    ( 0x0a050101U )
77         #endif
78 
79 /** @brief Normal retransmission:
80  * A packet will be retransmitted after a Retransmit Time-Out (RTO).
81  * Fast retransmission:
82  * When 3 packets with a higher sequence number have been acknowledged
83  * by the peer, it is very unlikely a current packet will ever arrive.
84  * It will be retransmitted far before the RTO.
85  */
86         #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT    ( 3U )
87 
88 /** @brief If there have been several retransmissions (4), decrease the
89  * size of the transmission window to at most 2 times MSS.
90  */
91         #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW    ( 4U )
92 
93     #endif /* configUSE_TCP_WIN */
94 /*-----------------------------------------------------------*/
95 
96     #if ( ipconfigUSE_TCP_WIN == 1 )
97         static void vListInsertGeneric( List_t * const pxList,
98                                         ListItem_t * const pxNewListItem,
99                                         MiniListItem_t * pxWhere );
100     #endif
101 
102 /*
103  * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
104  * Available descriptors are stored in the 'xSegmentList'
105  * When a socket owns a descriptor, it will either be stored in
106  * 'xTxSegments' or 'xRxSegments'
107  * As soon as a package has been confirmed, the descriptor will be returned
108  * to the segment pool
109  */
110     #if ( ipconfigUSE_TCP_WIN == 1 )
111         static BaseType_t prvCreateSectors( void );
112     #endif /* ipconfigUSE_TCP_WIN == 1 */
113 
114 /*
115  * Find a segment with a given sequence number in the list of received
116  * segments: 'pxWindow->xRxSegments'.
117  */
118     #if ( ipconfigUSE_TCP_WIN == 1 )
119         static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow,
120                                                 uint32_t ulSequenceNumber );
121     #endif /* ipconfigUSE_TCP_WIN == 1 */
122 
123 /*
124  * Allocate a new segment
125  * The socket will borrow all segments from a common pool: 'xSegmentList',
126  * which is a list of 'TCPSegment_t'
127  */
128     #if ( ipconfigUSE_TCP_WIN == 1 )
129         static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow,
130                                              uint32_t ulSequenceNumber,
131                                              int32_t lCount,
132                                              BaseType_t xIsForRx );
133     #endif /* ipconfigUSE_TCP_WIN == 1 */
134 
135 /*
136  * Detaches and returns the head of a queue
137  */
138     #if ( ipconfigUSE_TCP_WIN == 1 )
139         static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList );
140     #endif /* ipconfigUSE_TCP_WIN == 1 */
141 
142 /*
143  * Returns the head of a queue but it won't be detached
144  */
145     #if ( ipconfigUSE_TCP_WIN == 1 )
146         static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList );
147     #endif /* ipconfigUSE_TCP_WIN == 1 */
148 
149 /*
150  * Free entry pxSegment because it's not used anymore
151  * The ownership will be passed back to the segment pool
152  */
153     #if ( ipconfigUSE_TCP_WIN == 1 )
154         static void vTCPWindowFree( TCPSegment_t * pxSegment );
155     #endif /* ipconfigUSE_TCP_WIN == 1 */
156 
157 /*
158  * A segment has been received with sequence number 'ulSequenceNumber', where
159  * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
160  * segment was expected.  xTCPWindowRxConfirm() will check if there is already
161  * another segment with a sequence number between (ulSequenceNumber) and
162  * (ulSequenceNumber+xLength).  Normally none will be found, because the next Rx
163  * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
164  */
165     #if ( ipconfigUSE_TCP_WIN == 1 )
166         static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow,
167                                                    uint32_t ulSequenceNumber,
168                                                    uint32_t ulLength );
169     #endif /* ipconfigUSE_TCP_WIN == 1 */
170 
171 /*
172  * FreeRTOS+TCP stores data in circular buffers.  Calculate the next position to
173  * store.
174  */
175     #if ( ipconfigUSE_TCP_WIN == 1 )
176         static int32_t lTCPIncrementTxPosition( int32_t lPosition,
177                                                 int32_t lMax,
178                                                 int32_t lCount );
179     #endif /* ipconfigUSE_TCP_WIN == 1 */
180 
181 /*
182  * This function will look if there is new transmission data.  It will return
183  * true if there is data to be sent.
184  */
185     #if ( ipconfigUSE_TCP_WIN == 1 )
186         static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
187                                                   uint32_t ulWindowSize );
188     #endif /* ipconfigUSE_TCP_WIN == 1 */
189 
190 /*
191  * An acknowledge was received.  See if some outstanding data may be removed
192  * from the transmission queue(s).
193  */
194     #if ( ipconfigUSE_TCP_WIN == 1 )
195         static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow,
196                                                 uint32_t ulFirst,
197                                                 uint32_t ulLast );
198     #endif /* ipconfigUSE_TCP_WIN == 1 */
199 
200 /*
201  * A higher Tx block has been acknowledged.  Now iterate through the xWaitQueue
202  * to find a possible condition for a FAST retransmission.
203  */
204     #if ( ipconfigUSE_TCP_WIN == 1 )
205         static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow,
206                                                     uint32_t ulFirst );
207     #endif /* ipconfigUSE_TCP_WIN == 1 */
208 
209 /*-----------------------------------------------------------*/
210 
211 /**< TCP segment pool. */
212     #if ( ipconfigUSE_TCP_WIN == 1 )
213         static TCPSegment_t * xTCPSegments = NULL;
214     #endif /* ipconfigUSE_TCP_WIN == 1 */
215 
216 /**< List of free TCP segments. */
217     #if ( ipconfigUSE_TCP_WIN == 1 )
218         _static List_t xSegmentList;
219     #endif
220 
221     #if ( ipconfigUSE_TCP_WIN == 1 )
222 /** @brief Logging verbosity level. */
223         BaseType_t xTCPWindowLoggingLevel = 0;
224     #endif
225 
226     #if ( ipconfigUSE_TCP_WIN == 1 )
227         /* Some 32-bit arithmetic: comparing sequence numbers */
228         static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a,
229                                                                uint32_t b );
230 
231 /**
232  * @brief Check if a <= b.
233  *
234  * @param[in] a The value on the left-hand side.
235  * @param[in] b The value on the right-hand side.
236  *
237  * @return pdTRUE when "( b - a ) < 0x80000000". Else, pdFALSE.
238  */
xSequenceLessThanOrEqual(uint32_t a,uint32_t b)239         static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a,
240                                                                uint32_t b )
241         {
242             BaseType_t xResult = pdFALSE;
243 
244             /* Test if a <= b
245              * Return true if the unsigned subtraction of (b-a) doesn't generate an
246              * arithmetic overflow. */
247             if( ( ( b - a ) & 0x80000000U ) == 0U )
248             {
249                 xResult = pdTRUE;
250             }
251 
252             return xResult;
253         }
254 
255     #endif /* ipconfigUSE_TCP_WIN */
256 /*-----------------------------------------------------------*/
257 
258 /**
259  * @brief Check if a < b.
260  *
261  * @param[in] a The value on the left-hand side.
262  * @param[in] b The value on the right-hand side.
263  *
264  * @return pdTRUE when "( b - ( a + 1 ) ) < 0x80000000", else pdFALSE.
265  */
xSequenceLessThan(uint32_t a,uint32_t b)266     BaseType_t xSequenceLessThan( uint32_t a,
267                                   uint32_t b )
268     {
269         BaseType_t xResult = pdFALSE;
270 
271         /* Test if a < b */
272         if( ( ( b - ( a + 1U ) ) & 0x80000000U ) == 0U )
273         {
274             xResult = pdTRUE;
275         }
276 
277         return xResult;
278     }
279 
280 /*-----------------------------------------------------------*/
281 
282 /**
283  * @brief Check if a > b.
284  *
285  * @param[in] a The value on the left-hand side.
286  * @param[in] b The value on the right-hand side.
287  *
288  * @return pdTRUE when "( a - b ) < 0x80000000", else pdFALSE.
289  */
xSequenceGreaterThan(uint32_t a,uint32_t b)290     BaseType_t xSequenceGreaterThan( uint32_t a,
291                                      uint32_t b )
292     {
293         BaseType_t xResult = pdFALSE;
294 
295         /* Test if a > b */
296         if( ( ( a - ( b + 1U ) ) & 0x80000000U ) == 0U )
297         {
298             xResult = pdTRUE;
299         }
300 
301         return xResult;
302     }
303 
304 
305 /*-----------------------------------------------------------*/
306     static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
307                                                               uint32_t b );
308 
309 /**
310  * @brief Test if a>=b. This function is required since the sequence numbers can roll over.
311  *
312  * @param[in] a The first sequence number.
313  * @param[in] b The second sequence number.
314  *
315  * @return pdTRUE if a>=b, else pdFALSE.
316  */
xSequenceGreaterThanOrEqual(uint32_t a,uint32_t b)317     static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a,
318                                                               uint32_t b )
319     {
320         BaseType_t xResult = pdFALSE;
321 
322         /* Test if a >= b */
323         if( ( ( a - b ) & 0x80000000U ) == 0U )
324         {
325             xResult = pdTRUE;
326         }
327 
328         return xResult;
329     }
330 /*-----------------------------------------------------------*/
331 
332     #if ( ipconfigUSE_TCP_WIN == 1 )
333         static portINLINE void vListInsertFifo( List_t * const pxList,
334                                                 ListItem_t * const pxNewListItem );
335 
336 /**
337  * @brief Insert the given item in the list in FIFO manner.
338  *
339  * @param[in] pxList The list in which the item is to inserted.
340  * @param[in] pxNewListItem The item to be inserted.
341  */
vListInsertFifo(List_t * const pxList,ListItem_t * const pxNewListItem)342         static portINLINE void vListInsertFifo( List_t * const pxList,
343                                                 ListItem_t * const pxNewListItem )
344         {
345             vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
346         }
347     #endif
348 /*-----------------------------------------------------------*/
349 
350     static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer );
351 
352 /**
353  * @brief Set the timer's "born" time.
354  *
355  * @param[in] pxTimer The TCP timer.
356  */
vTCPTimerSet(TCPTimer_t * pxTimer)357     static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer )
358     {
359         pxTimer->uxBorn = xTaskGetTickCount();
360     }
361 /*-----------------------------------------------------------*/
362 
363     static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer );
364 
365 /**
366  * @brief Get the timer age in milliseconds.
367  *
368  * @param[in] pxTimer The timer whose age is to be fetched.
369  *
370  * @return The time in milliseconds since the timer was born.
371  */
ulTimerGetAge(const TCPTimer_t * pxTimer)372     static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer )
373     {
374         TickType_t uxNow = xTaskGetTickCount();
375         TickType_t uxDiff = uxNow - pxTimer->uxBorn;
376 
377         return ( uint32_t ) ( uxDiff * portTICK_PERIOD_MS );
378     }
379 /*-----------------------------------------------------------*/
380 
381 /**
382  * @brief Insert a new list item into a list.
383  *
384  * @param[in] pxList The list in which the item is to be inserted.
385  * @param[in] pxNewListItem The item to be inserted.
386  * @param[in] pxWhere Where should the item be inserted.
387  */
388     #if ( ipconfigUSE_TCP_WIN == 1 )
vListInsertGeneric(List_t * const pxList,ListItem_t * const pxNewListItem,MiniListItem_t * pxWhere)389         static void vListInsertGeneric( List_t * const pxList,
390                                         ListItem_t * const pxNewListItem,
391                                         MiniListItem_t * pxWhere )
392         {
393             /* Insert a new list item into pxList, it does not sort the list,
394              * but it puts the item just before xListEnd, so it will be the last item
395              * returned by listGET_HEAD_ENTRY() */
396 
397             /* MISRA Ref 11.3.1 [Misaligned access] */
398             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
399             /* coverity[misra_c_2012_rule_11_3_violation] */
400             pxNewListItem->pxNext = ( ( ListItem_t * ) pxWhere );
401 
402             pxNewListItem->pxPrevious = pxWhere->pxPrevious;
403             pxWhere->pxPrevious->pxNext = pxNewListItem;
404             pxWhere->pxPrevious = pxNewListItem;
405 
406             /* Remember which list the item is in. */
407             listLIST_ITEM_CONTAINER( pxNewListItem ) = ( struct xLIST * configLIST_VOLATILE ) pxList;
408 
409             ( pxList->uxNumberOfItems )++;
410         }
411     #endif /* if ( ipconfigUSE_TCP_WIN == 1 ) */
412 /*-----------------------------------------------------------*/
413 
414     #if ( ipconfigUSE_TCP_WIN == 1 )
415 
416 /**
417  * @brief Creates a pool of 'ipconfigTCP_WIN_SEG_COUNT' sector buffers. Should be called once only.
418  *
419  * @return When the allocation was successful: pdPASS, otherwise pdFAIL.
420  */
prvCreateSectors(void)421         static BaseType_t prvCreateSectors( void )
422         {
423             BaseType_t xIndex;
424             BaseType_t xReturn;
425 
426             /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
427 
428             vListInitialise( &xSegmentList );
429             xTCPSegments = ( ( TCPSegment_t * ) pvPortMallocLarge( ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
430 
431             if( xTCPSegments == NULL )
432             {
433                 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %u failed\n",
434                                          ( unsigned ) ( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) ) );
435 
436                 xReturn = pdFAIL;
437             }
438             else
439             {
440                 /* Clear the allocated space. */
441                 ( void ) memset( xTCPSegments, 0, ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
442 
443                 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
444                 {
445                     /* Could call vListInitialiseItem here but all data has been
446                     * nulled already.  Set the owner to a segment descriptor. */
447 
448                     #if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 )
449                         {
450                             vListInitialiseItem( &( xTCPSegments[ xIndex ].xSegmentItem ) );
451                             vListInitialiseItem( &( xTCPSegments[ xIndex ].xQueueItem ) );
452                         }
453                     #endif
454 
455                     listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xSegmentItem ), ( void * ) &( xTCPSegments[ xIndex ] ) );
456                     listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void * ) &( xTCPSegments[ xIndex ] ) );
457 
458                     /* And add it to the pool of available segments */
459                     vListInsertFifo( &xSegmentList, &( xTCPSegments[ xIndex ].xSegmentItem ) );
460                 }
461 
462                 xReturn = pdPASS;
463             }
464 
465             return xReturn;
466         }
467     #endif /* ipconfigUSE_TCP_WIN == 1 */
468 /*-----------------------------------------------------------*/
469 
470     #if ( ipconfigUSE_TCP_WIN == 1 )
471 
472 /**
473  * @brief Find a segment with a given sequence number in the list of received segments.
474  *
475  * @param[in] pxWindow The descriptor of the TCP sliding windows.
476  * @param[in] ulSequenceNumber the sequence number to look-up
477  *
478  * @return The address of the segment descriptor found, or NULL when not found.
479  */
xTCPWindowRxFind(const TCPWindow_t * pxWindow,uint32_t ulSequenceNumber)480         static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow,
481                                                 uint32_t ulSequenceNumber )
482         {
483             const ListItem_t * pxIterator;
484             const ListItem_t * pxEnd;
485             TCPSegment_t * pxSegment, * pxReturn = NULL;
486 
487             /* Find a segment with a given sequence number in the list of received
488              * segments. */
489 
490             /* MISRA Ref 11.3.1 [Misaligned access] */
491 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
492             /* coverity[misra_c_2012_rule_11_3_violation] */
493             pxEnd = ( ( const ListItem_t * ) &( pxWindow->xRxSegments.xListEnd ) );
494 
495             for( pxIterator = listGET_NEXT( pxEnd );
496                  pxIterator != pxEnd;
497                  pxIterator = listGET_NEXT( pxIterator ) )
498             {
499                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
500 
501                 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
502                 {
503                     pxReturn = pxSegment;
504                     break;
505                 }
506             }
507 
508             return pxReturn;
509         }
510     #endif /* ipconfigUSE_TCP_WIN == 1 */
511 /*-----------------------------------------------------------*/
512 
513     #if ( ipconfigUSE_TCP_WIN == 1 )
514 
515 /**
516  * @brief Allocate a new segment object, either for transmission or reception.
517  *
518  * @param[in] pxWindow The descriptor of the TCP sliding windows.
519  * @param[in] ulSequenceNumber The sequence number.
520  * @param[in] lCount The number of bytes stored in this segment.
521  * @param[in] xIsForRx True when this is a reception segment.
522  *
523  * @return Allocate and initialise a segment descriptor, or NULL when none was available.
524  */
xTCPWindowNew(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,int32_t lCount,BaseType_t xIsForRx)525         static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow,
526                                              uint32_t ulSequenceNumber,
527                                              int32_t lCount,
528                                              BaseType_t xIsForRx )
529         {
530             TCPSegment_t * pxSegment;
531             ListItem_t * pxItem;
532 
533             /* Allocate a new segment.  The socket will borrow all segments from a
534              * common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
535             if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
536             {
537                 /* If the TCP-stack runs out of segments, you might consider
538                  * increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
539                 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", ( xIsForRx != 0 ) ? 'R' : 'T' ) );
540                 pxSegment = NULL;
541             }
542             else
543             {
544                 /* Pop the item at the head of the list.  Semaphore protection is
545                 * not required as only the IP task will call these functions.  */
546                 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
547                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) );
548 
549                 configASSERT( pxItem != NULL );
550                 configASSERT( pxSegment != NULL );
551 
552                 /* Remove the item from xSegmentList. */
553                 ( void ) uxListRemove( pxItem );
554 
555                 /* Add it to either the connections' Rx or Tx queue. */
556                 if( xIsForRx != 0 )
557                 {
558                     vListInsertFifo( &pxWindow->xRxSegments, pxItem );
559                 }
560                 else
561                 {
562                     vListInsertFifo( &pxWindow->xTxSegments, pxItem );
563                 }
564 
565                 /* And set the segment's timer to zero */
566                 vTCPTimerSet( &pxSegment->xTransmitTimer );
567 
568                 pxSegment->u.ulFlags = 0;
569                 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 ) ? 1U : 0U;
570                 pxSegment->lMaxLength = lCount;
571                 pxSegment->lDataLength = lCount;
572                 pxSegment->ulSequenceNumber = ulSequenceNumber;
573                 #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
574                     {
575                         static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
576                         UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
577 
578                         if( xLowestLength > xLength )
579                         {
580                             xLowestLength = xLength;
581                         }
582                     }
583                 #endif /* ipconfigHAS_DEBUG_PRINTF */
584             }
585 
586             return pxSegment;
587         }
588     #endif /* ipconfigUSE_TCP_WIN == 1 */
589 /*-----------------------------------------------------------*/
590 
591     #if ( ipconfigUSE_TCP_WIN == 1 )
592 
593 /**
594  * @brief See if the peer has more packets for this node, before allowing to shut down the connection.
595  *
596  * @param[in] pxWindow The descriptor of the TCP sliding windows.
597  *
598  * @return pdTRUE if the connection can be closed. Else, pdFALSE.
599  */
xTCPWindowRxEmpty(const TCPWindow_t * pxWindow)600         BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow )
601         {
602             BaseType_t xReturn;
603 
604             /* When the peer has a close request (FIN flag), the driver will check
605              * if there are missing packets in the Rx-queue.  It will accept the
606              * closure of the connection if both conditions are true:
607              * - the Rx-queue is empty
608              * - the highest Rx sequence number has been ACK'ed */
609             if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
610             {
611                 /* Rx data has been stored while earlier packets were missing. */
612                 xReturn = pdFALSE;
613             }
614             else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber + 1U, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
615             {
616                 /* No Rx packets are being stored and the highest sequence number
617                  * that has been received has been ACKed. */
618                 xReturn = pdTRUE;
619             }
620             else
621             {
622                 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %u highest %u (empty)\n",
623                                          ( unsigned ) ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
624                                          ( unsigned ) ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
625                 xReturn = pdFALSE;
626             }
627 
628             return xReturn;
629         }
630     #endif /* ipconfigUSE_TCP_WIN == 1 */
631 /*-----------------------------------------------------------*/
632 
633     #if ( ipconfigUSE_TCP_WIN == 1 )
634 
635 /**
636  * @brief Remove the head item of a list (generic function).
637  *
638  * @param[in] pxList The list of segment descriptors.
639  *
640  * @return The address of the segment descriptor, or NULL when not found.
641  */
xTCPWindowGetHead(const List_t * pxList)642         static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList )
643         {
644             TCPSegment_t * pxSegment;
645             ListItem_t * pxItem;
646 
647             /* Detaches and returns the head of a queue. */
648             if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
649             {
650                 pxSegment = NULL;
651             }
652             else
653             {
654                 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
655                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) );
656 
657                 ( void ) uxListRemove( pxItem );
658             }
659 
660             return pxSegment;
661         }
662     #endif /* ipconfigUSE_TCP_WIN == 1 */
663 /*-----------------------------------------------------------*/
664 
665     #if ( ipconfigUSE_TCP_WIN == 1 )
666 
667 /**
668  * @brief Return the head item of a list (generic function).
669  *
670  * @param[in] pxList The list of segment descriptors.
671  *
672  * @return The address of the segment descriptor, or NULL when the list is empty.
673  */
xTCPWindowPeekHead(const List_t * pxList)674         static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList )
675         {
676             const ListItem_t * pxItem;
677             TCPSegment_t * pxReturn;
678 
679             /* Returns the head of a queue but it won't be detached. */
680             if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
681             {
682                 pxReturn = NULL;
683             }
684             else
685             {
686                 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
687                 pxReturn = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) );
688             }
689 
690             return pxReturn;
691         }
692     #endif /* ipconfigUSE_TCP_WIN == 1 */
693 /*-----------------------------------------------------------*/
694 
695     #if ( ipconfigUSE_TCP_WIN == 1 )
696 
697 /**
698  * @brief Release a segment object, return it to the list of available segment holders.
699  *
700  * @param[in] pxSegment The segment descriptor that must be freed.
701  */
vTCPWindowFree(TCPSegment_t * pxSegment)702         static void vTCPWindowFree( TCPSegment_t * pxSegment )
703         {
704             /*  Free entry pxSegment because it's not used any more.  The ownership
705              * will be passed back to the segment pool.
706              *
707              * Unlink it from one of the queues, if any. */
708             if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
709             {
710                 ( void ) uxListRemove( &( pxSegment->xQueueItem ) );
711             }
712 
713             pxSegment->ulSequenceNumber = 0U;
714             pxSegment->lDataLength = 0;
715             pxSegment->u.ulFlags = 0U;
716 
717             /* Take it out of xRxSegments/xTxSegments */
718             if( listLIST_ITEM_CONTAINER( &( pxSegment->xSegmentItem ) ) != NULL )
719             {
720                 ( void ) uxListRemove( &( pxSegment->xSegmentItem ) );
721             }
722 
723             /* Return it to xSegmentList */
724             vListInsertFifo( &xSegmentList, &( pxSegment->xSegmentItem ) );
725         }
726     #endif /* ipconfigUSE_TCP_WIN == 1 */
727 /*-----------------------------------------------------------*/
728 
729     #if ( ipconfigUSE_TCP_WIN == 1 )
730 
731 /**
732  * @brief Return all segment descriptor to the poll of descriptors, before deleting a socket.
733  *
734  * @param[in] pxWindow The descriptor of the TCP sliding windows.
735  */
vTCPWindowDestroy(TCPWindow_t const * pxWindow)736         void vTCPWindowDestroy( TCPWindow_t const * pxWindow )
737         {
738             const List_t * pxSegments;
739             BaseType_t xRound;
740             TCPSegment_t * pxSegment;
741 
742             /*  Destroy a window.  A TCP window doesn't serve any more.  Return all
743              * owned segments to the pool.  In order to save code, it will make 2 rounds,
744              * one to remove the segments from xRxSegments, and a second round to clear
745              * xTxSegments*/
746             for( xRound = 0; xRound < 2; xRound++ )
747             {
748                 if( xRound != 0 )
749                 {
750                     pxSegments = &( pxWindow->xRxSegments );
751                 }
752                 else
753                 {
754                     pxSegments = &( pxWindow->xTxSegments );
755                 }
756 
757                 if( listLIST_IS_INITIALISED( pxSegments ) )
758                 {
759                     while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
760                     {
761                         pxSegment = ( ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments ) );
762                         vTCPWindowFree( pxSegment );
763                     }
764                 }
765             }
766         }
767     #endif /* ipconfigUSE_TCP_WIN == 1 */
768 /*-----------------------------------------------------------*/
769 
770 /**
771  * @brief Create a window for TCP.
772  *
773  * @param[in] pxWindow The window to be created.
774  * @param[in] ulRxWindowLength The length of the receive window.
775  * @param[in] ulTxWindowLength The length of the transmit window.
776  * @param[in] ulAckNumber The first ACK number.
777  * @param[in] ulSequenceNumber The first sequence number.
778  * @param[in] ulMSS The MSS of the connection.
779  */
vTCPWindowCreate(TCPWindow_t * pxWindow,uint32_t ulRxWindowLength,uint32_t ulTxWindowLength,uint32_t ulAckNumber,uint32_t ulSequenceNumber,uint32_t ulMSS)780     void vTCPWindowCreate( TCPWindow_t * pxWindow,
781                            uint32_t ulRxWindowLength,
782                            uint32_t ulTxWindowLength,
783                            uint32_t ulAckNumber,
784                            uint32_t ulSequenceNumber,
785                            uint32_t ulMSS )
786     {
787         /* Create and initialize a window. */
788 
789         #if ( ipconfigUSE_TCP_WIN == 1 )
790             {
791                 if( xTCPSegments == NULL )
792                 {
793                     ( void ) prvCreateSectors();
794                 }
795 
796                 vListInitialise( &( pxWindow->xTxSegments ) );
797                 vListInitialise( &( pxWindow->xRxSegments ) );
798 
799                 vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
800                 vListInitialise( &( pxWindow->xTxQueue ) );       /* Transmit queue: segments queued for transmission */
801                 vListInitialise( &( pxWindow->xWaitQueue ) );     /* Waiting queue:  outstanding segments */
802             }
803         #endif /* ipconfigUSE_TCP_WIN == 1 */
804 
805         if( xTCPWindowLoggingLevel != 0 )
806         {
807             FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %u/%u\n",
808                                      ( unsigned ) ulRxWindowLength, ( unsigned ) ulTxWindowLength ) );
809         }
810 
811         pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
812         pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
813 
814         vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
815     }
816 /*-----------------------------------------------------------*/
817 
818 /**
819  * @brief Initialise a TCP window.
820  *
821  * @param[in] pxWindow The window to be initialised.
822  * @param[in] ulAckNumber The number of the first ACK.
823  * @param[in] ulSequenceNumber The first sequence number.
824  * @param[in] ulMSS The MSS of the connection.
825  */
vTCPWindowInit(TCPWindow_t * pxWindow,uint32_t ulAckNumber,uint32_t ulSequenceNumber,uint32_t ulMSS)826     void vTCPWindowInit( TCPWindow_t * pxWindow,
827                          uint32_t ulAckNumber,
828                          uint32_t ulSequenceNumber,
829                          uint32_t ulMSS )
830     {
831         const int32_t l500ms = 500;
832 
833         pxWindow->u.ulFlags = 0U;
834         pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
835 
836         if( ulMSS != 0U )
837         {
838             if( pxWindow->usMSSInit != 0U )
839             {
840                 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
841             }
842 
843             if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0U ) )
844             {
845                 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
846                 pxWindow->usMSS = ( uint16_t ) ulMSS;
847             }
848         }
849 
850         #if ( ipconfigUSE_TCP_WIN == 0 )
851             {
852                 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
853             }
854         #endif /* ipconfigUSE_TCP_WIN == 1 */
855 
856         /*Start with a timeout of 2 * 500 ms (1 sec). */
857         pxWindow->lSRTT = l500ms;
858 
859         /* Just for logging, to print relative sequence numbers. */
860         pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
861 
862         /* The segment asked for in the next transmission. */
863         pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
864 
865         /* The right-hand side of the receive window. */
866         pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
867 
868         pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
869 
870         /* The segment asked for in next transmission. */
871         pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
872 
873         /* The sequence number given to the next outgoing byte to be added is
874          * maintained by lTCPWindowTxAdd(). */
875         pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
876 
877         /* The right-hand side of the transmit window. */
878         pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
879         pxWindow->ulOurSequenceNumber = ulSequenceNumber;
880     }
881 /*-----------------------------------------------------------*/
882 
883     #if ( ipconfigUSE_TCP_WIN == 1 )
884 
885 /**
886  * @brief Free the space occupied by the pool of segment descriptors, normally never used
887  */
vTCPSegmentCleanup(void)888         void vTCPSegmentCleanup( void )
889         {
890             /* Free and clear the TCP segments pointer. This function should only be called
891              * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this
892              * function. */
893             if( xTCPSegments != NULL )
894             {
895                 vPortFreeLarge( xTCPSegments );
896                 xTCPSegments = NULL;
897             }
898         }
899     #endif /* ipconfgiUSE_TCP_WIN == 1 */
900 /*-----------------------------------------------------------*/
901 
902 /*=============================================================================
903  *
904  *                ######        #    #
905  *                 #    #       #    #
906  *                 #    #       #    #
907  *                 #    #        ####
908  *                 ######         ##
909  *                 #  ##         ####
910  *                 #   #        #    #
911  *                 #    #       #    #
912  *                ###  ##       #    #
913  * Rx functions
914  *
915  *=============================================================================*/
916 
917     #if ( ipconfigUSE_TCP_WIN == 1 )
918 
919 /**
920  * @brief A expected segment has been received, see if there is overlap with earlier segments.
921  *
922  * @param[in] pxWindow The descriptor of the TCP sliding windows.
923  * @param[in] ulSequenceNumber The sequence number of the segment that was received.
924  * @param[in] ulLength The number of bytes that were received.
925  *
926  * @return The first segment descriptor involved, or NULL when no matching descriptor was found.
927  */
xTCPWindowRxConfirm(const TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength)928         static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow,
929                                                    uint32_t ulSequenceNumber,
930                                                    uint32_t ulLength )
931         {
932             TCPSegment_t * pxBest = NULL;
933             const ListItem_t * pxIterator;
934             uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
935 
936             /* MISRA Ref 11.3.1 [Misaligned access] */
937 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
938             /* coverity[misra_c_2012_rule_11_3_violation] */
939             const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxWindow->xRxSegments.xListEnd ) );
940             TCPSegment_t * pxSegment;
941 
942             /* A segment has been received with sequence number 'ulSequenceNumber',
943              * where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
944              * exactly this segment was expected.  xTCPWindowRxConfirm() will check if
945              * there is already another segment with a sequence number between (ulSequenceNumber)
946              * and (ulSequenceNumber+ulLength).  Normally none will be found, because
947              * the next RX segment should have a sequence number equal to
948              * '(ulSequenceNumber+ulLength)'. */
949 
950             /* Iterate through all RX segments that are stored: */
951             for( pxIterator = listGET_NEXT( pxEnd );
952                  pxIterator != pxEnd;
953                  pxIterator = listGET_NEXT( pxIterator ) )
954             {
955                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
956 
957                 /* And see if there is a segment for which:
958                  * 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
959                  * If there are more matching segments, the one with the lowest sequence number
960                  * shall be taken */
961                 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
962                     ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
963                 {
964                     if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
965                     {
966                         pxBest = pxSegment;
967                     }
968                 }
969             }
970 
971             if( ( pxBest != NULL ) &&
972                 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
973             {
974                 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %u (+%u=%u) found %u (+%d=%u)\n",
975                                          pxWindow->usPeerPortNumber,
976                                          ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
977                                          ( unsigned ) ulLength,
978                                          ( unsigned ) ( ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber ),
979                                          ( unsigned ) ( pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
980                                          ( int ) pxBest->lDataLength,
981                                          ( unsigned ) ( pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) ) );
982             }
983 
984             return pxBest;
985         }
986     #endif /* ipconfgiUSE_TCP_WIN == 1 */
987 /*-----------------------------------------------------------*/
988 
989     #if ( ipconfigUSE_TCP_WIN == 1 )
990 
991 /**
992  * @brief Data has been received with the correct ( expected  ) sequence number.
993  *        It can be added to the RX stream buffer.
994  * @param[in] pxWindow The TCP sliding window data of the socket.
995  * @param[in] ulLength The number of bytes that can be added.
996  */
prvTCPWindowRx_ExpectedRX(TCPWindow_t * pxWindow,uint32_t ulLength)997         static void prvTCPWindowRx_ExpectedRX( TCPWindow_t * pxWindow,
998                                                uint32_t ulLength )
999         {
1000             uint32_t ulSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
1001             uint32_t ulCurrentSequenceNumber = ulSequenceNumber + ulLength;
1002 
1003             if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0U )
1004             {
1005                 uint32_t ulSavedSequenceNumber = ulCurrentSequenceNumber;
1006                 TCPSegment_t * pxFound;
1007 
1008                 /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
1009                  * If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
1010                  * So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
1011                  * clean them out. */
1012                 do
1013                 {
1014                     pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
1015 
1016                     if( pxFound != NULL )
1017                     {
1018                         /* Remove it because it will be passed to user directly. */
1019                         vTCPWindowFree( pxFound );
1020                     }
1021                 } while( pxFound != NULL );
1022 
1023                 /*  Check for following segments that are already in the
1024                  * queue and increment ulCurrentSequenceNumber. */
1025                 for( ; ; )
1026                 {
1027                     pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber );
1028 
1029                     if( pxFound == NULL )
1030                     {
1031                         break;
1032                     }
1033 
1034                     ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
1035 
1036                     /* As all packet below this one have been passed to the
1037                      * user it can be discarded. */
1038                     vTCPWindowFree( pxFound );
1039                 }
1040 
1041                 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
1042                 {
1043                     /*  After the current data-package, there is more data
1044                      * to be popped. */
1045                     pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
1046 
1047                     if( xTCPWindowLoggingLevel >= 1 )
1048                     {
1049                         FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: retran %u (Found %u bytes at %u cnt %d)\n",
1050                                                  pxWindow->usPeerPortNumber,
1051                                                  pxWindow->usOurPortNumber,
1052                                                  ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1053                                                  ( unsigned ) pxWindow->ulUserDataLength,
1054                                                  ( unsigned ) ( ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1055                                                  ( int ) listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
1056                     }
1057                 }
1058             }
1059 
1060             pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
1061         }
1062     #endif /* ipconfgiUSE_TCP_WIN == 1 */
1063 /*-----------------------------------------------------------*/
1064 
1065     #if ( ipconfigUSE_TCP_WIN == 1 )
1066 
1067 /**
1068  * @brief Data has been received with a non-expected sequence number.
1069  *        This function will check if the RX data can be accepted.
1070  * @param[in] pxWindow The TCP sliding window data of the socket.
1071  * @param[in] ulSequenceNumber The sequence number at which the data should be placed.
1072  * @param[in] ulLength The number of bytes that can be added.
1073  * @return Return -1 if the data must be refused, otherwise it returns the
1074  *         offset ( from the head ) at which the data can be placed.
1075  */
prvTCPWindowRx_UnexpectedRX(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength)1076         static int32_t prvTCPWindowRx_UnexpectedRX( TCPWindow_t * pxWindow,
1077                                                     uint32_t ulSequenceNumber,
1078                                                     uint32_t ulLength )
1079         {
1080             int32_t lReturn = -1;
1081             uint32_t ulLast = ulSequenceNumber + ulLength;
1082             uint32_t ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
1083             const TCPSegment_t * pxFound;
1084 
1085             /* See if there is more data in a contiguous block to make the
1086              * SACK describe a longer range of data. */
1087 
1088             /* TODO: SACK's may also be delayed for a short period
1089              * This is useful because subsequent packets will be SACK'd with
1090              * single one message
1091              */
1092             for( ; ; )
1093             {
1094                 pxFound = xTCPWindowRxFind( pxWindow, ulLast );
1095 
1096                 if( pxFound == NULL )
1097                 {
1098                     break;
1099                 }
1100 
1101                 ulLast += ( uint32_t ) pxFound->lDataLength;
1102             }
1103 
1104             if( xTCPWindowLoggingLevel >= 1 )
1105             {
1106                 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %u exp %u (dist %d) SACK to %u\n",
1107                                          ( int ) pxWindow->usPeerPortNumber,
1108                                          ( int ) pxWindow->usOurPortNumber,
1109                                          ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1110                                          ( unsigned ) ( ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1111                                          ( int ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
1112                                          ( unsigned ) ( ulLast - pxWindow->rx.ulFirstSequenceNumber ) ) );
1113             }
1114 
1115             /* Now prepare the SACK message.
1116              * Code OPTION_CODE_SINGLE_SACK already in network byte order. */
1117             pxWindow->ulOptionsData[ 0 ] = OPTION_CODE_SINGLE_SACK;
1118 
1119             /* First sequence number that we received. */
1120             pxWindow->ulOptionsData[ 1 ] = FreeRTOS_htonl( ulSequenceNumber );
1121 
1122             /* Last + 1 */
1123             pxWindow->ulOptionsData[ 2 ] = FreeRTOS_htonl( ulLast );
1124 
1125             /* Which make 12 (3*4) option bytes. */
1126             pxWindow->ucOptionLength = ( uint8_t ) ( 3U * sizeof( pxWindow->ulOptionsData[ 0 ] ) );
1127 
1128             pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
1129 
1130             if( pxFound != NULL )
1131             {
1132                 /* This out-of-sequence packet has been received for a
1133                  * second time.  It is already stored but do send a SACK
1134                  * again. */
1135                 /* A negative value will be returned to indicate than error. */
1136             }
1137             else
1138             {
1139                 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
1140 
1141                 if( pxFound == NULL )
1142                 {
1143                     /* Can not send a SACK, because the segment cannot be
1144                      * stored. */
1145                     pxWindow->ucOptionLength = 0U;
1146 
1147                     /* Needs to be stored but there is no segment
1148                      * available. A negative value will be returned. */
1149                 }
1150                 else
1151                 {
1152                     uint32_t ulIntermediateResult;
1153 
1154                     if( xTCPWindowLoggingLevel != 0 )
1155                     {
1156                         FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %u (cnt %u)\n",
1157                                                  pxWindow->usPeerPortNumber,
1158                                                  pxWindow->usOurPortNumber,
1159                                                  ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1160                                                  ( unsigned ) listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
1161                         FreeRTOS_flush_logging();
1162                     }
1163 
1164                     /* Return a positive value.  The packet may be accepted
1165                     * and stored but an earlier packet is still missing. */
1166                     ulIntermediateResult = ulSequenceNumber - ulCurrentSequenceNumber;
1167                     lReturn = ( int32_t ) ulIntermediateResult;
1168                 }
1169             }
1170 
1171             return lReturn;
1172         }
1173     #endif /* ipconfgiUSE_TCP_WIN == 1 */
1174 /*-----------------------------------------------------------*/
1175 
1176     #if ( ipconfigUSE_TCP_WIN == 1 )
1177 
1178 /**
1179  * @brief Check what to do with a new incoming packet: store or ignore.
1180  *
1181  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1182  * @param[in] ulSequenceNumber The sequence number of the packet received.
1183  * @param[in] ulLength The number of bytes received.
1184  * @param[in] ulSpace The available space in the RX stream buffer.
1185  * @param[out] pulSkipCount the number of bytes to skip in the receive buffer.
1186  *
1187  * @return 0 or positive value indicating the offset at which the packet is to
1188  *         be stored, -1 if the packet is to be ignored.
1189  */
lTCPWindowRxCheck(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength,uint32_t ulSpace,uint32_t * pulSkipCount)1190         int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow,
1191                                    uint32_t ulSequenceNumber,
1192                                    uint32_t ulLength,
1193                                    uint32_t ulSpace,
1194                                    uint32_t * pulSkipCount )
1195         {
1196             uint32_t ulCurrentSequenceNumber;
1197             uint32_t ulIntermediateResult;
1198             int32_t lReturn = -1;
1199             int32_t lStartDistance;
1200             int32_t lLastDistance;
1201             uint32_t ulLast;
1202             uint32_t ulRxSequenceNumber = ulSequenceNumber;
1203             uint32_t ulRxLength = ulLength;
1204 
1205             /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
1206              * directly to user (segment is expected).  If it returns a positive
1207              * number, an earlier packet is missing, but this packet may be stored.
1208              * If negative, the packet has already been stored, or it is out-of-order,
1209              * or there is not enough space.
1210              *
1211              * As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
1212              * if more Rx data may be passed to the user after this packet. */
1213 
1214             /* Only in an exceptional case, where a packet starts before
1215              * ulCurrentSequenceNumber, and ends after it, the skip-count
1216              * will be set. See below. */
1217 
1218             *( pulSkipCount ) = 0U;
1219 
1220             ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
1221 
1222             ulLast = ulRxSequenceNumber + ulRxLength;
1223             ulIntermediateResult = ulLast - ulCurrentSequenceNumber;
1224             /* The cast from unsigned long to signed long is on purpose. */
1225             lLastDistance = ( int32_t ) ulIntermediateResult;
1226 
1227             ulIntermediateResult = ulRxSequenceNumber - ulCurrentSequenceNumber;
1228             lStartDistance = ( int32_t ) ulIntermediateResult;
1229 
1230             if( ( lStartDistance < 0 ) && ( lLastDistance > 0 ) )
1231             {
1232                 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Received +%u bytes for %u, only using %d\n",
1233                                          ( unsigned ) ulRxLength,
1234                                          ( unsigned ) ( ulRxSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
1235                                          ( int ) lLastDistance ) );
1236                 /* Increase the sequence number, decrease the length. */
1237                 ulRxSequenceNumber += ( uint32_t ) ( -lStartDistance );
1238                 ulRxLength += ( uint32_t ) lStartDistance;
1239 
1240                 /* Tell the caller that the first 'pulSkipCount' bytes don't
1241                  * need to be stored. */
1242                 *( pulSkipCount ) = ( uint32_t ) ( -lStartDistance );
1243             }
1244 
1245             /* For Selective Ack (SACK), used when out-of-sequence data come in. */
1246             pxWindow->ucOptionLength = 0U;
1247 
1248             /* Non-zero if TCP-windows contains data which must be popped. */
1249             pxWindow->ulUserDataLength = 0U;
1250 
1251             if( ulCurrentSequenceNumber == ulRxSequenceNumber )
1252             {
1253                 /* This is the packet with the lowest sequence number we're waiting
1254                  * for.  It can be passed directly to the rx stream. */
1255                 if( ulRxLength > ulSpace )
1256                 {
1257                     FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %u bytes, due to lack of space (%u)\n", ( unsigned ) ulRxLength, ( unsigned ) ulSpace ) );
1258                 }
1259                 else
1260                 {
1261                     /* Packet was expected, may be passed directly to the socket
1262                      * buffer or application.  Store the packet at offset 0. */
1263                     prvTCPWindowRx_ExpectedRX( pxWindow, ulRxLength );
1264                     lReturn = 0;
1265                 }
1266             }
1267             else if( ulCurrentSequenceNumber == ( ulRxSequenceNumber + 1U ) )
1268             {
1269                 /* Looks like a TCP keep-alive message.  Do not accept/store Rx data
1270                  * ulUserDataLength = 0. Not packet out-of-sync.  Just reply to it. */
1271             }
1272             else
1273             {
1274                 /* The packet is not the one expected.  See if it falls within the Rx
1275                  * window so it can be stored. */
1276 
1277                 /*  An "out-of-sequence" segment was received, must have missed one.
1278                  * Prepare a SACK (Selective ACK). */
1279 
1280                 if( lLastDistance <= 0 )
1281                 {
1282                     /* An earlier packet has been received, must be a retransmission of a
1283                      * packet that has been accepted already.  No need to send out a
1284                      * Selective ACK (SACK). */
1285                 }
1286                 else if( lLastDistance > ( int32_t ) ulSpace )
1287                 {
1288                     /* The new segment is ahead of rx.ulCurrentSequenceNumber.  The
1289                      * sequence number of this packet is too far ahead, ignore it. */
1290                     FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %d+%u bytes, due to lack of space (%u)\n",
1291                                              ( int ) lLastDistance,
1292                                              ( unsigned ) ulRxLength,
1293                                              ( unsigned ) ulSpace ) );
1294                 }
1295                 else
1296                 {
1297                     lReturn = prvTCPWindowRx_UnexpectedRX( pxWindow, ulRxSequenceNumber, ulRxLength );
1298                 }
1299             }
1300 
1301             return lReturn;
1302         }
1303     #endif /* ipconfgiUSE_TCP_WIN == 1 */
1304 /*-----------------------------------------------------------*/
1305 
1306 /*=============================================================================
1307  *
1308  *                    #########   #    #
1309  *                    #   #   #   #    #
1310  *                        #       #    #
1311  *                        #        ####
1312  *                        #         ##
1313  *                        #        ####
1314  *                        #       #    #
1315  *                        #       #    #
1316  *                      #####     #    #
1317  *
1318  * Tx functions
1319  *
1320  *=============================================================================*/
1321 
1322     #if ( ipconfigUSE_TCP_WIN == 1 )
1323 
1324 /**
1325  * @brief Increment the position in a circular buffer of size 'lMax'.
1326  *
1327  * @param[in] lPosition The current index in the buffer.
1328  * @param[in] lMax The total number of items in this buffer.
1329  * @param[in] lCount The number of bytes that must be advanced.
1330  *
1331  * @return The new incremented position, or "( lPosition + lCount ) % lMax".
1332  */
lTCPIncrementTxPosition(int32_t lPosition,int32_t lMax,int32_t lCount)1333         static int32_t lTCPIncrementTxPosition( int32_t lPosition,
1334                                                 int32_t lMax,
1335                                                 int32_t lCount )
1336         {
1337             int32_t lReturn;
1338 
1339 
1340             /* +TCP stores data in circular buffers.  Calculate the next position to
1341              * store. */
1342             lReturn = lPosition + lCount;
1343 
1344             if( lReturn >= lMax )
1345             {
1346                 lReturn -= lMax;
1347             }
1348 
1349             return lReturn;
1350         }
1351     #endif /* ipconfigUSE_TCP_WIN == 1 */
1352 /*-----------------------------------------------------------*/
1353 
1354     #if ( ipconfigUSE_TCP_WIN == 1 )
1355 
1356 /**
1357  * @brief Adding data to a segment that was already in the TX queue.  It
1358  *        will be filled-up to a maximum of MSS ( maximum segment size ).
1359  *
1360  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1361  * @param[in] pxSegment The TX segment with the highest sequence number,
1362  *                       i.e. the "front segment".
1363  * @param[in] lBytesLeft The number of bytes that must be added.
1364  *
1365  * @return lToWrite: the number of bytes added to the segment.
1366  */
prvTCPWindowTxAdd_FrontSegment(TCPWindow_t * pxWindow,TCPSegment_t * pxSegment,int32_t lBytesLeft)1367         static int32_t prvTCPWindowTxAdd_FrontSegment( TCPWindow_t * pxWindow,
1368                                                        TCPSegment_t * pxSegment,
1369                                                        int32_t lBytesLeft )
1370         {
1371             int32_t lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
1372 
1373             pxSegment->lDataLength += lToWrite;
1374 
1375             if( pxSegment->lDataLength >= pxSegment->lMaxLength )
1376             {
1377                 /* This segment is full, don't add more bytes. */
1378                 pxWindow->pxHeadSegment = NULL;
1379             }
1380 
1381             /* ulNextTxSequenceNumber is the sequence number of the next byte to
1382              * be stored for transmission. */
1383             pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
1384 
1385             /* Some detailed logging, for those who're interested. */
1386             if( ( xTCPWindowLoggingLevel >= 2 ) && ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) )
1387             {
1388                 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4d bytes for seqNr %u len %4d (nxt %u) pos %d\n",
1389                                          ( int ) lBytesLeft,
1390                                          ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
1391                                          ( int ) pxSegment->lDataLength,
1392                                          ( unsigned ) ( pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
1393                                          ( int ) pxSegment->lStreamPos ) );
1394                 FreeRTOS_flush_logging();
1395             }
1396 
1397             return lToWrite;
1398         }
1399     #endif /* ipconfigUSE_TCP_WIN == 1 */
1400 /*-----------------------------------------------------------*/
1401 
1402     #if ( ipconfigUSE_TCP_WIN == 1 )
1403 
1404 /**
1405  * @brief Will add data to be transmitted to the front of the segment fifo.
1406  *
1407  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1408  * @param[in] ulLength The number of bytes that will be sent.
1409  * @param[in] lPosition The index in the TX stream buffer.
1410  * @param[in] lMax The size of the ( circular ) TX stream buffer.
1411  *
1412  * @return The number of bytes added to the sliding window for transmission.
1413  *
1414  */
lTCPWindowTxAdd(TCPWindow_t * pxWindow,uint32_t ulLength,int32_t lPosition,int32_t lMax)1415         int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow,
1416                                  uint32_t ulLength,
1417                                  int32_t lPosition,
1418                                  int32_t lMax )
1419         {
1420             int32_t lBytesLeft = ( int32_t ) ulLength;
1421             int32_t lToWrite;
1422             int32_t lDone = 0;
1423             int32_t lBufferIndex = lPosition;
1424             TCPSegment_t * pxSegment = pxWindow->pxHeadSegment;
1425 
1426             /* Puts a message in the Tx-window (after buffer size has been
1427              * verified). */
1428             if( ( pxSegment != NULL ) &&
1429                 ( pxSegment->lDataLength < pxSegment->lMaxLength ) &&
1430                 ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) &&
1431                 ( pxSegment->lDataLength != 0 ) )
1432             {
1433                 lToWrite = prvTCPWindowTxAdd_FrontSegment( pxWindow, pxSegment, lBytesLeft );
1434                 lBytesLeft -= lToWrite;
1435                 /* Increased the return value. */
1436                 lDone += lToWrite;
1437 
1438                 /* Calculate the next position in the circular data buffer, knowing
1439                  * its maximum length 'lMax'. */
1440                 lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite );
1441             }
1442 
1443             while( lBytesLeft > 0 )
1444             {
1445                 /* The current transmission segment is full, create new segments as
1446                  * needed. */
1447                 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, ( int32_t ) pxWindow->usMSS );
1448 
1449                 if( pxSegment != NULL )
1450                 {
1451                     /* Store as many as needed, but no more than the maximum
1452                      * (MSS). */
1453                     lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
1454 
1455                     pxSegment->lDataLength = lToWrite;
1456                     pxSegment->lStreamPos = lBufferIndex;
1457                     lBytesLeft -= lToWrite;
1458                     lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite );
1459                     pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
1460                     lDone += lToWrite;
1461 
1462                     /* Link this segment in the Tx-Queue. */
1463                     vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
1464 
1465                     /* Let 'pxHeadSegment' point to this segment if there is still
1466                      * space. */
1467                     if( pxSegment->lDataLength < pxSegment->lMaxLength )
1468                     {
1469                         pxWindow->pxHeadSegment = pxSegment;
1470                     }
1471                     else
1472                     {
1473                         pxWindow->pxHeadSegment = NULL;
1474                     }
1475                 }
1476                 else
1477                 {
1478                     /* A sever situation: running out of segments for transmission.
1479                      * No more data can be sent at the moment. */
1480                     if( lDone != 0 )
1481                     {
1482                         FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %d bytes)\n", ( int ) lBytesLeft ) );
1483                     }
1484 
1485                     break;
1486                 }
1487             }
1488 
1489             return lDone;
1490         }
1491     #endif /* ipconfigUSE_TCP_WIN == 1 */
1492 /*-----------------------------------------------------------*/
1493 
1494     #if ( ipconfigUSE_TCP_WIN == 1 )
1495 
1496 /**
1497  * @brief Returns true if there are no more outstanding TX segments.
1498  *
1499  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1500  *
1501  * @return pdTRUE if there are no more outstanding Tx segments, else pdFALSE.
1502  */
xTCPWindowTxDone(const TCPWindow_t * pxWindow)1503         BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow )
1504         {
1505             return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments ) );
1506         }
1507     #endif /* ipconfigUSE_TCP_WIN == 1 */
1508 /*-----------------------------------------------------------*/
1509 
1510     #if ( ipconfigUSE_TCP_WIN == 1 )
1511 
1512 /**
1513  * @brief Find out if the peer is able to receive more data.
1514  *
1515  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1516  * @param[in] ulWindowSize The number of bytes in this segment.
1517  *
1518  * @return True if the peer has space in it window to receive more data.
1519  */
prvTCPWindowTxHasSpace(TCPWindow_t const * pxWindow,uint32_t ulWindowSize)1520         static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow,
1521                                                   uint32_t ulWindowSize )
1522         {
1523             uint32_t ulTxOutstanding;
1524             BaseType_t xHasSpace;
1525             const TCPSegment_t * pxSegment;
1526             uint32_t ulNettSize;
1527 
1528             /* This function will look if there is new transmission data.  It will
1529              * return true if there is data to be sent. */
1530 
1531             pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
1532 
1533             if( pxSegment == NULL )
1534             {
1535                 xHasSpace = pdFALSE;
1536             }
1537             else
1538             {
1539                 /* How much data is outstanding, i.e. how much data has been sent
1540                  * but not yet acknowledged ? */
1541                 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
1542                 {
1543                     ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
1544                 }
1545                 else
1546                 {
1547                     ulTxOutstanding = 0U;
1548                 }
1549 
1550                 /* Subtract this from the peer's space. */
1551                 ulNettSize = ulWindowSize - FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
1552 
1553                 /* See if the next segment may be sent. */
1554                 if( ulNettSize >= ( uint32_t ) pxSegment->lDataLength )
1555                 {
1556                     xHasSpace = pdTRUE;
1557                 }
1558                 else
1559                 {
1560                     xHasSpace = pdFALSE;
1561                 }
1562 
1563                 /* If 'xHasSpace', it looks like the peer has at least space for 1
1564                  * more new segment of size MSS.  xSize.ulTxWindowLength is the self-imposed
1565                  * limitation of the transmission window (in case of many resends it
1566                  * may be decreased). */
1567                 if( ( ulTxOutstanding != 0U ) &&
1568                     ( pxWindow->xSize.ulTxWindowLength <
1569                       ( ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) ) )
1570                 {
1571                     xHasSpace = pdFALSE;
1572                 }
1573             }
1574 
1575             return xHasSpace;
1576         }
1577     #endif /* ipconfigUSE_TCP_WIN == 1 */
1578 /*-----------------------------------------------------------*/
1579 
1580     #if ( ipconfigUSE_TCP_WIN == 1 )
1581 
1582 /**
1583  * @brief Returns true if there is TX data that can be sent right now.
1584  *
1585  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1586  * @param[in] ulWindowSize The current size of the sliding RX window of the peer.
1587  * @param[out] pulDelay The delay before the packet may be sent.
1588  *
1589  * @return pdTRUE if there is Tx data that can be sent, else pdFALSE.
1590  */
xTCPWindowTxHasData(TCPWindow_t const * pxWindow,uint32_t ulWindowSize,TickType_t * pulDelay)1591         BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow,
1592                                         uint32_t ulWindowSize,
1593                                         TickType_t * pulDelay )
1594         {
1595             TCPSegment_t const * pxSegment;
1596             BaseType_t xReturn;
1597             TickType_t ulAge, ulMaxAge;
1598 
1599             *pulDelay = 0U;
1600 
1601             if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
1602             {
1603                 /* No need to look at retransmissions or new transmission as long as
1604                  * there are priority segments.  *pulDelay equals zero, meaning it must
1605                  * be sent out immediately. */
1606                 xReturn = pdTRUE;
1607             }
1608             else
1609             {
1610                 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
1611 
1612                 if( pxSegment != NULL )
1613                 {
1614                     uint32_t ulSRTT = ( uint32_t ) pxWindow->lSRTT;
1615 
1616                     /* There is an outstanding segment, see if it is time to resend
1617                      * it. */
1618                     ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
1619 
1620                     /* After a packet has been sent for the first time, it will wait
1621                      * '1 * ulSRTT' ms for an ACK. A second time it will wait '2 * ulSRTT' ms,
1622                      * each time doubling the time-out */
1623                     ulMaxAge = ( ( uint32_t ) 1U << pxSegment->u.bits.ucTransmitCount );
1624                     ulMaxAge *= ulSRTT;
1625 
1626                     if( ulMaxAge > ulAge )
1627                     {
1628                         /* A segment must be sent after this amount of msecs */
1629                         *pulDelay = ulMaxAge - ulAge;
1630                     }
1631 
1632                     xReturn = pdTRUE;
1633                 }
1634                 else
1635                 {
1636                     /* No priority segment, no outstanding data, see if there is new
1637                      * transmission data. */
1638                     pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
1639 
1640                     /* See if it fits in the peer's reception window. */
1641                     if( pxSegment == NULL )
1642                     {
1643                         xReturn = pdFALSE;
1644                     }
1645                     else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
1646                     {
1647                         /* Too many outstanding messages. */
1648                         xReturn = pdFALSE;
1649                     }
1650                     else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) &&
1651                              ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
1652                     {
1653                         /* 'bSendFullSize' is a special optimisation.  If true, the
1654                          * driver will only sent completely filled packets (of MSS
1655                          * bytes). */
1656                         xReturn = pdFALSE;
1657                     }
1658                     else
1659                     {
1660                         xReturn = pdTRUE;
1661                     }
1662                 }
1663             }
1664 
1665             return xReturn;
1666         }
1667     #endif /* ipconfigUSE_TCP_WIN == 1 */
1668 /*-----------------------------------------------------------*/
1669 
1670     #if ( ipconfigUSE_TCP_WIN == 1 )
1671 
1672 /**
1673  * @brief Three type of queues are used for transmission: priority, waiting, and
1674  *        the normal TX queue of unsent data.  Message in the waiting queue will
1675  *        be sent when their timer has expired.
1676  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1677  */
pxTCPWindowTx_GetWaitQueue(const TCPWindow_t * pxWindow)1678         static TCPSegment_t * pxTCPWindowTx_GetWaitQueue( const TCPWindow_t * pxWindow )
1679         {
1680             TCPSegment_t * pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
1681 
1682             if( pxSegment != NULL )
1683             {
1684                 /* Do check the timing. */
1685                 uint32_t ulMaxTime;
1686 
1687                 ulMaxTime = ( ( uint32_t ) 1U ) << pxSegment->u.bits.ucTransmitCount;
1688                 ulMaxTime *= ( uint32_t ) pxWindow->lSRTT;
1689 
1690                 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
1691                 {
1692                     /* A normal (non-fast) retransmission.  Move it from the
1693                      * head of the waiting queue. */
1694                     pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
1695                     pxSegment->u.bits.ucDupAckCount = ( uint8_t ) pdFALSE_UNSIGNED;
1696 
1697                     /* Some detailed logging. */
1698                     if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
1699                     {
1700                         FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %d bytes for sequence number %u (0x%X)\n",
1701                                                  pxWindow->usPeerPortNumber,
1702                                                  pxWindow->usOurPortNumber,
1703                                                  ( int ) pxSegment->lDataLength,
1704                                                  ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
1705                                                  ( unsigned ) pxSegment->ulSequenceNumber ) );
1706                         FreeRTOS_flush_logging();
1707                     }
1708                 }
1709                 else
1710                 {
1711                     pxSegment = NULL;
1712                 }
1713             }
1714 
1715             return pxSegment;
1716         }
1717     #endif /* ipconfigUSE_TCP_WIN == 1 */
1718 
1719 /*-----------------------------------------------------------*/
1720 
1721     #if ( ipconfigUSE_TCP_WIN == 1 )
1722 
1723 /**
1724  * @brief See if there is a transmission in the normal TX queue. It is the
1725  *        first time these data are being sent. After sending they will move
1726  *        the waiting queue.
1727  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1728  * @param[in] ulWindowSize The available space that the peer has in his
1729  *                          reception window.
1730  * @return Either a segment that has to be sent, or NULL.
1731  */
pxTCPWindowTx_GetTXQueue(TCPWindow_t * pxWindow,uint32_t ulWindowSize)1732         static TCPSegment_t * pxTCPWindowTx_GetTXQueue( TCPWindow_t * pxWindow,
1733                                                         uint32_t ulWindowSize )
1734         {
1735             TCPSegment_t * pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
1736 
1737             if( pxSegment == NULL )
1738             {
1739                 /* No segments queued. */
1740             }
1741             else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) &&
1742                      ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
1743             {
1744                 /* A segment has been queued but the driver waits until it
1745                  * has a full size of MSS. */
1746                 pxSegment = NULL;
1747             }
1748             else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
1749             {
1750                 /* Peer has no more space at this moment. */
1751                 pxSegment = NULL;
1752             }
1753             else
1754             {
1755                 /* pxSegment was just obtained with a peek function,
1756                  * now remove it from of the Tx queue. */
1757                 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
1758 
1759                 /* Don't let pxHeadSegment point to this segment any more,
1760                  * so no more data will be added. */
1761                 if( pxWindow->pxHeadSegment == pxSegment )
1762                 {
1763                     pxWindow->pxHeadSegment = NULL;
1764                 }
1765 
1766                 /* pxWindow->tx.highest registers the highest sequence
1767                  * number in our transmission window. */
1768                 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
1769 
1770                 /* ...and more detailed logging */
1771                 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
1772                 {
1773                     FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %d bytes for sequence number %u (ws %u)\n",
1774                                              pxWindow->usPeerPortNumber,
1775                                              pxWindow->usOurPortNumber,
1776                                              ( int ) pxSegment->lDataLength,
1777                                              ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
1778                                              ( unsigned ) ulWindowSize ) );
1779                     FreeRTOS_flush_logging();
1780                 }
1781             }
1782 
1783             return pxSegment;
1784         }
1785     #endif /* ipconfigUSE_TCP_WIN == 1 */
1786 /*-----------------------------------------------------------*/
1787 
1788     #if ( ipconfigUSE_TCP_WIN == 1 )
1789 
1790 /**
1791  * @brief Get data that can be transmitted right now. There are three types of
1792  *        outstanding segments: Priority queue, Waiting queue, Normal TX queue.
1793  *
1794  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1795  * @param[in] ulWindowSize The current size of the sliding RX window of the peer.
1796  * @param[out] plPosition The index within the TX stream buffer of the first byte to be sent.
1797  *
1798  * @return The amount of data in bytes that can be transmitted right now.
1799  */
ulTCPWindowTxGet(TCPWindow_t * pxWindow,uint32_t ulWindowSize,int32_t * plPosition)1800         uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow,
1801                                    uint32_t ulWindowSize,
1802                                    int32_t * plPosition )
1803         {
1804             TCPSegment_t * pxSegment;
1805             uint32_t ulReturn = 0U;
1806 
1807             /* Fetches data to be sent-out now.
1808              *
1809              * Priority messages: segments with a resend need no check current sliding
1810              * window size. */
1811             pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
1812             pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
1813 
1814             if( pxSegment != NULL )
1815             {
1816                 /* There is a priority segment. It doesn't need any checking for
1817                  * space or timeouts. */
1818                 if( xTCPWindowLoggingLevel != 0 )
1819                 {
1820                     FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %d bytes for sequence number %u (ws %u)\n",
1821                                              pxWindow->usPeerPortNumber,
1822                                              pxWindow->usOurPortNumber,
1823                                              ( int ) pxSegment->lDataLength,
1824                                              ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
1825                                              ( unsigned ) ulWindowSize ) );
1826                     FreeRTOS_flush_logging();
1827                 }
1828             }
1829             else
1830             {
1831                 /* Waiting messages: outstanding messages with a running timer
1832                  * neither check peer's reception window size because these packets
1833                  * have been sent earlier. */
1834                 pxSegment = pxTCPWindowTx_GetWaitQueue( pxWindow );
1835 
1836                 if( pxSegment == NULL )
1837                 {
1838                     /* New messages: sent-out for the first time.  Check current
1839                      * sliding window size of peer. */
1840                     pxSegment = pxTCPWindowTx_GetTXQueue( pxWindow, ulWindowSize );
1841                 }
1842             }
1843 
1844             /* See if it has already been determined to return 0. */
1845             if( pxSegment != NULL )
1846             {
1847                 configASSERT( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) == NULL );
1848 
1849                 /* Now that the segment will be transmitted, add it to the tail of
1850                  * the waiting queue. */
1851                 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
1852 
1853                 /* And mark it as outstanding. */
1854                 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
1855 
1856                 /* Administer the transmit count, needed for fast
1857                  * retransmissions. */
1858                 ( pxSegment->u.bits.ucTransmitCount )++;
1859 
1860                 /* If there have been several retransmissions (4), decrease the
1861                  * size of the transmission window to at most 2 times MSS. */
1862                 if( ( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ) &&
1863                     ( pxWindow->xSize.ulTxWindowLength > ( 2U * ( ( uint32_t ) pxWindow->usMSS ) ) ) )
1864                 {
1865                     uint16_t usMSS2 = ( uint16_t ) ( pxWindow->usMSS * 2U );
1866                     FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %u]: Change Tx window: %u -> %u\n",
1867                                              pxWindow->usPeerPortNumber,
1868                                              pxWindow->usOurPortNumber,
1869                                              ( unsigned ) pxWindow->xSize.ulTxWindowLength,
1870                                              usMSS2 ) );
1871                     pxWindow->xSize.ulTxWindowLength = usMSS2;
1872                 }
1873 
1874                 /* Clear the transmit timer. */
1875                 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
1876 
1877                 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
1878 
1879                 /* Inform the caller where to find the data within the queue. */
1880                 *plPosition = pxSegment->lStreamPos;
1881 
1882                 /* And return the length of the data segment */
1883                 ulReturn = ( uint32_t ) pxSegment->lDataLength;
1884             }
1885 
1886             return ulReturn;
1887         }
1888     #endif /* ipconfigUSE_TCP_WIN == 1 */
1889 /*-----------------------------------------------------------*/
1890 
1891     #if ( ipconfigUSE_TCP_WIN == 1 )
1892 
1893 /**
1894  * @brief Data has been sent, and an ACK has been received. Make an estimate
1895  *        of the round-trip time, and calculate the new timeout for transmissions.
1896  *        More explanation in a comment here below.
1897  *
1898  * @param[in] pxWindow The descriptor of the TCP sliding windows.
1899  * @param[in] pxSegment The segment that was just acknowledged.
1900  */
prvTCPWindowTxCheckAck_CalcSRTT(TCPWindow_t * pxWindow,const TCPSegment_t * pxSegment)1901         static void prvTCPWindowTxCheckAck_CalcSRTT( TCPWindow_t * pxWindow,
1902                                                      const TCPSegment_t * pxSegment )
1903         {
1904             int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
1905 
1906             if( pxWindow->lSRTT >= mS )
1907             {
1908                 /* RTT becomes smaller: adapt slowly. */
1909                 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
1910             }
1911             else
1912             {
1913                 /* RTT becomes larger: adapt quicker */
1914                 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
1915             }
1916 
1917             /* Cap to the minimum of 50ms. */
1918             if( pxWindow->lSRTT < winSRTT_CAP_mS )
1919             {
1920                 pxWindow->lSRTT = winSRTT_CAP_mS;
1921             }
1922         }
1923     #endif /* ipconfigUSE_TCP_WIN == 1 */
1924 /*-----------------------------------------------------------*/
1925 
1926     #if ( ipconfigUSE_TCP_WIN == 1 )
1927 
1928 /**
1929  * @brief An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
1930  *        may be removed from the transmission queue(s). All TX segments for which
1931  *        ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a contiguous block.
1932  *        Note that the segments are stored in xTxSegments in a strict sequential order.
1933  *
1934  * @param[in] pxWindow The TCP-window object of the current connection.
1935  * @param[in] ulFirst The sequence number of the first byte that was acknowledged.
1936  * @param[in] ulLast The sequence number of the last byte ( minus one ) that was acknowledged.
1937  *
1938  * @return number of bytes that the tail of txStream may be advanced.
1939  */
prvTCPWindowTxCheckAck(TCPWindow_t * pxWindow,uint32_t ulFirst,uint32_t ulLast)1940         static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow,
1941                                                 uint32_t ulFirst,
1942                                                 uint32_t ulLast )
1943         {
1944             uint32_t ulBytesConfirmed = 0U;
1945             uint32_t ulSequenceNumber = ulFirst;
1946             uint32_t ulDataLength;
1947             const ListItem_t * pxIterator;
1948 
1949             /* MISRA Ref 11.3.1 [Misaligned access] */
1950 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1951             /* coverity[misra_c_2012_rule_11_3_violation] */
1952             const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxWindow->xTxSegments.xListEnd ) );
1953             BaseType_t xDoUnlink;
1954             TCPSegment_t * pxSegment;
1955 
1956             /* An acknowledgement or a selective ACK (SACK) was received.  See if some outstanding data
1957              * may be removed from the transmission queue(s).
1958              * All TX segments for which
1959              * ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
1960              * contiguous block.  Note that the segments are stored in xTxSegments in a
1961              * strict sequential order. */
1962 
1963             /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
1964              *
1965              * 0 < a < 1; usually a = 1/8
1966              *
1967              * RTO = 2 * SRTT
1968              *
1969              * where:
1970              * RTT is Round Trip Time
1971              * SRTT is Smoothed RTT
1972              * RTO is Retransmit timeout
1973              *
1974              * A Smoothed RTT will increase quickly, but it is conservative when
1975              * becoming smaller. */
1976 
1977             pxIterator = listGET_NEXT( pxEnd );
1978 
1979             while( ( pxIterator != pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 ) )
1980             {
1981                 xDoUnlink = pdFALSE;
1982                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
1983 
1984                 /* Move to the next item because the current item might get
1985                  * removed. */
1986                 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
1987 
1988                 /* Continue if this segment does not fall within the ACK'd range. */
1989                 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
1990                 {
1991                     continue;
1992                 }
1993 
1994                 /* Is it ready? */
1995                 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
1996                 {
1997                     /* coverity[break_stmt] : Break statement terminating the loop */
1998                     break;
1999                 }
2000 
2001                 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
2002 
2003                 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
2004                 {
2005                     if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t ) ulDataLength, ulLast ) != pdFALSE )
2006                     {
2007                         /* What happens?  Only part of this segment was accepted,
2008                          * probably due to WND limits
2009                          *
2010                          * AAAAAAA BBBBBBB << acked
2011                          * aaaaaaa aaaa    << sent */
2012                         #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
2013                             {
2014                                 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
2015                                 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %u - %u Partial sequence number %u - %u\n",
2016                                                          pxWindow->usPeerPortNumber,
2017                                                          pxWindow->usOurPortNumber,
2018                                                          ( unsigned ) ( ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber ),
2019                                                          ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ),
2020                                                          ( unsigned ) ulFirstSeq,
2021                                                          ( unsigned ) ( ulFirstSeq + ulDataLength ) ) );
2022                             }
2023                         #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
2024 
2025                         break;
2026                     }
2027 
2028                     /* This segment is fully ACK'd, set the flag. */
2029                     pxSegment->u.bits.bAcked = pdTRUE;
2030 
2031                     /* Calculate the RTT only if the segment was sent-out for the
2032                      * first time and if this is the last ACK'd segment in a range. */
2033                     if( ( pxSegment->u.bits.ucTransmitCount == 1U ) &&
2034                         ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
2035                     {
2036                         prvTCPWindowTxCheckAck_CalcSRTT( pxWindow, pxSegment );
2037                     }
2038 
2039                     /* Unlink it from the 3 queues, but do not destroy it (yet). */
2040                     xDoUnlink = pdTRUE;
2041                 }
2042 
2043                 /* pxSegment->u.bits.bAcked is now true.  Is it located at the left
2044                  * side of the transmission queue?  If so, it may be freed. */
2045                 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
2046                 {
2047                     if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
2048                     {
2049                         FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %u - %u Ready sequence number %u\n",
2050                                                  ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ),
2051                                                  ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ),
2052                                                  ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ) );
2053                     }
2054 
2055                     /* Increase the left-hand value of the transmission window. */
2056                     pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
2057 
2058                     /* This function will return the number of bytes that the tail
2059                      * of txStream may be advanced. */
2060                     ulBytesConfirmed += ulDataLength;
2061 
2062                     /* All segments below tx.ulCurrentSequenceNumber may be freed. */
2063                     vTCPWindowFree( pxSegment );
2064 
2065                     /* No need to unlink it any more. */
2066                     xDoUnlink = pdFALSE;
2067                 }
2068 
2069                 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
2070                 {
2071                     /* Remove item from its queues. */
2072                     ( void ) uxListRemove( &pxSegment->xQueueItem );
2073                 }
2074 
2075                 ulSequenceNumber += ulDataLength;
2076             }
2077 
2078             return ulBytesConfirmed;
2079         }
2080     #endif /* ipconfigUSE_TCP_WIN == 1 */
2081 /*-----------------------------------------------------------*/
2082 
2083     #if ( ipconfigUSE_TCP_WIN == 1 )
2084 
2085 /**
2086  * @brief See if there are segments that need a fast retransmission.
2087  *
2088  * @param[in] pxWindow The descriptor of the TCP sliding windows.
2089  * @param[in] ulFirst The sequence number of the first segment that must be checked.
2090  *
2091  * @return The number of segments that need a fast retransmission.
2092  */
prvTCPWindowFastRetransmit(TCPWindow_t * pxWindow,uint32_t ulFirst)2093         static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow,
2094                                                     uint32_t ulFirst )
2095         {
2096             const ListItem_t * pxIterator;
2097             const ListItem_t * pxEnd;
2098             TCPSegment_t * pxSegment;
2099             uint32_t ulCount = 0U;
2100 
2101             /* A higher Tx block has been acknowledged.  Now iterate through the
2102              * xWaitQueue to find a possible condition for a FAST retransmission. */
2103 
2104             /* MISRA Ref 11.3.1 [Misaligned access] */
2105 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2106             /* coverity[misra_c_2012_rule_11_3_violation] */
2107             pxEnd = ( ( const ListItem_t * ) &( pxWindow->xWaitQueue.xListEnd ) );
2108 
2109             pxIterator = listGET_NEXT( pxEnd );
2110 
2111             while( pxIterator != pxEnd )
2112             {
2113                 /* Get the owner, which is a TCP segment. */
2114                 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
2115 
2116                 /* Hop to the next item before the current gets unlinked. */
2117                 pxIterator = listGET_NEXT( pxIterator );
2118 
2119                 /* Fast retransmission:
2120                  * When 3 packets with a higher sequence number have been acknowledged
2121                  * by the peer, it is very unlikely a current packet will ever arrive.
2122                  * It will be retransmitted far before the RTO. */
2123                 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
2124                 {
2125                     if( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE )
2126                     {
2127                         pxSegment->u.bits.ucDupAckCount++;
2128 
2129                         if( pxSegment->u.bits.ucDupAckCount == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT )
2130                         {
2131                             pxSegment->u.bits.ucTransmitCount = ( uint8_t ) pdFALSE;
2132 
2133                             /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
2134                              * which might lead to a second fast rexmit. */
2135                             if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) )
2136                             {
2137                                 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %u < %u\n",
2138                                                          ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ),
2139                                                          ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ) ) );
2140                                 FreeRTOS_flush_logging();
2141                             }
2142 
2143                             /* Remove it from xWaitQueue. */
2144                             ( void ) uxListRemove( &pxSegment->xQueueItem );
2145 
2146                             /* Add this segment to the priority queue so it gets
2147                              * retransmitted immediately. */
2148                             vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
2149                             ulCount++;
2150                         }
2151                     }
2152                 }
2153             }
2154 
2155             return ulCount;
2156         }
2157     #endif /* ipconfigUSE_TCP_WIN == 1 */
2158 /*-----------------------------------------------------------*/
2159 
2160     #if ( ipconfigUSE_TCP_WIN == 1 )
2161 
2162 /**
2163  * @brief Receive a normal ACK.
2164  *
2165  * @param[in] pxWindow Window in which a data is receive.
2166  * @param[in] ulSequenceNumber The sequence number of the ACK.
2167  *
2168  * @return The location where the packet should be added.
2169  */
ulTCPWindowTxAck(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber)2170         uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow,
2171                                    uint32_t ulSequenceNumber )
2172         {
2173             uint32_t ulFirstSequence;
2174             uint32_t ulReturn;
2175 
2176             /* Receive a normal ACK. */
2177 
2178             ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
2179 
2180             if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
2181             {
2182                 ulReturn = 0U;
2183             }
2184             else
2185             {
2186                 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
2187             }
2188 
2189             return ulReturn;
2190         }
2191     #endif /* ipconfigUSE_TCP_WIN == 1 */
2192 /*-----------------------------------------------------------*/
2193 
2194     #if ( ipconfigUSE_TCP_WIN == 1 )
2195 
2196 /**
2197  * @brief Receive a SACK option.
2198  *
2199  * @param[in] pxWindow Window in which the data is received.
2200  * @param[in] ulFirst Index of starting position of options.
2201  * @param[in] ulLast Index of end position of the options.
2202  *
2203  * @return returns the number of bytes which have been acked starting from
2204  *         the head position.
2205  */
ulTCPWindowTxSack(TCPWindow_t * pxWindow,uint32_t ulFirst,uint32_t ulLast)2206         uint32_t ulTCPWindowTxSack( TCPWindow_t * pxWindow,
2207                                     uint32_t ulFirst,
2208                                     uint32_t ulLast )
2209         {
2210             uint32_t ulAckCount;
2211             uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
2212 
2213             /* Receive a SACK option. */
2214             ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
2215             ( void ) prvTCPWindowFastRetransmit( pxWindow, ulFirst );
2216 
2217             if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
2218             {
2219                 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %u to %u (ack = %u)\n",
2220                                          pxWindow->usPeerPortNumber,
2221                                          pxWindow->usOurPortNumber,
2222                                          ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ),
2223                                          ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ),
2224                                          ( unsigned ) ( pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ) );
2225                 FreeRTOS_flush_logging();
2226             }
2227 
2228             return ulAckCount;
2229         }
2230     #endif /* ipconfigUSE_TCP_WIN == 1 */
2231 /*-----------------------------------------------------------*/
2232 
2233 #endif /* ipconfigUSE_TCP == 1 */
2234