2 * FreeRTOS+TCP V2.0.7
\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 segement 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 pxNewListItem->pvContainer = ( void * ) pxList; /* If this line fails to build then ensure configENABLE_BACKWARD_COMPATIBILITY is set to 1 in FreeRTOSConfig.h. */
\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 /*=============================================================================
\r
689 *=============================================================================*/
\r
691 #if( ipconfigUSE_TCP_WIN == 1 )
\r
693 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
\r
695 TCPSegment_t *pxBest = NULL;
\r
696 const ListItem_t *pxIterator;
\r
697 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
\r
698 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
\r
699 TCPSegment_t *pxSegment;
\r
701 /* A segment has been received with sequence number 'ulSequenceNumber',
\r
702 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
\r
703 exactly this segment was expected. xTCPWindowRxConfirm() will check if
\r
704 there is already another segment with a sequence number between (ulSequenceNumber)
\r
705 and (ulSequenceNumber+ulLength). Normally none will be found, because
\r
706 the next RX segment should have a sequence number equal to
\r
707 '(ulSequenceNumber+ulLength)'. */
\r
709 /* Iterate through all RX segments that are stored: */
\r
710 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
711 pxIterator != ( const ListItem_t * ) pxEnd;
\r
712 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
714 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
715 /* And see if there is a segment for which:
\r
716 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
\r
717 If there are more matching segments, the one with the lowest sequence number
\r
719 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
\r
720 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
\r
722 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
\r
724 pxBest = pxSegment;
\r
729 if( ( pxBest != NULL ) &&
\r
730 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
\r
732 FreeRTOS_flush_logging();
\r
733 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
\r
734 pxWindow->usPeerPortNumber,
\r
735 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
737 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
\r
738 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
739 pxBest->lDataLength,
\r
740 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
\r
746 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
747 /*-----------------------------------------------------------*/
\r
749 #if( ipconfigUSE_TCP_WIN == 1 )
\r
751 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
753 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
\r
754 int32_t lReturn, lDistance;
\r
755 TCPSegment_t *pxFound;
\r
757 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
\r
758 directly to user (segment is expected). If it returns a positive
\r
759 number, an earlier packet is missing, but this packet may be stored.
\r
760 If negative, the packet has already been stored, or it is out-of-order,
\r
761 or there is not enough space.
\r
763 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
\r
764 if more Rx data may be passed to the user after this packet. */
\r
766 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
\r
768 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
\r
769 pxWindow->ucOptionLength = 0u;
\r
771 /* Non-zero if TCP-windows contains data which must be popped. */
\r
772 pxWindow->ulUserDataLength = 0ul;
\r
774 if( ulCurrentSequenceNumber == ulSequenceNumber )
\r
776 /* This is the packet with the lowest sequence number we're waiting
\r
777 for. It can be passed directly to the rx stream. */
\r
778 if( ulLength > ulSpace )
\r
780 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
\r
785 ulCurrentSequenceNumber += ulLength;
\r
787 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
\r
789 ulSavedSequenceNumber = ulCurrentSequenceNumber;
\r
791 /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated.
\r
792 If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed.
\r
793 So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just
\r
797 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
\r
799 if ( pxFound != NULL )
\r
801 /* Remove it because it will be passed to user directly. */
\r
802 vTCPWindowFree( pxFound );
\r
804 } while ( pxFound );
\r
806 /* Check for following segments that are already in the
\r
807 queue and increment ulCurrentSequenceNumber. */
\r
808 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
\r
810 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
\r
812 /* As all packet below this one have been passed to the
\r
813 user it can be discarded. */
\r
814 vTCPWindowFree( pxFound );
\r
817 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
\r
819 /* After the current data-package, there is more data
\r
821 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
\r
823 if( xTCPWindowLoggingLevel >= 1 )
\r
825 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
\r
826 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
827 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
828 pxWindow->ulUserDataLength,
\r
829 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
830 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
835 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
\r
837 /* Packet was expected, may be passed directly to the socket
\r
838 buffer or application. Store the packet at offset 0. */
\r
842 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
\r
844 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
\r
845 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
\r
850 /* The packet is not the one expected. See if it falls within the Rx
\r
851 window so it can be stored. */
\r
853 /* An "out-of-sequence" segment was received, must have missed one.
\r
854 Prepare a SACK (Selective ACK). */
\r
855 ulLast = ulSequenceNumber + ulLength;
\r
856 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
\r
858 if( lDistance <= 0 )
\r
860 /* An earlier has been received, must be a retransmission of a
\r
861 packet that has been accepted already. No need to send out a
\r
862 Selective ACK (SACK). */
\r
865 else if( lDistance > ( int32_t ) ulSpace )
\r
867 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
\r
868 sequence number of this packet is too far ahead, ignore it. */
\r
869 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
\r
874 /* See if there is more data in a contiguous block to make the
\r
875 SACK describe a longer range of data. */
\r
877 /* TODO: SACK's may also be delayed for a short period
\r
878 * This is useful because subsequent packets will be SACK'd with
\r
879 * single one message
\r
881 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
\r
883 ulLast += ( uint32_t ) pxFound->lDataLength;
\r
886 if( xTCPWindowLoggingLevel >= 1 )
\r
888 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
\r
889 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
890 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
891 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
892 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
\r
893 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
\r
896 /* Now prepare the SACK message.
\r
897 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
\r
898 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
\r
900 /* First sequence number that we received. */
\r
901 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
\r
904 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
\r
906 /* Which make 12 (3*4) option bytes. */
\r
907 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
\r
909 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
\r
911 if( pxFound != NULL )
\r
913 /* This out-of-sequence packet has been received for a
\r
914 second time. It is already stored but do send a SACK
\r
920 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
\r
922 if( pxFound == NULL )
\r
924 /* Can not send a SACK, because the segment cannot be
\r
926 pxWindow->ucOptionLength = 0u;
\r
928 /* Needs to be stored but there is no segment
\r
934 if( xTCPWindowLoggingLevel != 0 )
\r
936 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
\r
937 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
938 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
939 FreeRTOS_flush_logging( );
\r
942 /* Return a positive value. The packet may be accepted
\r
943 and stored but an earlier packet is still missing. */
\r
944 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
\r
953 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
954 /*-----------------------------------------------------------*/
\r
956 /*=============================================================================
\r
970 *=============================================================================*/
\r
972 #if( ipconfigUSE_TCP_WIN == 1 )
\r
974 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
\r
976 /* +TCP stores data in circular buffers. Calculate the next position to
\r
978 lPosition += lCount;
\r
979 if( lPosition >= lMax )
\r
987 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
988 /*-----------------------------------------------------------*/
\r
990 #if( ipconfigUSE_TCP_WIN == 1 )
\r
992 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
994 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
\r
996 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
\r
998 /* Puts a message in the Tx-window (after buffer size has been
\r
1000 if( pxSegment != NULL )
\r
1002 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1004 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
\r
1006 /* Adding data to a segment that was already in the TX queue. It
\r
1007 will be filled-up to a maximum of MSS (maximum segment size). */
\r
1008 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
\r
1010 pxSegment->lDataLength += lToWrite;
\r
1012 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
\r
1014 /* This segment is full, don't add more bytes. */
\r
1015 pxWindow->pxHeadSegment = NULL;
\r
1018 lBytesLeft -= lToWrite;
\r
1020 /* ulNextTxSequenceNumber is the sequence number of the next byte to
\r
1021 be stored for transmission. */
\r
1022 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1024 /* Increased the return value. */
\r
1025 lDone += lToWrite;
\r
1027 /* Some detailed logging, for those who're interested. */
\r
1028 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1030 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1032 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1033 pxSegment->lDataLength,
\r
1034 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1035 pxSegment->lStreamPos ) );
\r
1036 FreeRTOS_flush_logging( );
\r
1039 /* Calculate the next position in the circular data buffer, knowing
\r
1040 its maximum length 'lMax'. */
\r
1041 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1046 while( lBytesLeft > 0 )
\r
1048 /* The current transmission segment is full, create new segments as
\r
1050 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
\r
1052 if( pxSegment != NULL )
\r
1054 /* Store as many as needed, but no more than the maximum
\r
1056 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
\r
1058 pxSegment->lDataLength = lToWrite;
\r
1059 pxSegment->lStreamPos = lPosition;
\r
1060 lBytesLeft -= lToWrite;
\r
1061 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1062 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1063 lDone += lToWrite;
\r
1065 /* Link this segment in the Tx-Queue. */
\r
1066 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
\r
1068 /* Let 'pxHeadSegment' point to this segment if there is still
\r
1070 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1072 pxWindow->pxHeadSegment = pxSegment;
\r
1076 pxWindow->pxHeadSegment = NULL;
\r
1079 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
\r
1081 if( ( xTCPWindowLoggingLevel >= 3 ) ||
\r
1082 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
\r
1084 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1086 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1087 pxSegment->lDataLength,
\r
1088 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1089 pxSegment->lStreamPos ) );
\r
1090 FreeRTOS_flush_logging( );
\r
1096 /* A sever situation: running out of segments for transmission.
\r
1097 No more data can be sent at the moment. */
\r
1100 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
\r
1109 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1110 /*-----------------------------------------------------------*/
\r
1112 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1114 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1116 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
\r
1119 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1120 /*-----------------------------------------------------------*/
\r
1122 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1124 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1126 uint32_t ulTxOutstanding;
\r
1127 BaseType_t xHasSpace;
\r
1128 TCPSegment_t *pxSegment;
\r
1130 /* This function will look if there is new transmission data. It will
\r
1131 return true if there is data to be sent. */
\r
1133 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1135 if( pxSegment == NULL )
\r
1137 xHasSpace = pdFALSE;
\r
1141 /* How much data is outstanding, i.e. how much data has been sent
\r
1142 but not yet acknowledged ? */
\r
1143 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
\r
1145 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
\r
1149 ulTxOutstanding = 0UL;
\r
1152 /* Subtract this from the peer's space. */
\r
1153 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
\r
1155 /* See if the next segment may be sent. */
\r
1156 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
\r
1158 xHasSpace = pdTRUE;
\r
1162 xHasSpace = pdFALSE;
\r
1165 /* If 'xHasSpace', it looks like the peer has at least space for 1
\r
1166 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
\r
1167 limitation of the transmission window (in case of many resends it
\r
1168 may be decreased). */
\r
1169 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
\r
1171 xHasSpace = pdFALSE;
\r
1178 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1179 /*-----------------------------------------------------------*/
\r
1181 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1183 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1185 TCPSegment_t *pxSegment;
\r
1186 BaseType_t xReturn;
\r
1187 TickType_t ulAge, ulMaxAge;
\r
1191 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
\r
1193 /* No need to look at retransmissions or new transmission as long as
\r
1194 there are priority segments. *pulDelay equals zero, meaning it must
\r
1195 be sent out immediately. */
\r
1200 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1202 if( pxSegment != NULL )
\r
1204 /* There is an outstanding segment, see if it is time to resend
\r
1206 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
\r
1208 /* After a packet has been sent for the first time, it will wait
\r
1209 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
\r
1210 each time doubling the time-out */
\r
1211 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1213 if( ulMaxAge > ulAge )
\r
1215 /* A segment must be sent after this amount of msecs */
\r
1216 *pulDelay = ulMaxAge - ulAge;
\r
1223 /* No priority segment, no outstanding data, see if there is new
\r
1224 transmission data. */
\r
1225 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
\r
1227 /* See if it fits in the peer's reception window. */
\r
1228 if( pxSegment == NULL )
\r
1230 xReturn = pdFALSE;
\r
1232 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1234 /* Too many outstanding messages. */
\r
1235 xReturn = pdFALSE;
\r
1237 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1239 /* 'bSendFullSize' is a special optimisation. If true, the
\r
1240 driver will only sent completely filled packets (of MSS
\r
1242 xReturn = pdFALSE;
\r
1254 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1255 /*-----------------------------------------------------------*/
\r
1257 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1259 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1261 TCPSegment_t *pxSegment;
\r
1262 uint32_t ulMaxTime;
\r
1263 uint32_t ulReturn = ~0UL;
\r
1266 /* Fetches data to be sent-out now.
\r
1268 Priority messages: segments with a resend need no check current sliding
\r
1270 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
\r
1271 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
\r
1273 if( pxSegment == NULL )
\r
1275 /* Waiting messages: outstanding messages with a running timer
\r
1276 neither check peer's reception window size because these packets
\r
1277 have been sent earlier. */
\r
1278 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1280 if( pxSegment != NULL )
\r
1282 /* Do check the timing. */
\r
1283 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1285 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
\r
1287 /* A normal (non-fast) retransmission. Move it from the
\r
1288 head of the waiting queue. */
\r
1289 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
\r
1290 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
\r
1292 /* Some detailed logging. */
\r
1293 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1295 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
\r
1296 pxWindow->usPeerPortNumber,
\r
1297 pxWindow->usOurPortNumber,
\r
1298 pxSegment->lDataLength,
\r
1299 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1300 pxSegment->ulSequenceNumber ) );
\r
1301 FreeRTOS_flush_logging( );
\r
1310 if( pxSegment == NULL )
\r
1312 /* New messages: sent-out for the first time. Check current
\r
1313 sliding window size of peer. */
\r
1314 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1316 if( pxSegment == NULL )
\r
1318 /* No segments queued. */
\r
1321 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1323 /* A segment has been queued but the driver waits until it
\r
1324 has a full size of MSS. */
\r
1327 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1329 /* Peer has no more space at this moment. */
\r
1334 /* Move it out of the Tx queue. */
\r
1335 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
\r
1337 /* Don't let pxHeadSegment point to this segment any more,
\r
1338 so no more data will be added. */
\r
1339 if( pxWindow->pxHeadSegment == pxSegment )
\r
1341 pxWindow->pxHeadSegment = NULL;
\r
1344 /* pxWindow->tx.highest registers the highest sequence
\r
1345 number in our transmission window. */
\r
1346 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
\r
1348 /* ...and more detailed logging */
\r
1349 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1351 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1352 pxWindow->usPeerPortNumber,
\r
1353 pxWindow->usOurPortNumber,
\r
1354 pxSegment->lDataLength,
\r
1355 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1357 FreeRTOS_flush_logging( );
\r
1364 /* There is a priority segment. It doesn't need any checking for
\r
1365 space or timeouts. */
\r
1366 if( xTCPWindowLoggingLevel != 0 )
\r
1368 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %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
1378 /* See if it has already been determined to return 0. */
\r
1379 if( ulReturn != 0UL )
\r
1381 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
\r
1383 /* Now that the segment will be transmitted, add it to the tail of
\r
1384 the waiting queue. */
\r
1385 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
\r
1387 /* And mark it as outstanding. */
\r
1388 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1390 /* Administer the transmit count, needed for fast
\r
1391 retransmissions. */
\r
1392 ( pxSegment->u.bits.ucTransmitCount )++;
\r
1394 /* If there have been several retransmissions (4), decrease the
\r
1395 size of the transmission window to at most 2 times MSS. */
\r
1396 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
\r
1398 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
\r
1400 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
\r
1401 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
1402 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
\r
1403 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
\r
1407 /* Clear the transmit timer. */
\r
1408 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1410 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1412 /* Inform the caller where to find the data within the queue. */
\r
1413 *plPosition = pxSegment->lStreamPos;
\r
1415 /* And return the length of the data segment */
\r
1416 ulReturn = ( uint32_t ) pxSegment->lDataLength;
\r
1422 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1423 /*-----------------------------------------------------------*/
\r
1425 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1427 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1429 uint32_t ulBytesConfirmed = 0u;
\r
1430 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
\r
1431 const ListItem_t *pxIterator;
\r
1432 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
\r
1433 BaseType_t xDoUnlink;
\r
1434 TCPSegment_t *pxSegment;
\r
1435 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
\r
1436 may be removed from the transmission queue(s).
\r
1437 All TX segments for which
\r
1438 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
\r
1439 contiguous block. Note that the segments are stored in xTxSegments in a
\r
1440 strict sequential order. */
\r
1442 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
\r
1444 0 < a < 1; usually a = 1/8
\r
1449 RTT is Round Trip Time
\r
1450 SRTT is Smoothed RTT
\r
1451 RTO is Retransmit timeout
\r
1453 A Smoothed RTT will increase quickly, but it is conservative when
\r
1454 becoming smaller. */
\r
1457 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1458 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
\r
1461 xDoUnlink = pdFALSE;
\r
1462 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1464 /* Move to the next item because the current item might get
\r
1466 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1468 /* Continue if this segment does not fall within the ACK'd range. */
\r
1469 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
\r
1474 /* Is it ready? */
\r
1475 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
\r
1480 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1482 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
\r
1484 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
\r
1486 /* What happens? Only part of this segment was accepted,
\r
1487 probably due to WND limits
\r
1489 AAAAAAA BBBBBBB << acked
\r
1490 aaaaaaa aaaa << sent */
\r
1491 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1493 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
\r
1494 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
\r
1495 pxWindow->usPeerPortNumber,
\r
1496 pxWindow->usOurPortNumber,
\r
1497 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
\r
1498 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1499 ulFirstSeq, ulFirstSeq + ulDataLength ) );
\r
1501 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1505 /* This segment is fully ACK'd, set the flag. */
\r
1506 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
\r
1508 /* Calculate the RTT only if the segment was sent-out for the
\r
1509 first time and if this is the last ACK'd segment in a range. */
\r
1510 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
\r
1512 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
\r
1514 if( pxWindow->lSRTT >= mS )
\r
1516 /* RTT becomes smaller: adapt slowly. */
\r
1517 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
\r
1521 /* RTT becomes larger: adapt quicker */
\r
1522 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
\r
1525 /* Cap to the minimum of 50ms. */
\r
1526 if( pxWindow->lSRTT < winSRTT_CAP_mS )
\r
1528 pxWindow->lSRTT = winSRTT_CAP_mS;
\r
1532 /* Unlink it from the 3 queues, but do not destroy it (yet). */
\r
1533 xDoUnlink = pdTRUE;
\r
1536 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
\r
1537 side of the transmission queue? If so, it may be freed. */
\r
1538 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
\r
1540 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1542 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
\r
1543 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1544 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1545 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1548 /* Increase the left-hand value of the transmission window. */
\r
1549 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1551 /* This function will return the number of bytes that the tail
\r
1552 of txStream may be advanced. */
\r
1553 ulBytesConfirmed += ulDataLength;
\r
1555 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
\r
1556 vTCPWindowFree( pxSegment );
\r
1558 /* No need to unlink it any more. */
\r
1559 xDoUnlink = pdFALSE;
\r
1562 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
\r
1564 /* Remove item from its queues. */
\r
1565 uxListRemove( &pxSegment->xQueueItem );
\r
1568 ulSequenceNumber += ulDataLength;
\r
1571 return ulBytesConfirmed;
\r
1573 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1574 /*-----------------------------------------------------------*/
\r
1576 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1578 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
\r
1580 const ListItem_t *pxIterator;
\r
1581 const MiniListItem_t* pxEnd;
\r
1582 TCPSegment_t *pxSegment;
\r
1583 uint32_t ulCount = 0UL;
\r
1585 /* A higher Tx block has been acknowledged. Now iterate through the
\r
1586 xWaitQueue to find a possible condition for a FAST retransmission. */
\r
1588 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
\r
1590 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1591 pxIterator != ( const ListItem_t * ) pxEnd; )
\r
1593 /* Get the owner, which is a TCP segment. */
\r
1594 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1596 /* Hop to the next item before the current gets unlinked. */
\r
1597 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1599 /* Fast retransmission:
\r
1600 When 3 packets with a higher sequence number have been acknowledged
\r
1601 by the peer, it is very unlikely a current packet will ever arrive.
\r
1602 It will be retransmitted far before the RTO. */
\r
1603 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
\r
1604 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
\r
1605 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
\r
1607 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
\r
1609 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
\r
1610 which might lead to a second fast rexmit. */
\r
1611 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1613 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
\r
1614 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1615 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1616 FreeRTOS_flush_logging( );
\r
1619 /* Remove it from xWaitQueue. */
\r
1620 uxListRemove( &pxSegment->xQueueItem );
\r
1622 /* Add this segment to the priority queue so it gets
\r
1623 retransmitted immediately. */
\r
1624 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
\r
1631 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1632 /*-----------------------------------------------------------*/
\r
1634 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1636 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1638 uint32_t ulFirstSequence, ulReturn;
\r
1640 /* Receive a normal ACK. */
\r
1642 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
\r
1644 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
\r
1650 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
\r
1656 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1657 /*-----------------------------------------------------------*/
\r
1659 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1661 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1663 uint32_t ulAckCount = 0UL;
\r
1664 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
\r
1666 /* Receive a SACK option. */
\r
1667 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
\r
1668 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
\r
1670 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
\r
1672 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
\r
1673 pxWindow->usPeerPortNumber,
\r
1674 pxWindow->usOurPortNumber,
\r
1675 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1676 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1677 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1678 FreeRTOS_flush_logging( );
\r
1681 return ulAckCount;
\r
1684 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1685 /*-----------------------------------------------------------*/
\r
1688 ##### # ##### #### ######
\r
1689 # # # # # # # # # # #
\r
1691 # ### ##### # # # # # #
\r
1692 # # # # # # # # #####
\r
1693 # # # # # # #### # # #
\r
1694 # # # # # # # # # #
\r
1695 # # # # #### # # # #
\r
1696 #### ##### # # # #### #### ####
\r
1700 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1702 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
1706 /* Data was received at 'ulSequenceNumber'. See if it was expected
\r
1707 and if there is enough space to store the new data. */
\r
1708 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
\r
1714 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
\r
1721 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1722 /*-----------------------------------------------------------*/
\r
1724 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1726 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1728 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1731 /* Data is being scheduled for transmission. */
\r
1733 /* lMax would indicate the size of the txStream. */
\r
1735 /* This is tiny TCP: there is only 1 segment for outgoing data.
\r
1736 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
\r
1737 if( pxSegment->lDataLength > 0 )
\r
1743 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
\r
1745 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1747 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
\r
1750 ulLength = ( uint32_t ) pxSegment->lMaxLength;
\r
1753 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1755 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
\r
1756 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1757 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1761 /* The sequence number of the first byte in this packet. */
\r
1762 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
\r
1763 pxSegment->lDataLength = ( int32_t ) ulLength;
\r
1764 pxSegment->lStreamPos = lPosition;
\r
1765 pxSegment->u.ulFlags = 0UL;
\r
1766 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1768 /* Increase the sequence number of the next data to be stored for
\r
1770 pxWindow->ulNextTxSequenceNumber += ulLength;
\r
1771 lResult = ( int32_t )ulLength;
\r
1777 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1778 /*-----------------------------------------------------------*/
\r
1780 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1782 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1784 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1785 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
\r
1786 uint32_t ulMaxTime;
\r
1788 if( ulLength != 0UL )
\r
1790 /* _HT_ Still under investigation */
\r
1791 ( void ) ulWindowSize;
\r
1793 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1795 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
\r
1796 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1798 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
\r
1804 if( ulLength != 0ul )
\r
1806 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1807 pxSegment->u.bits.ucTransmitCount++;
\r
1808 vTCPTimerSet (&pxSegment->xTransmitTimer);
\r
1809 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1810 *plPosition = pxSegment->lStreamPos;
\r
1817 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1818 /*-----------------------------------------------------------*/
\r
1820 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1822 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1824 BaseType_t xReturn;
\r
1826 /* Has the outstanding data been sent because user wants to shutdown? */
\r
1827 if( pxWindow->xTxSegment.lDataLength == 0 )
\r
1833 xReturn = pdFALSE;
\r
1839 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1840 /*-----------------------------------------------------------*/
\r
1842 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1844 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
1845 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1847 BaseType_t xReturn;
\r
1849 if( ulWindowSize >= pxWindow->usMSSInit )
\r
1855 xReturn = pdFALSE;
\r
1861 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1862 /*-----------------------------------------------------------*/
\r
1864 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1866 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1868 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1869 BaseType_t xReturn;
\r
1870 TickType_t ulAge, ulMaxAge;
\r
1872 /* Check data to be sent. */
\r
1873 *pulDelay = ( TickType_t ) 0;
\r
1874 if( pxSegment->lDataLength == 0 )
\r
1876 /* Got nothing to send right now. */
\r
1877 xReturn = pdFALSE;
\r
1881 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1883 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
\r
1884 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1886 if( ulMaxAge > ulAge )
\r
1888 *pulDelay = ulMaxAge - ulAge;
\r
1893 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1895 /* Too many outstanding messages. */
\r
1896 xReturn = pdFALSE;
\r
1907 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1908 /*-----------------------------------------------------------*/
\r
1910 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1912 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1914 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1915 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1917 /* Receive a normal ACK */
\r
1919 if( ulDataLength != 0ul )
\r
1921 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
\r
1923 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
\r
1925 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
\r
1926 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1927 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1931 /* Nothing to send right now. */
\r
1932 ulDataLength = 0ul;
\r
1936 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1938 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1940 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
\r
1941 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1945 pxSegment->lDataLength = 0;
\r
1949 return ulDataLength;
\r
1952 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1953 /*-----------------------------------------------------------*/
\r
1955 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1957 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
1959 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
\r
1960 'ulCurrentSequenceNumber' is the highest sequence number stored,
\r
1961 'ulHighestSequenceNumber' is the highest sequence number seen. */
\r
1962 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
\r
1965 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1966 /*-----------------------------------------------------------*/
\r
1968 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1970 /* Destroy a window (always returns NULL) */
\r
1971 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
1973 /* As in tiny TCP there are no shared segments descriptors, there is
\r
1974 nothing to release. */
\r
1975 ( void ) pxWindow;
\r
1978 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1979 /*-----------------------------------------------------------*/
\r