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