2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
59 * FreeRTOS_TCP_WIN.c
\r
60 * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
\r
61 * functions have two versions - one for FreeRTOS+TCP (full) and one for
\r
62 * FreeRTOS+TCP (lite).
\r
64 * In this module all ports and IP addresses and sequence numbers are
\r
65 * being stored in host byte-order.
\r
68 /* Standard includes. */
\r
71 /* FreeRTOS includes. */
\r
72 #include "FreeRTOS.h"
\r
77 /* FreeRTOS+TCP includes. */
\r
78 #include "FreeRTOS_UDP_IP.h"
\r
79 #include "FreeRTOS_IP.h"
\r
80 #include "FreeRTOS_Sockets.h"
\r
81 #include "FreeRTOS_IP_Private.h"
\r
82 #include "NetworkBufferManagement.h"
\r
83 #include "FreeRTOS_TCP_WIN.h"
\r
85 /* Constants used for Smoothed Round Trip Time (SRTT). */
\r
86 #define winSRTT_INCREMENT_NEW 2
\r
87 #define winSRTT_INCREMENT_CURRENT 6
\r
88 #define winSRTT_DECREMENT_NEW 1
\r
89 #define winSRTT_DECREMENT_CURRENT 7
\r
90 #define winSRTT_CAP_mS 50
\r
92 #if( ipconfigUSE_TCP_WIN == 1 )
\r
94 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
\r
96 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
\r
98 /* The code to send a single Selective ACK (SACK):
\r
99 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
\r
100 * followed by a lower and a higher sequence number,
\r
101 * where LEN is 2 + 2*4 = 10 bytes. */
\r
102 #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
\r
103 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
\r
105 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
\r
108 /* Normal retransmission:
\r
109 * A packet will be retransmitted after a Retransmit Time-Out (RTO).
\r
110 * Fast retransmission:
\r
111 * When 3 packets with a higher sequence number have been acknowledged
\r
112 * by the peer, it is very unlikely a current packet will ever arrive.
\r
113 * It will be retransmitted far before the RTO.
\r
115 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
\r
117 /* If there have been several retransmissions (4), decrease the
\r
118 * size of the transmission window to at most 2 times MSS.
\r
120 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
\r
122 #endif /* configUSE_TCP_WIN */
\r
123 /*-----------------------------------------------------------*/
\r
125 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
128 * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
\r
129 * Available descriptors are stored in the 'xSegmentList'
\r
130 * When a socket owns a descriptor, it will either be stored in
\r
131 * 'xTxSegments' or 'xRxSegments'
\r
132 * As soon as a package has been confirmed, the descriptor will be returned
\r
133 * to the segment pool
\r
135 #if( ipconfigUSE_TCP_WIN == 1 )
\r
136 static BaseType_t prvCreateSectors( void );
\r
137 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
140 * Find a segment with a given sequence number in the list of received
\r
141 * segments: 'pxWindow->xRxSegments'.
\r
143 #if( ipconfigUSE_TCP_WIN == 1 )
\r
144 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
\r
145 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
148 * Allocate a new segment
\r
149 * The socket will borrow all segments from a common pool: 'xSegmentList',
\r
150 * which is a list of 'TCPSegment_t'
\r
152 #if( ipconfigUSE_TCP_WIN == 1 )
\r
153 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
\r
154 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
156 /* When the peer has a close request (FIN flag), the driver will check if
\r
157 * there are missing packets in the Rx-queue
\r
158 * It will accept the closure of the connection if both conditions are true:
\r
159 * - the Rx-queue is empty
\r
160 * - we've ACK'd the highest Rx sequence number seen
\r
162 #if( ipconfigUSE_TCP_WIN == 1 )
\r
163 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
\r
164 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
167 * Detaches and returns the head of a queue
\r
169 #if( ipconfigUSE_TCP_WIN == 1 )
\r
170 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
\r
171 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
174 * Returns the head of a queue but it won't be detached
\r
176 #if( ipconfigUSE_TCP_WIN == 1 )
\r
177 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
\r
178 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
181 * Free entry pxSegment because it's not used anymore
\r
182 * The ownership will be passed back to the segment pool
\r
184 #if( ipconfigUSE_TCP_WIN == 1 )
\r
185 static void vTCPWindowFree( TCPSegment_t *pxSegment );
\r
186 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
189 * A segment has been received with sequence number 'ulSequenceNumber', where
\r
190 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
\r
191 * segment was expected. xTCPWindowRxConfirm() will check if there is already
\r
192 * another segment with a sequence number between (ulSequenceNumber) and
\r
193 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
\r
194 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
\r
196 #if( ipconfigUSE_TCP_WIN == 1 )
\r
197 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
\r
198 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
201 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
\r
204 #if( ipconfigUSE_TCP_WIN == 1 )
\r
205 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
\r
206 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
209 * This function will look if there is new transmission data. It will return
\r
210 * true if there is data to be sent.
\r
212 #if( ipconfigUSE_TCP_WIN == 1 )
\r
213 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
214 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
217 * An acknowledge was received. See if some outstanding data may be removed
\r
218 * from the transmission queue(s).
\r
220 #if( ipconfigUSE_TCP_WIN == 1 )
\r
221 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
\r
222 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
225 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
\r
226 * to find a possible condition for a FAST retransmission.
\r
228 #if( ipconfigUSE_TCP_WIN == 1 )
\r
229 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
\r
230 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
232 /*-----------------------------------------------------------*/
\r
234 /* TCP segement pool. */
\r
235 #if( ipconfigUSE_TCP_WIN == 1 )
\r
236 static TCPSegment_t *xTCPSegments = NULL;
\r
237 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
239 /* List of free TCP segments. */
\r
240 #if( ipconfigUSE_TCP_WIN == 1 )
\r
241 static List_t xSegmentList;
\r
244 /* Logging verbosity level. */
\r
245 BaseType_t xTCPWindowLoggingLevel = 0;
\r
247 #if( ipconfigUSE_TCP_WIN == 1 )
\r
248 /* Some 32-bit arithmetic: comparing sequence numbers */
\r
249 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
\r
250 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
\r
253 Return true if the unsigned subtraction of (b-a) doesn't generate an
\r
254 arithmetic overflow. */
\r
255 return ( ( b - a ) & 0x80000000UL ) == 0UL;
\r
257 #endif /* ipconfigUSE_TCP_WIN */
\r
258 /*-----------------------------------------------------------*/
\r
260 #if( ipconfigUSE_TCP_WIN == 1 )
\r
261 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
\r
262 static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
\r
264 /* Test if a < b */
\r
265 return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
\r
267 #endif /* ipconfigUSE_TCP_WIN */
\r
268 /*-----------------------------------------------------------*/
\r
270 #if( ipconfigUSE_TCP_WIN == 1 )
\r
271 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
\r
272 static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
\r
274 /* Test if a > b */
\r
275 return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
\r
277 #endif /* ipconfigUSE_TCP_WIN */
\r
279 /*-----------------------------------------------------------*/
\r
280 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
\r
281 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
\r
283 /* Test if a >= b */
\r
284 return ( ( a - b ) & 0x80000000UL ) == 0UL;
\r
286 /*-----------------------------------------------------------*/
\r
288 #if( ipconfigUSE_TCP_WIN == 1 )
\r
289 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
\r
290 static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
\r
292 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
\r
295 /*-----------------------------------------------------------*/
\r
297 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
\r
298 static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
\r
300 pxTimer->ulBorn = xTaskGetTickCount ( );
\r
302 /*-----------------------------------------------------------*/
\r
304 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
\r
305 static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
\r
307 return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
\r
309 /*-----------------------------------------------------------*/
\r
311 /* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
\r
312 preceded by a prototype. Later this prototype will be located in list.h? */
\r
314 extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
\r
316 void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
\r
318 /* Insert a new list item into pxList, it does not sort the list,
\r
319 but it puts the item just before xListEnd, so it will be the last item
\r
320 returned by listGET_HEAD_ENTRY() */
\r
321 pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
\r
322 pxNewListItem->pxPrevious = pxWhere->pxPrevious;
\r
323 pxWhere->pxPrevious->pxNext = pxNewListItem;
\r
324 pxWhere->pxPrevious = pxNewListItem;
\r
326 /* Remember which list the item is in. */
\r
327 pxNewListItem->pvContainer = ( void * ) pxList;
\r
329 ( pxList->uxNumberOfItems )++;
\r
331 /*-----------------------------------------------------------*/
\r
333 #if( ipconfigUSE_TCP_WIN == 1 )
\r
335 static BaseType_t prvCreateSectors( void )
\r
337 BaseType_t xIndex, xReturn;
\r
339 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
\r
341 vListInitialise( &xSegmentList );
\r
342 xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
344 if( xTCPSegments == NULL )
\r
346 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
\r
347 ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
\r
353 /* Clear the allocated space. */
\r
354 memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
\r
356 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
\r
358 /* Could call vListInitialiseItem here but all data has been
\r
359 nulled already. Set the owner to a segment descriptor. */
\r
360 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
361 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
\r
363 /* And add it to the pool of available segments */
\r
364 vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
\r
373 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
374 /*-----------------------------------------------------------*/
\r
376 #if( ipconfigUSE_TCP_WIN == 1 )
\r
378 static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
380 const ListItem_t *pxIterator;
\r
381 const MiniListItem_t* pxEnd;
\r
382 TCPSegment_t *pxSegment, *pxReturn = NULL;
\r
384 /* Find a segment with a given sequence number in the list of received
\r
387 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
\r
389 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
390 pxIterator != ( const ListItem_t * ) pxEnd;
\r
391 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
393 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
395 if( pxSegment->ulSequenceNumber == ulSequenceNumber )
\r
397 pxReturn = pxSegment;
\r
405 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
406 /*-----------------------------------------------------------*/
\r
408 #if( ipconfigUSE_TCP_WIN == 1 )
\r
410 static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
\r
412 TCPSegment_t *pxSegment;
\r
413 ListItem_t * pxItem;
\r
415 /* Allocate a new segment. The socket will borrow all segments from a
\r
416 common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
\r
417 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
\r
419 /* If the TCP-stack runs out of segments, you might consider
\r
420 increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
\r
421 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
\r
426 /* Pop the item at the head of the list. Semaphore protection is
\r
427 not required as only the IP task will call these functions. */
\r
428 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
\r
429 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
431 configASSERT( pxItem != NULL );
\r
432 configASSERT( pxSegment != NULL );
\r
434 /* Remove the item from xSegmentList. */
\r
435 uxListRemove( pxItem );
\r
437 /* Add it to either the connections' Rx or Tx queue. */
\r
438 vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
\r
440 /* And set the segment's timer to zero */
\r
441 vTCPTimerSet( &pxSegment->xTransmitTimer );
\r
443 pxSegment->u.ulFlags = 0;
\r
444 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
\r
445 pxSegment->lMaxLength = lCount;
\r
446 pxSegment->lDataLength = lCount;
\r
447 pxSegment->ulSequenceNumber = ulSequenceNumber;
\r
448 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
450 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
\r
451 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
\r
453 if( xLowestLength > xLength )
\r
455 xLowestLength = xLength;
\r
458 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
464 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
465 /*-----------------------------------------------------------*/
\r
467 #if( ipconfigUSE_TCP_WIN == 1 )
\r
469 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
471 BaseType_t xReturn;
\r
473 /* When the peer has a close request (FIN flag), the driver will check
\r
474 if there are missing packets in the Rx-queue. It will accept the
\r
475 closure of the connection if both conditions are true:
\r
476 - the Rx-queue is empty
\r
477 - the highest Rx sequence number has been ACK'ed */
\r
478 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
\r
480 /* Rx data has been stored while earlier packets were missing. */
\r
483 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
\r
485 /* No Rx packets are being stored and the highest sequence number
\r
486 that has been received has been ACKed. */
\r
491 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
\r
492 ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
\r
493 ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
\r
500 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
501 /*-----------------------------------------------------------*/
\r
503 #if( ipconfigUSE_TCP_WIN == 1 )
\r
505 static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
\r
507 TCPSegment_t *pxSegment;
\r
508 ListItem_t * pxItem;
\r
510 /* Detaches and returns the head of a queue. */
\r
511 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
517 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
518 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
520 uxListRemove( pxItem );
\r
526 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
527 /*-----------------------------------------------------------*/
\r
529 #if( ipconfigUSE_TCP_WIN == 1 )
\r
531 static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
\r
533 ListItem_t *pxItem;
\r
534 TCPSegment_t *pxReturn;
\r
536 /* Returns the head of a queue but it won't be detached. */
\r
537 if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
\r
543 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
\r
544 pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
\r
550 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
551 /*-----------------------------------------------------------*/
\r
553 #if( ipconfigUSE_TCP_WIN == 1 )
\r
555 static void vTCPWindowFree( TCPSegment_t *pxSegment )
\r
557 /* Free entry pxSegment because it's not used any more. The ownership
\r
558 will be passed back to the segment pool.
\r
560 Unlink it from one of the queues, if any. */
\r
561 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
\r
563 uxListRemove( &( pxSegment->xQueueItem ) );
\r
566 pxSegment->ulSequenceNumber = 0u;
\r
567 pxSegment->lDataLength = 0l;
\r
568 pxSegment->u.ulFlags = 0u;
\r
570 /* Take it out of xRxSegments/xTxSegments */
\r
571 if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
\r
573 uxListRemove( &( pxSegment->xListItem ) );
\r
576 /* Return it to xSegmentList */
\r
577 vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
\r
580 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
581 /*-----------------------------------------------------------*/
\r
583 #if( ipconfigUSE_TCP_WIN == 1 )
\r
585 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
587 List_t * pxSegments;
\r
589 TCPSegment_t *pxSegment;
\r
591 /* Destroy a window. A TCP window doesn't serve any more. Return all
\r
592 owned segments to the pool. In order to save code, it will make 2 rounds,
\r
593 one to remove the segments from xRxSegments, and a second round to clear
\r
595 for( xRound = 0; xRound < 2; xRound++ )
\r
599 pxSegments = &( pxWindow->xRxSegments );
\r
603 pxSegments = &( pxWindow->xTxSegments );
\r
606 if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
\r
608 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
\r
610 pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
\r
611 vTCPWindowFree( pxSegment );
\r
617 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
618 /*-----------------------------------------------------------*/
\r
620 void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
\r
621 uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
623 /* Create and initialize a window. */
\r
625 #if( ipconfigUSE_TCP_WIN == 1 )
\r
627 if( xTCPSegments == NULL )
\r
629 prvCreateSectors();
\r
632 vListInitialise( &( pxWindow->xTxSegments ) );
\r
633 vListInitialise( &( pxWindow->xRxSegments ) );
\r
635 vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
\r
636 vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */
\r
637 vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */
\r
639 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
641 if( xTCPWindowLoggingLevel != 0 )
\r
643 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
\r
644 ulRxWindowLength, ulTxWindowLength ) );
\r
647 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
\r
648 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
\r
650 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
\r
652 /*-----------------------------------------------------------*/
\r
654 void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
\r
656 const int32_t l500ms = 500;
\r
658 pxWindow->u.ulFlags = 0ul;
\r
659 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
\r
663 if( pxWindow->usMSSInit != 0u )
\r
665 pxWindow->usMSSInit = ( uint16_t ) ulMSS;
\r
668 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
\r
670 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
\r
671 pxWindow->usMSS = ( uint16_t ) ulMSS;
\r
675 #if( ipconfigUSE_TCP_WIN == 0 )
\r
677 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
\r
679 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
681 /*Start with a timeout of 2 * 500 ms (1 sec). */
\r
682 pxWindow->lSRTT = l500ms;
\r
684 /* Just for logging, to print relative sequence numbers. */
\r
685 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
\r
687 /* The segment asked for in the next transmission. */
\r
688 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
\r
690 /* The right-hand side of the receive window. */
\r
691 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
\r
693 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
\r
695 /* The segment asked for in next transmission. */
\r
696 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
\r
698 /* The sequence number given to the next outgoing byte to be added is
\r
699 maintained by lTCPWindowTxAdd(). */
\r
700 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
\r
702 /* The right-hand side of the transmit window. */
\r
703 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
\r
704 pxWindow->ulOurSequenceNumber = ulSequenceNumber;
\r
706 /*-----------------------------------------------------------*/
\r
708 /*=============================================================================
\r
721 *=============================================================================*/
\r
723 #if( ipconfigUSE_TCP_WIN == 1 )
\r
725 static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
\r
727 TCPSegment_t *pxBest = NULL;
\r
728 const ListItem_t *pxIterator;
\r
729 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
\r
730 const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
\r
731 TCPSegment_t *pxSegment;
\r
733 /* A segment has been received with sequence number 'ulSequenceNumber',
\r
734 where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
\r
735 exactly this segment was expected. xTCPWindowRxConfirm() will check if
\r
736 there is already another segment with a sequence number between (ulSequenceNumber)
\r
737 and (ulSequenceNumber+ulLength). Normally none will be found, because
\r
738 the next RX segment should have a sequence number equal to
\r
739 '(ulSequenceNumber+ulLength)'. */
\r
741 /* Iterate through all RX segments that are stored: */
\r
742 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
743 pxIterator != ( const ListItem_t * ) pxEnd;
\r
744 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
746 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
747 /* And see if there is a segment for which:
\r
748 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
\r
749 If there are more matching segments, the one with the lowest sequence number
\r
751 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
\r
752 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
\r
754 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
\r
756 pxBest = pxSegment;
\r
761 if( ( pxBest != NULL ) &&
\r
762 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
\r
764 FreeRTOS_flush_logging();
\r
765 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
\r
766 pxWindow->usPeerPortNumber,
\r
767 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
769 ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
\r
770 pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
771 pxBest->lDataLength,
\r
772 pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
\r
778 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
779 /*-----------------------------------------------------------*/
\r
781 #if( ipconfigUSE_TCP_WIN == 1 )
\r
783 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
785 uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
\r
786 int32_t lReturn, lDistance;
\r
787 TCPSegment_t *pxFound;
\r
789 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
\r
790 directly to user (segment is expected). If it returns a positive
\r
791 number, an earlier packet is missing, but this packet may be stored.
\r
792 If negative, the packet has already been stored, or it is out-of-order,
\r
793 or there is not enough space.
\r
795 As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
\r
796 if more Rx data may be passed to the user after this packet. */
\r
798 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
\r
800 /* For Selective Ack (SACK), used when out-of-sequence data come in. */
\r
801 pxWindow->ucOptionLength = 0u;
\r
803 /* Non-zero if TCP-windows contains data which must be popped. */
\r
804 pxWindow->ulUserDataLength = 0ul;
\r
806 if( ulCurrentSequenceNumber == ulSequenceNumber )
\r
808 /* This is the packet with the lowest sequence number we're waiting
\r
809 for. It can be passed directly to the rx stream. */
\r
810 if( ulLength > ulSpace )
\r
812 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
\r
817 ulCurrentSequenceNumber += ulLength;
\r
819 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
\r
821 ulSavedSequenceNumber = ulCurrentSequenceNumber;
\r
823 /* See if (part of) this segment has been stored already,
\r
824 but this rarely happens. */
\r
825 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
\r
826 if( pxFound != NULL )
\r
828 ulCurrentSequenceNumber = pxFound->ulSequenceNumber + ( ( uint32_t ) pxFound->lDataLength );
\r
830 /* Remove it because it will be passed to user directly. */
\r
831 vTCPWindowFree( pxFound );
\r
834 /* Check for following segments that are already in the
\r
835 queue and increment ulCurrentSequenceNumber. */
\r
836 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
\r
838 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
\r
840 /* As all packet below this one have been passed to the
\r
841 user it can be discarded. */
\r
842 vTCPWindowFree( pxFound );
\r
845 if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
\r
847 /* After the current data-package, there is more data
\r
849 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
\r
851 if( xTCPWindowLoggingLevel >= 1 )
\r
853 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
\r
854 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
855 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
856 pxWindow->ulUserDataLength,
\r
857 ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
858 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
863 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
\r
865 /* Packet was expected, may be passed directly to the socket
\r
866 buffer or application. Store the packet at offset 0. */
\r
870 else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
\r
872 /* Looks like a TCP keep-alive message. Do not accept/store Rx data
\r
873 ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
\r
878 /* The packet is not the one expected. See if it falls within the Rx
\r
879 window so it can be stored. */
\r
881 /* An "out-of-sequence" segment was received, must have missed one.
\r
882 Prepare a SACK (Selective ACK). */
\r
883 ulLast = ulSequenceNumber + ulLength;
\r
884 lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
\r
886 if( lDistance <= 0 )
\r
888 /* An earlier has been received, must be a retransmission of a
\r
889 packet that has been accepted already. No need to send out a
\r
890 Selective ACK (SACK). */
\r
893 else if( lDistance > ( int32_t ) ulSpace )
\r
895 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
\r
896 sequence number of this packet is too far ahead, ignore it. */
\r
897 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
\r
902 /* See if there is more data in a contiguous block to make the
\r
903 SACK describe a longer range of data. */
\r
905 /* TODO: SACK's may also be delayed for a short period
\r
906 * This is useful because subsequent packets will be SACK'd with
\r
907 * single one message
\r
909 while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
\r
911 ulLast += ( uint32_t ) pxFound->lDataLength;
\r
914 if( xTCPWindowLoggingLevel >= 1 )
\r
916 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
\r
917 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
918 ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
919 ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
920 ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
\r
921 ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
\r
924 /* Now prepare the SACK message.
\r
925 Code OPTION_CODE_SINGLE_SACK already in network byte order. */
\r
926 pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
\r
928 /* First sequence number that we received. */
\r
929 pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
\r
932 pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
\r
934 /* Which make 12 (3*4) option bytes. */
\r
935 pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
\r
937 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
\r
939 if( pxFound != NULL )
\r
941 /* This out-of-sequence packet has been received for a
\r
942 second time. It is already stored but do send a SACK
\r
948 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
\r
950 if( pxFound == NULL )
\r
952 /* Can not send a SACK, because the segment cannot be
\r
954 pxWindow->ucOptionLength = 0u;
\r
956 /* Needs to be stored but there is no segment
\r
962 if( xTCPWindowLoggingLevel != 0 )
\r
964 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
\r
965 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
\r
966 listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
\r
967 FreeRTOS_flush_logging( );
\r
970 /* Return a positive value. The packet may be accepted
\r
971 and stored but an earlier packet is still missing. */
\r
972 lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
\r
981 #endif /* ipconfgiUSE_TCP_WIN == 1 */
\r
982 /*-----------------------------------------------------------*/
\r
984 /*=============================================================================
\r
998 *=============================================================================*/
\r
1000 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1002 static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
\r
1004 /* +TCP stores data in circular buffers. Calculate the next position to
\r
1006 lPosition += lCount;
\r
1007 if( lPosition >= lMax )
\r
1009 lPosition -= lMax;
\r
1015 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1016 /*-----------------------------------------------------------*/
\r
1018 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1020 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1022 int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
\r
1023 int32_t lDone = 0;
\r
1024 TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
\r
1026 /* Puts a message in the Tx-window (after buffer size has been
\r
1028 if( pxSegment != NULL )
\r
1030 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1032 if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
\r
1034 /* Adding data to a segment that was already in the TX queue. It
\r
1035 will be filled-up to a maximum of MSS (maximum segment size). */
\r
1036 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
\r
1038 pxSegment->lDataLength += lToWrite;
\r
1040 if( pxSegment->lDataLength >= pxSegment->lMaxLength )
\r
1042 /* This segment is full, don't add more bytes. */
\r
1043 pxWindow->pxHeadSegment = NULL;
\r
1046 lBytesLeft -= lToWrite;
\r
1048 /* ulNextTxSequenceNumber is the sequence number of the next byte to
\r
1049 be stored for transmission. */
\r
1050 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1052 /* Increased the return value. */
\r
1053 lDone += lToWrite;
\r
1055 /* Some detailed logging, for those who're interested. */
\r
1056 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1058 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1060 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1061 pxSegment->lDataLength,
\r
1062 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1063 pxSegment->lStreamPos ) );
\r
1064 FreeRTOS_flush_logging( );
\r
1067 /* Calculate the next position in the circular data buffer, knowing
\r
1068 its maximum length 'lMax'. */
\r
1069 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1074 while( lBytesLeft > 0 )
\r
1076 /* The current transmission segment is full, create new segments as
\r
1078 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
\r
1080 if( pxSegment != NULL )
\r
1082 /* Store as many as needed, but no more than the maximum
\r
1084 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
\r
1086 pxSegment->lDataLength = lToWrite;
\r
1087 pxSegment->lStreamPos = lPosition;
\r
1088 lBytesLeft -= lToWrite;
\r
1089 lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
\r
1090 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
\r
1091 lDone += lToWrite;
\r
1093 /* Link this segment in the Tx-Queue. */
\r
1094 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
\r
1096 /* Let 'pxHeadSegment' point to this segment if there is still
\r
1098 if( pxSegment->lDataLength < pxSegment->lMaxLength )
\r
1100 pxWindow->pxHeadSegment = pxSegment;
\r
1104 pxWindow->pxHeadSegment = NULL;
\r
1107 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
\r
1109 if( ( xTCPWindowLoggingLevel >= 3 ) ||
\r
1110 ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
\r
1112 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
\r
1114 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1115 pxSegment->lDataLength,
\r
1116 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1117 pxSegment->lStreamPos ) );
\r
1118 FreeRTOS_flush_logging( );
\r
1124 /* A sever situation: running out of segments for transmission.
\r
1125 No more data can be sent at the moment. */
\r
1128 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
\r
1137 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1138 /*-----------------------------------------------------------*/
\r
1140 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1142 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1144 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
\r
1147 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1148 /*-----------------------------------------------------------*/
\r
1150 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1152 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1154 uint32_t ulTxOutstanding;
\r
1155 BaseType_t xHasSpace;
\r
1156 TCPSegment_t *pxSegment;
\r
1158 /* This function will look if there is new transmission data. It will
\r
1159 return true if there is data to be sent. */
\r
1161 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1163 if( pxSegment == NULL )
\r
1165 xHasSpace = pdFALSE;
\r
1169 /* How much data is outstanding, i.e. how much data has been sent
\r
1170 but not yet acknowledged ? */
\r
1171 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
\r
1173 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
\r
1177 ulTxOutstanding = 0UL;
\r
1180 /* Subtract this from the peer's space. */
\r
1181 ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
\r
1183 /* See if the next segment may be sent. */
\r
1184 if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
\r
1186 xHasSpace = pdTRUE;
\r
1190 xHasSpace = pdFALSE;
\r
1193 /* If 'xHasSpace', it looks like the peer has at least space for 1
\r
1194 more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
\r
1195 limitation of the transmission window (in case of many resends it
\r
1196 may be decreased). */
\r
1197 if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
\r
1199 xHasSpace = pdFALSE;
\r
1206 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1207 /*-----------------------------------------------------------*/
\r
1209 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1211 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1213 TCPSegment_t *pxSegment;
\r
1214 BaseType_t xReturn;
\r
1215 TickType_t ulAge, ulMaxAge;
\r
1219 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
\r
1221 /* No need to look at retransmissions or new transmission as long as
\r
1222 there are priority segments. *pulDelay equals zero, meaning it must
\r
1223 be sent out immediately. */
\r
1228 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1230 if( pxSegment != NULL )
\r
1232 /* There is an outstanding segment, see if it is time to resend
\r
1234 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
\r
1236 /* After a packet has been sent for the first time, it will wait
\r
1237 '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
\r
1238 each time doubling the time-out */
\r
1239 ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1241 if( ulMaxAge > ulAge )
\r
1243 /* A segment must be sent after this amount of msecs */
\r
1244 *pulDelay = ulMaxAge - ulAge;
\r
1251 /* No priority segment, no outstanding data, see if there is new
\r
1252 transmission data. */
\r
1253 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
\r
1255 /* See if it fits in the peer's reception window. */
\r
1256 if( pxSegment == NULL )
\r
1258 xReturn = pdFALSE;
\r
1260 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1262 /* Too many outstanding messages. */
\r
1263 xReturn = pdFALSE;
\r
1265 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1267 /* 'bSendFullSize' is a special optimisation. If true, the
\r
1268 driver will only sent completely filled packets (of MSS
\r
1270 xReturn = pdFALSE;
\r
1282 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1283 /*-----------------------------------------------------------*/
\r
1285 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1287 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1289 TCPSegment_t *pxSegment;
\r
1290 uint32_t ulMaxTime;
\r
1291 uint32_t ulReturn = ~0UL;
\r
1294 /* Fetches data to be sent-out now.
\r
1296 Priority messages: segments with a resend need no check current sliding
\r
1298 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
\r
1299 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
\r
1301 if( pxSegment == NULL )
\r
1303 /* Waiting messages: outstanding messages with a running timer
\r
1304 neither check peer's reception window size because these packets
\r
1305 have been sent earlier. */
\r
1306 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
\r
1308 if( pxSegment != NULL )
\r
1310 /* Do check the timing. */
\r
1311 ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1313 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
\r
1315 /* A normal (non-fast) retransmission. Move it from the
\r
1316 head of the waiting queue. */
\r
1317 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
\r
1318 pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
\r
1320 /* Some detailed logging. */
\r
1321 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
\r
1323 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
\r
1324 pxWindow->usPeerPortNumber,
\r
1325 pxWindow->usOurPortNumber,
\r
1326 pxSegment->lDataLength,
\r
1327 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1328 pxSegment->ulSequenceNumber ) );
\r
1329 FreeRTOS_flush_logging( );
\r
1338 if( pxSegment == NULL )
\r
1340 /* New messages: sent-out for the first time. Check current
\r
1341 sliding window size of peer. */
\r
1342 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
\r
1344 if( pxSegment == NULL )
\r
1346 /* No segments queued. */
\r
1349 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
\r
1351 /* A segment has been queued but the driver waits until it
\r
1352 has a full size of MSS. */
\r
1355 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1357 /* Peer has no more space at this moment. */
\r
1362 /* Move it out of the Tx queue. */
\r
1363 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
\r
1365 /* Don't let pxHeadSegment point to this segment any more,
\r
1366 so no more data will be added. */
\r
1367 if( pxWindow->pxHeadSegment == pxSegment )
\r
1369 pxWindow->pxHeadSegment = NULL;
\r
1372 /* pxWindow->tx.highest registers the highest sequence
\r
1373 number in our transmission window. */
\r
1374 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
\r
1376 /* ...and more detailed logging */
\r
1377 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1379 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1380 pxWindow->usPeerPortNumber,
\r
1381 pxWindow->usOurPortNumber,
\r
1382 pxSegment->lDataLength,
\r
1383 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1385 FreeRTOS_flush_logging( );
\r
1392 /* There is a priority segment. It doesn't need any checking for
\r
1393 space or timeouts. */
\r
1394 if( xTCPWindowLoggingLevel != 0 )
\r
1396 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
\r
1397 pxWindow->usPeerPortNumber,
\r
1398 pxWindow->usOurPortNumber,
\r
1399 pxSegment->lDataLength,
\r
1400 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1402 FreeRTOS_flush_logging( );
\r
1406 /* See if it has already been determined to return 0. */
\r
1407 if( ulReturn != 0UL )
\r
1409 configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
\r
1411 /* Now that the segment will be transmitted, add it to the tail of
\r
1412 the waiting queue. */
\r
1413 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
\r
1415 /* And mark it as outstanding. */
\r
1416 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1418 /* Administer the transmit count, needed for fast
\r
1419 retransmissions. */
\r
1420 ( pxSegment->u.bits.ucTransmitCount )++;
\r
1422 /* If there have been several retransmissions (4), decrease the
\r
1423 size of the transmission window to at most 2 times MSS. */
\r
1424 if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
\r
1426 if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
\r
1428 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
\r
1429 pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
\r
1430 pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
\r
1431 pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
\r
1435 /* Clear the transmit timer. */
\r
1436 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1438 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1440 /* Inform the caller where to find the data within the queue. */
\r
1441 *plPosition = pxSegment->lStreamPos;
\r
1443 /* And return the length of the data segment */
\r
1444 ulReturn = ( uint32_t ) pxSegment->lDataLength;
\r
1450 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1451 /*-----------------------------------------------------------*/
\r
1453 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1455 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1457 uint32_t ulBytesConfirmed = 0u;
\r
1458 uint32_t ulSequenceNumber = ulFirst, ulDataLength;
\r
1459 const ListItem_t *pxIterator;
\r
1460 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
\r
1461 BaseType_t xDoUnlink;
\r
1462 TCPSegment_t *pxSegment;
\r
1463 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
\r
1464 may be removed from the transmission queue(s).
\r
1465 All TX segments for which
\r
1466 ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
\r
1467 contiguous block. Note that the segments are stored in xTxSegments in a
\r
1468 strict sequential order. */
\r
1470 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
\r
1472 0 < a < 1; usually a = 1/8
\r
1477 RTT is Round Trip Time
\r
1478 SRTT is Smoothed RTT
\r
1479 RTO is Retransmit timeout
\r
1481 A Smoothed RTT will increase quickly, but it is conservative when
\r
1482 becoming smaller. */
\r
1485 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1486 ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
\r
1489 xDoUnlink = pdFALSE;
\r
1490 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1492 /* Move to the next item because the current item might get
\r
1494 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1496 /* Continue if this segment does not fall within the ACK'd range. */
\r
1497 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
\r
1502 /* Is it ready? */
\r
1503 if( ulSequenceNumber != pxSegment->ulSequenceNumber )
\r
1508 ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1510 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
\r
1512 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
\r
1514 /* What happens? Only part of this segment was accepted,
\r
1515 probably due to WND limits
\r
1517 AAAAAAA BBBBBBB << acked
\r
1518 aaaaaaa aaaa << sent */
\r
1519 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
1521 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
\r
1522 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
\r
1523 pxWindow->usPeerPortNumber,
\r
1524 pxWindow->usOurPortNumber,
\r
1525 ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
\r
1526 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1527 ulFirstSeq, ulFirstSeq + ulDataLength ) );
\r
1529 #endif /* ipconfigHAS_DEBUG_PRINTF */
\r
1533 /* This segment is fully ACK'd, set the flag. */
\r
1534 pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
\r
1536 /* Calculate the RTT only if the segment was sent-out for the
\r
1537 first time and if this is the last ACK'd segment in a range. */
\r
1538 if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
\r
1540 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
\r
1542 if( pxWindow->lSRTT >= mS )
\r
1544 /* RTT becomes smaller: adapt slowly. */
\r
1545 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
\r
1549 /* RTT becomes larger: adapt quicker */
\r
1550 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
\r
1553 /* Cap to the minimum of 50ms. */
\r
1554 if( pxWindow->lSRTT < winSRTT_CAP_mS )
\r
1556 pxWindow->lSRTT = winSRTT_CAP_mS;
\r
1560 /* Unlink it from the 3 queues, but do not destroy it (yet). */
\r
1561 xDoUnlink = pdTRUE;
\r
1564 /* pxSegment->u.bits.bAcked is now true. Is it located at the left
\r
1565 side of the transmission queue? If so, it may be freed. */
\r
1566 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
\r
1568 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1570 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
\r
1571 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1572 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1573 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1576 /* Increase the left-hand value of the transmission window. */
\r
1577 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1579 /* This function will return the number of bytes that the tail
\r
1580 of txStream may be advanced. */
\r
1581 ulBytesConfirmed += ulDataLength;
\r
1583 /* All segments below tx.ulCurrentSequenceNumber may be freed. */
\r
1584 vTCPWindowFree( pxSegment );
\r
1586 /* No need to unlink it any more. */
\r
1587 xDoUnlink = pdFALSE;
\r
1590 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
\r
1592 /* Remove item from its queues. */
\r
1593 uxListRemove( &pxSegment->xQueueItem );
\r
1596 ulSequenceNumber += ulDataLength;
\r
1599 return ulBytesConfirmed;
\r
1601 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1602 /*-----------------------------------------------------------*/
\r
1604 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1606 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
\r
1608 const ListItem_t *pxIterator;
\r
1609 const MiniListItem_t* pxEnd;
\r
1610 TCPSegment_t *pxSegment;
\r
1611 uint32_t ulCount = 0UL;
\r
1613 /* A higher Tx block has been acknowledged. Now iterate through the
\r
1614 xWaitQueue to find a possible condition for a FAST retransmission. */
\r
1616 pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
\r
1618 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
\r
1619 pxIterator != ( const ListItem_t * ) pxEnd; )
\r
1621 /* Get the owner, which is a TCP segment. */
\r
1622 pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
1624 /* Hop to the next item before the current gets unlinked. */
\r
1625 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
1627 /* Fast retransmission:
\r
1628 When 3 packets with a higher sequence number have been acknowledged
\r
1629 by the peer, it is very unlikely a current packet will ever arrive.
\r
1630 It will be retransmitted far before the RTO. */
\r
1631 if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
\r
1632 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
\r
1633 ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
\r
1635 pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
\r
1637 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
\r
1638 which might lead to a second fast rexmit. */
\r
1639 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1641 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
\r
1642 pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1643 ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1644 FreeRTOS_flush_logging( );
\r
1647 /* Remove it from xWaitQueue. */
\r
1648 uxListRemove( &pxSegment->xQueueItem );
\r
1650 /* Add this segment to the priority queue so it gets
\r
1651 retransmitted immediately. */
\r
1652 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
\r
1659 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1660 /*-----------------------------------------------------------*/
\r
1662 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1664 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1666 uint32_t ulFirstSequence, ulReturn;
\r
1668 /* Receive a normal ACK. */
\r
1670 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
\r
1672 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
\r
1678 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
\r
1684 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1685 /*-----------------------------------------------------------*/
\r
1687 #if( ipconfigUSE_TCP_WIN == 1 )
\r
1689 uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
\r
1691 uint32_t ulAckCount = 0UL;
\r
1692 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
\r
1694 /* Receive a SACK option. */
\r
1695 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
\r
1696 prvTCPWindowFastRetransmit( pxWindow, ulFirst );
\r
1698 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
\r
1700 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
\r
1701 pxWindow->usPeerPortNumber,
\r
1702 pxWindow->usOurPortNumber,
\r
1703 ulFirst - pxWindow->tx.ulFirstSequenceNumber,
\r
1704 ulLast - pxWindow->tx.ulFirstSequenceNumber,
\r
1705 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
\r
1706 FreeRTOS_flush_logging( );
\r
1709 return ulAckCount;
\r
1712 #endif /* ipconfigUSE_TCP_WIN == 1 */
\r
1713 /*-----------------------------------------------------------*/
\r
1716 ##### # ##### #### ######
\r
1717 # # # # # # # # # # #
\r
1719 # ### ##### # # # # # #
\r
1720 # # # # # # # # #####
\r
1721 # # # # # # #### # # #
\r
1722 # # # # # # # # # #
\r
1723 # # # # #### # # # #
\r
1724 #### ##### # # # #### #### ####
\r
1728 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1730 int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
\r
1734 /* Data was received at 'ulSequenceNumber'. See if it was expected
\r
1735 and if there is enough space to store the new data. */
\r
1736 if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
\r
1742 pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
\r
1749 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1750 /*-----------------------------------------------------------*/
\r
1752 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1754 int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
\r
1756 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1759 /* Data is being scheduled for transmission. */
\r
1761 /* lMax would indicate the size of the txStream. */
\r
1763 /* This is tiny TCP: there is only 1 segment for outgoing data.
\r
1764 As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
\r
1765 if( pxSegment->lDataLength > 0 )
\r
1771 if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
\r
1773 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1775 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
\r
1778 ulLength = ( uint32_t ) pxSegment->lMaxLength;
\r
1781 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1783 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
\r
1784 pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1785 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1789 /* The sequence number of the first byte in this packet. */
\r
1790 pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
\r
1791 pxSegment->lDataLength = ( int32_t ) ulLength;
\r
1792 pxSegment->lStreamPos = lPosition;
\r
1793 pxSegment->u.ulFlags = 0UL;
\r
1794 vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
\r
1796 /* Increase the sequence number of the next data to be stored for
\r
1798 pxWindow->ulNextTxSequenceNumber += ulLength;
\r
1799 lResult = ( int32_t )ulLength;
\r
1805 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1806 /*-----------------------------------------------------------*/
\r
1808 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1810 uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
\r
1812 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1813 uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
\r
1814 uint32_t ulMaxTime;
\r
1816 if( ulLength != 0UL )
\r
1818 /* _HT_ Still under investigation */
\r
1819 ( void ) ulWindowSize;
\r
1821 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1823 /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
\r
1824 ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1826 if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
\r
1832 if( ulLength != 0ul )
\r
1834 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
\r
1835 pxSegment->u.bits.ucTransmitCount++;
\r
1836 vTCPTimerSet (&pxSegment->xTransmitTimer);
\r
1837 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
\r
1838 *plPosition = pxSegment->lStreamPos;
\r
1845 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1846 /*-----------------------------------------------------------*/
\r
1848 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1850 BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
\r
1852 BaseType_t xReturn;
\r
1854 /* Has the outstanding data been sent because user wants to shutdown? */
\r
1855 if( pxWindow->xTxSegment.lDataLength == 0 )
\r
1861 xReturn = pdFALSE;
\r
1867 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1868 /*-----------------------------------------------------------*/
\r
1870 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1872 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
\r
1873 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
\r
1875 BaseType_t xReturn;
\r
1877 if( ulWindowSize >= pxWindow->usMSSInit )
\r
1883 xReturn = pdFALSE;
\r
1889 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1890 /*-----------------------------------------------------------*/
\r
1892 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1894 BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
\r
1896 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1897 BaseType_t xReturn;
\r
1898 TickType_t ulAge, ulMaxAge;
\r
1900 /* Check data to be sent. */
\r
1901 *pulDelay = ( TickType_t ) 0;
\r
1902 if( pxSegment->lDataLength == 0 )
\r
1904 /* Got nothing to send right now. */
\r
1905 xReturn = pdFALSE;
\r
1909 if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
\r
1911 ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
\r
1912 ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
\r
1914 if( ulMaxAge > ulAge )
\r
1916 *pulDelay = ulMaxAge - ulAge;
\r
1921 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
\r
1923 /* Too many outstanding messages. */
\r
1924 xReturn = pdFALSE;
\r
1935 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1936 /*-----------------------------------------------------------*/
\r
1938 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1940 uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
\r
1942 TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
\r
1943 uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
\r
1945 /* Receive a normal ACK */
\r
1947 if( ulDataLength != 0ul )
\r
1949 if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
\r
1951 if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
\r
1953 FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
\r
1954 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1955 pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1959 /* Nothing to send right now. */
\r
1960 ulDataLength = 0ul;
\r
1964 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
\r
1966 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
\r
1968 FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
\r
1969 ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
\r
1973 pxSegment->lDataLength = 0;
\r
1977 return ulDataLength;
\r
1980 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1981 /*-----------------------------------------------------------*/
\r
1983 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1985 BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
\r
1987 /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
\r
1988 'ulCurrentSequenceNumber' is the highest sequence number stored,
\r
1989 'ulHighestSequenceNumber' is the highest sequence number seen. */
\r
1990 return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
\r
1993 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
1994 /*-----------------------------------------------------------*/
\r
1996 #if( ipconfigUSE_TCP_WIN == 0 )
\r
1998 /* Destroy a window (always returns NULL) */
\r
1999 void vTCPWindowDestroy( TCPWindow_t *pxWindow )
\r
2001 /* As in tiny TCP there are no shared segments descriptors, there is
\r
2002 nothing to release. */
\r
2003 ( void ) pxWindow;
\r
2006 #endif /* ipconfigUSE_TCP_WIN == 0 */
\r
2007 /*-----------------------------------------------------------*/
\r