2 * FreeRTOS+TCP 2.2.x Labs copy
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * FreeRTOS_TCP_WIN.c
\r
28 * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
\r
29 * functions have two versions - one for FreeRTOS+TCP (full) and one for
\r
30 * FreeRTOS+TCP (lite).
\r
32 * In this module all ports and IP addresses and sequence numbers are
\r
33 * being stored in host byte-order.
\r
36 /* Standard includes. */
\r
39 /* FreeRTOS includes. */
\r
40 #include "FreeRTOS.h"
\r
45 /* FreeRTOS+TCP includes. */
\r
46 #include "FreeRTOS_UDP_IP.h"
\r
47 #include "FreeRTOS_IP.h"
\r
48 #include "FreeRTOS_Sockets.h"
\r
49 #include "FreeRTOS_IP_Private.h"
\r
50 #include "NetworkBufferManagement.h"
\r
51 #include "FreeRTOS_TCP_WIN.h"
\r
53 /* Constants used for Smoothed Round Trip Time (SRTT). */
\r
54 #define winSRTT_INCREMENT_NEW 2
\r
55 #define winSRTT_INCREMENT_CURRENT 6
\r
56 #define winSRTT_DECREMENT_NEW 1
\r
57 #define winSRTT_DECREMENT_CURRENT 7
\r
58 #define winSRTT_CAP_mS 50
\r
60 #if( ipconfigUSE_TCP_WIN == 1 )
\r
62 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
\r
64 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
\r
66 /* The code to send a single Selective ACK (SACK):
\r
67 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
\r
68 * followed by a lower and a higher sequence number,
\r
69 * where LEN is 2 + 2*4 = 10 bytes. */
\r
70 #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
\r
71 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
\r
73 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
\r
76 /* Normal retransmission:
\r
77 * A packet will be retransmitted after a Retransmit Time-Out (RTO).
\r
78 * Fast retransmission:
\r
79 * When 3 packets with a higher sequence number have been acknowledged
\r
80 * by the peer, it is very unlikely a current packet will ever arrive.
\r
81 * It will be retransmitted far before the RTO.
\r
83 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
\r
85 /* If there have been several retransmissions (4), decrease the
\r
86 * size of the transmission window to at most 2 times MSS.
\r
88 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
\r
90 #endif /* configUSE_TCP_WIN */
\r
91 /*-----------------------------------------------------------*/
\r
93 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
96 * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
\r
97 * Available descriptors are stored in the 'xSegmentList'
\r
98 * When a socket owns a descriptor, it will either be stored in
\r
99 * 'xTxSegments' or 'xRxSegments'
\r
100 * As soon as a package has been confirmed, the descriptor will be returned
\r
101 * to the segment pool
\r
103 #if( ipconfigUSE_TCP_WIN == 1 )
\r
104 static BaseType_t prvCreateSectors( void );
\r
105 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
108 * Find a segment with a given sequence number in the list of received
\r
109 * segments: 'pxWindow->xRxSegments'.
\r
111 #if( ipconfigUSE_TCP_WIN == 1 )
\r
112 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
\r
113 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
116 * Allocate a new segment
\r
117 * The socket will borrow all segments from a common pool: 'xSegmentList',
\r
118 * which is a list of 'TCPSegment_t'
\r
120 #if( ipconfigUSE_TCP_WIN == 1 )
\r
121 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
\r
122 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
124 /* When the peer has a close request (FIN flag), the driver will check if
\r
125 * there are missing packets in the Rx-queue
\r
126 * It will accept the closure of the connection if both conditions are true:
\r
127 * - the Rx-queue is empty
\r
128 * - we've ACK'd the highest Rx sequence number seen
\r
130 #if( ipconfigUSE_TCP_WIN == 1 )
\r
131 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
\r
132 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
135 * Detaches and returns the head of a queue
\r
137 #if( ipconfigUSE_TCP_WIN == 1 )
\r
138 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
\r
139 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
142 * Returns the head of a queue but it won't be detached
\r
144 #if( ipconfigUSE_TCP_WIN == 1 )
\r
145 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
\r
146 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
149 * Free entry pxSegment because it's not used anymore
\r
150 * The ownership will be passed back to the segment pool
\r
152 #if( ipconfigUSE_TCP_WIN == 1 )
\r
153 static void vTCPWindowFree( TCPSegment_t *pxSegment );
\r
154 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
157 * A segment has been received with sequence number 'ulSequenceNumber', where
\r
158 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
\r
159 * segment was expected. xTCPWindowRxConfirm() will check if there is already
\r
160 * another segment with a sequence number between (ulSequenceNumber) and
\r
161 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
\r
162 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
\r
164 #if( ipconfigUSE_TCP_WIN == 1 )
\r
165 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
\r
166 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
169 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
\r
172 #if( ipconfigUSE_TCP_WIN == 1 )
\r
173 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
\r
174 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
177 * This function will look if there is new transmission data. It will return
\r
178 * true if there is data to be sent.
\r
180 #if( ipconfigUSE_TCP_WIN == 1 )
\r
181 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
182 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
185 * An acknowledge was received. See if some outstanding data may be removed
\r
186 * from the transmission queue(s).
\r
188 #if( ipconfigUSE_TCP_WIN == 1 )
\r
189 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
\r
190 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
193 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
\r
194 * to find a possible condition for a FAST retransmission.
\r
196 #if( ipconfigUSE_TCP_WIN == 1 )
\r
197 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
\r
198 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
200 /*-----------------------------------------------------------*/
\r
202 /* TCP segment pool. */
\r
203 #if( ipconfigUSE_TCP_WIN == 1 )
\r
204 static TCPSegment_t *xTCPSegments = NULL;
\r
205 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
207 /* List of free TCP segments. */
\r
208 #if( ipconfigUSE_TCP_WIN == 1 )
\r
209 static List_t xSegmentList;
\r
212 /* Logging verbosity level. */
\r
213 BaseType_t xTCPWindowLoggingLevel = 0;
\r
215 #if( ipconfigUSE_TCP_WIN == 1 )
\r
216 /* Some 32-bit arithmetic: comparing sequence numbers */
\r
217 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
\r
218 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
\r
221 Return true if the unsigned subtraction of (b-a) doesn't generate an
\r
222 arithmetic overflow. */
\r
223 return ( ( b - a ) & 0x80000000UL ) == 0UL;
\r
225 #endif /* ipconfigUSE_TCP_WIN */
\r
226 /*-----------------------------------------------------------*/
\r
228 #if( ipconfigUSE_TCP_WIN == 1 )
\r
229 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
\r
230 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
\r
232 /* Test if a < b */
\r
233 return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
\r
235 #endif /* ipconfigUSE_TCP_WIN */
\r
236 /*-----------------------------------------------------------*/
\r
238 #if( ipconfigUSE_TCP_WIN == 1 )
\r
239 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
\r
240 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
\r
242 /* Test if a > b */
\r
243 return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
\r
245 #endif /* ipconfigUSE_TCP_WIN */
\r
247 /*-----------------------------------------------------------*/
\r
248 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
\r
249 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
\r
251 /* Test if a >= b */
\r
252 return ( ( a - b ) & 0x80000000UL ) == 0UL;
\r
254 /*-----------------------------------------------------------*/
\r
256 #if( ipconfigUSE_TCP_WIN == 1 )
\r
257 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
\r
258 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
\r
260 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
\r
263 /*-----------------------------------------------------------*/
\r
265 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
\r
266 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
\r
268 pxTimer->ulBorn = xTaskGetTickCount ( );
\r
270 /*-----------------------------------------------------------*/
\r
272 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
\r
273 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
\r
275 return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
\r
277 /*-----------------------------------------------------------*/
\r
279 /* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
\r
280 preceded by a prototype. Later this prototype will be located in list.h? */
\r
282 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
284 void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
\r
286 /* Insert a new list item into pxList, it does not sort the list,
\r
287 but it puts the item just before xListEnd, so it will be the last item
\r
288 returned by listGET_HEAD_ENTRY() */
\r
289 pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
\r
290 pxNewListItem->pxPrevious = pxWhere->pxPrevious;
\r
291 pxWhere->pxPrevious->pxNext = pxNewListItem;
\r
292 pxWhere->pxPrevious = pxNewListItem;
\r
294 /* Remember which list the item is in. */
\r
295 listLIST_ITEM_CONTAINER( pxNewListItem ) = ( void * ) pxList;
\r
297 ( pxList->uxNumberOfItems )++;
\r
299 /*-----------------------------------------------------------*/
\r
301 #if( ipconfigUSE_TCP_WIN == 1 )
\r
303 static BaseType_t prvCreateSectors( void )
\r
305 BaseType_t xIndex, xReturn;
\r
307 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
\r
309 vListInitialise( &xSegmentList );
\r
310 xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
312 if( xTCPSegments == NULL )
\r
314 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
\r
315 ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
\r
321 /* Clear the allocated space. */
\r
322 memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
324 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
\r
326 /* Could call vListInitialiseItem here but all data has been
\r
327 nulled already. Set the owner to a segment descriptor. */
\r
328 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
329 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
331 /* And add it to the pool of available segments */
\r
332 vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
\r
341 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
342 /*-----------------------------------------------------------*/
\r
344 #if( ipconfigUSE_TCP_WIN == 1 )
\r
346 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
348 const ListItem_t *pxIterator;
\r
349 const MiniListItem_t* pxEnd;
\r
350 TCPSegment_t *pxSegment, *pxReturn = NULL;
\r
352 /* Find a segment with a given sequence number in the list of received
\r
355 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
\r
357 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
358 pxIterator != ( const ListItem_t * ) pxEnd;
\r
359 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
361 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
363 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
\r
365 pxReturn = pxSegment;
\r
373 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
374 /*-----------------------------------------------------------*/
\r
376 #if( ipconfigUSE_TCP_WIN == 1 )
\r
378 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
\r
380 TCPSegment_t *pxSegment;
\r
381 ListItem_t * pxItem;
\r
383 /* Allocate a new segment. The socket will borrow all segments from a
\r
384 common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
\r
385 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
\r
387 /* If the TCP-stack runs out of segments, you might consider
\r
388 increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
\r
389 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
\r
394 /* Pop the item at the head of the list. Semaphore protection is
\r
395 not required as only the IP task will call these functions. */
\r
396 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
\r
397 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
399 configASSERT( pxItem != NULL );
\r
400 configASSERT( pxSegment != NULL );
\r
402 /* Remove the item from xSegmentList. */
\r
403 uxListRemove( pxItem );
\r
405 /* Add it to either the connections' Rx or Tx queue. */
\r
406 vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
\r
408 /* And set the segment's timer to zero */
\r
409 vTCPTimerSet( &pxSegment->xTransmitTimer );
\r
411 pxSegment->u.ulFlags = 0;
\r
412 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
\r
413 pxSegment->lMaxLength = lCount;
\r
414 pxSegment->lDataLength = lCount;
\r
415 pxSegment->ulSequenceNumber = ulSequenceNumber;
\r
416 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
418 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
\r
419 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
\r
421 if( xLowestLength > xLength )
\r
423 xLowestLength = xLength;
\r
426 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
432 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
433 /*-----------------------------------------------------------*/
\r
435 #if( ipconfigUSE_TCP_WIN == 1 )
\r
437 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
439 BaseType_t xReturn;
\r
441 /* When the peer has a close request (FIN flag), the driver will check
\r
442 if there are missing packets in the Rx-queue. It will accept the
\r
443 closure of the connection if both conditions are true:
\r
444 - the Rx-queue is empty
\r
445 - the highest Rx sequence number has been ACK'ed */
\r
446 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
\r
448 /* Rx data has been stored while earlier packets were missing. */
\r
451 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
\r
453 /* No Rx packets are being stored and the highest sequence number
\r
454 that has been received has been ACKed. */
\r
459 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
\r
460 ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
\r
461 ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
\r
468 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
469 /*-----------------------------------------------------------*/
\r
471 #if( ipconfigUSE_TCP_WIN == 1 )
\r
473 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
\r
475 TCPSegment_t *pxSegment;
\r
476 ListItem_t * pxItem;
\r
478 /* Detaches and returns the head of a queue. */
\r
479 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
485 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
486 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
488 uxListRemove( pxItem );
\r
494 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
495 /*-----------------------------------------------------------*/
\r
497 #if( ipconfigUSE_TCP_WIN == 1 )
\r
499 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
\r
501 ListItem_t *pxItem;
\r
502 TCPSegment_t *pxReturn;
\r
504 /* Returns the head of a queue but it won't be detached. */
\r
505 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
511 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
512 pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
518 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
519 /*-----------------------------------------------------------*/
\r
521 #if( ipconfigUSE_TCP_WIN == 1 )
\r
523 static void vTCPWindowFree( TCPSegment_t *pxSegment )
\r
525 /* Free entry pxSegment because it's not used any more. The ownership
\r
526 will be passed back to the segment pool.
\r
528 Unlink it from one of the queues, if any. */
\r
529 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
\r
531 uxListRemove( &( pxSegment->xQueueItem ) );
\r
534 pxSegment->ulSequenceNumber = 0u;
\r
535 pxSegment->lDataLength = 0l;
\r
536 pxSegment->u.ulFlags = 0u;
\r
538 /* Take it out of xRxSegments/xTxSegments */
\r
539 if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
\r
541 uxListRemove( &( pxSegment->xListItem ) );
\r
544 /* Return it to xSegmentList */
\r
545 vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
\r
548 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
549 /*-----------------------------------------------------------*/
\r
551 #if( ipconfigUSE_TCP_WIN == 1 )
\r
553 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
555 List_t * pxSegments;
\r
557 TCPSegment_t *pxSegment;
\r
559 /* Destroy a window. A TCP window doesn't serve any more. Return all
\r
560 owned segments to the pool. In order to save code, it will make 2 rounds,
\r
561 one to remove the segments from xRxSegments, and a second round to clear
\r
563 for( xRound = 0; xRound < 2; xRound++ )
\r
567 pxSegments = &( pxWindow->xRxSegments );
\r
571 pxSegments = &( pxWindow->xTxSegments );
\r
574 if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
\r
576 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
\r
578 pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
\r
579 vTCPWindowFree( pxSegment );
\r
585 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
586 /*-----------------------------------------------------------*/
\r
588 void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
\r
589 uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
591 /* Create and initialize a window. */
\r
593 #if( ipconfigUSE_TCP_WIN == 1 )
\r
595 if( xTCPSegments == NULL )
\r
597 prvCreateSectors();
\r
600 vListInitialise( &pxWindow->xTxSegments );
\r
601 vListInitialise( &pxWindow->xRxSegments );
\r
603 vListInitialise( &pxWindow->xPriorityQueue ); /* Priority queue: segments which must be sent immediately */
\r
604 vListInitialise( &pxWindow->xTxQueue ); /* Transmit queue: segments queued for transmission */
\r
605 vListInitialise( &pxWindow->xWaitQueue ); /* Waiting queue: outstanding segments */
\r
607 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
609 if( xTCPWindowLoggingLevel != 0 )
\r
611 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
\r
612 ulRxWindowLength, ulTxWindowLength ) );
\r
615 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
\r
616 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
\r
618 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
\r
620 /*-----------------------------------------------------------*/
\r
622 void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
624 const int32_t l500ms = 500;
\r
626 pxWindow->u.ulFlags = 0ul;
\r
627 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
\r
631 if( pxWindow->usMSSInit != 0u )
\r
633 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
\r
636 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
\r
638 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
\r
639 pxWindow->usMSS = ( uint16_t ) ulMSS;
\r
643 #if( ipconfigUSE_TCP_WIN == 0 )
\r
645 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
\r
647 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
649 /*Start with a timeout of 2 * 500 ms (1 sec). */
\r
650 pxWindow->lSRTT = l500ms;
\r
652 /* Just for logging, to print relative sequence numbers. */
\r
653 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
\r
655 /* The segment asked for in the next transmission. */
\r
656 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
\r
658 /* The right-hand side of the receive window. */
\r
659 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
\r
661 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
\r
663 /* The segment asked for in next transmission. */
\r
664 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
666 /* The sequence number given to the next outgoing byte to be added is
\r
667 maintained by lTCPWindowTxAdd(). */
\r
668 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
\r
670 /* The right-hand side of the transmit window. */
\r
671 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
\r
672 pxWindow->ulOurSequenceNumber = ulSequenceNumber;
\r
674 /*-----------------------------------------------------------*/
\r
676 #if( ipconfigUSE_TCP_WIN == 1 )
\r
678 void vTCPSegmentCleanup( void )
\r
680 /* Free and clear the TCP segments pointer. This function should only be called
\r
681 * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this
\r
683 if( xTCPSegments != NULL )
\r
685 vPortFreeLarge( xTCPSegments );
\r
686 xTCPSegments = NULL;
\r
690 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
691 /*-----------------------------------------------------------*/
\r
693 /*=============================================================================
\r
706 *=============================================================================*/
\r
708 #if( ipconfigUSE_TCP_WIN == 1 )
\r
710 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
\r
712 TCPSegment_t *pxBest = NULL;
\r
713 const ListItem_t *pxIterator;
\r
714 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
\r
715 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
\r
716 TCPSegment_t *pxSegment;
\r
718 /* A segment has been received with sequence number 'ulSequenceNumber',
\r
719 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
\r
720 exactly this segment was expected. xTCPWindowRxConfirm() will check if
\r
721 there is already another segment with a sequence number between (ulSequenceNumber)
\r
722 and (ulSequenceNumber+ulLength). Normally none will be found, because
\r
723 the next RX segment should have a sequence number equal to
\r
724 '(ulSequenceNumber+ulLength)'. */
\r
726 /* Iterate through all RX segments that are stored: */
\r
727 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
728 pxIterator != ( const ListItem_t * ) pxEnd;
\r
729 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
731 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
732 /* And see if there is a segment for which:
\r
733 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
\r
734 If there are more matching segments, the one with the lowest sequence number
\r
736 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
\r
737 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
\r
739 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
\r
741 pxBest = pxSegment;
\r
746 if( ( pxBest != NULL ) &&
\r
747 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
\r
749 FreeRTOS_flush_logging();
\r
750 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
\r
751 pxWindow->usPeerPortNumber,
\r
752 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
754 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
\r
755 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
756 pxBest->lDataLength,
\r
757 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
\r
763 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
764 /*-----------------------------------------------------------*/
\r
766 #if( ipconfigUSE_TCP_WIN == 1 )
\r
768 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
770 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
\r
771 int32_t lReturn, lDistance;
\r
772 TCPSegment_t *pxFound;
\r
774 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
\r
775 directly to user (segment is expected). If it returns a positive
\r
776 number, an earlier packet is missing, but this packet may be stored.
\r
777 If negative, the packet has already been stored, or it is out-of-order,
\r
778 or there is not enough space.
\r
780 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
\r
781 if more Rx data may be passed to the user after this packet. */
\r
783 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
\r
785 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
\r
786 pxWindow->ucOptionLength = 0u;
\r
788 /* Non-zero if TCP-windows contains data which must be popped. */
\r
789 pxWindow->ulUserDataLength = 0ul;
\r
791 if( ulCurrentSequenceNumber == ulSequenceNumber )
\r
793 /* This is the packet with the lowest sequence number we're waiting
\r
794 for. It can be passed directly to the rx stream. */
\r
795 if( ulLength > ulSpace )
\r
797 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
\r
802 ulCurrentSequenceNumber += ulLength;
\r
804 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
\r
806 ulSavedSequenceNumber = ulCurrentSequenceNumber;
\r
808 /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
\r
809 If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
\r
810 So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
\r
814 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
\r
816 if ( pxFound != NULL )
\r
818 /* Remove it because it will be passed to user directly. */
\r
819 vTCPWindowFree( pxFound );
\r
821 } while ( pxFound );
\r
823 /* Check for following segments that are already in the
\r
824 queue and increment ulCurrentSequenceNumber. */
\r
825 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
\r
827 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
\r
829 /* As all packet below this one have been passed to the
\r
830 user it can be discarded. */
\r
831 vTCPWindowFree( pxFound );
\r
834 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
\r
836 /* After the current data-package, there is more data
\r
838 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
\r
840 if( xTCPWindowLoggingLevel >= 1 )
\r
842 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
\r
843 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
844 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
845 pxWindow->ulUserDataLength,
\r
846 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
847 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
852 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
\r
854 /* Packet was expected, may be passed directly to the socket
\r
855 buffer or application. Store the packet at offset 0. */
\r
859 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
\r
861 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
\r
862 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
\r
867 /* The packet is not the one expected. See if it falls within the Rx
\r
868 window so it can be stored. */
\r
870 /* An "out-of-sequence" segment was received, must have missed one.
\r
871 Prepare a SACK (Selective ACK). */
\r
872 ulLast = ulSequenceNumber + ulLength;
\r
873 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
\r
875 if( lDistance <= 0 )
\r
877 /* An earlier has been received, must be a retransmission of a
\r
878 packet that has been accepted already. No need to send out a
\r
879 Selective ACK (SACK). */
\r
882 else if( lDistance > ( int32_t ) ulSpace )
\r
884 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
\r
885 sequence number of this packet is too far ahead, ignore it. */
\r
886 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
\r
891 /* See if there is more data in a contiguous block to make the
\r
892 SACK describe a longer range of data. */
\r
894 /* TODO: SACK's may also be delayed for a short period
\r
895 * This is useful because subsequent packets will be SACK'd with
\r
896 * single one message
\r
898 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
\r
900 ulLast += ( uint32_t ) pxFound->lDataLength;
\r
903 if( xTCPWindowLoggingLevel >= 1 )
\r
905 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
\r
906 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
907 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
908 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
909 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
\r
910 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
\r
913 /* Now prepare the SACK message.
\r
914 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
\r
915 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
\r
917 /* First sequence number that we received. */
\r
918 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
\r
921 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
\r
923 /* Which make 12 (3*4) option bytes. */
\r
924 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
\r
926 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
\r
928 if( pxFound != NULL )
\r
930 /* This out-of-sequence packet has been received for a
\r
931 second time. It is already stored but do send a SACK
\r
937 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
\r
939 if( pxFound == NULL )
\r
941 /* Can not send a SACK, because the segment cannot be
\r
943 pxWindow->ucOptionLength = 0u;
\r
945 /* Needs to be stored but there is no segment
\r
951 if( xTCPWindowLoggingLevel != 0 )
\r
953 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
\r
954 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
955 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
956 FreeRTOS_flush_logging( );
\r
959 /* Return a positive value. The packet may be accepted
\r
960 and stored but an earlier packet is still missing. */
\r
961 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
\r
970 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
971 /*-----------------------------------------------------------*/
\r
973 /*=============================================================================
\r
987 *=============================================================================*/
\r
989 #if( ipconfigUSE_TCP_WIN == 1 )
\r
991 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
\r
993 /* +TCP stores data in circular buffers. Calculate the next position to
\r
995 lPosition += lCount;
\r
996 if( lPosition >= lMax )
\r
1004 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1005 /*-----------------------------------------------------------*/
\r
1007 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1009 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1011 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
\r
1012 int32_t lDone = 0;
\r
1013 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
\r
1015 /* Puts a message in the Tx-window (after buffer size has been
\r
1017 if( pxSegment != NULL )
\r
1019 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1021 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
\r
1023 /* Adding data to a segment that was already in the TX queue. It
\r
1024 will be filled-up to a maximum of MSS (maximum segment size). */
\r
1025 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
\r
1027 pxSegment->lDataLength += lToWrite;
\r
1029 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
\r
1031 /* This segment is full, don't add more bytes. */
\r
1032 pxWindow->pxHeadSegment = NULL;
\r
1035 lBytesLeft -= lToWrite;
\r
1037 /* ulNextTxSequenceNumber is the sequence number of the next byte to
\r
1038 be stored for transmission. */
\r
1039 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1041 /* Increased the return value. */
\r
1042 lDone += lToWrite;
\r
1044 /* Some detailed logging, for those who're interested. */
\r
1045 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1047 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1049 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1050 pxSegment->lDataLength,
\r
1051 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1052 pxSegment->lStreamPos ) );
\r
1053 FreeRTOS_flush_logging( );
\r
1056 /* Calculate the next position in the circular data buffer, knowing
\r
1057 its maximum length 'lMax'. */
\r
1058 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1063 while( lBytesLeft > 0 )
\r
1065 /* The current transmission segment is full, create new segments as
\r
1067 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
\r
1069 if( pxSegment != NULL )
\r
1071 /* Store as many as needed, but no more than the maximum
\r
1073 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
\r
1075 pxSegment->lDataLength = lToWrite;
\r
1076 pxSegment->lStreamPos = lPosition;
\r
1077 lBytesLeft -= lToWrite;
\r
1078 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1079 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1080 lDone += lToWrite;
\r
1082 /* Link this segment in the Tx-Queue. */
\r
1083 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
\r
1085 /* Let 'pxHeadSegment' point to this segment if there is still
\r
1087 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1089 pxWindow->pxHeadSegment = pxSegment;
\r
1093 pxWindow->pxHeadSegment = NULL;
\r
1096 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
\r
1098 if( ( xTCPWindowLoggingLevel >= 3 ) ||
\r
1099 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
\r
1101 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1103 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1104 pxSegment->lDataLength,
\r
1105 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1106 pxSegment->lStreamPos ) );
\r
1107 FreeRTOS_flush_logging( );
\r
1113 /* A sever situation: running out of segments for transmission.
\r
1114 No more data can be sent at the moment. */
\r
1117 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
\r
1126 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1127 /*-----------------------------------------------------------*/
\r
1129 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1131 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1133 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
\r
1136 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1137 /*-----------------------------------------------------------*/
\r
1139 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1141 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1143 uint32_t ulTxOutstanding;
\r
1144 BaseType_t xHasSpace;
\r
1145 TCPSegment_t *pxSegment;
\r
1147 /* This function will look if there is new transmission data. It will
\r
1148 return true if there is data to be sent. */
\r
1150 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1152 if( pxSegment == NULL )
\r
1154 xHasSpace = pdFALSE;
\r
1158 /* How much data is outstanding, i.e. how much data has been sent
\r
1159 but not yet acknowledged ? */
\r
1160 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
\r
1162 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
\r
1166 ulTxOutstanding = 0UL;
\r
1169 /* Subtract this from the peer's space. */
\r
1170 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
\r
1172 /* See if the next segment may be sent. */
\r
1173 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
\r
1175 xHasSpace = pdTRUE;
\r
1179 xHasSpace = pdFALSE;
\r
1182 /* If 'xHasSpace', it looks like the peer has at least space for 1
\r
1183 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
\r
1184 limitation of the transmission window (in case of many resends it
\r
1185 may be decreased). */
\r
1186 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
\r
1188 xHasSpace = pdFALSE;
\r
1195 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1196 /*-----------------------------------------------------------*/
\r
1198 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1200 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1202 TCPSegment_t *pxSegment;
\r
1203 BaseType_t xReturn;
\r
1204 TickType_t ulAge, ulMaxAge;
\r
1208 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
\r
1210 /* No need to look at retransmissions or new transmission as long as
\r
1211 there are priority segments. *pulDelay equals zero, meaning it must
\r
1212 be sent out immediately. */
\r
1217 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1219 if( pxSegment != NULL )
\r
1221 /* There is an outstanding segment, see if it is time to resend
\r
1223 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
\r
1225 /* After a packet has been sent for the first time, it will wait
\r
1226 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
\r
1227 each time doubling the time-out */
\r
1228 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1230 if( ulMaxAge > ulAge )
\r
1232 /* A segment must be sent after this amount of msecs */
\r
1233 *pulDelay = ulMaxAge - ulAge;
\r
1240 /* No priority segment, no outstanding data, see if there is new
\r
1241 transmission data. */
\r
1242 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
\r
1244 /* See if it fits in the peer's reception window. */
\r
1245 if( pxSegment == NULL )
\r
1247 xReturn = pdFALSE;
\r
1249 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1251 /* Too many outstanding messages. */
\r
1252 xReturn = pdFALSE;
\r
1254 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1256 /* 'bSendFullSize' is a special optimisation. If true, the
\r
1257 driver will only sent completely filled packets (of MSS
\r
1259 xReturn = pdFALSE;
\r
1271 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1272 /*-----------------------------------------------------------*/
\r
1274 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1276 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1278 TCPSegment_t *pxSegment;
\r
1279 uint32_t ulMaxTime;
\r
1280 uint32_t ulReturn = ~0UL;
\r
1283 /* Fetches data to be sent-out now.
\r
1285 Priority messages: segments with a resend need no check current sliding
\r
1287 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
\r
1288 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
\r
1290 if( pxSegment == NULL )
\r
1292 /* Waiting messages: outstanding messages with a running timer
\r
1293 neither check peer's reception window size because these packets
\r
1294 have been sent earlier. */
\r
1295 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1297 if( pxSegment != NULL )
\r
1299 /* Do check the timing. */
\r
1300 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1302 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
\r
1304 /* A normal (non-fast) retransmission. Move it from the
\r
1305 head of the waiting queue. */
\r
1306 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
\r
1307 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
\r
1309 /* Some detailed logging. */
\r
1310 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1312 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
\r
1313 pxWindow->usPeerPortNumber,
\r
1314 pxWindow->usOurPortNumber,
\r
1315 pxSegment->lDataLength,
\r
1316 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1317 pxSegment->ulSequenceNumber ) );
\r
1318 FreeRTOS_flush_logging( );
\r
1327 if( pxSegment == NULL )
\r
1329 /* New messages: sent-out for the first time. Check current
\r
1330 sliding window size of peer. */
\r
1331 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1333 if( pxSegment == NULL )
\r
1335 /* No segments queued. */
\r
1338 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1340 /* A segment has been queued but the driver waits until it
\r
1341 has a full size of MSS. */
\r
1344 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1346 /* Peer has no more space at this moment. */
\r
1351 /* Move it out of the Tx queue. */
\r
1352 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
\r
1354 /* Don't let pxHeadSegment point to this segment any more,
\r
1355 so no more data will be added. */
\r
1356 if( pxWindow->pxHeadSegment == pxSegment )
\r
1358 pxWindow->pxHeadSegment = NULL;
\r
1361 /* pxWindow->tx.highest registers the highest sequence
\r
1362 number in our transmission window. */
\r
1363 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
\r
1365 /* ...and more detailed logging */
\r
1366 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1368 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1369 pxWindow->usPeerPortNumber,
\r
1370 pxWindow->usOurPortNumber,
\r
1371 pxSegment->lDataLength,
\r
1372 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1374 FreeRTOS_flush_logging( );
\r
1381 /* There is a priority segment. It doesn't need any checking for
\r
1382 space or timeouts. */
\r
1383 if( xTCPWindowLoggingLevel != 0 )
\r
1385 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1386 pxWindow->usPeerPortNumber,
\r
1387 pxWindow->usOurPortNumber,
\r
1388 pxSegment->lDataLength,
\r
1389 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1391 FreeRTOS_flush_logging( );
\r
1395 /* See if it has already been determined to return 0. */
\r
1396 if( ulReturn != 0UL )
\r
1398 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
\r
1400 /* Now that the segment will be transmitted, add it to the tail of
\r
1401 the waiting queue. */
\r
1402 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
\r
1404 /* And mark it as outstanding. */
\r
1405 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1407 /* Administer the transmit count, needed for fast
\r
1408 retransmissions. */
\r
1409 ( pxSegment->u.bits.ucTransmitCount )++;
\r
1411 /* If there have been several retransmissions (4), decrease the
\r
1412 size of the transmission window to at most 2 times MSS. */
\r
1413 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
\r
1415 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
\r
1417 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
\r
1418 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
1419 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
\r
1420 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
\r
1424 /* Clear the transmit timer. */
\r
1425 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1427 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1429 /* Inform the caller where to find the data within the queue. */
\r
1430 *plPosition = pxSegment->lStreamPos;
\r
1432 /* And return the length of the data segment */
\r
1433 ulReturn = ( uint32_t ) pxSegment->lDataLength;
\r
1439 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1440 /*-----------------------------------------------------------*/
\r
1442 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1444 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1446 uint32_t ulBytesConfirmed = 0u;
\r
1447 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
\r
1448 const ListItem_t *pxIterator;
\r
1449 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
\r
1450 BaseType_t xDoUnlink;
\r
1451 TCPSegment_t *pxSegment;
\r
1452 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
\r
1453 may be removed from the transmission queue(s).
\r
1454 All TX segments for which
\r
1455 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
\r
1456 contiguous block. Note that the segments are stored in xTxSegments in a
\r
1457 strict sequential order. */
\r
1459 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
\r
1461 0 < a < 1; usually a = 1/8
\r
1466 RTT is Round Trip Time
\r
1467 SRTT is Smoothed RTT
\r
1468 RTO is Retransmit timeout
\r
1470 A Smoothed RTT will increase quickly, but it is conservative when
\r
1471 becoming smaller. */
\r
1474 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1475 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
\r
1478 xDoUnlink = pdFALSE;
\r
1479 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1481 /* Move to the next item because the current item might get
\r
1483 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1485 /* Continue if this segment does not fall within the ACK'd range. */
\r
1486 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
\r
1491 /* Is it ready? */
\r
1492 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
\r
1497 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1499 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
\r
1501 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
\r
1503 /* What happens? Only part of this segment was accepted,
\r
1504 probably due to WND limits
\r
1506 AAAAAAA BBBBBBB << acked
\r
1507 aaaaaaa aaaa << sent */
\r
1508 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1510 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
\r
1511 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
\r
1512 pxWindow->usPeerPortNumber,
\r
1513 pxWindow->usOurPortNumber,
\r
1514 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
\r
1515 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1516 ulFirstSeq, ulFirstSeq + ulDataLength ) );
\r
1518 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1522 /* This segment is fully ACK'd, set the flag. */
\r
1523 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
\r
1525 /* Calculate the RTT only if the segment was sent-out for the
\r
1526 first time and if this is the last ACK'd segment in a range. */
\r
1527 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
\r
1529 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
\r
1531 if( pxWindow->lSRTT >= mS )
\r
1533 /* RTT becomes smaller: adapt slowly. */
\r
1534 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
\r
1538 /* RTT becomes larger: adapt quicker */
\r
1539 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
\r
1542 /* Cap to the minimum of 50ms. */
\r
1543 if( pxWindow->lSRTT < winSRTT_CAP_mS )
\r
1545 pxWindow->lSRTT = winSRTT_CAP_mS;
\r
1549 /* Unlink it from the 3 queues, but do not destroy it (yet). */
\r
1550 xDoUnlink = pdTRUE;
\r
1553 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
\r
1554 side of the transmission queue? If so, it may be freed. */
\r
1555 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
\r
1557 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1559 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
\r
1560 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1561 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1562 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1565 /* Increase the left-hand value of the transmission window. */
\r
1566 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1568 /* This function will return the number of bytes that the tail
\r
1569 of txStream may be advanced. */
\r
1570 ulBytesConfirmed += ulDataLength;
\r
1572 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
\r
1573 vTCPWindowFree( pxSegment );
\r
1575 /* No need to unlink it any more. */
\r
1576 xDoUnlink = pdFALSE;
\r
1579 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
\r
1581 /* Remove item from its queues. */
\r
1582 uxListRemove( &pxSegment->xQueueItem );
\r
1585 ulSequenceNumber += ulDataLength;
\r
1588 return ulBytesConfirmed;
\r
1590 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1591 /*-----------------------------------------------------------*/
\r
1593 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1595 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
\r
1597 const ListItem_t *pxIterator;
\r
1598 const MiniListItem_t* pxEnd;
\r
1599 TCPSegment_t *pxSegment;
\r
1600 uint32_t ulCount = 0UL;
\r
1602 /* A higher Tx block has been acknowledged. Now iterate through the
\r
1603 xWaitQueue to find a possible condition for a FAST retransmission. */
\r
1605 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
\r
1607 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1608 pxIterator != ( const ListItem_t * ) pxEnd; )
\r
1610 /* Get the owner, which is a TCP segment. */
\r
1611 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1613 /* Hop to the next item before the current gets unlinked. */
\r
1614 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1616 /* Fast retransmission:
\r
1617 When 3 packets with a higher sequence number have been acknowledged
\r
1618 by the peer, it is very unlikely a current packet will ever arrive.
\r
1619 It will be retransmitted far before the RTO. */
\r
1620 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
\r
1621 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
\r
1622 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
\r
1624 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
\r
1626 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
\r
1627 which might lead to a second fast rexmit. */
\r
1628 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1630 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
\r
1631 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1632 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1633 FreeRTOS_flush_logging( );
\r
1636 /* Remove it from xWaitQueue. */
\r
1637 uxListRemove( &pxSegment->xQueueItem );
\r
1639 /* Add this segment to the priority queue so it gets
\r
1640 retransmitted immediately. */
\r
1641 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
\r
1648 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1649 /*-----------------------------------------------------------*/
\r
1651 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1653 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1655 uint32_t ulFirstSequence, ulReturn;
\r
1657 /* Receive a normal ACK. */
\r
1659 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
\r
1661 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
\r
1667 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
\r
1673 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1674 /*-----------------------------------------------------------*/
\r
1676 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1678 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1680 uint32_t ulAckCount = 0UL;
\r
1681 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
\r
1683 /* Receive a SACK option. */
\r
1684 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
\r
1685 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
\r
1687 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
\r
1689 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
\r
1690 pxWindow->usPeerPortNumber,
\r
1691 pxWindow->usOurPortNumber,
\r
1692 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1693 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1694 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1695 FreeRTOS_flush_logging( );
\r
1698 return ulAckCount;
\r
1701 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1702 /*-----------------------------------------------------------*/
\r
1705 ##### # ##### #### ######
\r
1706 # # # # # # # # # # #
\r
1708 # ### ##### # # # # # #
\r
1709 # # # # # # # # #####
\r
1710 # # # # # # #### # # #
\r
1711 # # # # # # # # # #
\r
1712 # # # # #### # # # #
\r
1713 #### ##### # # # #### #### ####
\r
1717 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1719 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
1723 /* Data was received at 'ulSequenceNumber'. See if it was expected
\r
1724 and if there is enough space to store the new data. */
\r
1725 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
\r
1731 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
\r
1738 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1739 /*-----------------------------------------------------------*/
\r
1741 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1743 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1745 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1748 /* Data is being scheduled for transmission. */
\r
1750 /* lMax would indicate the size of the txStream. */
\r
1752 /* This is tiny TCP: there is only 1 segment for outgoing data.
\r
1753 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
\r
1754 if( pxSegment->lDataLength > 0 )
\r
1760 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
\r
1762 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1764 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
\r
1767 ulLength = ( uint32_t ) pxSegment->lMaxLength;
\r
1770 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1772 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
\r
1773 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1774 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1778 /* The sequence number of the first byte in this packet. */
\r
1779 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
\r
1780 pxSegment->lDataLength = ( int32_t ) ulLength;
\r
1781 pxSegment->lStreamPos = lPosition;
\r
1782 pxSegment->u.ulFlags = 0UL;
\r
1783 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1785 /* Increase the sequence number of the next data to be stored for
\r
1787 pxWindow->ulNextTxSequenceNumber += ulLength;
\r
1788 lResult = ( int32_t )ulLength;
\r
1794 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1795 /*-----------------------------------------------------------*/
\r
1797 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1799 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1801 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1802 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
\r
1803 uint32_t ulMaxTime;
\r
1805 if( ulLength != 0UL )
\r
1807 /* _HT_ Still under investigation */
\r
1808 ( void ) ulWindowSize;
\r
1810 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1812 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
\r
1813 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1815 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
\r
1821 if( ulLength != 0ul )
\r
1823 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1824 pxSegment->u.bits.ucTransmitCount++;
\r
1825 vTCPTimerSet (&pxSegment->xTransmitTimer);
\r
1826 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1827 *plPosition = pxSegment->lStreamPos;
\r
1834 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1835 /*-----------------------------------------------------------*/
\r
1837 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1839 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1841 BaseType_t xReturn;
\r
1843 /* Has the outstanding data been sent because user wants to shutdown? */
\r
1844 if( pxWindow->xTxSegment.lDataLength == 0 )
\r
1850 xReturn = pdFALSE;
\r
1856 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1857 /*-----------------------------------------------------------*/
\r
1859 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1861 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
1862 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1864 BaseType_t xReturn;
\r
1866 if( ulWindowSize >= pxWindow->usMSSInit )
\r
1872 xReturn = pdFALSE;
\r
1878 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1879 /*-----------------------------------------------------------*/
\r
1881 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1883 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1885 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1886 BaseType_t xReturn;
\r
1887 TickType_t ulAge, ulMaxAge;
\r
1889 /* Check data to be sent. */
\r
1890 *pulDelay = ( TickType_t ) 0;
\r
1891 if( pxSegment->lDataLength == 0 )
\r
1893 /* Got nothing to send right now. */
\r
1894 xReturn = pdFALSE;
\r
1898 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1900 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
\r
1901 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1903 if( ulMaxAge > ulAge )
\r
1905 *pulDelay = ulMaxAge - ulAge;
\r
1910 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1912 /* Too many outstanding messages. */
\r
1913 xReturn = pdFALSE;
\r
1924 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1925 /*-----------------------------------------------------------*/
\r
1927 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1929 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1931 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1932 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1934 /* Receive a normal ACK */
\r
1936 if( ulDataLength != 0ul )
\r
1938 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
\r
1940 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
\r
1942 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
\r
1943 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1944 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1948 /* Nothing to send right now. */
\r
1949 ulDataLength = 0ul;
\r
1953 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1955 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1957 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
\r
1958 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1962 pxSegment->lDataLength = 0;
\r
1966 return ulDataLength;
\r
1969 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1970 /*-----------------------------------------------------------*/
\r
1972 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1974 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
1976 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
\r
1977 'ulCurrentSequenceNumber' is the highest sequence number stored,
\r
1978 'ulHighestSequenceNumber' is the highest sequence number seen. */
\r
1979 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
\r
1982 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1983 /*-----------------------------------------------------------*/
\r
1985 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1987 /* Destroy a window (always returns NULL) */
\r
1988 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
1990 /* As in tiny TCP there are no shared segments descriptors, there is
\r
1991 nothing to release. */
\r
1992 ( void ) pxWindow;
\r
1995 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1996 /*-----------------------------------------------------------*/
\r