2 * FreeRTOS+TCP V2.0.1
\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://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 * FreeRTOS_TCP_WIN.c
\r
30 * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
\r
31 * functions have two versions - one for FreeRTOS+TCP (full) and one for
\r
32 * FreeRTOS+TCP (lite).
\r
34 * In this module all ports and IP addresses and sequence numbers are
\r
35 * being stored in host byte-order.
\r
38 /* Standard includes. */
\r
41 /* FreeRTOS includes. */
\r
42 #include "FreeRTOS.h"
\r
47 /* FreeRTOS+TCP includes. */
\r
48 #include "FreeRTOS_UDP_IP.h"
\r
49 #include "FreeRTOS_IP.h"
\r
50 #include "FreeRTOS_Sockets.h"
\r
51 #include "FreeRTOS_IP_Private.h"
\r
52 #include "NetworkBufferManagement.h"
\r
53 #include "FreeRTOS_TCP_WIN.h"
\r
55 /* Constants used for Smoothed Round Trip Time (SRTT). */
\r
56 #define winSRTT_INCREMENT_NEW 2
\r
57 #define winSRTT_INCREMENT_CURRENT 6
\r
58 #define winSRTT_DECREMENT_NEW 1
\r
59 #define winSRTT_DECREMENT_CURRENT 7
\r
60 #define winSRTT_CAP_mS 50
\r
62 #if( ipconfigUSE_TCP_WIN == 1 )
\r
64 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
\r
66 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
\r
68 /* The code to send a single Selective ACK (SACK):
\r
69 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
\r
70 * followed by a lower and a higher sequence number,
\r
71 * where LEN is 2 + 2*4 = 10 bytes. */
\r
72 #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
\r
73 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
\r
75 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
\r
78 /* Normal retransmission:
\r
79 * A packet will be retransmitted after a Retransmit Time-Out (RTO).
\r
80 * Fast retransmission:
\r
81 * When 3 packets with a higher sequence number have been acknowledged
\r
82 * by the peer, it is very unlikely a current packet will ever arrive.
\r
83 * It will be retransmitted far before the RTO.
\r
85 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
\r
87 /* If there have been several retransmissions (4), decrease the
\r
88 * size of the transmission window to at most 2 times MSS.
\r
90 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
\r
92 #endif /* configUSE_TCP_WIN */
\r
93 /*-----------------------------------------------------------*/
\r
95 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
98 * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
\r
99 * Available descriptors are stored in the 'xSegmentList'
\r
100 * When a socket owns a descriptor, it will either be stored in
\r
101 * 'xTxSegments' or 'xRxSegments'
\r
102 * As soon as a package has been confirmed, the descriptor will be returned
\r
103 * to the segment pool
\r
105 #if( ipconfigUSE_TCP_WIN == 1 )
\r
106 static BaseType_t prvCreateSectors( void );
\r
107 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
110 * Find a segment with a given sequence number in the list of received
\r
111 * segments: 'pxWindow->xRxSegments'.
\r
113 #if( ipconfigUSE_TCP_WIN == 1 )
\r
114 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
\r
115 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
118 * Allocate a new segment
\r
119 * The socket will borrow all segments from a common pool: 'xSegmentList',
\r
120 * which is a list of 'TCPSegment_t'
\r
122 #if( ipconfigUSE_TCP_WIN == 1 )
\r
123 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
\r
124 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
126 /* When the peer has a close request (FIN flag), the driver will check if
\r
127 * there are missing packets in the Rx-queue
\r
128 * It will accept the closure of the connection if both conditions are true:
\r
129 * - the Rx-queue is empty
\r
130 * - we've ACK'd the highest Rx sequence number seen
\r
132 #if( ipconfigUSE_TCP_WIN == 1 )
\r
133 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
\r
134 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
137 * Detaches and returns the head of a queue
\r
139 #if( ipconfigUSE_TCP_WIN == 1 )
\r
140 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
\r
141 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
144 * Returns the head of a queue but it won't be detached
\r
146 #if( ipconfigUSE_TCP_WIN == 1 )
\r
147 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
\r
148 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
151 * Free entry pxSegment because it's not used anymore
\r
152 * The ownership will be passed back to the segment pool
\r
154 #if( ipconfigUSE_TCP_WIN == 1 )
\r
155 static void vTCPWindowFree( TCPSegment_t *pxSegment );
\r
156 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
159 * A segment has been received with sequence number 'ulSequenceNumber', where
\r
160 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
\r
161 * segment was expected. xTCPWindowRxConfirm() will check if there is already
\r
162 * another segment with a sequence number between (ulSequenceNumber) and
\r
163 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
\r
164 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
\r
166 #if( ipconfigUSE_TCP_WIN == 1 )
\r
167 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
\r
168 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
171 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
\r
174 #if( ipconfigUSE_TCP_WIN == 1 )
\r
175 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
\r
176 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
179 * This function will look if there is new transmission data. It will return
\r
180 * true if there is data to be sent.
\r
182 #if( ipconfigUSE_TCP_WIN == 1 )
\r
183 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
184 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
187 * An acknowledge was received. See if some outstanding data may be removed
\r
188 * from the transmission queue(s).
\r
190 #if( ipconfigUSE_TCP_WIN == 1 )
\r
191 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
\r
192 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
195 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
\r
196 * to find a possible condition for a FAST retransmission.
\r
198 #if( ipconfigUSE_TCP_WIN == 1 )
\r
199 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
\r
200 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
202 /*-----------------------------------------------------------*/
\r
204 /* TCP segment pool. */
\r
205 #if( ipconfigUSE_TCP_WIN == 1 )
\r
206 static TCPSegment_t *xTCPSegments = NULL;
\r
207 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
209 /* List of free TCP segments. */
\r
210 #if( ipconfigUSE_TCP_WIN == 1 )
\r
211 static List_t xSegmentList;
\r
214 /* Logging verbosity level. */
\r
215 BaseType_t xTCPWindowLoggingLevel = 0;
\r
217 #if( ipconfigUSE_TCP_WIN == 1 )
\r
218 /* Some 32-bit arithmetic: comparing sequence numbers */
\r
219 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
\r
220 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
\r
223 Return true if the unsigned subtraction of (b-a) doesn't generate an
\r
224 arithmetic overflow. */
\r
225 return ( ( b - a ) & 0x80000000UL ) == 0UL;
\r
227 #endif /* ipconfigUSE_TCP_WIN */
\r
228 /*-----------------------------------------------------------*/
\r
230 #if( ipconfigUSE_TCP_WIN == 1 )
\r
231 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
\r
232 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
\r
234 /* Test if a < b */
\r
235 return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
\r
237 #endif /* ipconfigUSE_TCP_WIN */
\r
238 /*-----------------------------------------------------------*/
\r
240 #if( ipconfigUSE_TCP_WIN == 1 )
\r
241 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
\r
242 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
\r
244 /* Test if a > b */
\r
245 return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
\r
247 #endif /* ipconfigUSE_TCP_WIN */
\r
249 /*-----------------------------------------------------------*/
\r
250 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
\r
251 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
\r
253 /* Test if a >= b */
\r
254 return ( ( a - b ) & 0x80000000UL ) == 0UL;
\r
256 /*-----------------------------------------------------------*/
\r
258 #if( ipconfigUSE_TCP_WIN == 1 )
\r
259 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
\r
260 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
\r
262 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
\r
265 /*-----------------------------------------------------------*/
\r
267 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
\r
268 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
\r
270 pxTimer->ulBorn = xTaskGetTickCount ( );
\r
272 /*-----------------------------------------------------------*/
\r
274 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
\r
275 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
\r
277 return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
\r
279 /*-----------------------------------------------------------*/
\r
281 /* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
\r
282 preceded by a prototype. Later this prototype will be located in list.h? */
\r
284 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
286 void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
\r
288 /* Insert a new list item into pxList, it does not sort the list,
\r
289 but it puts the item just before xListEnd, so it will be the last item
\r
290 returned by listGET_HEAD_ENTRY() */
\r
291 pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
\r
292 pxNewListItem->pxPrevious = pxWhere->pxPrevious;
\r
293 pxWhere->pxPrevious->pxNext = pxNewListItem;
\r
294 pxWhere->pxPrevious = pxNewListItem;
\r
296 /* Remember which list the item is in. */
\r
297 pxNewListItem->pvContainer = ( void * ) pxList;
\r
299 ( pxList->uxNumberOfItems )++;
\r
301 /*-----------------------------------------------------------*/
\r
303 #if( ipconfigUSE_TCP_WIN == 1 )
\r
305 static BaseType_t prvCreateSectors( void )
\r
307 BaseType_t xIndex, xReturn;
\r
309 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
\r
311 vListInitialise( &xSegmentList );
\r
312 xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
314 if( xTCPSegments == NULL )
\r
316 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
\r
317 ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
\r
323 /* Clear the allocated space. */
\r
324 memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
326 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
\r
328 /* Could call vListInitialiseItem here but all data has been
\r
329 nulled already. Set the owner to a segment descriptor. */
\r
330 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
331 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
333 /* And add it to the pool of available segments */
\r
334 vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
\r
343 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
344 /*-----------------------------------------------------------*/
\r
346 #if( ipconfigUSE_TCP_WIN == 1 )
\r
348 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
350 const ListItem_t *pxIterator;
\r
351 const MiniListItem_t* pxEnd;
\r
352 TCPSegment_t *pxSegment, *pxReturn = NULL;
\r
354 /* Find a segment with a given sequence number in the list of received
\r
357 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
\r
359 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
360 pxIterator != ( const ListItem_t * ) pxEnd;
\r
361 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
363 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
365 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
\r
367 pxReturn = pxSegment;
\r
375 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
376 /*-----------------------------------------------------------*/
\r
378 #if( ipconfigUSE_TCP_WIN == 1 )
\r
380 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
\r
382 TCPSegment_t *pxSegment;
\r
383 ListItem_t * pxItem;
\r
385 /* Allocate a new segment. The socket will borrow all segments from a
\r
386 common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
\r
387 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
\r
389 /* If the TCP-stack runs out of segments, you might consider
\r
390 increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
\r
391 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
\r
396 /* Pop the item at the head of the list. Semaphore protection is
\r
397 not required as only the IP task will call these functions. */
\r
398 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
\r
399 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
401 configASSERT( pxItem != NULL );
\r
402 configASSERT( pxSegment != NULL );
\r
404 /* Remove the item from xSegmentList. */
\r
405 uxListRemove( pxItem );
\r
407 /* Add it to either the connections' Rx or Tx queue. */
\r
408 vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
\r
410 /* And set the segment's timer to zero */
\r
411 vTCPTimerSet( &pxSegment->xTransmitTimer );
\r
413 pxSegment->u.ulFlags = 0;
\r
414 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
\r
415 pxSegment->lMaxLength = lCount;
\r
416 pxSegment->lDataLength = lCount;
\r
417 pxSegment->ulSequenceNumber = ulSequenceNumber;
\r
418 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
420 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
\r
421 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
\r
423 if( xLowestLength > xLength )
\r
425 xLowestLength = xLength;
\r
428 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
434 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
435 /*-----------------------------------------------------------*/
\r
437 #if( ipconfigUSE_TCP_WIN == 1 )
\r
439 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
441 BaseType_t xReturn;
\r
443 /* When the peer has a close request (FIN flag), the driver will check
\r
444 if there are missing packets in the Rx-queue. It will accept the
\r
445 closure of the connection if both conditions are true:
\r
446 - the Rx-queue is empty
\r
447 - the highest Rx sequence number has been ACK'ed */
\r
448 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
\r
450 /* Rx data has been stored while earlier packets were missing. */
\r
453 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
\r
455 /* No Rx packets are being stored and the highest sequence number
\r
456 that has been received has been ACKed. */
\r
461 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
\r
462 ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
\r
463 ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
\r
470 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
471 /*-----------------------------------------------------------*/
\r
473 #if( ipconfigUSE_TCP_WIN == 1 )
\r
475 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
\r
477 TCPSegment_t *pxSegment;
\r
478 ListItem_t * pxItem;
\r
480 /* Detaches and returns the head of a queue. */
\r
481 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
487 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
488 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
490 uxListRemove( pxItem );
\r
496 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
497 /*-----------------------------------------------------------*/
\r
499 #if( ipconfigUSE_TCP_WIN == 1 )
\r
501 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
\r
503 ListItem_t *pxItem;
\r
504 TCPSegment_t *pxReturn;
\r
506 /* Returns the head of a queue but it won't be detached. */
\r
507 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
513 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
514 pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
520 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
521 /*-----------------------------------------------------------*/
\r
523 #if( ipconfigUSE_TCP_WIN == 1 )
\r
525 static void vTCPWindowFree( TCPSegment_t *pxSegment )
\r
527 /* Free entry pxSegment because it's not used any more. The ownership
\r
528 will be passed back to the segment pool.
\r
530 Unlink it from one of the queues, if any. */
\r
531 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
\r
533 uxListRemove( &( pxSegment->xQueueItem ) );
\r
536 pxSegment->ulSequenceNumber = 0u;
\r
537 pxSegment->lDataLength = 0l;
\r
538 pxSegment->u.ulFlags = 0u;
\r
540 /* Take it out of xRxSegments/xTxSegments */
\r
541 if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
\r
543 uxListRemove( &( pxSegment->xListItem ) );
\r
546 /* Return it to xSegmentList */
\r
547 vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
\r
550 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
551 /*-----------------------------------------------------------*/
\r
553 #if( ipconfigUSE_TCP_WIN == 1 )
\r
555 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
557 List_t * pxSegments;
\r
559 TCPSegment_t *pxSegment;
\r
561 /* Destroy a window. A TCP window doesn't serve any more. Return all
\r
562 owned segments to the pool. In order to save code, it will make 2 rounds,
\r
563 one to remove the segments from xRxSegments, and a second round to clear
\r
565 for( xRound = 0; xRound < 2; xRound++ )
\r
569 pxSegments = &( pxWindow->xRxSegments );
\r
573 pxSegments = &( pxWindow->xTxSegments );
\r
576 if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
\r
578 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
\r
580 pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
\r
581 vTCPWindowFree( pxSegment );
\r
587 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
588 /*-----------------------------------------------------------*/
\r
590 void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
\r
591 uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
593 /* Create and initialize a window. */
\r
595 #if( ipconfigUSE_TCP_WIN == 1 )
\r
597 if( xTCPSegments == NULL )
\r
599 prvCreateSectors();
\r
602 vListInitialise( &( pxWindow->xTxSegments ) );
\r
603 vListInitialise( &( pxWindow->xRxSegments ) );
\r
605 vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
\r
606 vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */
\r
607 vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */
\r
609 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
611 if( xTCPWindowLoggingLevel != 0 )
\r
613 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
\r
614 ulRxWindowLength, ulTxWindowLength ) );
\r
617 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
\r
618 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
\r
620 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
\r
622 /*-----------------------------------------------------------*/
\r
624 void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
626 const int32_t l500ms = 500;
\r
628 pxWindow->u.ulFlags = 0ul;
\r
629 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
\r
633 if( pxWindow->usMSSInit != 0u )
\r
635 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
\r
638 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
\r
640 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
\r
641 pxWindow->usMSS = ( uint16_t ) ulMSS;
\r
645 #if( ipconfigUSE_TCP_WIN == 0 )
\r
647 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
\r
649 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
651 /*Start with a timeout of 2 * 500 ms (1 sec). */
\r
652 pxWindow->lSRTT = l500ms;
\r
654 /* Just for logging, to print relative sequence numbers. */
\r
655 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
\r
657 /* The segment asked for in the next transmission. */
\r
658 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
\r
660 /* The right-hand side of the receive window. */
\r
661 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
\r
663 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
\r
665 /* The segment asked for in next transmission. */
\r
666 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
668 /* The sequence number given to the next outgoing byte to be added is
\r
669 maintained by lTCPWindowTxAdd(). */
\r
670 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
\r
672 /* The right-hand side of the transmit window. */
\r
673 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
\r
674 pxWindow->ulOurSequenceNumber = ulSequenceNumber;
\r
676 /*-----------------------------------------------------------*/
\r
678 /*=============================================================================
\r
691 *=============================================================================*/
\r
693 #if( ipconfigUSE_TCP_WIN == 1 )
\r
695 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
\r
697 TCPSegment_t *pxBest = NULL;
\r
698 const ListItem_t *pxIterator;
\r
699 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
\r
700 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
\r
701 TCPSegment_t *pxSegment;
\r
703 /* A segment has been received with sequence number 'ulSequenceNumber',
\r
704 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
\r
705 exactly this segment was expected. xTCPWindowRxConfirm() will check if
\r
706 there is already another segment with a sequence number between (ulSequenceNumber)
\r
707 and (ulSequenceNumber+ulLength). Normally none will be found, because
\r
708 the next RX segment should have a sequence number equal to
\r
709 '(ulSequenceNumber+ulLength)'. */
\r
711 /* Iterate through all RX segments that are stored: */
\r
712 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
713 pxIterator != ( const ListItem_t * ) pxEnd;
\r
714 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
716 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
717 /* And see if there is a segment for which:
\r
718 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
\r
719 If there are more matching segments, the one with the lowest sequence number
\r
721 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
\r
722 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
\r
724 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
\r
726 pxBest = pxSegment;
\r
731 if( ( pxBest != NULL ) &&
\r
732 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
\r
734 FreeRTOS_flush_logging();
\r
735 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
\r
736 pxWindow->usPeerPortNumber,
\r
737 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
739 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
\r
740 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
741 pxBest->lDataLength,
\r
742 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
\r
748 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
749 /*-----------------------------------------------------------*/
\r
751 #if( ipconfigUSE_TCP_WIN == 1 )
\r
753 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
755 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
\r
756 int32_t lReturn, lDistance;
\r
757 TCPSegment_t *pxFound;
\r
759 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
\r
760 directly to user (segment is expected). If it returns a positive
\r
761 number, an earlier packet is missing, but this packet may be stored.
\r
762 If negative, the packet has already been stored, or it is out-of-order,
\r
763 or there is not enough space.
\r
765 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
\r
766 if more Rx data may be passed to the user after this packet. */
\r
768 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
\r
770 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
\r
771 pxWindow->ucOptionLength = 0u;
\r
773 /* Non-zero if TCP-windows contains data which must be popped. */
\r
774 pxWindow->ulUserDataLength = 0ul;
\r
776 if( ulCurrentSequenceNumber == ulSequenceNumber )
\r
778 /* This is the packet with the lowest sequence number we're waiting
\r
779 for. It can be passed directly to the rx stream. */
\r
780 if( ulLength > ulSpace )
\r
782 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
\r
787 ulCurrentSequenceNumber += ulLength;
\r
789 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
\r
791 ulSavedSequenceNumber = ulCurrentSequenceNumber;
\r
793 /* See if (part of) this segment has been stored already,
\r
794 but this rarely happens. */
\r
795 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
\r
796 if( pxFound != NULL )
\r
798 ulCurrentSequenceNumber = pxFound->ulSequenceNumber + ( ( uint32_t ) pxFound->lDataLength );
\r
800 /* Remove it because it will be passed to user directly. */
\r
801 vTCPWindowFree( pxFound );
\r
804 /* Check for following segments that are already in the
\r
805 queue and increment ulCurrentSequenceNumber. */
\r
806 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
\r
808 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
\r
810 /* As all packet below this one have been passed to the
\r
811 user it can be discarded. */
\r
812 vTCPWindowFree( pxFound );
\r
815 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
\r
817 /* After the current data-package, there is more data
\r
819 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
\r
821 if( xTCPWindowLoggingLevel >= 1 )
\r
823 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
\r
824 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
825 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
826 pxWindow->ulUserDataLength,
\r
827 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
828 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
833 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
\r
835 /* Packet was expected, may be passed directly to the socket
\r
836 buffer or application. Store the packet at offset 0. */
\r
840 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
\r
842 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
\r
843 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
\r
848 /* The packet is not the one expected. See if it falls within the Rx
\r
849 window so it can be stored. */
\r
851 /* An "out-of-sequence" segment was received, must have missed one.
\r
852 Prepare a SACK (Selective ACK). */
\r
853 ulLast = ulSequenceNumber + ulLength;
\r
854 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
\r
856 if( lDistance <= 0 )
\r
858 /* An earlier has been received, must be a retransmission of a
\r
859 packet that has been accepted already. No need to send out a
\r
860 Selective ACK (SACK). */
\r
863 else if( lDistance > ( int32_t ) ulSpace )
\r
865 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
\r
866 sequence number of this packet is too far ahead, ignore it. */
\r
867 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
\r
872 /* See if there is more data in a contiguous block to make the
\r
873 SACK describe a longer range of data. */
\r
875 /* TODO: SACK's may also be delayed for a short period
\r
876 * This is useful because subsequent packets will be SACK'd with
\r
877 * single one message
\r
879 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
\r
881 ulLast += ( uint32_t ) pxFound->lDataLength;
\r
884 if( xTCPWindowLoggingLevel >= 1 )
\r
886 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
\r
887 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
888 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
889 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
890 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
\r
891 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
\r
894 /* Now prepare the SACK message.
\r
895 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
\r
896 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
\r
898 /* First sequence number that we received. */
\r
899 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
\r
902 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
\r
904 /* Which make 12 (3*4) option bytes. */
\r
905 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
\r
907 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
\r
909 if( pxFound != NULL )
\r
911 /* This out-of-sequence packet has been received for a
\r
912 second time. It is already stored but do send a SACK
\r
918 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
\r
920 if( pxFound == NULL )
\r
922 /* Can not send a SACK, because the segment cannot be
\r
924 pxWindow->ucOptionLength = 0u;
\r
926 /* Needs to be stored but there is no segment
\r
932 if( xTCPWindowLoggingLevel != 0 )
\r
934 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
\r
935 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
936 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
937 FreeRTOS_flush_logging( );
\r
940 /* Return a positive value. The packet may be accepted
\r
941 and stored but an earlier packet is still missing. */
\r
942 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
\r
951 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
952 /*-----------------------------------------------------------*/
\r
954 /*=============================================================================
\r
968 *=============================================================================*/
\r
970 #if( ipconfigUSE_TCP_WIN == 1 )
\r
972 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
\r
974 /* +TCP stores data in circular buffers. Calculate the next position to
\r
976 lPosition += lCount;
\r
977 if( lPosition >= lMax )
\r
985 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
986 /*-----------------------------------------------------------*/
\r
988 #if( ipconfigUSE_TCP_WIN == 1 )
\r
990 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
992 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
\r
994 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
\r
996 /* Puts a message in the Tx-window (after buffer size has been
\r
998 if( pxSegment != NULL )
\r
1000 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1002 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
\r
1004 /* Adding data to a segment that was already in the TX queue. It
\r
1005 will be filled-up to a maximum of MSS (maximum segment size). */
\r
1006 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
\r
1008 pxSegment->lDataLength += lToWrite;
\r
1010 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
\r
1012 /* This segment is full, don't add more bytes. */
\r
1013 pxWindow->pxHeadSegment = NULL;
\r
1016 lBytesLeft -= lToWrite;
\r
1018 /* ulNextTxSequenceNumber is the sequence number of the next byte to
\r
1019 be stored for transmission. */
\r
1020 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1022 /* Increased the return value. */
\r
1023 lDone += lToWrite;
\r
1025 /* Some detailed logging, for those who're interested. */
\r
1026 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1028 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1030 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1031 pxSegment->lDataLength,
\r
1032 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1033 pxSegment->lStreamPos ) );
\r
1034 FreeRTOS_flush_logging( );
\r
1037 /* Calculate the next position in the circular data buffer, knowing
\r
1038 its maximum length 'lMax'. */
\r
1039 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1044 while( lBytesLeft > 0 )
\r
1046 /* The current transmission segment is full, create new segments as
\r
1048 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
\r
1050 if( pxSegment != NULL )
\r
1052 /* Store as many as needed, but no more than the maximum
\r
1054 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
\r
1056 pxSegment->lDataLength = lToWrite;
\r
1057 pxSegment->lStreamPos = lPosition;
\r
1058 lBytesLeft -= lToWrite;
\r
1059 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1060 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1061 lDone += lToWrite;
\r
1063 /* Link this segment in the Tx-Queue. */
\r
1064 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
\r
1066 /* Let 'pxHeadSegment' point to this segment if there is still
\r
1068 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1070 pxWindow->pxHeadSegment = pxSegment;
\r
1074 pxWindow->pxHeadSegment = NULL;
\r
1077 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
\r
1079 if( ( xTCPWindowLoggingLevel >= 3 ) ||
\r
1080 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
\r
1082 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1084 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1085 pxSegment->lDataLength,
\r
1086 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1087 pxSegment->lStreamPos ) );
\r
1088 FreeRTOS_flush_logging( );
\r
1094 /* A sever situation: running out of segments for transmission.
\r
1095 No more data can be sent at the moment. */
\r
1098 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
\r
1107 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1108 /*-----------------------------------------------------------*/
\r
1110 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1112 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1114 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
\r
1117 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1118 /*-----------------------------------------------------------*/
\r
1120 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1122 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1124 uint32_t ulTxOutstanding;
\r
1125 BaseType_t xHasSpace;
\r
1126 TCPSegment_t *pxSegment;
\r
1128 /* This function will look if there is new transmission data. It will
\r
1129 return true if there is data to be sent. */
\r
1131 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1133 if( pxSegment == NULL )
\r
1135 xHasSpace = pdFALSE;
\r
1139 /* How much data is outstanding, i.e. how much data has been sent
\r
1140 but not yet acknowledged ? */
\r
1141 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
\r
1143 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
\r
1147 ulTxOutstanding = 0UL;
\r
1150 /* Subtract this from the peer's space. */
\r
1151 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
\r
1153 /* See if the next segment may be sent. */
\r
1154 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
\r
1156 xHasSpace = pdTRUE;
\r
1160 xHasSpace = pdFALSE;
\r
1163 /* If 'xHasSpace', it looks like the peer has at least space for 1
\r
1164 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
\r
1165 limitation of the transmission window (in case of many resends it
\r
1166 may be decreased). */
\r
1167 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
\r
1169 xHasSpace = pdFALSE;
\r
1176 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1177 /*-----------------------------------------------------------*/
\r
1179 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1181 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1183 TCPSegment_t *pxSegment;
\r
1184 BaseType_t xReturn;
\r
1185 TickType_t ulAge, ulMaxAge;
\r
1189 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
\r
1191 /* No need to look at retransmissions or new transmission as long as
\r
1192 there are priority segments. *pulDelay equals zero, meaning it must
\r
1193 be sent out immediately. */
\r
1198 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1200 if( pxSegment != NULL )
\r
1202 /* There is an outstanding segment, see if it is time to resend
\r
1204 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
\r
1206 /* After a packet has been sent for the first time, it will wait
\r
1207 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
\r
1208 each time doubling the time-out */
\r
1209 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1211 if( ulMaxAge > ulAge )
\r
1213 /* A segment must be sent after this amount of msecs */
\r
1214 *pulDelay = ulMaxAge - ulAge;
\r
1221 /* No priority segment, no outstanding data, see if there is new
\r
1222 transmission data. */
\r
1223 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
\r
1225 /* See if it fits in the peer's reception window. */
\r
1226 if( pxSegment == NULL )
\r
1228 xReturn = pdFALSE;
\r
1230 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1232 /* Too many outstanding messages. */
\r
1233 xReturn = pdFALSE;
\r
1235 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1237 /* 'bSendFullSize' is a special optimisation. If true, the
\r
1238 driver will only sent completely filled packets (of MSS
\r
1240 xReturn = pdFALSE;
\r
1252 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1253 /*-----------------------------------------------------------*/
\r
1255 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1257 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1259 TCPSegment_t *pxSegment;
\r
1260 uint32_t ulMaxTime;
\r
1261 uint32_t ulReturn = ~0UL;
\r
1264 /* Fetches data to be sent-out now.
\r
1266 Priority messages: segments with a resend need no check current sliding
\r
1268 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
\r
1269 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
\r
1271 if( pxSegment == NULL )
\r
1273 /* Waiting messages: outstanding messages with a running timer
\r
1274 neither check peer's reception window size because these packets
\r
1275 have been sent earlier. */
\r
1276 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1278 if( pxSegment != NULL )
\r
1280 /* Do check the timing. */
\r
1281 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1283 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
\r
1285 /* A normal (non-fast) retransmission. Move it from the
\r
1286 head of the waiting queue. */
\r
1287 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
\r
1288 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
\r
1290 /* Some detailed logging. */
\r
1291 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1293 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
\r
1294 pxWindow->usPeerPortNumber,
\r
1295 pxWindow->usOurPortNumber,
\r
1296 pxSegment->lDataLength,
\r
1297 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1298 pxSegment->ulSequenceNumber ) );
\r
1299 FreeRTOS_flush_logging( );
\r
1308 if( pxSegment == NULL )
\r
1310 /* New messages: sent-out for the first time. Check current
\r
1311 sliding window size of peer. */
\r
1312 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1314 if( pxSegment == NULL )
\r
1316 /* No segments queued. */
\r
1319 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1321 /* A segment has been queued but the driver waits until it
\r
1322 has a full size of MSS. */
\r
1325 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1327 /* Peer has no more space at this moment. */
\r
1332 /* Move it out of the Tx queue. */
\r
1333 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
\r
1335 /* Don't let pxHeadSegment point to this segment any more,
\r
1336 so no more data will be added. */
\r
1337 if( pxWindow->pxHeadSegment == pxSegment )
\r
1339 pxWindow->pxHeadSegment = NULL;
\r
1342 /* pxWindow->tx.highest registers the highest sequence
\r
1343 number in our transmission window. */
\r
1344 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
\r
1346 /* ...and more detailed logging */
\r
1347 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1349 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1350 pxWindow->usPeerPortNumber,
\r
1351 pxWindow->usOurPortNumber,
\r
1352 pxSegment->lDataLength,
\r
1353 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1355 FreeRTOS_flush_logging( );
\r
1362 /* There is a priority segment. It doesn't need any checking for
\r
1363 space or timeouts. */
\r
1364 if( xTCPWindowLoggingLevel != 0 )
\r
1366 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1367 pxWindow->usPeerPortNumber,
\r
1368 pxWindow->usOurPortNumber,
\r
1369 pxSegment->lDataLength,
\r
1370 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1372 FreeRTOS_flush_logging( );
\r
1376 /* See if it has already been determined to return 0. */
\r
1377 if( ulReturn != 0UL )
\r
1379 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
\r
1381 /* Now that the segment will be transmitted, add it to the tail of
\r
1382 the waiting queue. */
\r
1383 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
\r
1385 /* And mark it as outstanding. */
\r
1386 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1388 /* Administer the transmit count, needed for fast
\r
1389 retransmissions. */
\r
1390 ( pxSegment->u.bits.ucTransmitCount )++;
\r
1392 /* If there have been several retransmissions (4), decrease the
\r
1393 size of the transmission window to at most 2 times MSS. */
\r
1394 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
\r
1396 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
\r
1398 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
\r
1399 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
1400 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
\r
1401 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
\r
1405 /* Clear the transmit timer. */
\r
1406 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1408 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1410 /* Inform the caller where to find the data within the queue. */
\r
1411 *plPosition = pxSegment->lStreamPos;
\r
1413 /* And return the length of the data segment */
\r
1414 ulReturn = ( uint32_t ) pxSegment->lDataLength;
\r
1420 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1421 /*-----------------------------------------------------------*/
\r
1423 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1425 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1427 uint32_t ulBytesConfirmed = 0u;
\r
1428 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
\r
1429 const ListItem_t *pxIterator;
\r
1430 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
\r
1431 BaseType_t xDoUnlink;
\r
1432 TCPSegment_t *pxSegment;
\r
1433 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
\r
1434 may be removed from the transmission queue(s).
\r
1435 All TX segments for which
\r
1436 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
\r
1437 contiguous block. Note that the segments are stored in xTxSegments in a
\r
1438 strict sequential order. */
\r
1440 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
\r
1442 0 < a < 1; usually a = 1/8
\r
1447 RTT is Round Trip Time
\r
1448 SRTT is Smoothed RTT
\r
1449 RTO is Retransmit timeout
\r
1451 A Smoothed RTT will increase quickly, but it is conservative when
\r
1452 becoming smaller. */
\r
1455 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1456 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
\r
1459 xDoUnlink = pdFALSE;
\r
1460 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1462 /* Move to the next item because the current item might get
\r
1464 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1466 /* Continue if this segment does not fall within the ACK'd range. */
\r
1467 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
\r
1472 /* Is it ready? */
\r
1473 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
\r
1478 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1480 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
\r
1482 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
\r
1484 /* What happens? Only part of this segment was accepted,
\r
1485 probably due to WND limits
\r
1487 AAAAAAA BBBBBBB << acked
\r
1488 aaaaaaa aaaa << sent */
\r
1489 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1491 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
\r
1492 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
\r
1493 pxWindow->usPeerPortNumber,
\r
1494 pxWindow->usOurPortNumber,
\r
1495 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
\r
1496 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1497 ulFirstSeq, ulFirstSeq + ulDataLength ) );
\r
1499 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1503 /* This segment is fully ACK'd, set the flag. */
\r
1504 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
\r
1506 /* Calculate the RTT only if the segment was sent-out for the
\r
1507 first time and if this is the last ACK'd segment in a range. */
\r
1508 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
\r
1510 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
\r
1512 if( pxWindow->lSRTT >= mS )
\r
1514 /* RTT becomes smaller: adapt slowly. */
\r
1515 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
\r
1519 /* RTT becomes larger: adapt quicker */
\r
1520 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
\r
1523 /* Cap to the minimum of 50ms. */
\r
1524 if( pxWindow->lSRTT < winSRTT_CAP_mS )
\r
1526 pxWindow->lSRTT = winSRTT_CAP_mS;
\r
1530 /* Unlink it from the 3 queues, but do not destroy it (yet). */
\r
1531 xDoUnlink = pdTRUE;
\r
1534 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
\r
1535 side of the transmission queue? If so, it may be freed. */
\r
1536 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
\r
1538 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1540 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
\r
1541 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1542 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1543 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1546 /* Increase the left-hand value of the transmission window. */
\r
1547 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1549 /* This function will return the number of bytes that the tail
\r
1550 of txStream may be advanced. */
\r
1551 ulBytesConfirmed += ulDataLength;
\r
1553 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
\r
1554 vTCPWindowFree( pxSegment );
\r
1556 /* No need to unlink it any more. */
\r
1557 xDoUnlink = pdFALSE;
\r
1560 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
\r
1562 /* Remove item from its queues. */
\r
1563 uxListRemove( &pxSegment->xQueueItem );
\r
1566 ulSequenceNumber += ulDataLength;
\r
1569 return ulBytesConfirmed;
\r
1571 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1572 /*-----------------------------------------------------------*/
\r
1574 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1576 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
\r
1578 const ListItem_t *pxIterator;
\r
1579 const MiniListItem_t* pxEnd;
\r
1580 TCPSegment_t *pxSegment;
\r
1581 uint32_t ulCount = 0UL;
\r
1583 /* A higher Tx block has been acknowledged. Now iterate through the
\r
1584 xWaitQueue to find a possible condition for a FAST retransmission. */
\r
1586 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
\r
1588 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1589 pxIterator != ( const ListItem_t * ) pxEnd; )
\r
1591 /* Get the owner, which is a TCP segment. */
\r
1592 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1594 /* Hop to the next item before the current gets unlinked. */
\r
1595 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1597 /* Fast retransmission:
\r
1598 When 3 packets with a higher sequence number have been acknowledged
\r
1599 by the peer, it is very unlikely a current packet will ever arrive.
\r
1600 It will be retransmitted far before the RTO. */
\r
1601 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
\r
1602 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
\r
1603 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
\r
1605 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
\r
1607 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
\r
1608 which might lead to a second fast rexmit. */
\r
1609 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1611 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
\r
1612 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1613 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1614 FreeRTOS_flush_logging( );
\r
1617 /* Remove it from xWaitQueue. */
\r
1618 uxListRemove( &pxSegment->xQueueItem );
\r
1620 /* Add this segment to the priority queue so it gets
\r
1621 retransmitted immediately. */
\r
1622 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
\r
1629 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1630 /*-----------------------------------------------------------*/
\r
1632 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1634 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1636 uint32_t ulFirstSequence, ulReturn;
\r
1638 /* Receive a normal ACK. */
\r
1640 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
\r
1642 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
\r
1648 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
\r
1654 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1655 /*-----------------------------------------------------------*/
\r
1657 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1659 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1661 uint32_t ulAckCount = 0UL;
\r
1662 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
\r
1664 /* Receive a SACK option. */
\r
1665 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
\r
1666 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
\r
1668 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
\r
1670 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
\r
1671 pxWindow->usPeerPortNumber,
\r
1672 pxWindow->usOurPortNumber,
\r
1673 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1674 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1675 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1676 FreeRTOS_flush_logging( );
\r
1679 return ulAckCount;
\r
1682 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1683 /*-----------------------------------------------------------*/
\r
1686 ##### # ##### #### ######
\r
1687 # # # # # # # # # # #
\r
1689 # ### ##### # # # # # #
\r
1690 # # # # # # # # #####
\r
1691 # # # # # # #### # # #
\r
1692 # # # # # # # # # #
\r
1693 # # # # #### # # # #
\r
1694 #### ##### # # # #### #### ####
\r
1698 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1700 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
1704 /* Data was received at 'ulSequenceNumber'. See if it was expected
\r
1705 and if there is enough space to store the new data. */
\r
1706 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
\r
1712 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
\r
1719 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1720 /*-----------------------------------------------------------*/
\r
1722 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1724 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1726 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1729 /* Data is being scheduled for transmission. */
\r
1731 /* lMax would indicate the size of the txStream. */
\r
1733 /* This is tiny TCP: there is only 1 segment for outgoing data.
\r
1734 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
\r
1735 if( pxSegment->lDataLength > 0 )
\r
1741 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
\r
1743 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1745 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
\r
1748 ulLength = ( uint32_t ) pxSegment->lMaxLength;
\r
1751 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1753 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
\r
1754 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1755 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1759 /* The sequence number of the first byte in this packet. */
\r
1760 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
\r
1761 pxSegment->lDataLength = ( int32_t ) ulLength;
\r
1762 pxSegment->lStreamPos = lPosition;
\r
1763 pxSegment->u.ulFlags = 0UL;
\r
1764 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1766 /* Increase the sequence number of the next data to be stored for
\r
1768 pxWindow->ulNextTxSequenceNumber += ulLength;
\r
1769 lResult = ( int32_t )ulLength;
\r
1775 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1776 /*-----------------------------------------------------------*/
\r
1778 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1780 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1782 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1783 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
\r
1784 uint32_t ulMaxTime;
\r
1786 if( ulLength != 0UL )
\r
1788 /* _HT_ Still under investigation */
\r
1789 ( void ) ulWindowSize;
\r
1791 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1793 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
\r
1794 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1796 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
\r
1802 if( ulLength != 0ul )
\r
1804 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1805 pxSegment->u.bits.ucTransmitCount++;
\r
1806 vTCPTimerSet (&pxSegment->xTransmitTimer);
\r
1807 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1808 *plPosition = pxSegment->lStreamPos;
\r
1815 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1816 /*-----------------------------------------------------------*/
\r
1818 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1820 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1822 BaseType_t xReturn;
\r
1824 /* Has the outstanding data been sent because user wants to shutdown? */
\r
1825 if( pxWindow->xTxSegment.lDataLength == 0 )
\r
1831 xReturn = pdFALSE;
\r
1837 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1838 /*-----------------------------------------------------------*/
\r
1840 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1842 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
1843 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1845 BaseType_t xReturn;
\r
1847 if( ulWindowSize >= pxWindow->usMSSInit )
\r
1853 xReturn = pdFALSE;
\r
1859 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1860 /*-----------------------------------------------------------*/
\r
1862 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1864 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1866 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1867 BaseType_t xReturn;
\r
1868 TickType_t ulAge, ulMaxAge;
\r
1870 /* Check data to be sent. */
\r
1871 *pulDelay = ( TickType_t ) 0;
\r
1872 if( pxSegment->lDataLength == 0 )
\r
1874 /* Got nothing to send right now. */
\r
1875 xReturn = pdFALSE;
\r
1879 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1881 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
\r
1882 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1884 if( ulMaxAge > ulAge )
\r
1886 *pulDelay = ulMaxAge - ulAge;
\r
1891 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1893 /* Too many outstanding messages. */
\r
1894 xReturn = pdFALSE;
\r
1905 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1906 /*-----------------------------------------------------------*/
\r
1908 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1910 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1912 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1913 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1915 /* Receive a normal ACK */
\r
1917 if( ulDataLength != 0ul )
\r
1919 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
\r
1921 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
\r
1923 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
\r
1924 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1925 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1929 /* Nothing to send right now. */
\r
1930 ulDataLength = 0ul;
\r
1934 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1936 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1938 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
\r
1939 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1943 pxSegment->lDataLength = 0;
\r
1947 return ulDataLength;
\r
1950 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1951 /*-----------------------------------------------------------*/
\r
1953 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1955 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
1957 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
\r
1958 'ulCurrentSequenceNumber' is the highest sequence number stored,
\r
1959 'ulHighestSequenceNumber' is the highest sequence number seen. */
\r
1960 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
\r
1963 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1964 /*-----------------------------------------------------------*/
\r
1966 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1968 /* Destroy a window (always returns NULL) */
\r
1969 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
1971 /* As in tiny TCP there are no shared segments descriptors, there is
\r
1972 nothing to release. */
\r
1973 ( void ) pxWindow;
\r
1976 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1977 /*-----------------------------------------------------------*/
\r