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