2 * FreeRTOS+TCP V2.0.0
\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. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
30 * FreeRTOS_TCP_WIN.c
\r
31 * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
\r
32 * functions have two versions - one for FreeRTOS+TCP (full) and one for
\r
33 * FreeRTOS+TCP (lite).
\r
35 * In this module all ports and IP addresses and sequence numbers are
\r
36 * being stored in host byte-order.
\r
39 /* Standard includes. */
\r
42 /* FreeRTOS includes. */
\r
43 #include "FreeRTOS.h"
\r
48 /* FreeRTOS+TCP includes. */
\r
49 #include "FreeRTOS_UDP_IP.h"
\r
50 #include "FreeRTOS_IP.h"
\r
51 #include "FreeRTOS_Sockets.h"
\r
52 #include "FreeRTOS_IP_Private.h"
\r
53 #include "NetworkBufferManagement.h"
\r
54 #include "FreeRTOS_TCP_WIN.h"
\r
56 /* Constants used for Smoothed Round Trip Time (SRTT). */
\r
57 #define winSRTT_INCREMENT_NEW 2
\r
58 #define winSRTT_INCREMENT_CURRENT 6
\r
59 #define winSRTT_DECREMENT_NEW 1
\r
60 #define winSRTT_DECREMENT_CURRENT 7
\r
61 #define winSRTT_CAP_mS 50
\r
63 #if( ipconfigUSE_TCP_WIN == 1 )
\r
65 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
\r
67 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
\r
69 /* The code to send a single Selective ACK (SACK):
\r
70 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
\r
71 * followed by a lower and a higher sequence number,
\r
72 * where LEN is 2 + 2*4 = 10 bytes. */
\r
73 #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
\r
74 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
\r
76 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
\r
79 /* Normal retransmission:
\r
80 * A packet will be retransmitted after a Retransmit Time-Out (RTO).
\r
81 * Fast retransmission:
\r
82 * When 3 packets with a higher sequence number have been acknowledged
\r
83 * by the peer, it is very unlikely a current packet will ever arrive.
\r
84 * It will be retransmitted far before the RTO.
\r
86 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
\r
88 /* If there have been several retransmissions (4), decrease the
\r
89 * size of the transmission window to at most 2 times MSS.
\r
91 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
\r
93 #endif /* configUSE_TCP_WIN */
\r
94 /*-----------------------------------------------------------*/
\r
96 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
99 * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
\r
100 * Available descriptors are stored in the 'xSegmentList'
\r
101 * When a socket owns a descriptor, it will either be stored in
\r
102 * 'xTxSegments' or 'xRxSegments'
\r
103 * As soon as a package has been confirmed, the descriptor will be returned
\r
104 * to the segment pool
\r
106 #if( ipconfigUSE_TCP_WIN == 1 )
\r
107 static BaseType_t prvCreateSectors( void );
\r
108 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
111 * Find a segment with a given sequence number in the list of received
\r
112 * segments: 'pxWindow->xRxSegments'.
\r
114 #if( ipconfigUSE_TCP_WIN == 1 )
\r
115 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
\r
116 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
119 * Allocate a new segment
\r
120 * The socket will borrow all segments from a common pool: 'xSegmentList',
\r
121 * which is a list of 'TCPSegment_t'
\r
123 #if( ipconfigUSE_TCP_WIN == 1 )
\r
124 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
\r
125 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
127 /* When the peer has a close request (FIN flag), the driver will check if
\r
128 * there are missing packets in the Rx-queue
\r
129 * It will accept the closure of the connection if both conditions are true:
\r
130 * - the Rx-queue is empty
\r
131 * - we've ACK'd the highest Rx sequence number seen
\r
133 #if( ipconfigUSE_TCP_WIN == 1 )
\r
134 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
\r
135 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
138 * Detaches and returns the head of a queue
\r
140 #if( ipconfigUSE_TCP_WIN == 1 )
\r
141 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
\r
142 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
145 * Returns the head of a queue but it won't be detached
\r
147 #if( ipconfigUSE_TCP_WIN == 1 )
\r
148 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
\r
149 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
152 * Free entry pxSegment because it's not used anymore
\r
153 * The ownership will be passed back to the segment pool
\r
155 #if( ipconfigUSE_TCP_WIN == 1 )
\r
156 static void vTCPWindowFree( TCPSegment_t *pxSegment );
\r
157 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
160 * A segment has been received with sequence number 'ulSequenceNumber', where
\r
161 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
\r
162 * segment was expected. xTCPWindowRxConfirm() will check if there is already
\r
163 * another segment with a sequence number between (ulSequenceNumber) and
\r
164 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
\r
165 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
\r
167 #if( ipconfigUSE_TCP_WIN == 1 )
\r
168 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
\r
169 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
172 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
\r
175 #if( ipconfigUSE_TCP_WIN == 1 )
\r
176 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
\r
177 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
180 * This function will look if there is new transmission data. It will return
\r
181 * true if there is data to be sent.
\r
183 #if( ipconfigUSE_TCP_WIN == 1 )
\r
184 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
185 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
188 * An acknowledge was received. See if some outstanding data may be removed
\r
189 * from the transmission queue(s).
\r
191 #if( ipconfigUSE_TCP_WIN == 1 )
\r
192 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
\r
193 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
196 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
\r
197 * to find a possible condition for a FAST retransmission.
\r
199 #if( ipconfigUSE_TCP_WIN == 1 )
\r
200 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
\r
201 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
203 /*-----------------------------------------------------------*/
\r
205 /* TCP segement pool. */
\r
206 #if( ipconfigUSE_TCP_WIN == 1 )
\r
207 static TCPSegment_t *xTCPSegments = NULL;
\r
208 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
210 /* List of free TCP segments. */
\r
211 #if( ipconfigUSE_TCP_WIN == 1 )
\r
212 static List_t xSegmentList;
\r
215 /* Logging verbosity level. */
\r
216 BaseType_t xTCPWindowLoggingLevel = 0;
\r
218 #if( ipconfigUSE_TCP_WIN == 1 )
\r
219 /* Some 32-bit arithmetic: comparing sequence numbers */
\r
220 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
\r
221 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
\r
224 Return true if the unsigned subtraction of (b-a) doesn't generate an
\r
225 arithmetic overflow. */
\r
226 return ( ( b - a ) & 0x80000000UL ) == 0UL;
\r
228 #endif /* ipconfigUSE_TCP_WIN */
\r
229 /*-----------------------------------------------------------*/
\r
231 #if( ipconfigUSE_TCP_WIN == 1 )
\r
232 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
\r
233 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
\r
235 /* Test if a < b */
\r
236 return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
\r
238 #endif /* ipconfigUSE_TCP_WIN */
\r
239 /*-----------------------------------------------------------*/
\r
241 #if( ipconfigUSE_TCP_WIN == 1 )
\r
242 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
\r
243 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
\r
245 /* Test if a > b */
\r
246 return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
\r
248 #endif /* ipconfigUSE_TCP_WIN */
\r
250 /*-----------------------------------------------------------*/
\r
251 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
\r
252 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
\r
254 /* Test if a >= b */
\r
255 return ( ( a - b ) & 0x80000000UL ) == 0UL;
\r
257 /*-----------------------------------------------------------*/
\r
259 #if( ipconfigUSE_TCP_WIN == 1 )
\r
260 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
\r
261 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
\r
263 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
\r
266 /*-----------------------------------------------------------*/
\r
268 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
\r
269 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
\r
271 pxTimer->ulBorn = xTaskGetTickCount ( );
\r
273 /*-----------------------------------------------------------*/
\r
275 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
\r
276 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
\r
278 return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
\r
280 /*-----------------------------------------------------------*/
\r
282 /* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
\r
283 preceded by a prototype. Later this prototype will be located in list.h? */
\r
285 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
287 void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
\r
289 /* Insert a new list item into pxList, it does not sort the list,
\r
290 but it puts the item just before xListEnd, so it will be the last item
\r
291 returned by listGET_HEAD_ENTRY() */
\r
292 pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
\r
293 pxNewListItem->pxPrevious = pxWhere->pxPrevious;
\r
294 pxWhere->pxPrevious->pxNext = pxNewListItem;
\r
295 pxWhere->pxPrevious = pxNewListItem;
\r
297 /* Remember which list the item is in. */
\r
298 pxNewListItem->pvContainer = ( void * ) pxList;
\r
300 ( pxList->uxNumberOfItems )++;
\r
302 /*-----------------------------------------------------------*/
\r
304 #if( ipconfigUSE_TCP_WIN == 1 )
\r
306 static BaseType_t prvCreateSectors( void )
\r
308 BaseType_t xIndex, xReturn;
\r
310 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
\r
312 vListInitialise( &xSegmentList );
\r
313 xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
315 if( xTCPSegments == NULL )
\r
317 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
\r
318 ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
\r
324 /* Clear the allocated space. */
\r
325 memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
327 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
\r
329 /* Could call vListInitialiseItem here but all data has been
\r
330 nulled already. Set the owner to a segment descriptor. */
\r
331 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
332 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
334 /* And add it to the pool of available segments */
\r
335 vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
\r
344 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
345 /*-----------------------------------------------------------*/
\r
347 #if( ipconfigUSE_TCP_WIN == 1 )
\r
349 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
351 const ListItem_t *pxIterator;
\r
352 const MiniListItem_t* pxEnd;
\r
353 TCPSegment_t *pxSegment, *pxReturn = NULL;
\r
355 /* Find a segment with a given sequence number in the list of received
\r
358 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
\r
360 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
361 pxIterator != ( const ListItem_t * ) pxEnd;
\r
362 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
364 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
366 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
\r
368 pxReturn = pxSegment;
\r
376 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
377 /*-----------------------------------------------------------*/
\r
379 #if( ipconfigUSE_TCP_WIN == 1 )
\r
381 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
\r
383 TCPSegment_t *pxSegment;
\r
384 ListItem_t * pxItem;
\r
386 /* Allocate a new segment. The socket will borrow all segments from a
\r
387 common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
\r
388 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
\r
390 /* If the TCP-stack runs out of segments, you might consider
\r
391 increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
\r
392 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
\r
397 /* Pop the item at the head of the list. Semaphore protection is
\r
398 not required as only the IP task will call these functions. */
\r
399 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
\r
400 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
402 configASSERT( pxItem != NULL );
\r
403 configASSERT( pxSegment != NULL );
\r
405 /* Remove the item from xSegmentList. */
\r
406 uxListRemove( pxItem );
\r
408 /* Add it to either the connections' Rx or Tx queue. */
\r
409 vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
\r
411 /* And set the segment's timer to zero */
\r
412 vTCPTimerSet( &pxSegment->xTransmitTimer );
\r
414 pxSegment->u.ulFlags = 0;
\r
415 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
\r
416 pxSegment->lMaxLength = lCount;
\r
417 pxSegment->lDataLength = lCount;
\r
418 pxSegment->ulSequenceNumber = ulSequenceNumber;
\r
419 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
421 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
\r
422 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
\r
424 if( xLowestLength > xLength )
\r
426 xLowestLength = xLength;
\r
429 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
435 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
436 /*-----------------------------------------------------------*/
\r
438 #if( ipconfigUSE_TCP_WIN == 1 )
\r
440 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
442 BaseType_t xReturn;
\r
444 /* When the peer has a close request (FIN flag), the driver will check
\r
445 if there are missing packets in the Rx-queue. It will accept the
\r
446 closure of the connection if both conditions are true:
\r
447 - the Rx-queue is empty
\r
448 - the highest Rx sequence number has been ACK'ed */
\r
449 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
\r
451 /* Rx data has been stored while earlier packets were missing. */
\r
454 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
\r
456 /* No Rx packets are being stored and the highest sequence number
\r
457 that has been received has been ACKed. */
\r
462 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
\r
463 ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
\r
464 ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
\r
471 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
472 /*-----------------------------------------------------------*/
\r
474 #if( ipconfigUSE_TCP_WIN == 1 )
\r
476 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
\r
478 TCPSegment_t *pxSegment;
\r
479 ListItem_t * pxItem;
\r
481 /* Detaches and returns the head of a queue. */
\r
482 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
488 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
489 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
491 uxListRemove( pxItem );
\r
497 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
498 /*-----------------------------------------------------------*/
\r
500 #if( ipconfigUSE_TCP_WIN == 1 )
\r
502 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
\r
504 ListItem_t *pxItem;
\r
505 TCPSegment_t *pxReturn;
\r
507 /* Returns the head of a queue but it won't be detached. */
\r
508 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
514 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
515 pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
521 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
522 /*-----------------------------------------------------------*/
\r
524 #if( ipconfigUSE_TCP_WIN == 1 )
\r
526 static void vTCPWindowFree( TCPSegment_t *pxSegment )
\r
528 /* Free entry pxSegment because it's not used any more. The ownership
\r
529 will be passed back to the segment pool.
\r
531 Unlink it from one of the queues, if any. */
\r
532 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
\r
534 uxListRemove( &( pxSegment->xQueueItem ) );
\r
537 pxSegment->ulSequenceNumber = 0u;
\r
538 pxSegment->lDataLength = 0l;
\r
539 pxSegment->u.ulFlags = 0u;
\r
541 /* Take it out of xRxSegments/xTxSegments */
\r
542 if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
\r
544 uxListRemove( &( pxSegment->xListItem ) );
\r
547 /* Return it to xSegmentList */
\r
548 vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
\r
551 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
552 /*-----------------------------------------------------------*/
\r
554 #if( ipconfigUSE_TCP_WIN == 1 )
\r
556 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
558 List_t * pxSegments;
\r
560 TCPSegment_t *pxSegment;
\r
562 /* Destroy a window. A TCP window doesn't serve any more. Return all
\r
563 owned segments to the pool. In order to save code, it will make 2 rounds,
\r
564 one to remove the segments from xRxSegments, and a second round to clear
\r
566 for( xRound = 0; xRound < 2; xRound++ )
\r
570 pxSegments = &( pxWindow->xRxSegments );
\r
574 pxSegments = &( pxWindow->xTxSegments );
\r
577 if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
\r
579 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
\r
581 pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
\r
582 vTCPWindowFree( pxSegment );
\r
588 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
589 /*-----------------------------------------------------------*/
\r
591 void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
\r
592 uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
594 /* Create and initialize a window. */
\r
596 #if( ipconfigUSE_TCP_WIN == 1 )
\r
598 if( xTCPSegments == NULL )
\r
600 prvCreateSectors();
\r
603 vListInitialise( &( pxWindow->xTxSegments ) );
\r
604 vListInitialise( &( pxWindow->xRxSegments ) );
\r
606 vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
\r
607 vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */
\r
608 vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */
\r
610 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
612 if( xTCPWindowLoggingLevel != 0 )
\r
614 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
\r
615 ulRxWindowLength, ulTxWindowLength ) );
\r
618 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
\r
619 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
\r
621 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
\r
623 /*-----------------------------------------------------------*/
\r
625 void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
627 const int32_t l500ms = 500;
\r
629 pxWindow->u.ulFlags = 0ul;
\r
630 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
\r
634 if( pxWindow->usMSSInit != 0u )
\r
636 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
\r
639 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
\r
641 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
\r
642 pxWindow->usMSS = ( uint16_t ) ulMSS;
\r
646 #if( ipconfigUSE_TCP_WIN == 0 )
\r
648 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
\r
650 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
652 /*Start with a timeout of 2 * 500 ms (1 sec). */
\r
653 pxWindow->lSRTT = l500ms;
\r
655 /* Just for logging, to print relative sequence numbers. */
\r
656 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
\r
658 /* The segment asked for in the next transmission. */
\r
659 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
\r
661 /* The right-hand side of the receive window. */
\r
662 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
\r
664 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
\r
666 /* The segment asked for in next transmission. */
\r
667 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
669 /* The sequence number given to the next outgoing byte to be added is
\r
670 maintained by lTCPWindowTxAdd(). */
\r
671 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
\r
673 /* The right-hand side of the transmit window. */
\r
674 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
\r
675 pxWindow->ulOurSequenceNumber = ulSequenceNumber;
\r
677 /*-----------------------------------------------------------*/
\r
679 /*=============================================================================
\r
692 *=============================================================================*/
\r
694 #if( ipconfigUSE_TCP_WIN == 1 )
\r
696 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
\r
698 TCPSegment_t *pxBest = NULL;
\r
699 const ListItem_t *pxIterator;
\r
700 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
\r
701 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
\r
702 TCPSegment_t *pxSegment;
\r
704 /* A segment has been received with sequence number 'ulSequenceNumber',
\r
705 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
\r
706 exactly this segment was expected. xTCPWindowRxConfirm() will check if
\r
707 there is already another segment with a sequence number between (ulSequenceNumber)
\r
708 and (ulSequenceNumber+ulLength). Normally none will be found, because
\r
709 the next RX segment should have a sequence number equal to
\r
710 '(ulSequenceNumber+ulLength)'. */
\r
712 /* Iterate through all RX segments that are stored: */
\r
713 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
714 pxIterator != ( const ListItem_t * ) pxEnd;
\r
715 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
717 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
718 /* And see if there is a segment for which:
\r
719 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
\r
720 If there are more matching segments, the one with the lowest sequence number
\r
722 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
\r
723 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
\r
725 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
\r
727 pxBest = pxSegment;
\r
732 if( ( pxBest != NULL ) &&
\r
733 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
\r
735 FreeRTOS_flush_logging();
\r
736 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
\r
737 pxWindow->usPeerPortNumber,
\r
738 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
740 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
\r
741 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
742 pxBest->lDataLength,
\r
743 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
\r
749 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
750 /*-----------------------------------------------------------*/
\r
752 #if( ipconfigUSE_TCP_WIN == 1 )
\r
754 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
756 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
\r
757 int32_t lReturn, lDistance;
\r
758 TCPSegment_t *pxFound;
\r
760 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
\r
761 directly to user (segment is expected). If it returns a positive
\r
762 number, an earlier packet is missing, but this packet may be stored.
\r
763 If negative, the packet has already been stored, or it is out-of-order,
\r
764 or there is not enough space.
\r
766 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
\r
767 if more Rx data may be passed to the user after this packet. */
\r
769 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
\r
771 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
\r
772 pxWindow->ucOptionLength = 0u;
\r
774 /* Non-zero if TCP-windows contains data which must be popped. */
\r
775 pxWindow->ulUserDataLength = 0ul;
\r
777 if( ulCurrentSequenceNumber == ulSequenceNumber )
\r
779 /* This is the packet with the lowest sequence number we're waiting
\r
780 for. It can be passed directly to the rx stream. */
\r
781 if( ulLength > ulSpace )
\r
783 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
\r
788 ulCurrentSequenceNumber += ulLength;
\r
790 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
\r
792 ulSavedSequenceNumber = ulCurrentSequenceNumber;
\r
794 /* See if (part of) this segment has been stored already,
\r
795 but this rarely happens. */
\r
796 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
\r
797 if( pxFound != NULL )
\r
799 ulCurrentSequenceNumber = pxFound->ulSequenceNumber + ( ( uint32_t ) pxFound->lDataLength );
\r
801 /* Remove it because it will be passed to user directly. */
\r
802 vTCPWindowFree( pxFound );
\r
805 /* Check for following segments that are already in the
\r
806 queue and increment ulCurrentSequenceNumber. */
\r
807 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
\r
809 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
\r
811 /* As all packet below this one have been passed to the
\r
812 user it can be discarded. */
\r
813 vTCPWindowFree( pxFound );
\r
816 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
\r
818 /* After the current data-package, there is more data
\r
820 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
\r
822 if( xTCPWindowLoggingLevel >= 1 )
\r
824 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
\r
825 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
826 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
827 pxWindow->ulUserDataLength,
\r
828 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
829 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
834 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
\r
836 /* Packet was expected, may be passed directly to the socket
\r
837 buffer or application. Store the packet at offset 0. */
\r
841 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
\r
843 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
\r
844 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
\r
849 /* The packet is not the one expected. See if it falls within the Rx
\r
850 window so it can be stored. */
\r
852 /* An "out-of-sequence" segment was received, must have missed one.
\r
853 Prepare a SACK (Selective ACK). */
\r
854 ulLast = ulSequenceNumber + ulLength;
\r
855 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
\r
857 if( lDistance <= 0 )
\r
859 /* An earlier has been received, must be a retransmission of a
\r
860 packet that has been accepted already. No need to send out a
\r
861 Selective ACK (SACK). */
\r
864 else if( lDistance > ( int32_t ) ulSpace )
\r
866 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
\r
867 sequence number of this packet is too far ahead, ignore it. */
\r
868 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
\r
873 /* See if there is more data in a contiguous block to make the
\r
874 SACK describe a longer range of data. */
\r
876 /* TODO: SACK's may also be delayed for a short period
\r
877 * This is useful because subsequent packets will be SACK'd with
\r
878 * single one message
\r
880 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
\r
882 ulLast += ( uint32_t ) pxFound->lDataLength;
\r
885 if( xTCPWindowLoggingLevel >= 1 )
\r
887 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
\r
888 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
889 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
890 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
891 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
\r
892 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
\r
895 /* Now prepare the SACK message.
\r
896 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
\r
897 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
\r
899 /* First sequence number that we received. */
\r
900 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
\r
903 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
\r
905 /* Which make 12 (3*4) option bytes. */
\r
906 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
\r
908 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
\r
910 if( pxFound != NULL )
\r
912 /* This out-of-sequence packet has been received for a
\r
913 second time. It is already stored but do send a SACK
\r
919 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
\r
921 if( pxFound == NULL )
\r
923 /* Can not send a SACK, because the segment cannot be
\r
925 pxWindow->ucOptionLength = 0u;
\r
927 /* Needs to be stored but there is no segment
\r
933 if( xTCPWindowLoggingLevel != 0 )
\r
935 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
\r
936 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
937 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
938 FreeRTOS_flush_logging( );
\r
941 /* Return a positive value. The packet may be accepted
\r
942 and stored but an earlier packet is still missing. */
\r
943 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
\r
952 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
953 /*-----------------------------------------------------------*/
\r
955 /*=============================================================================
\r
969 *=============================================================================*/
\r
971 #if( ipconfigUSE_TCP_WIN == 1 )
\r
973 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
\r
975 /* +TCP stores data in circular buffers. Calculate the next position to
\r
977 lPosition += lCount;
\r
978 if( lPosition >= lMax )
\r
986 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
987 /*-----------------------------------------------------------*/
\r
989 #if( ipconfigUSE_TCP_WIN == 1 )
\r
991 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
993 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
\r
995 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
\r
997 /* Puts a message in the Tx-window (after buffer size has been
\r
999 if( pxSegment != NULL )
\r
1001 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1003 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
\r
1005 /* Adding data to a segment that was already in the TX queue. It
\r
1006 will be filled-up to a maximum of MSS (maximum segment size). */
\r
1007 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
\r
1009 pxSegment->lDataLength += lToWrite;
\r
1011 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
\r
1013 /* This segment is full, don't add more bytes. */
\r
1014 pxWindow->pxHeadSegment = NULL;
\r
1017 lBytesLeft -= lToWrite;
\r
1019 /* ulNextTxSequenceNumber is the sequence number of the next byte to
\r
1020 be stored for transmission. */
\r
1021 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1023 /* Increased the return value. */
\r
1024 lDone += lToWrite;
\r
1026 /* Some detailed logging, for those who're interested. */
\r
1027 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1029 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1031 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1032 pxSegment->lDataLength,
\r
1033 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1034 pxSegment->lStreamPos ) );
\r
1035 FreeRTOS_flush_logging( );
\r
1038 /* Calculate the next position in the circular data buffer, knowing
\r
1039 its maximum length 'lMax'. */
\r
1040 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1045 while( lBytesLeft > 0 )
\r
1047 /* The current transmission segment is full, create new segments as
\r
1049 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
\r
1051 if( pxSegment != NULL )
\r
1053 /* Store as many as needed, but no more than the maximum
\r
1055 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
\r
1057 pxSegment->lDataLength = lToWrite;
\r
1058 pxSegment->lStreamPos = lPosition;
\r
1059 lBytesLeft -= lToWrite;
\r
1060 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1061 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1062 lDone += lToWrite;
\r
1064 /* Link this segment in the Tx-Queue. */
\r
1065 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
\r
1067 /* Let 'pxHeadSegment' point to this segment if there is still
\r
1069 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1071 pxWindow->pxHeadSegment = pxSegment;
\r
1075 pxWindow->pxHeadSegment = NULL;
\r
1078 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
\r
1080 if( ( xTCPWindowLoggingLevel >= 3 ) ||
\r
1081 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
\r
1083 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1085 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1086 pxSegment->lDataLength,
\r
1087 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1088 pxSegment->lStreamPos ) );
\r
1089 FreeRTOS_flush_logging( );
\r
1095 /* A sever situation: running out of segments for transmission.
\r
1096 No more data can be sent at the moment. */
\r
1099 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
\r
1108 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1109 /*-----------------------------------------------------------*/
\r
1111 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1113 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1115 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
\r
1118 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1119 /*-----------------------------------------------------------*/
\r
1121 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1123 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1125 uint32_t ulTxOutstanding;
\r
1126 BaseType_t xHasSpace;
\r
1127 TCPSegment_t *pxSegment;
\r
1129 /* This function will look if there is new transmission data. It will
\r
1130 return true if there is data to be sent. */
\r
1132 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1134 if( pxSegment == NULL )
\r
1136 xHasSpace = pdFALSE;
\r
1140 /* How much data is outstanding, i.e. how much data has been sent
\r
1141 but not yet acknowledged ? */
\r
1142 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
\r
1144 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
\r
1148 ulTxOutstanding = 0UL;
\r
1151 /* Subtract this from the peer's space. */
\r
1152 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
\r
1154 /* See if the next segment may be sent. */
\r
1155 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
\r
1157 xHasSpace = pdTRUE;
\r
1161 xHasSpace = pdFALSE;
\r
1164 /* If 'xHasSpace', it looks like the peer has at least space for 1
\r
1165 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
\r
1166 limitation of the transmission window (in case of many resends it
\r
1167 may be decreased). */
\r
1168 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
\r
1170 xHasSpace = pdFALSE;
\r
1177 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1178 /*-----------------------------------------------------------*/
\r
1180 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1182 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1184 TCPSegment_t *pxSegment;
\r
1185 BaseType_t xReturn;
\r
1186 TickType_t ulAge, ulMaxAge;
\r
1190 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
\r
1192 /* No need to look at retransmissions or new transmission as long as
\r
1193 there are priority segments. *pulDelay equals zero, meaning it must
\r
1194 be sent out immediately. */
\r
1199 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1201 if( pxSegment != NULL )
\r
1203 /* There is an outstanding segment, see if it is time to resend
\r
1205 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
\r
1207 /* After a packet has been sent for the first time, it will wait
\r
1208 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
\r
1209 each time doubling the time-out */
\r
1210 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1212 if( ulMaxAge > ulAge )
\r
1214 /* A segment must be sent after this amount of msecs */
\r
1215 *pulDelay = ulMaxAge - ulAge;
\r
1222 /* No priority segment, no outstanding data, see if there is new
\r
1223 transmission data. */
\r
1224 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
\r
1226 /* See if it fits in the peer's reception window. */
\r
1227 if( pxSegment == NULL )
\r
1229 xReturn = pdFALSE;
\r
1231 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1233 /* Too many outstanding messages. */
\r
1234 xReturn = pdFALSE;
\r
1236 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1238 /* 'bSendFullSize' is a special optimisation. If true, the
\r
1239 driver will only sent completely filled packets (of MSS
\r
1241 xReturn = pdFALSE;
\r
1253 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1254 /*-----------------------------------------------------------*/
\r
1256 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1258 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1260 TCPSegment_t *pxSegment;
\r
1261 uint32_t ulMaxTime;
\r
1262 uint32_t ulReturn = ~0UL;
\r
1265 /* Fetches data to be sent-out now.
\r
1267 Priority messages: segments with a resend need no check current sliding
\r
1269 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
\r
1270 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
\r
1272 if( pxSegment == NULL )
\r
1274 /* Waiting messages: outstanding messages with a running timer
\r
1275 neither check peer's reception window size because these packets
\r
1276 have been sent earlier. */
\r
1277 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1279 if( pxSegment != NULL )
\r
1281 /* Do check the timing. */
\r
1282 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1284 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
\r
1286 /* A normal (non-fast) retransmission. Move it from the
\r
1287 head of the waiting queue. */
\r
1288 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
\r
1289 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
\r
1291 /* Some detailed logging. */
\r
1292 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1294 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
\r
1295 pxWindow->usPeerPortNumber,
\r
1296 pxWindow->usOurPortNumber,
\r
1297 pxSegment->lDataLength,
\r
1298 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1299 pxSegment->ulSequenceNumber ) );
\r
1300 FreeRTOS_flush_logging( );
\r
1309 if( pxSegment == NULL )
\r
1311 /* New messages: sent-out for the first time. Check current
\r
1312 sliding window size of peer. */
\r
1313 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1315 if( pxSegment == NULL )
\r
1317 /* No segments queued. */
\r
1320 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1322 /* A segment has been queued but the driver waits until it
\r
1323 has a full size of MSS. */
\r
1326 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1328 /* Peer has no more space at this moment. */
\r
1333 /* Move it out of the Tx queue. */
\r
1334 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
\r
1336 /* Don't let pxHeadSegment point to this segment any more,
\r
1337 so no more data will be added. */
\r
1338 if( pxWindow->pxHeadSegment == pxSegment )
\r
1340 pxWindow->pxHeadSegment = NULL;
\r
1343 /* pxWindow->tx.highest registers the highest sequence
\r
1344 number in our transmission window. */
\r
1345 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
\r
1347 /* ...and more detailed logging */
\r
1348 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1350 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1351 pxWindow->usPeerPortNumber,
\r
1352 pxWindow->usOurPortNumber,
\r
1353 pxSegment->lDataLength,
\r
1354 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1356 FreeRTOS_flush_logging( );
\r
1363 /* There is a priority segment. It doesn't need any checking for
\r
1364 space or timeouts. */
\r
1365 if( xTCPWindowLoggingLevel != 0 )
\r
1367 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1368 pxWindow->usPeerPortNumber,
\r
1369 pxWindow->usOurPortNumber,
\r
1370 pxSegment->lDataLength,
\r
1371 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1373 FreeRTOS_flush_logging( );
\r
1377 /* See if it has already been determined to return 0. */
\r
1378 if( ulReturn != 0UL )
\r
1380 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
\r
1382 /* Now that the segment will be transmitted, add it to the tail of
\r
1383 the waiting queue. */
\r
1384 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
\r
1386 /* And mark it as outstanding. */
\r
1387 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1389 /* Administer the transmit count, needed for fast
\r
1390 retransmissions. */
\r
1391 ( pxSegment->u.bits.ucTransmitCount )++;
\r
1393 /* If there have been several retransmissions (4), decrease the
\r
1394 size of the transmission window to at most 2 times MSS. */
\r
1395 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
\r
1397 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
\r
1399 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
\r
1400 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
1401 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
\r
1402 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
\r
1406 /* Clear the transmit timer. */
\r
1407 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1409 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1411 /* Inform the caller where to find the data within the queue. */
\r
1412 *plPosition = pxSegment->lStreamPos;
\r
1414 /* And return the length of the data segment */
\r
1415 ulReturn = ( uint32_t ) pxSegment->lDataLength;
\r
1421 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1422 /*-----------------------------------------------------------*/
\r
1424 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1426 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1428 uint32_t ulBytesConfirmed = 0u;
\r
1429 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
\r
1430 const ListItem_t *pxIterator;
\r
1431 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
\r
1432 BaseType_t xDoUnlink;
\r
1433 TCPSegment_t *pxSegment;
\r
1434 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
\r
1435 may be removed from the transmission queue(s).
\r
1436 All TX segments for which
\r
1437 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
\r
1438 contiguous block. Note that the segments are stored in xTxSegments in a
\r
1439 strict sequential order. */
\r
1441 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
\r
1443 0 < a < 1; usually a = 1/8
\r
1448 RTT is Round Trip Time
\r
1449 SRTT is Smoothed RTT
\r
1450 RTO is Retransmit timeout
\r
1452 A Smoothed RTT will increase quickly, but it is conservative when
\r
1453 becoming smaller. */
\r
1456 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1457 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
\r
1460 xDoUnlink = pdFALSE;
\r
1461 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1463 /* Move to the next item because the current item might get
\r
1465 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1467 /* Continue if this segment does not fall within the ACK'd range. */
\r
1468 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
\r
1473 /* Is it ready? */
\r
1474 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
\r
1479 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1481 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
\r
1483 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
\r
1485 /* What happens? Only part of this segment was accepted,
\r
1486 probably due to WND limits
\r
1488 AAAAAAA BBBBBBB << acked
\r
1489 aaaaaaa aaaa << sent */
\r
1490 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1492 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
\r
1493 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
\r
1494 pxWindow->usPeerPortNumber,
\r
1495 pxWindow->usOurPortNumber,
\r
1496 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
\r
1497 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1498 ulFirstSeq, ulFirstSeq + ulDataLength ) );
\r
1500 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1504 /* This segment is fully ACK'd, set the flag. */
\r
1505 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
\r
1507 /* Calculate the RTT only if the segment was sent-out for the
\r
1508 first time and if this is the last ACK'd segment in a range. */
\r
1509 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
\r
1511 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
\r
1513 if( pxWindow->lSRTT >= mS )
\r
1515 /* RTT becomes smaller: adapt slowly. */
\r
1516 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
\r
1520 /* RTT becomes larger: adapt quicker */
\r
1521 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
\r
1524 /* Cap to the minimum of 50ms. */
\r
1525 if( pxWindow->lSRTT < winSRTT_CAP_mS )
\r
1527 pxWindow->lSRTT = winSRTT_CAP_mS;
\r
1531 /* Unlink it from the 3 queues, but do not destroy it (yet). */
\r
1532 xDoUnlink = pdTRUE;
\r
1535 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
\r
1536 side of the transmission queue? If so, it may be freed. */
\r
1537 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
\r
1539 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1541 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
\r
1542 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1543 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1544 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1547 /* Increase the left-hand value of the transmission window. */
\r
1548 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1550 /* This function will return the number of bytes that the tail
\r
1551 of txStream may be advanced. */
\r
1552 ulBytesConfirmed += ulDataLength;
\r
1554 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
\r
1555 vTCPWindowFree( pxSegment );
\r
1557 /* No need to unlink it any more. */
\r
1558 xDoUnlink = pdFALSE;
\r
1561 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
\r
1563 /* Remove item from its queues. */
\r
1564 uxListRemove( &pxSegment->xQueueItem );
\r
1567 ulSequenceNumber += ulDataLength;
\r
1570 return ulBytesConfirmed;
\r
1572 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1573 /*-----------------------------------------------------------*/
\r
1575 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1577 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
\r
1579 const ListItem_t *pxIterator;
\r
1580 const MiniListItem_t* pxEnd;
\r
1581 TCPSegment_t *pxSegment;
\r
1582 uint32_t ulCount = 0UL;
\r
1584 /* A higher Tx block has been acknowledged. Now iterate through the
\r
1585 xWaitQueue to find a possible condition for a FAST retransmission. */
\r
1587 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
\r
1589 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1590 pxIterator != ( const ListItem_t * ) pxEnd; )
\r
1592 /* Get the owner, which is a TCP segment. */
\r
1593 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1595 /* Hop to the next item before the current gets unlinked. */
\r
1596 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1598 /* Fast retransmission:
\r
1599 When 3 packets with a higher sequence number have been acknowledged
\r
1600 by the peer, it is very unlikely a current packet will ever arrive.
\r
1601 It will be retransmitted far before the RTO. */
\r
1602 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
\r
1603 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
\r
1604 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
\r
1606 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
\r
1608 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
\r
1609 which might lead to a second fast rexmit. */
\r
1610 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1612 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
\r
1613 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1614 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1615 FreeRTOS_flush_logging( );
\r
1618 /* Remove it from xWaitQueue. */
\r
1619 uxListRemove( &pxSegment->xQueueItem );
\r
1621 /* Add this segment to the priority queue so it gets
\r
1622 retransmitted immediately. */
\r
1623 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
\r
1630 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1631 /*-----------------------------------------------------------*/
\r
1633 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1635 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1637 uint32_t ulFirstSequence, ulReturn;
\r
1639 /* Receive a normal ACK. */
\r
1641 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
\r
1643 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
\r
1649 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
\r
1655 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1656 /*-----------------------------------------------------------*/
\r
1658 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1660 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1662 uint32_t ulAckCount = 0UL;
\r
1663 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
\r
1665 /* Receive a SACK option. */
\r
1666 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
\r
1667 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
\r
1669 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
\r
1671 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
\r
1672 pxWindow->usPeerPortNumber,
\r
1673 pxWindow->usOurPortNumber,
\r
1674 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1675 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1676 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1677 FreeRTOS_flush_logging( );
\r
1680 return ulAckCount;
\r
1683 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1684 /*-----------------------------------------------------------*/
\r
1687 ##### # ##### #### ######
\r
1688 # # # # # # # # # # #
\r
1690 # ### ##### # # # # # #
\r
1691 # # # # # # # # #####
\r
1692 # # # # # # #### # # #
\r
1693 # # # # # # # # # #
\r
1694 # # # # #### # # # #
\r
1695 #### ##### # # # #### #### ####
\r
1699 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1701 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
1705 /* Data was received at 'ulSequenceNumber'. See if it was expected
\r
1706 and if there is enough space to store the new data. */
\r
1707 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
\r
1713 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
\r
1720 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1721 /*-----------------------------------------------------------*/
\r
1723 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1725 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1727 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1730 /* Data is being scheduled for transmission. */
\r
1732 /* lMax would indicate the size of the txStream. */
\r
1734 /* This is tiny TCP: there is only 1 segment for outgoing data.
\r
1735 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
\r
1736 if( pxSegment->lDataLength > 0 )
\r
1742 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
\r
1744 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1746 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
\r
1749 ulLength = ( uint32_t ) pxSegment->lMaxLength;
\r
1752 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1754 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
\r
1755 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1756 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1760 /* The sequence number of the first byte in this packet. */
\r
1761 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
\r
1762 pxSegment->lDataLength = ( int32_t ) ulLength;
\r
1763 pxSegment->lStreamPos = lPosition;
\r
1764 pxSegment->u.ulFlags = 0UL;
\r
1765 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1767 /* Increase the sequence number of the next data to be stored for
\r
1769 pxWindow->ulNextTxSequenceNumber += ulLength;
\r
1770 lResult = ( int32_t )ulLength;
\r
1776 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1777 /*-----------------------------------------------------------*/
\r
1779 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1781 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1783 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1784 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
\r
1785 uint32_t ulMaxTime;
\r
1787 if( ulLength != 0UL )
\r
1789 /* _HT_ Still under investigation */
\r
1790 ( void ) ulWindowSize;
\r
1792 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1794 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
\r
1795 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1797 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
\r
1803 if( ulLength != 0ul )
\r
1805 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1806 pxSegment->u.bits.ucTransmitCount++;
\r
1807 vTCPTimerSet (&pxSegment->xTransmitTimer);
\r
1808 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1809 *plPosition = pxSegment->lStreamPos;
\r
1816 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1817 /*-----------------------------------------------------------*/
\r
1819 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1821 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1823 BaseType_t xReturn;
\r
1825 /* Has the outstanding data been sent because user wants to shutdown? */
\r
1826 if( pxWindow->xTxSegment.lDataLength == 0 )
\r
1832 xReturn = pdFALSE;
\r
1838 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1839 /*-----------------------------------------------------------*/
\r
1841 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1843 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
1844 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1846 BaseType_t xReturn;
\r
1848 if( ulWindowSize >= pxWindow->usMSSInit )
\r
1854 xReturn = pdFALSE;
\r
1860 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1861 /*-----------------------------------------------------------*/
\r
1863 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1865 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1867 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1868 BaseType_t xReturn;
\r
1869 TickType_t ulAge, ulMaxAge;
\r
1871 /* Check data to be sent. */
\r
1872 *pulDelay = ( TickType_t ) 0;
\r
1873 if( pxSegment->lDataLength == 0 )
\r
1875 /* Got nothing to send right now. */
\r
1876 xReturn = pdFALSE;
\r
1880 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1882 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
\r
1883 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1885 if( ulMaxAge > ulAge )
\r
1887 *pulDelay = ulMaxAge - ulAge;
\r
1892 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1894 /* Too many outstanding messages. */
\r
1895 xReturn = pdFALSE;
\r
1906 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1907 /*-----------------------------------------------------------*/
\r
1909 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1911 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1913 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1914 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1916 /* Receive a normal ACK */
\r
1918 if( ulDataLength != 0ul )
\r
1920 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
\r
1922 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
\r
1924 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
\r
1925 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1926 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1930 /* Nothing to send right now. */
\r
1931 ulDataLength = 0ul;
\r
1935 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1937 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1939 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
\r
1940 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1944 pxSegment->lDataLength = 0;
\r
1948 return ulDataLength;
\r
1951 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1952 /*-----------------------------------------------------------*/
\r
1954 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1956 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
1958 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
\r
1959 'ulCurrentSequenceNumber' is the highest sequence number stored,
\r
1960 'ulHighestSequenceNumber' is the highest sequence number seen. */
\r
1961 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
\r
1964 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1965 /*-----------------------------------------------------------*/
\r
1967 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1969 /* Destroy a window (always returns NULL) */
\r
1970 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
1972 /* As in tiny TCP there are no shared segments descriptors, there is
\r
1973 nothing to release. */
\r
1974 ( void ) pxWindow;
\r
1977 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1978 /*-----------------------------------------------------------*/
\r