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