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