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