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