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