1 /* 2 * FreeRTOS+TCP <DEVELOPMENT BRANCH> 3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * SPDX-License-Identifier: MIT 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 * this software and associated documentation files (the "Software"), to deal in 9 * the Software without restriction, including without limitation the rights to 10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 * the Software, and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * http://aws.amazon.com/freertos 25 * http://www.FreeRTOS.org 26 */ 27 28 29 /** 30 * @file FreeRTOS_TCP_WIN.c 31 * @brief Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many 32 * functions have two versions - one for FreeRTOS+TCP (full) and one for 33 * FreeRTOS+TCP (lite). 34 * 35 * In this module all ports and IP addresses and sequence numbers are 36 * being stored in host byte-order. 37 */ 38 39 /* Standard includes. */ 40 #include <stdint.h> 41 42 /* FreeRTOS includes. */ 43 #include "FreeRTOS.h" 44 #include "task.h" 45 46 /* FreeRTOS+TCP includes. */ 47 #include "FreeRTOS_IP.h" 48 #include "FreeRTOS_UDP_IP.h" 49 #include "FreeRTOS_Sockets.h" 50 #include "FreeRTOS_IP_Private.h" 51 52 #if ( ipconfigUSE_TCP == 1 ) 53 54 /* Constants used for Smoothed Round Trip Time (SRTT). */ 55 #define winSRTT_INCREMENT_NEW 2 /**< New increment for the smoothed RTT. */ 56 #define winSRTT_INCREMENT_CURRENT 6 /**< Current increment for the smoothed RTT. */ 57 #define winSRTT_DECREMENT_NEW 1 /**< New decrement for the smoothed RTT. */ 58 #define winSRTT_DECREMENT_CURRENT 7 /**< Current decrement for the smoothed RTT. */ 59 #define winSRTT_CAP_mS ( ipconfigTCP_SRTT_MINIMUM_VALUE_MS ) /**< Cap in milliseconds. */ 60 61 #if ( ipconfigUSE_TCP_WIN == 1 ) 62 63 /** @brief Create a new Rx window. */ 64 #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE ) 65 66 /** @brief Create a new Tx window. */ 67 #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE ) 68 69 /** @brief The code to send a single Selective ACK (SACK): 70 * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a), 71 * followed by a lower and a higher sequence number, 72 * where LEN is 2 + 2*4 = 10 bytes. */ 73 #if ( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN ) 74 #define OPTION_CODE_SINGLE_SACK ( 0x0101050aU ) 75 #else 76 #define OPTION_CODE_SINGLE_SACK ( 0x0a050101U ) 77 #endif 78 79 /** @brief Normal retransmission: 80 * A packet will be retransmitted after a Retransmit Time-Out (RTO). 81 * Fast retransmission: 82 * When 3 packets with a higher sequence number have been acknowledged 83 * by the peer, it is very unlikely a current packet will ever arrive. 84 * It will be retransmitted far before the RTO. 85 */ 86 #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3U ) 87 88 /** @brief If there have been several retransmissions (4), decrease the 89 * size of the transmission window to at most 2 times MSS. 90 */ 91 #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4U ) 92 93 #endif /* configUSE_TCP_WIN */ 94 /*-----------------------------------------------------------*/ 95 96 #if ( ipconfigUSE_TCP_WIN == 1 ) 97 static void vListInsertGeneric( List_t * const pxList, 98 ListItem_t * const pxNewListItem, 99 MiniListItem_t * pxWhere ); 100 #endif 101 102 /* 103 * All TCP sockets share a pool of segment descriptors (TCPSegment_t) 104 * Available descriptors are stored in the 'xSegmentList' 105 * When a socket owns a descriptor, it will either be stored in 106 * 'xTxSegments' or 'xRxSegments' 107 * As soon as a package has been confirmed, the descriptor will be returned 108 * to the segment pool 109 */ 110 #if ( ipconfigUSE_TCP_WIN == 1 ) 111 static BaseType_t prvCreateSectors( void ); 112 #endif /* ipconfigUSE_TCP_WIN == 1 */ 113 114 /* 115 * Find a segment with a given sequence number in the list of received 116 * segments: 'pxWindow->xRxSegments'. 117 */ 118 #if ( ipconfigUSE_TCP_WIN == 1 ) 119 static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow, 120 uint32_t ulSequenceNumber ); 121 #endif /* ipconfigUSE_TCP_WIN == 1 */ 122 123 /* 124 * Allocate a new segment 125 * The socket will borrow all segments from a common pool: 'xSegmentList', 126 * which is a list of 'TCPSegment_t' 127 */ 128 #if ( ipconfigUSE_TCP_WIN == 1 ) 129 static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow, 130 uint32_t ulSequenceNumber, 131 int32_t lCount, 132 BaseType_t xIsForRx ); 133 #endif /* ipconfigUSE_TCP_WIN == 1 */ 134 135 /* 136 * Detaches and returns the head of a queue 137 */ 138 #if ( ipconfigUSE_TCP_WIN == 1 ) 139 static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList ); 140 #endif /* ipconfigUSE_TCP_WIN == 1 */ 141 142 /* 143 * Returns the head of a queue but it won't be detached 144 */ 145 #if ( ipconfigUSE_TCP_WIN == 1 ) 146 static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList ); 147 #endif /* ipconfigUSE_TCP_WIN == 1 */ 148 149 /* 150 * Free entry pxSegment because it's not used anymore 151 * The ownership will be passed back to the segment pool 152 */ 153 #if ( ipconfigUSE_TCP_WIN == 1 ) 154 static void vTCPWindowFree( TCPSegment_t * pxSegment ); 155 #endif /* ipconfigUSE_TCP_WIN == 1 */ 156 157 /* 158 * A segment has been received with sequence number 'ulSequenceNumber', where 159 * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this 160 * segment was expected. xTCPWindowRxConfirm() will check if there is already 161 * another segment with a sequence number between (ulSequenceNumber) and 162 * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx 163 * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'. 164 */ 165 #if ( ipconfigUSE_TCP_WIN == 1 ) 166 static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow, 167 uint32_t ulSequenceNumber, 168 uint32_t ulLength ); 169 #endif /* ipconfigUSE_TCP_WIN == 1 */ 170 171 /* 172 * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to 173 * store. 174 */ 175 #if ( ipconfigUSE_TCP_WIN == 1 ) 176 static int32_t lTCPIncrementTxPosition( int32_t lPosition, 177 int32_t lMax, 178 int32_t lCount ); 179 #endif /* ipconfigUSE_TCP_WIN == 1 */ 180 181 /* 182 * This function will look if there is new transmission data. It will return 183 * true if there is data to be sent. 184 */ 185 #if ( ipconfigUSE_TCP_WIN == 1 ) 186 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow, 187 uint32_t ulWindowSize ); 188 #endif /* ipconfigUSE_TCP_WIN == 1 */ 189 190 /* 191 * An acknowledge was received. See if some outstanding data may be removed 192 * from the transmission queue(s). 193 */ 194 #if ( ipconfigUSE_TCP_WIN == 1 ) 195 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow, 196 uint32_t ulFirst, 197 uint32_t ulLast ); 198 #endif /* ipconfigUSE_TCP_WIN == 1 */ 199 200 /* 201 * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue 202 * to find a possible condition for a FAST retransmission. 203 */ 204 #if ( ipconfigUSE_TCP_WIN == 1 ) 205 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow, 206 uint32_t ulFirst ); 207 #endif /* ipconfigUSE_TCP_WIN == 1 */ 208 209 /*-----------------------------------------------------------*/ 210 211 /**< TCP segment pool. */ 212 #if ( ipconfigUSE_TCP_WIN == 1 ) 213 static TCPSegment_t * xTCPSegments = NULL; 214 #endif /* ipconfigUSE_TCP_WIN == 1 */ 215 216 /**< List of free TCP segments. */ 217 #if ( ipconfigUSE_TCP_WIN == 1 ) 218 _static List_t xSegmentList; 219 #endif 220 221 #if ( ipconfigUSE_TCP_WIN == 1 ) 222 /** @brief Logging verbosity level. */ 223 BaseType_t xTCPWindowLoggingLevel = 0; 224 #endif 225 226 #if ( ipconfigUSE_TCP_WIN == 1 ) 227 /* Some 32-bit arithmetic: comparing sequence numbers */ 228 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, 229 uint32_t b ); 230 231 /** 232 * @brief Check if a <= b. 233 * 234 * @param[in] a The value on the left-hand side. 235 * @param[in] b The value on the right-hand side. 236 * 237 * @return pdTRUE when "( b - a ) < 0x80000000". Else, pdFALSE. 238 */ xSequenceLessThanOrEqual(uint32_t a,uint32_t b)239 static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, 240 uint32_t b ) 241 { 242 BaseType_t xResult = pdFALSE; 243 244 /* Test if a <= b 245 * Return true if the unsigned subtraction of (b-a) doesn't generate an 246 * arithmetic overflow. */ 247 if( ( ( b - a ) & 0x80000000U ) == 0U ) 248 { 249 xResult = pdTRUE; 250 } 251 252 return xResult; 253 } 254 255 #endif /* ipconfigUSE_TCP_WIN */ 256 /*-----------------------------------------------------------*/ 257 258 /** 259 * @brief Check if a < b. 260 * 261 * @param[in] a The value on the left-hand side. 262 * @param[in] b The value on the right-hand side. 263 * 264 * @return pdTRUE when "( b - ( a + 1 ) ) < 0x80000000", else pdFALSE. 265 */ xSequenceLessThan(uint32_t a,uint32_t b)266 BaseType_t xSequenceLessThan( uint32_t a, 267 uint32_t b ) 268 { 269 BaseType_t xResult = pdFALSE; 270 271 /* Test if a < b */ 272 if( ( ( b - ( a + 1U ) ) & 0x80000000U ) == 0U ) 273 { 274 xResult = pdTRUE; 275 } 276 277 return xResult; 278 } 279 280 /*-----------------------------------------------------------*/ 281 282 /** 283 * @brief Check if a > b. 284 * 285 * @param[in] a The value on the left-hand side. 286 * @param[in] b The value on the right-hand side. 287 * 288 * @return pdTRUE when "( a - b ) < 0x80000000", else pdFALSE. 289 */ xSequenceGreaterThan(uint32_t a,uint32_t b)290 BaseType_t xSequenceGreaterThan( uint32_t a, 291 uint32_t b ) 292 { 293 BaseType_t xResult = pdFALSE; 294 295 /* Test if a > b */ 296 if( ( ( a - ( b + 1U ) ) & 0x80000000U ) == 0U ) 297 { 298 xResult = pdTRUE; 299 } 300 301 return xResult; 302 } 303 304 305 /*-----------------------------------------------------------*/ 306 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, 307 uint32_t b ); 308 309 /** 310 * @brief Test if a>=b. This function is required since the sequence numbers can roll over. 311 * 312 * @param[in] a The first sequence number. 313 * @param[in] b The second sequence number. 314 * 315 * @return pdTRUE if a>=b, else pdFALSE. 316 */ xSequenceGreaterThanOrEqual(uint32_t a,uint32_t b)317 static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, 318 uint32_t b ) 319 { 320 BaseType_t xResult = pdFALSE; 321 322 /* Test if a >= b */ 323 if( ( ( a - b ) & 0x80000000U ) == 0U ) 324 { 325 xResult = pdTRUE; 326 } 327 328 return xResult; 329 } 330 /*-----------------------------------------------------------*/ 331 332 #if ( ipconfigUSE_TCP_WIN == 1 ) 333 static portINLINE void vListInsertFifo( List_t * const pxList, 334 ListItem_t * const pxNewListItem ); 335 336 /** 337 * @brief Insert the given item in the list in FIFO manner. 338 * 339 * @param[in] pxList The list in which the item is to inserted. 340 * @param[in] pxNewListItem The item to be inserted. 341 */ vListInsertFifo(List_t * const pxList,ListItem_t * const pxNewListItem)342 static portINLINE void vListInsertFifo( List_t * const pxList, 343 ListItem_t * const pxNewListItem ) 344 { 345 vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd ); 346 } 347 #endif 348 /*-----------------------------------------------------------*/ 349 350 static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer ); 351 352 /** 353 * @brief Set the timer's "born" time. 354 * 355 * @param[in] pxTimer The TCP timer. 356 */ vTCPTimerSet(TCPTimer_t * pxTimer)357 static portINLINE void vTCPTimerSet( TCPTimer_t * pxTimer ) 358 { 359 pxTimer->uxBorn = xTaskGetTickCount(); 360 } 361 /*-----------------------------------------------------------*/ 362 363 static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer ); 364 365 /** 366 * @brief Get the timer age in milliseconds. 367 * 368 * @param[in] pxTimer The timer whose age is to be fetched. 369 * 370 * @return The time in milliseconds since the timer was born. 371 */ ulTimerGetAge(const TCPTimer_t * pxTimer)372 static portINLINE uint32_t ulTimerGetAge( const TCPTimer_t * pxTimer ) 373 { 374 TickType_t uxNow = xTaskGetTickCount(); 375 TickType_t uxDiff = uxNow - pxTimer->uxBorn; 376 377 return ( uint32_t ) ( uxDiff * portTICK_PERIOD_MS ); 378 } 379 /*-----------------------------------------------------------*/ 380 381 /** 382 * @brief Insert a new list item into a list. 383 * 384 * @param[in] pxList The list in which the item is to be inserted. 385 * @param[in] pxNewListItem The item to be inserted. 386 * @param[in] pxWhere Where should the item be inserted. 387 */ 388 #if ( ipconfigUSE_TCP_WIN == 1 ) vListInsertGeneric(List_t * const pxList,ListItem_t * const pxNewListItem,MiniListItem_t * pxWhere)389 static void vListInsertGeneric( List_t * const pxList, 390 ListItem_t * const pxNewListItem, 391 MiniListItem_t * pxWhere ) 392 { 393 /* Insert a new list item into pxList, it does not sort the list, 394 * but it puts the item just before xListEnd, so it will be the last item 395 * returned by listGET_HEAD_ENTRY() */ 396 397 /* MISRA Ref 11.3.1 [Misaligned access] */ 398 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 399 /* coverity[misra_c_2012_rule_11_3_violation] */ 400 pxNewListItem->pxNext = ( ( ListItem_t * ) pxWhere ); 401 402 pxNewListItem->pxPrevious = pxWhere->pxPrevious; 403 pxWhere->pxPrevious->pxNext = pxNewListItem; 404 pxWhere->pxPrevious = pxNewListItem; 405 406 /* Remember which list the item is in. */ 407 listLIST_ITEM_CONTAINER( pxNewListItem ) = ( struct xLIST * configLIST_VOLATILE ) pxList; 408 409 ( pxList->uxNumberOfItems )++; 410 } 411 #endif /* if ( ipconfigUSE_TCP_WIN == 1 ) */ 412 /*-----------------------------------------------------------*/ 413 414 #if ( ipconfigUSE_TCP_WIN == 1 ) 415 416 /** 417 * @brief Creates a pool of 'ipconfigTCP_WIN_SEG_COUNT' sector buffers. Should be called once only. 418 * 419 * @return When the allocation was successful: pdPASS, otherwise pdFAIL. 420 */ prvCreateSectors(void)421 static BaseType_t prvCreateSectors( void ) 422 { 423 BaseType_t xIndex; 424 BaseType_t xReturn; 425 426 /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */ 427 428 vListInitialise( &xSegmentList ); 429 xTCPSegments = ( ( TCPSegment_t * ) pvPortMallocLarge( ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) ); 430 431 if( xTCPSegments == NULL ) 432 { 433 FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %u failed\n", 434 ( unsigned ) ( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) ) ); 435 436 xReturn = pdFAIL; 437 } 438 else 439 { 440 /* Clear the allocated space. */ 441 ( void ) memset( xTCPSegments, 0, ( size_t ) ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ); 442 443 for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ ) 444 { 445 /* Could call vListInitialiseItem here but all data has been 446 * nulled already. Set the owner to a segment descriptor. */ 447 448 #if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) 449 { 450 vListInitialiseItem( &( xTCPSegments[ xIndex ].xSegmentItem ) ); 451 vListInitialiseItem( &( xTCPSegments[ xIndex ].xQueueItem ) ); 452 } 453 #endif 454 455 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xSegmentItem ), ( void * ) &( xTCPSegments[ xIndex ] ) ); 456 listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void * ) &( xTCPSegments[ xIndex ] ) ); 457 458 /* And add it to the pool of available segments */ 459 vListInsertFifo( &xSegmentList, &( xTCPSegments[ xIndex ].xSegmentItem ) ); 460 } 461 462 xReturn = pdPASS; 463 } 464 465 return xReturn; 466 } 467 #endif /* ipconfigUSE_TCP_WIN == 1 */ 468 /*-----------------------------------------------------------*/ 469 470 #if ( ipconfigUSE_TCP_WIN == 1 ) 471 472 /** 473 * @brief Find a segment with a given sequence number in the list of received segments. 474 * 475 * @param[in] pxWindow The descriptor of the TCP sliding windows. 476 * @param[in] ulSequenceNumber the sequence number to look-up 477 * 478 * @return The address of the segment descriptor found, or NULL when not found. 479 */ xTCPWindowRxFind(const TCPWindow_t * pxWindow,uint32_t ulSequenceNumber)480 static TCPSegment_t * xTCPWindowRxFind( const TCPWindow_t * pxWindow, 481 uint32_t ulSequenceNumber ) 482 { 483 const ListItem_t * pxIterator; 484 const ListItem_t * pxEnd; 485 TCPSegment_t * pxSegment, * pxReturn = NULL; 486 487 /* Find a segment with a given sequence number in the list of received 488 * segments. */ 489 490 /* MISRA Ref 11.3.1 [Misaligned access] */ 491 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 492 /* coverity[misra_c_2012_rule_11_3_violation] */ 493 pxEnd = ( ( const ListItem_t * ) &( pxWindow->xRxSegments.xListEnd ) ); 494 495 for( pxIterator = listGET_NEXT( pxEnd ); 496 pxIterator != pxEnd; 497 pxIterator = listGET_NEXT( pxIterator ) ) 498 { 499 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) ); 500 501 if( pxSegment->ulSequenceNumber == ulSequenceNumber ) 502 { 503 pxReturn = pxSegment; 504 break; 505 } 506 } 507 508 return pxReturn; 509 } 510 #endif /* ipconfigUSE_TCP_WIN == 1 */ 511 /*-----------------------------------------------------------*/ 512 513 #if ( ipconfigUSE_TCP_WIN == 1 ) 514 515 /** 516 * @brief Allocate a new segment object, either for transmission or reception. 517 * 518 * @param[in] pxWindow The descriptor of the TCP sliding windows. 519 * @param[in] ulSequenceNumber The sequence number. 520 * @param[in] lCount The number of bytes stored in this segment. 521 * @param[in] xIsForRx True when this is a reception segment. 522 * 523 * @return Allocate and initialise a segment descriptor, or NULL when none was available. 524 */ xTCPWindowNew(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,int32_t lCount,BaseType_t xIsForRx)525 static TCPSegment_t * xTCPWindowNew( TCPWindow_t * pxWindow, 526 uint32_t ulSequenceNumber, 527 int32_t lCount, 528 BaseType_t xIsForRx ) 529 { 530 TCPSegment_t * pxSegment; 531 ListItem_t * pxItem; 532 533 /* Allocate a new segment. The socket will borrow all segments from a 534 * common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */ 535 if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE ) 536 { 537 /* If the TCP-stack runs out of segments, you might consider 538 * increasing 'ipconfigTCP_WIN_SEG_COUNT'. */ 539 FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", ( xIsForRx != 0 ) ? 'R' : 'T' ) ); 540 pxSegment = NULL; 541 } 542 else 543 { 544 /* Pop the item at the head of the list. Semaphore protection is 545 * not required as only the IP task will call these functions. */ 546 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList ); 547 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) ); 548 549 configASSERT( pxItem != NULL ); 550 configASSERT( pxSegment != NULL ); 551 552 /* Remove the item from xSegmentList. */ 553 ( void ) uxListRemove( pxItem ); 554 555 /* Add it to either the connections' Rx or Tx queue. */ 556 if( xIsForRx != 0 ) 557 { 558 vListInsertFifo( &pxWindow->xRxSegments, pxItem ); 559 } 560 else 561 { 562 vListInsertFifo( &pxWindow->xTxSegments, pxItem ); 563 } 564 565 /* And set the segment's timer to zero */ 566 vTCPTimerSet( &pxSegment->xTransmitTimer ); 567 568 pxSegment->u.ulFlags = 0; 569 pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 ) ? 1U : 0U; 570 pxSegment->lMaxLength = lCount; 571 pxSegment->lDataLength = lCount; 572 pxSegment->ulSequenceNumber = ulSequenceNumber; 573 #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) 574 { 575 static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT; 576 UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList ); 577 578 if( xLowestLength > xLength ) 579 { 580 xLowestLength = xLength; 581 } 582 } 583 #endif /* ipconfigHAS_DEBUG_PRINTF */ 584 } 585 586 return pxSegment; 587 } 588 #endif /* ipconfigUSE_TCP_WIN == 1 */ 589 /*-----------------------------------------------------------*/ 590 591 #if ( ipconfigUSE_TCP_WIN == 1 ) 592 593 /** 594 * @brief See if the peer has more packets for this node, before allowing to shut down the connection. 595 * 596 * @param[in] pxWindow The descriptor of the TCP sliding windows. 597 * 598 * @return pdTRUE if the connection can be closed. Else, pdFALSE. 599 */ xTCPWindowRxEmpty(const TCPWindow_t * pxWindow)600 BaseType_t xTCPWindowRxEmpty( const TCPWindow_t * pxWindow ) 601 { 602 BaseType_t xReturn; 603 604 /* When the peer has a close request (FIN flag), the driver will check 605 * if there are missing packets in the Rx-queue. It will accept the 606 * closure of the connection if both conditions are true: 607 * - the Rx-queue is empty 608 * - the highest Rx sequence number has been ACK'ed */ 609 if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE ) 610 { 611 /* Rx data has been stored while earlier packets were missing. */ 612 xReturn = pdFALSE; 613 } 614 else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber + 1U, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE ) 615 { 616 /* No Rx packets are being stored and the highest sequence number 617 * that has been received has been ACKed. */ 618 xReturn = pdTRUE; 619 } 620 else 621 { 622 FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %u highest %u (empty)\n", 623 ( unsigned ) ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 624 ( unsigned ) ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) ); 625 xReturn = pdFALSE; 626 } 627 628 return xReturn; 629 } 630 #endif /* ipconfigUSE_TCP_WIN == 1 */ 631 /*-----------------------------------------------------------*/ 632 633 #if ( ipconfigUSE_TCP_WIN == 1 ) 634 635 /** 636 * @brief Remove the head item of a list (generic function). 637 * 638 * @param[in] pxList The list of segment descriptors. 639 * 640 * @return The address of the segment descriptor, or NULL when not found. 641 */ xTCPWindowGetHead(const List_t * pxList)642 static TCPSegment_t * xTCPWindowGetHead( const List_t * pxList ) 643 { 644 TCPSegment_t * pxSegment; 645 ListItem_t * pxItem; 646 647 /* Detaches and returns the head of a queue. */ 648 if( listLIST_IS_EMPTY( pxList ) != pdFALSE ) 649 { 650 pxSegment = NULL; 651 } 652 else 653 { 654 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList ); 655 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) ); 656 657 ( void ) uxListRemove( pxItem ); 658 } 659 660 return pxSegment; 661 } 662 #endif /* ipconfigUSE_TCP_WIN == 1 */ 663 /*-----------------------------------------------------------*/ 664 665 #if ( ipconfigUSE_TCP_WIN == 1 ) 666 667 /** 668 * @brief Return the head item of a list (generic function). 669 * 670 * @param[in] pxList The list of segment descriptors. 671 * 672 * @return The address of the segment descriptor, or NULL when the list is empty. 673 */ xTCPWindowPeekHead(const List_t * pxList)674 static TCPSegment_t * xTCPWindowPeekHead( const List_t * pxList ) 675 { 676 const ListItem_t * pxItem; 677 TCPSegment_t * pxReturn; 678 679 /* Returns the head of a queue but it won't be detached. */ 680 if( listLIST_IS_EMPTY( pxList ) != pdFALSE ) 681 { 682 pxReturn = NULL; 683 } 684 else 685 { 686 pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList ); 687 pxReturn = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ) ); 688 } 689 690 return pxReturn; 691 } 692 #endif /* ipconfigUSE_TCP_WIN == 1 */ 693 /*-----------------------------------------------------------*/ 694 695 #if ( ipconfigUSE_TCP_WIN == 1 ) 696 697 /** 698 * @brief Release a segment object, return it to the list of available segment holders. 699 * 700 * @param[in] pxSegment The segment descriptor that must be freed. 701 */ vTCPWindowFree(TCPSegment_t * pxSegment)702 static void vTCPWindowFree( TCPSegment_t * pxSegment ) 703 { 704 /* Free entry pxSegment because it's not used any more. The ownership 705 * will be passed back to the segment pool. 706 * 707 * Unlink it from one of the queues, if any. */ 708 if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) 709 { 710 ( void ) uxListRemove( &( pxSegment->xQueueItem ) ); 711 } 712 713 pxSegment->ulSequenceNumber = 0U; 714 pxSegment->lDataLength = 0; 715 pxSegment->u.ulFlags = 0U; 716 717 /* Take it out of xRxSegments/xTxSegments */ 718 if( listLIST_ITEM_CONTAINER( &( pxSegment->xSegmentItem ) ) != NULL ) 719 { 720 ( void ) uxListRemove( &( pxSegment->xSegmentItem ) ); 721 } 722 723 /* Return it to xSegmentList */ 724 vListInsertFifo( &xSegmentList, &( pxSegment->xSegmentItem ) ); 725 } 726 #endif /* ipconfigUSE_TCP_WIN == 1 */ 727 /*-----------------------------------------------------------*/ 728 729 #if ( ipconfigUSE_TCP_WIN == 1 ) 730 731 /** 732 * @brief Return all segment descriptor to the poll of descriptors, before deleting a socket. 733 * 734 * @param[in] pxWindow The descriptor of the TCP sliding windows. 735 */ vTCPWindowDestroy(TCPWindow_t const * pxWindow)736 void vTCPWindowDestroy( TCPWindow_t const * pxWindow ) 737 { 738 const List_t * pxSegments; 739 BaseType_t xRound; 740 TCPSegment_t * pxSegment; 741 742 /* Destroy a window. A TCP window doesn't serve any more. Return all 743 * owned segments to the pool. In order to save code, it will make 2 rounds, 744 * one to remove the segments from xRxSegments, and a second round to clear 745 * xTxSegments*/ 746 for( xRound = 0; xRound < 2; xRound++ ) 747 { 748 if( xRound != 0 ) 749 { 750 pxSegments = &( pxWindow->xRxSegments ); 751 } 752 else 753 { 754 pxSegments = &( pxWindow->xTxSegments ); 755 } 756 757 if( listLIST_IS_INITIALISED( pxSegments ) ) 758 { 759 while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U ) 760 { 761 pxSegment = ( ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments ) ); 762 vTCPWindowFree( pxSegment ); 763 } 764 } 765 } 766 } 767 #endif /* ipconfigUSE_TCP_WIN == 1 */ 768 /*-----------------------------------------------------------*/ 769 770 /** 771 * @brief Create a window for TCP. 772 * 773 * @param[in] pxWindow The window to be created. 774 * @param[in] ulRxWindowLength The length of the receive window. 775 * @param[in] ulTxWindowLength The length of the transmit window. 776 * @param[in] ulAckNumber The first ACK number. 777 * @param[in] ulSequenceNumber The first sequence number. 778 * @param[in] ulMSS The MSS of the connection. 779 */ vTCPWindowCreate(TCPWindow_t * pxWindow,uint32_t ulRxWindowLength,uint32_t ulTxWindowLength,uint32_t ulAckNumber,uint32_t ulSequenceNumber,uint32_t ulMSS)780 void vTCPWindowCreate( TCPWindow_t * pxWindow, 781 uint32_t ulRxWindowLength, 782 uint32_t ulTxWindowLength, 783 uint32_t ulAckNumber, 784 uint32_t ulSequenceNumber, 785 uint32_t ulMSS ) 786 { 787 /* Create and initialize a window. */ 788 789 #if ( ipconfigUSE_TCP_WIN == 1 ) 790 { 791 if( xTCPSegments == NULL ) 792 { 793 ( void ) prvCreateSectors(); 794 } 795 796 vListInitialise( &( pxWindow->xTxSegments ) ); 797 vListInitialise( &( pxWindow->xRxSegments ) ); 798 799 vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */ 800 vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */ 801 vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */ 802 } 803 #endif /* ipconfigUSE_TCP_WIN == 1 */ 804 805 if( xTCPWindowLoggingLevel != 0 ) 806 { 807 FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %u/%u\n", 808 ( unsigned ) ulRxWindowLength, ( unsigned ) ulTxWindowLength ) ); 809 } 810 811 pxWindow->xSize.ulRxWindowLength = ulRxWindowLength; 812 pxWindow->xSize.ulTxWindowLength = ulTxWindowLength; 813 814 vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS ); 815 } 816 /*-----------------------------------------------------------*/ 817 818 /** 819 * @brief Initialise a TCP window. 820 * 821 * @param[in] pxWindow The window to be initialised. 822 * @param[in] ulAckNumber The number of the first ACK. 823 * @param[in] ulSequenceNumber The first sequence number. 824 * @param[in] ulMSS The MSS of the connection. 825 */ vTCPWindowInit(TCPWindow_t * pxWindow,uint32_t ulAckNumber,uint32_t ulSequenceNumber,uint32_t ulMSS)826 void vTCPWindowInit( TCPWindow_t * pxWindow, 827 uint32_t ulAckNumber, 828 uint32_t ulSequenceNumber, 829 uint32_t ulMSS ) 830 { 831 const int32_t l500ms = 500; 832 833 pxWindow->u.ulFlags = 0U; 834 pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED; 835 836 if( ulMSS != 0U ) 837 { 838 if( pxWindow->usMSSInit != 0U ) 839 { 840 pxWindow->usMSSInit = ( uint16_t ) ulMSS; 841 } 842 843 if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0U ) ) 844 { 845 pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS; 846 pxWindow->usMSS = ( uint16_t ) ulMSS; 847 } 848 } 849 850 #if ( ipconfigUSE_TCP_WIN == 0 ) 851 { 852 pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS; 853 } 854 #endif /* ipconfigUSE_TCP_WIN == 1 */ 855 856 /*Start with a timeout of 2 * 500 ms (1 sec). */ 857 pxWindow->lSRTT = l500ms; 858 859 /* Just for logging, to print relative sequence numbers. */ 860 pxWindow->rx.ulFirstSequenceNumber = ulAckNumber; 861 862 /* The segment asked for in the next transmission. */ 863 pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber; 864 865 /* The right-hand side of the receive window. */ 866 pxWindow->rx.ulHighestSequenceNumber = ulAckNumber; 867 868 pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber; 869 870 /* The segment asked for in next transmission. */ 871 pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber; 872 873 /* The sequence number given to the next outgoing byte to be added is 874 * maintained by lTCPWindowTxAdd(). */ 875 pxWindow->ulNextTxSequenceNumber = ulSequenceNumber; 876 877 /* The right-hand side of the transmit window. */ 878 pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber; 879 pxWindow->ulOurSequenceNumber = ulSequenceNumber; 880 } 881 /*-----------------------------------------------------------*/ 882 883 #if ( ipconfigUSE_TCP_WIN == 1 ) 884 885 /** 886 * @brief Free the space occupied by the pool of segment descriptors, normally never used 887 */ vTCPSegmentCleanup(void)888 void vTCPSegmentCleanup( void ) 889 { 890 /* Free and clear the TCP segments pointer. This function should only be called 891 * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this 892 * function. */ 893 if( xTCPSegments != NULL ) 894 { 895 vPortFreeLarge( xTCPSegments ); 896 xTCPSegments = NULL; 897 } 898 } 899 #endif /* ipconfgiUSE_TCP_WIN == 1 */ 900 /*-----------------------------------------------------------*/ 901 902 /*============================================================================= 903 * 904 * ###### # # 905 * # # # # 906 * # # # # 907 * # # #### 908 * ###### ## 909 * # ## #### 910 * # # # # 911 * # # # # 912 * ### ## # # 913 * Rx functions 914 * 915 *=============================================================================*/ 916 917 #if ( ipconfigUSE_TCP_WIN == 1 ) 918 919 /** 920 * @brief A expected segment has been received, see if there is overlap with earlier segments. 921 * 922 * @param[in] pxWindow The descriptor of the TCP sliding windows. 923 * @param[in] ulSequenceNumber The sequence number of the segment that was received. 924 * @param[in] ulLength The number of bytes that were received. 925 * 926 * @return The first segment descriptor involved, or NULL when no matching descriptor was found. 927 */ xTCPWindowRxConfirm(const TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength)928 static TCPSegment_t * xTCPWindowRxConfirm( const TCPWindow_t * pxWindow, 929 uint32_t ulSequenceNumber, 930 uint32_t ulLength ) 931 { 932 TCPSegment_t * pxBest = NULL; 933 const ListItem_t * pxIterator; 934 uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength; 935 936 /* MISRA Ref 11.3.1 [Misaligned access] */ 937 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 938 /* coverity[misra_c_2012_rule_11_3_violation] */ 939 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxWindow->xRxSegments.xListEnd ) ); 940 TCPSegment_t * pxSegment; 941 942 /* A segment has been received with sequence number 'ulSequenceNumber', 943 * where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that 944 * exactly this segment was expected. xTCPWindowRxConfirm() will check if 945 * there is already another segment with a sequence number between (ulSequenceNumber) 946 * and (ulSequenceNumber+ulLength). Normally none will be found, because 947 * the next RX segment should have a sequence number equal to 948 * '(ulSequenceNumber+ulLength)'. */ 949 950 /* Iterate through all RX segments that are stored: */ 951 for( pxIterator = listGET_NEXT( pxEnd ); 952 pxIterator != pxEnd; 953 pxIterator = listGET_NEXT( pxIterator ) ) 954 { 955 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) ); 956 957 /* And see if there is a segment for which: 958 * 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber' 959 * If there are more matching segments, the one with the lowest sequence number 960 * shall be taken */ 961 if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) && 962 ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) ) 963 { 964 if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) ) 965 { 966 pxBest = pxSegment; 967 } 968 } 969 } 970 971 if( ( pxBest != NULL ) && 972 ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) ) 973 { 974 FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %u (+%u=%u) found %u (+%d=%u)\n", 975 pxWindow->usPeerPortNumber, 976 ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 977 ( unsigned ) ulLength, 978 ( unsigned ) ( ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber ), 979 ( unsigned ) ( pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 980 ( int ) pxBest->lDataLength, 981 ( unsigned ) ( pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) ) ); 982 } 983 984 return pxBest; 985 } 986 #endif /* ipconfgiUSE_TCP_WIN == 1 */ 987 /*-----------------------------------------------------------*/ 988 989 #if ( ipconfigUSE_TCP_WIN == 1 ) 990 991 /** 992 * @brief Data has been received with the correct ( expected ) sequence number. 993 * It can be added to the RX stream buffer. 994 * @param[in] pxWindow The TCP sliding window data of the socket. 995 * @param[in] ulLength The number of bytes that can be added. 996 */ prvTCPWindowRx_ExpectedRX(TCPWindow_t * pxWindow,uint32_t ulLength)997 static void prvTCPWindowRx_ExpectedRX( TCPWindow_t * pxWindow, 998 uint32_t ulLength ) 999 { 1000 uint32_t ulSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber; 1001 uint32_t ulCurrentSequenceNumber = ulSequenceNumber + ulLength; 1002 1003 if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0U ) 1004 { 1005 uint32_t ulSavedSequenceNumber = ulCurrentSequenceNumber; 1006 TCPSegment_t * pxFound; 1007 1008 /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated. 1009 * If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed. 1010 * So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just 1011 * clean them out. */ 1012 do 1013 { 1014 pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); 1015 1016 if( pxFound != NULL ) 1017 { 1018 /* Remove it because it will be passed to user directly. */ 1019 vTCPWindowFree( pxFound ); 1020 } 1021 } while( pxFound != NULL ); 1022 1023 /* Check for following segments that are already in the 1024 * queue and increment ulCurrentSequenceNumber. */ 1025 for( ; ; ) 1026 { 1027 pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ); 1028 1029 if( pxFound == NULL ) 1030 { 1031 break; 1032 } 1033 1034 ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength; 1035 1036 /* As all packet below this one have been passed to the 1037 * user it can be discarded. */ 1038 vTCPWindowFree( pxFound ); 1039 } 1040 1041 if( ulSavedSequenceNumber != ulCurrentSequenceNumber ) 1042 { 1043 /* After the current data-package, there is more data 1044 * to be popped. */ 1045 pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber; 1046 1047 if( xTCPWindowLoggingLevel >= 1 ) 1048 { 1049 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: retran %u (Found %u bytes at %u cnt %d)\n", 1050 pxWindow->usPeerPortNumber, 1051 pxWindow->usOurPortNumber, 1052 ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1053 ( unsigned ) pxWindow->ulUserDataLength, 1054 ( unsigned ) ( ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1055 ( int ) listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) ); 1056 } 1057 } 1058 } 1059 1060 pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber; 1061 } 1062 #endif /* ipconfgiUSE_TCP_WIN == 1 */ 1063 /*-----------------------------------------------------------*/ 1064 1065 #if ( ipconfigUSE_TCP_WIN == 1 ) 1066 1067 /** 1068 * @brief Data has been received with a non-expected sequence number. 1069 * This function will check if the RX data can be accepted. 1070 * @param[in] pxWindow The TCP sliding window data of the socket. 1071 * @param[in] ulSequenceNumber The sequence number at which the data should be placed. 1072 * @param[in] ulLength The number of bytes that can be added. 1073 * @return Return -1 if the data must be refused, otherwise it returns the 1074 * offset ( from the head ) at which the data can be placed. 1075 */ prvTCPWindowRx_UnexpectedRX(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength)1076 static int32_t prvTCPWindowRx_UnexpectedRX( TCPWindow_t * pxWindow, 1077 uint32_t ulSequenceNumber, 1078 uint32_t ulLength ) 1079 { 1080 int32_t lReturn = -1; 1081 uint32_t ulLast = ulSequenceNumber + ulLength; 1082 uint32_t ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber; 1083 const TCPSegment_t * pxFound; 1084 1085 /* See if there is more data in a contiguous block to make the 1086 * SACK describe a longer range of data. */ 1087 1088 /* TODO: SACK's may also be delayed for a short period 1089 * This is useful because subsequent packets will be SACK'd with 1090 * single one message 1091 */ 1092 for( ; ; ) 1093 { 1094 pxFound = xTCPWindowRxFind( pxWindow, ulLast ); 1095 1096 if( pxFound == NULL ) 1097 { 1098 break; 1099 } 1100 1101 ulLast += ( uint32_t ) pxFound->lDataLength; 1102 } 1103 1104 if( xTCPWindowLoggingLevel >= 1 ) 1105 { 1106 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %u exp %u (dist %d) SACK to %u\n", 1107 ( int ) pxWindow->usPeerPortNumber, 1108 ( int ) pxWindow->usOurPortNumber, 1109 ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1110 ( unsigned ) ( ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1111 ( int ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */ 1112 ( unsigned ) ( ulLast - pxWindow->rx.ulFirstSequenceNumber ) ) ); 1113 } 1114 1115 /* Now prepare the SACK message. 1116 * Code OPTION_CODE_SINGLE_SACK already in network byte order. */ 1117 pxWindow->ulOptionsData[ 0 ] = OPTION_CODE_SINGLE_SACK; 1118 1119 /* First sequence number that we received. */ 1120 pxWindow->ulOptionsData[ 1 ] = FreeRTOS_htonl( ulSequenceNumber ); 1121 1122 /* Last + 1 */ 1123 pxWindow->ulOptionsData[ 2 ] = FreeRTOS_htonl( ulLast ); 1124 1125 /* Which make 12 (3*4) option bytes. */ 1126 pxWindow->ucOptionLength = ( uint8_t ) ( 3U * sizeof( pxWindow->ulOptionsData[ 0 ] ) ); 1127 1128 pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber ); 1129 1130 if( pxFound != NULL ) 1131 { 1132 /* This out-of-sequence packet has been received for a 1133 * second time. It is already stored but do send a SACK 1134 * again. */ 1135 /* A negative value will be returned to indicate than error. */ 1136 } 1137 else 1138 { 1139 pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength ); 1140 1141 if( pxFound == NULL ) 1142 { 1143 /* Can not send a SACK, because the segment cannot be 1144 * stored. */ 1145 pxWindow->ucOptionLength = 0U; 1146 1147 /* Needs to be stored but there is no segment 1148 * available. A negative value will be returned. */ 1149 } 1150 else 1151 { 1152 uint32_t ulIntermediateResult; 1153 1154 if( xTCPWindowLoggingLevel != 0 ) 1155 { 1156 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %u (cnt %u)\n", 1157 pxWindow->usPeerPortNumber, 1158 pxWindow->usOurPortNumber, 1159 ( unsigned ) ( ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1160 ( unsigned ) listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) ); 1161 FreeRTOS_flush_logging(); 1162 } 1163 1164 /* Return a positive value. The packet may be accepted 1165 * and stored but an earlier packet is still missing. */ 1166 ulIntermediateResult = ulSequenceNumber - ulCurrentSequenceNumber; 1167 lReturn = ( int32_t ) ulIntermediateResult; 1168 } 1169 } 1170 1171 return lReturn; 1172 } 1173 #endif /* ipconfgiUSE_TCP_WIN == 1 */ 1174 /*-----------------------------------------------------------*/ 1175 1176 #if ( ipconfigUSE_TCP_WIN == 1 ) 1177 1178 /** 1179 * @brief Check what to do with a new incoming packet: store or ignore. 1180 * 1181 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1182 * @param[in] ulSequenceNumber The sequence number of the packet received. 1183 * @param[in] ulLength The number of bytes received. 1184 * @param[in] ulSpace The available space in the RX stream buffer. 1185 * @param[out] pulSkipCount the number of bytes to skip in the receive buffer. 1186 * 1187 * @return 0 or positive value indicating the offset at which the packet is to 1188 * be stored, -1 if the packet is to be ignored. 1189 */ lTCPWindowRxCheck(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber,uint32_t ulLength,uint32_t ulSpace,uint32_t * pulSkipCount)1190 int32_t lTCPWindowRxCheck( TCPWindow_t * pxWindow, 1191 uint32_t ulSequenceNumber, 1192 uint32_t ulLength, 1193 uint32_t ulSpace, 1194 uint32_t * pulSkipCount ) 1195 { 1196 uint32_t ulCurrentSequenceNumber; 1197 uint32_t ulIntermediateResult; 1198 int32_t lReturn = -1; 1199 int32_t lStartDistance; 1200 int32_t lLastDistance; 1201 uint32_t ulLast; 1202 uint32_t ulRxSequenceNumber = ulSequenceNumber; 1203 uint32_t ulRxLength = ulLength; 1204 1205 /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed 1206 * directly to user (segment is expected). If it returns a positive 1207 * number, an earlier packet is missing, but this packet may be stored. 1208 * If negative, the packet has already been stored, or it is out-of-order, 1209 * or there is not enough space. 1210 * 1211 * As a side-effect, pxWindow->ulUserDataLength will get set to non-zero, 1212 * if more Rx data may be passed to the user after this packet. */ 1213 1214 /* Only in an exceptional case, where a packet starts before 1215 * ulCurrentSequenceNumber, and ends after it, the skip-count 1216 * will be set. See below. */ 1217 1218 *( pulSkipCount ) = 0U; 1219 1220 ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber; 1221 1222 ulLast = ulRxSequenceNumber + ulRxLength; 1223 ulIntermediateResult = ulLast - ulCurrentSequenceNumber; 1224 /* The cast from unsigned long to signed long is on purpose. */ 1225 lLastDistance = ( int32_t ) ulIntermediateResult; 1226 1227 ulIntermediateResult = ulRxSequenceNumber - ulCurrentSequenceNumber; 1228 lStartDistance = ( int32_t ) ulIntermediateResult; 1229 1230 if( ( lStartDistance < 0 ) && ( lLastDistance > 0 ) ) 1231 { 1232 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Received +%u bytes for %u, only using %d\n", 1233 ( unsigned ) ulRxLength, 1234 ( unsigned ) ( ulRxSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), 1235 ( int ) lLastDistance ) ); 1236 /* Increase the sequence number, decrease the length. */ 1237 ulRxSequenceNumber += ( uint32_t ) ( -lStartDistance ); 1238 ulRxLength += ( uint32_t ) lStartDistance; 1239 1240 /* Tell the caller that the first 'pulSkipCount' bytes don't 1241 * need to be stored. */ 1242 *( pulSkipCount ) = ( uint32_t ) ( -lStartDistance ); 1243 } 1244 1245 /* For Selective Ack (SACK), used when out-of-sequence data come in. */ 1246 pxWindow->ucOptionLength = 0U; 1247 1248 /* Non-zero if TCP-windows contains data which must be popped. */ 1249 pxWindow->ulUserDataLength = 0U; 1250 1251 if( ulCurrentSequenceNumber == ulRxSequenceNumber ) 1252 { 1253 /* This is the packet with the lowest sequence number we're waiting 1254 * for. It can be passed directly to the rx stream. */ 1255 if( ulRxLength > ulSpace ) 1256 { 1257 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %u bytes, due to lack of space (%u)\n", ( unsigned ) ulRxLength, ( unsigned ) ulSpace ) ); 1258 } 1259 else 1260 { 1261 /* Packet was expected, may be passed directly to the socket 1262 * buffer or application. Store the packet at offset 0. */ 1263 prvTCPWindowRx_ExpectedRX( pxWindow, ulRxLength ); 1264 lReturn = 0; 1265 } 1266 } 1267 else if( ulCurrentSequenceNumber == ( ulRxSequenceNumber + 1U ) ) 1268 { 1269 /* Looks like a TCP keep-alive message. Do not accept/store Rx data 1270 * ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */ 1271 } 1272 else 1273 { 1274 /* The packet is not the one expected. See if it falls within the Rx 1275 * window so it can be stored. */ 1276 1277 /* An "out-of-sequence" segment was received, must have missed one. 1278 * Prepare a SACK (Selective ACK). */ 1279 1280 if( lLastDistance <= 0 ) 1281 { 1282 /* An earlier packet has been received, must be a retransmission of a 1283 * packet that has been accepted already. No need to send out a 1284 * Selective ACK (SACK). */ 1285 } 1286 else if( lLastDistance > ( int32_t ) ulSpace ) 1287 { 1288 /* The new segment is ahead of rx.ulCurrentSequenceNumber. The 1289 * sequence number of this packet is too far ahead, ignore it. */ 1290 FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %d+%u bytes, due to lack of space (%u)\n", 1291 ( int ) lLastDistance, 1292 ( unsigned ) ulRxLength, 1293 ( unsigned ) ulSpace ) ); 1294 } 1295 else 1296 { 1297 lReturn = prvTCPWindowRx_UnexpectedRX( pxWindow, ulRxSequenceNumber, ulRxLength ); 1298 } 1299 } 1300 1301 return lReturn; 1302 } 1303 #endif /* ipconfgiUSE_TCP_WIN == 1 */ 1304 /*-----------------------------------------------------------*/ 1305 1306 /*============================================================================= 1307 * 1308 * ######### # # 1309 * # # # # # 1310 * # # # 1311 * # #### 1312 * # ## 1313 * # #### 1314 * # # # 1315 * # # # 1316 * ##### # # 1317 * 1318 * Tx functions 1319 * 1320 *=============================================================================*/ 1321 1322 #if ( ipconfigUSE_TCP_WIN == 1 ) 1323 1324 /** 1325 * @brief Increment the position in a circular buffer of size 'lMax'. 1326 * 1327 * @param[in] lPosition The current index in the buffer. 1328 * @param[in] lMax The total number of items in this buffer. 1329 * @param[in] lCount The number of bytes that must be advanced. 1330 * 1331 * @return The new incremented position, or "( lPosition + lCount ) % lMax". 1332 */ lTCPIncrementTxPosition(int32_t lPosition,int32_t lMax,int32_t lCount)1333 static int32_t lTCPIncrementTxPosition( int32_t lPosition, 1334 int32_t lMax, 1335 int32_t lCount ) 1336 { 1337 int32_t lReturn; 1338 1339 1340 /* +TCP stores data in circular buffers. Calculate the next position to 1341 * store. */ 1342 lReturn = lPosition + lCount; 1343 1344 if( lReturn >= lMax ) 1345 { 1346 lReturn -= lMax; 1347 } 1348 1349 return lReturn; 1350 } 1351 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1352 /*-----------------------------------------------------------*/ 1353 1354 #if ( ipconfigUSE_TCP_WIN == 1 ) 1355 1356 /** 1357 * @brief Adding data to a segment that was already in the TX queue. It 1358 * will be filled-up to a maximum of MSS ( maximum segment size ). 1359 * 1360 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1361 * @param[in] pxSegment The TX segment with the highest sequence number, 1362 * i.e. the "front segment". 1363 * @param[in] lBytesLeft The number of bytes that must be added. 1364 * 1365 * @return lToWrite: the number of bytes added to the segment. 1366 */ prvTCPWindowTxAdd_FrontSegment(TCPWindow_t * pxWindow,TCPSegment_t * pxSegment,int32_t lBytesLeft)1367 static int32_t prvTCPWindowTxAdd_FrontSegment( TCPWindow_t * pxWindow, 1368 TCPSegment_t * pxSegment, 1369 int32_t lBytesLeft ) 1370 { 1371 int32_t lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength ); 1372 1373 pxSegment->lDataLength += lToWrite; 1374 1375 if( pxSegment->lDataLength >= pxSegment->lMaxLength ) 1376 { 1377 /* This segment is full, don't add more bytes. */ 1378 pxWindow->pxHeadSegment = NULL; 1379 } 1380 1381 /* ulNextTxSequenceNumber is the sequence number of the next byte to 1382 * be stored for transmission. */ 1383 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite; 1384 1385 /* Some detailed logging, for those who're interested. */ 1386 if( ( xTCPWindowLoggingLevel >= 2 ) && ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) 1387 { 1388 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4d bytes for seqNr %u len %4d (nxt %u) pos %d\n", 1389 ( int ) lBytesLeft, 1390 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 1391 ( int ) pxSegment->lDataLength, 1392 ( unsigned ) ( pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 1393 ( int ) pxSegment->lStreamPos ) ); 1394 FreeRTOS_flush_logging(); 1395 } 1396 1397 return lToWrite; 1398 } 1399 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1400 /*-----------------------------------------------------------*/ 1401 1402 #if ( ipconfigUSE_TCP_WIN == 1 ) 1403 1404 /** 1405 * @brief Will add data to be transmitted to the front of the segment fifo. 1406 * 1407 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1408 * @param[in] ulLength The number of bytes that will be sent. 1409 * @param[in] lPosition The index in the TX stream buffer. 1410 * @param[in] lMax The size of the ( circular ) TX stream buffer. 1411 * 1412 * @return The number of bytes added to the sliding window for transmission. 1413 * 1414 */ lTCPWindowTxAdd(TCPWindow_t * pxWindow,uint32_t ulLength,int32_t lPosition,int32_t lMax)1415 int32_t lTCPWindowTxAdd( TCPWindow_t * pxWindow, 1416 uint32_t ulLength, 1417 int32_t lPosition, 1418 int32_t lMax ) 1419 { 1420 int32_t lBytesLeft = ( int32_t ) ulLength; 1421 int32_t lToWrite; 1422 int32_t lDone = 0; 1423 int32_t lBufferIndex = lPosition; 1424 TCPSegment_t * pxSegment = pxWindow->pxHeadSegment; 1425 1426 /* Puts a message in the Tx-window (after buffer size has been 1427 * verified). */ 1428 if( ( pxSegment != NULL ) && 1429 ( pxSegment->lDataLength < pxSegment->lMaxLength ) && 1430 ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && 1431 ( pxSegment->lDataLength != 0 ) ) 1432 { 1433 lToWrite = prvTCPWindowTxAdd_FrontSegment( pxWindow, pxSegment, lBytesLeft ); 1434 lBytesLeft -= lToWrite; 1435 /* Increased the return value. */ 1436 lDone += lToWrite; 1437 1438 /* Calculate the next position in the circular data buffer, knowing 1439 * its maximum length 'lMax'. */ 1440 lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite ); 1441 } 1442 1443 while( lBytesLeft > 0 ) 1444 { 1445 /* The current transmission segment is full, create new segments as 1446 * needed. */ 1447 pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, ( int32_t ) pxWindow->usMSS ); 1448 1449 if( pxSegment != NULL ) 1450 { 1451 /* Store as many as needed, but no more than the maximum 1452 * (MSS). */ 1453 lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength ); 1454 1455 pxSegment->lDataLength = lToWrite; 1456 pxSegment->lStreamPos = lBufferIndex; 1457 lBytesLeft -= lToWrite; 1458 lBufferIndex = lTCPIncrementTxPosition( lBufferIndex, lMax, lToWrite ); 1459 pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite; 1460 lDone += lToWrite; 1461 1462 /* Link this segment in the Tx-Queue. */ 1463 vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) ); 1464 1465 /* Let 'pxHeadSegment' point to this segment if there is still 1466 * space. */ 1467 if( pxSegment->lDataLength < pxSegment->lMaxLength ) 1468 { 1469 pxWindow->pxHeadSegment = pxSegment; 1470 } 1471 else 1472 { 1473 pxWindow->pxHeadSegment = NULL; 1474 } 1475 } 1476 else 1477 { 1478 /* A sever situation: running out of segments for transmission. 1479 * No more data can be sent at the moment. */ 1480 if( lDone != 0 ) 1481 { 1482 FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %d bytes)\n", ( int ) lBytesLeft ) ); 1483 } 1484 1485 break; 1486 } 1487 } 1488 1489 return lDone; 1490 } 1491 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1492 /*-----------------------------------------------------------*/ 1493 1494 #if ( ipconfigUSE_TCP_WIN == 1 ) 1495 1496 /** 1497 * @brief Returns true if there are no more outstanding TX segments. 1498 * 1499 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1500 * 1501 * @return pdTRUE if there are no more outstanding Tx segments, else pdFALSE. 1502 */ xTCPWindowTxDone(const TCPWindow_t * pxWindow)1503 BaseType_t xTCPWindowTxDone( const TCPWindow_t * pxWindow ) 1504 { 1505 return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments ) ); 1506 } 1507 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1508 /*-----------------------------------------------------------*/ 1509 1510 #if ( ipconfigUSE_TCP_WIN == 1 ) 1511 1512 /** 1513 * @brief Find out if the peer is able to receive more data. 1514 * 1515 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1516 * @param[in] ulWindowSize The number of bytes in this segment. 1517 * 1518 * @return True if the peer has space in it window to receive more data. 1519 */ prvTCPWindowTxHasSpace(TCPWindow_t const * pxWindow,uint32_t ulWindowSize)1520 static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t const * pxWindow, 1521 uint32_t ulWindowSize ) 1522 { 1523 uint32_t ulTxOutstanding; 1524 BaseType_t xHasSpace; 1525 const TCPSegment_t * pxSegment; 1526 uint32_t ulNettSize; 1527 1528 /* This function will look if there is new transmission data. It will 1529 * return true if there is data to be sent. */ 1530 1531 pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) ); 1532 1533 if( pxSegment == NULL ) 1534 { 1535 xHasSpace = pdFALSE; 1536 } 1537 else 1538 { 1539 /* How much data is outstanding, i.e. how much data has been sent 1540 * but not yet acknowledged ? */ 1541 if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber ) 1542 { 1543 ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber; 1544 } 1545 else 1546 { 1547 ulTxOutstanding = 0U; 1548 } 1549 1550 /* Subtract this from the peer's space. */ 1551 ulNettSize = ulWindowSize - FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding ); 1552 1553 /* See if the next segment may be sent. */ 1554 if( ulNettSize >= ( uint32_t ) pxSegment->lDataLength ) 1555 { 1556 xHasSpace = pdTRUE; 1557 } 1558 else 1559 { 1560 xHasSpace = pdFALSE; 1561 } 1562 1563 /* If 'xHasSpace', it looks like the peer has at least space for 1 1564 * more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed 1565 * limitation of the transmission window (in case of many resends it 1566 * may be decreased). */ 1567 if( ( ulTxOutstanding != 0U ) && 1568 ( pxWindow->xSize.ulTxWindowLength < 1569 ( ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) ) ) 1570 { 1571 xHasSpace = pdFALSE; 1572 } 1573 } 1574 1575 return xHasSpace; 1576 } 1577 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1578 /*-----------------------------------------------------------*/ 1579 1580 #if ( ipconfigUSE_TCP_WIN == 1 ) 1581 1582 /** 1583 * @brief Returns true if there is TX data that can be sent right now. 1584 * 1585 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1586 * @param[in] ulWindowSize The current size of the sliding RX window of the peer. 1587 * @param[out] pulDelay The delay before the packet may be sent. 1588 * 1589 * @return pdTRUE if there is Tx data that can be sent, else pdFALSE. 1590 */ xTCPWindowTxHasData(TCPWindow_t const * pxWindow,uint32_t ulWindowSize,TickType_t * pulDelay)1591 BaseType_t xTCPWindowTxHasData( TCPWindow_t const * pxWindow, 1592 uint32_t ulWindowSize, 1593 TickType_t * pulDelay ) 1594 { 1595 TCPSegment_t const * pxSegment; 1596 BaseType_t xReturn; 1597 TickType_t ulAge, ulMaxAge; 1598 1599 *pulDelay = 0U; 1600 1601 if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE ) 1602 { 1603 /* No need to look at retransmissions or new transmission as long as 1604 * there are priority segments. *pulDelay equals zero, meaning it must 1605 * be sent out immediately. */ 1606 xReturn = pdTRUE; 1607 } 1608 else 1609 { 1610 pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) ); 1611 1612 if( pxSegment != NULL ) 1613 { 1614 uint32_t ulSRTT = ( uint32_t ) pxWindow->lSRTT; 1615 1616 /* There is an outstanding segment, see if it is time to resend 1617 * it. */ 1618 ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer ); 1619 1620 /* After a packet has been sent for the first time, it will wait 1621 * '1 * ulSRTT' ms for an ACK. A second time it will wait '2 * ulSRTT' ms, 1622 * each time doubling the time-out */ 1623 ulMaxAge = ( ( uint32_t ) 1U << pxSegment->u.bits.ucTransmitCount ); 1624 ulMaxAge *= ulSRTT; 1625 1626 if( ulMaxAge > ulAge ) 1627 { 1628 /* A segment must be sent after this amount of msecs */ 1629 *pulDelay = ulMaxAge - ulAge; 1630 } 1631 1632 xReturn = pdTRUE; 1633 } 1634 else 1635 { 1636 /* No priority segment, no outstanding data, see if there is new 1637 * transmission data. */ 1638 pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue ); 1639 1640 /* See if it fits in the peer's reception window. */ 1641 if( pxSegment == NULL ) 1642 { 1643 xReturn = pdFALSE; 1644 } 1645 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE ) 1646 { 1647 /* Too many outstanding messages. */ 1648 xReturn = pdFALSE; 1649 } 1650 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && 1651 ( pxSegment->lDataLength < pxSegment->lMaxLength ) ) 1652 { 1653 /* 'bSendFullSize' is a special optimisation. If true, the 1654 * driver will only sent completely filled packets (of MSS 1655 * bytes). */ 1656 xReturn = pdFALSE; 1657 } 1658 else 1659 { 1660 xReturn = pdTRUE; 1661 } 1662 } 1663 } 1664 1665 return xReturn; 1666 } 1667 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1668 /*-----------------------------------------------------------*/ 1669 1670 #if ( ipconfigUSE_TCP_WIN == 1 ) 1671 1672 /** 1673 * @brief Three type of queues are used for transmission: priority, waiting, and 1674 * the normal TX queue of unsent data. Message in the waiting queue will 1675 * be sent when their timer has expired. 1676 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1677 */ pxTCPWindowTx_GetWaitQueue(const TCPWindow_t * pxWindow)1678 static TCPSegment_t * pxTCPWindowTx_GetWaitQueue( const TCPWindow_t * pxWindow ) 1679 { 1680 TCPSegment_t * pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) ); 1681 1682 if( pxSegment != NULL ) 1683 { 1684 /* Do check the timing. */ 1685 uint32_t ulMaxTime; 1686 1687 ulMaxTime = ( ( uint32_t ) 1U ) << pxSegment->u.bits.ucTransmitCount; 1688 ulMaxTime *= ( uint32_t ) pxWindow->lSRTT; 1689 1690 if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime ) 1691 { 1692 /* A normal (non-fast) retransmission. Move it from the 1693 * head of the waiting queue. */ 1694 pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) ); 1695 pxSegment->u.bits.ucDupAckCount = ( uint8_t ) pdFALSE_UNSIGNED; 1696 1697 /* Some detailed logging. */ 1698 if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) ) 1699 { 1700 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %d bytes for sequence number %u (0x%X)\n", 1701 pxWindow->usPeerPortNumber, 1702 pxWindow->usOurPortNumber, 1703 ( int ) pxSegment->lDataLength, 1704 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 1705 ( unsigned ) pxSegment->ulSequenceNumber ) ); 1706 FreeRTOS_flush_logging(); 1707 } 1708 } 1709 else 1710 { 1711 pxSegment = NULL; 1712 } 1713 } 1714 1715 return pxSegment; 1716 } 1717 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1718 1719 /*-----------------------------------------------------------*/ 1720 1721 #if ( ipconfigUSE_TCP_WIN == 1 ) 1722 1723 /** 1724 * @brief See if there is a transmission in the normal TX queue. It is the 1725 * first time these data are being sent. After sending they will move 1726 * the waiting queue. 1727 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1728 * @param[in] ulWindowSize The available space that the peer has in his 1729 * reception window. 1730 * @return Either a segment that has to be sent, or NULL. 1731 */ pxTCPWindowTx_GetTXQueue(TCPWindow_t * pxWindow,uint32_t ulWindowSize)1732 static TCPSegment_t * pxTCPWindowTx_GetTXQueue( TCPWindow_t * pxWindow, 1733 uint32_t ulWindowSize ) 1734 { 1735 TCPSegment_t * pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) ); 1736 1737 if( pxSegment == NULL ) 1738 { 1739 /* No segments queued. */ 1740 } 1741 else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && 1742 ( pxSegment->lDataLength < pxSegment->lMaxLength ) ) 1743 { 1744 /* A segment has been queued but the driver waits until it 1745 * has a full size of MSS. */ 1746 pxSegment = NULL; 1747 } 1748 else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE ) 1749 { 1750 /* Peer has no more space at this moment. */ 1751 pxSegment = NULL; 1752 } 1753 else 1754 { 1755 /* pxSegment was just obtained with a peek function, 1756 * now remove it from of the Tx queue. */ 1757 pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) ); 1758 1759 /* Don't let pxHeadSegment point to this segment any more, 1760 * so no more data will be added. */ 1761 if( pxWindow->pxHeadSegment == pxSegment ) 1762 { 1763 pxWindow->pxHeadSegment = NULL; 1764 } 1765 1766 /* pxWindow->tx.highest registers the highest sequence 1767 * number in our transmission window. */ 1768 pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength ); 1769 1770 /* ...and more detailed logging */ 1771 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) ) 1772 { 1773 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %d bytes for sequence number %u (ws %u)\n", 1774 pxWindow->usPeerPortNumber, 1775 pxWindow->usOurPortNumber, 1776 ( int ) pxSegment->lDataLength, 1777 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 1778 ( unsigned ) ulWindowSize ) ); 1779 FreeRTOS_flush_logging(); 1780 } 1781 } 1782 1783 return pxSegment; 1784 } 1785 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1786 /*-----------------------------------------------------------*/ 1787 1788 #if ( ipconfigUSE_TCP_WIN == 1 ) 1789 1790 /** 1791 * @brief Get data that can be transmitted right now. There are three types of 1792 * outstanding segments: Priority queue, Waiting queue, Normal TX queue. 1793 * 1794 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1795 * @param[in] ulWindowSize The current size of the sliding RX window of the peer. 1796 * @param[out] plPosition The index within the TX stream buffer of the first byte to be sent. 1797 * 1798 * @return The amount of data in bytes that can be transmitted right now. 1799 */ ulTCPWindowTxGet(TCPWindow_t * pxWindow,uint32_t ulWindowSize,int32_t * plPosition)1800 uint32_t ulTCPWindowTxGet( TCPWindow_t * pxWindow, 1801 uint32_t ulWindowSize, 1802 int32_t * plPosition ) 1803 { 1804 TCPSegment_t * pxSegment; 1805 uint32_t ulReturn = 0U; 1806 1807 /* Fetches data to be sent-out now. 1808 * 1809 * Priority messages: segments with a resend need no check current sliding 1810 * window size. */ 1811 pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) ); 1812 pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber; 1813 1814 if( pxSegment != NULL ) 1815 { 1816 /* There is a priority segment. It doesn't need any checking for 1817 * space or timeouts. */ 1818 if( xTCPWindowLoggingLevel != 0 ) 1819 { 1820 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %d bytes for sequence number %u (ws %u)\n", 1821 pxWindow->usPeerPortNumber, 1822 pxWindow->usOurPortNumber, 1823 ( int ) pxSegment->lDataLength, 1824 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 1825 ( unsigned ) ulWindowSize ) ); 1826 FreeRTOS_flush_logging(); 1827 } 1828 } 1829 else 1830 { 1831 /* Waiting messages: outstanding messages with a running timer 1832 * neither check peer's reception window size because these packets 1833 * have been sent earlier. */ 1834 pxSegment = pxTCPWindowTx_GetWaitQueue( pxWindow ); 1835 1836 if( pxSegment == NULL ) 1837 { 1838 /* New messages: sent-out for the first time. Check current 1839 * sliding window size of peer. */ 1840 pxSegment = pxTCPWindowTx_GetTXQueue( pxWindow, ulWindowSize ); 1841 } 1842 } 1843 1844 /* See if it has already been determined to return 0. */ 1845 if( pxSegment != NULL ) 1846 { 1847 configASSERT( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) == NULL ); 1848 1849 /* Now that the segment will be transmitted, add it to the tail of 1850 * the waiting queue. */ 1851 vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem ); 1852 1853 /* And mark it as outstanding. */ 1854 pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED; 1855 1856 /* Administer the transmit count, needed for fast 1857 * retransmissions. */ 1858 ( pxSegment->u.bits.ucTransmitCount )++; 1859 1860 /* If there have been several retransmissions (4), decrease the 1861 * size of the transmission window to at most 2 times MSS. */ 1862 if( ( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ) && 1863 ( pxWindow->xSize.ulTxWindowLength > ( 2U * ( ( uint32_t ) pxWindow->usMSS ) ) ) ) 1864 { 1865 uint16_t usMSS2 = ( uint16_t ) ( pxWindow->usMSS * 2U ); 1866 FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %u]: Change Tx window: %u -> %u\n", 1867 pxWindow->usPeerPortNumber, 1868 pxWindow->usOurPortNumber, 1869 ( unsigned ) pxWindow->xSize.ulTxWindowLength, 1870 usMSS2 ) ); 1871 pxWindow->xSize.ulTxWindowLength = usMSS2; 1872 } 1873 1874 /* Clear the transmit timer. */ 1875 vTCPTimerSet( &( pxSegment->xTransmitTimer ) ); 1876 1877 pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber; 1878 1879 /* Inform the caller where to find the data within the queue. */ 1880 *plPosition = pxSegment->lStreamPos; 1881 1882 /* And return the length of the data segment */ 1883 ulReturn = ( uint32_t ) pxSegment->lDataLength; 1884 } 1885 1886 return ulReturn; 1887 } 1888 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1889 /*-----------------------------------------------------------*/ 1890 1891 #if ( ipconfigUSE_TCP_WIN == 1 ) 1892 1893 /** 1894 * @brief Data has been sent, and an ACK has been received. Make an estimate 1895 * of the round-trip time, and calculate the new timeout for transmissions. 1896 * More explanation in a comment here below. 1897 * 1898 * @param[in] pxWindow The descriptor of the TCP sliding windows. 1899 * @param[in] pxSegment The segment that was just acknowledged. 1900 */ prvTCPWindowTxCheckAck_CalcSRTT(TCPWindow_t * pxWindow,const TCPSegment_t * pxSegment)1901 static void prvTCPWindowTxCheckAck_CalcSRTT( TCPWindow_t * pxWindow, 1902 const TCPSegment_t * pxSegment ) 1903 { 1904 int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) ); 1905 1906 if( pxWindow->lSRTT >= mS ) 1907 { 1908 /* RTT becomes smaller: adapt slowly. */ 1909 pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT ); 1910 } 1911 else 1912 { 1913 /* RTT becomes larger: adapt quicker */ 1914 pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT ); 1915 } 1916 1917 /* Cap to the minimum of 50ms. */ 1918 if( pxWindow->lSRTT < winSRTT_CAP_mS ) 1919 { 1920 pxWindow->lSRTT = winSRTT_CAP_mS; 1921 } 1922 } 1923 #endif /* ipconfigUSE_TCP_WIN == 1 */ 1924 /*-----------------------------------------------------------*/ 1925 1926 #if ( ipconfigUSE_TCP_WIN == 1 ) 1927 1928 /** 1929 * @brief An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data 1930 * may be removed from the transmission queue(s). All TX segments for which 1931 * ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a contiguous block. 1932 * Note that the segments are stored in xTxSegments in a strict sequential order. 1933 * 1934 * @param[in] pxWindow The TCP-window object of the current connection. 1935 * @param[in] ulFirst The sequence number of the first byte that was acknowledged. 1936 * @param[in] ulLast The sequence number of the last byte ( minus one ) that was acknowledged. 1937 * 1938 * @return number of bytes that the tail of txStream may be advanced. 1939 */ prvTCPWindowTxCheckAck(TCPWindow_t * pxWindow,uint32_t ulFirst,uint32_t ulLast)1940 static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t * pxWindow, 1941 uint32_t ulFirst, 1942 uint32_t ulLast ) 1943 { 1944 uint32_t ulBytesConfirmed = 0U; 1945 uint32_t ulSequenceNumber = ulFirst; 1946 uint32_t ulDataLength; 1947 const ListItem_t * pxIterator; 1948 1949 /* MISRA Ref 11.3.1 [Misaligned access] */ 1950 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1951 /* coverity[misra_c_2012_rule_11_3_violation] */ 1952 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxWindow->xTxSegments.xListEnd ) ); 1953 BaseType_t xDoUnlink; 1954 TCPSegment_t * pxSegment; 1955 1956 /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data 1957 * may be removed from the transmission queue(s). 1958 * All TX segments for which 1959 * ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a 1960 * contiguous block. Note that the segments are stored in xTxSegments in a 1961 * strict sequential order. */ 1962 1963 /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT 1964 * 1965 * 0 < a < 1; usually a = 1/8 1966 * 1967 * RTO = 2 * SRTT 1968 * 1969 * where: 1970 * RTT is Round Trip Time 1971 * SRTT is Smoothed RTT 1972 * RTO is Retransmit timeout 1973 * 1974 * A Smoothed RTT will increase quickly, but it is conservative when 1975 * becoming smaller. */ 1976 1977 pxIterator = listGET_NEXT( pxEnd ); 1978 1979 while( ( pxIterator != pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 ) ) 1980 { 1981 xDoUnlink = pdFALSE; 1982 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) ); 1983 1984 /* Move to the next item because the current item might get 1985 * removed. */ 1986 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); 1987 1988 /* Continue if this segment does not fall within the ACK'd range. */ 1989 if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE ) 1990 { 1991 continue; 1992 } 1993 1994 /* Is it ready? */ 1995 if( ulSequenceNumber != pxSegment->ulSequenceNumber ) 1996 { 1997 /* coverity[break_stmt] : Break statement terminating the loop */ 1998 break; 1999 } 2000 2001 ulDataLength = ( uint32_t ) pxSegment->lDataLength; 2002 2003 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) 2004 { 2005 if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t ) ulDataLength, ulLast ) != pdFALSE ) 2006 { 2007 /* What happens? Only part of this segment was accepted, 2008 * probably due to WND limits 2009 * 2010 * AAAAAAA BBBBBBB << acked 2011 * aaaaaaa aaaa << sent */ 2012 #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) 2013 { 2014 uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber; 2015 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %u - %u Partial sequence number %u - %u\n", 2016 pxWindow->usPeerPortNumber, 2017 pxWindow->usOurPortNumber, 2018 ( unsigned ) ( ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber ), 2019 ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ), 2020 ( unsigned ) ulFirstSeq, 2021 ( unsigned ) ( ulFirstSeq + ulDataLength ) ) ); 2022 } 2023 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ 2024 2025 break; 2026 } 2027 2028 /* This segment is fully ACK'd, set the flag. */ 2029 pxSegment->u.bits.bAcked = pdTRUE; 2030 2031 /* Calculate the RTT only if the segment was sent-out for the 2032 * first time and if this is the last ACK'd segment in a range. */ 2033 if( ( pxSegment->u.bits.ucTransmitCount == 1U ) && 2034 ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) ) 2035 { 2036 prvTCPWindowTxCheckAck_CalcSRTT( pxWindow, pxSegment ); 2037 } 2038 2039 /* Unlink it from the 3 queues, but do not destroy it (yet). */ 2040 xDoUnlink = pdTRUE; 2041 } 2042 2043 /* pxSegment->u.bits.bAcked is now true. Is it located at the left 2044 * side of the transmission queue? If so, it may be freed. */ 2045 if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber ) 2046 { 2047 if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) ) 2048 { 2049 FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %u - %u Ready sequence number %u\n", 2050 ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ), 2051 ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ), 2052 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ) ); 2053 } 2054 2055 /* Increase the left-hand value of the transmission window. */ 2056 pxWindow->tx.ulCurrentSequenceNumber += ulDataLength; 2057 2058 /* This function will return the number of bytes that the tail 2059 * of txStream may be advanced. */ 2060 ulBytesConfirmed += ulDataLength; 2061 2062 /* All segments below tx.ulCurrentSequenceNumber may be freed. */ 2063 vTCPWindowFree( pxSegment ); 2064 2065 /* No need to unlink it any more. */ 2066 xDoUnlink = pdFALSE; 2067 } 2068 2069 if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) ) 2070 { 2071 /* Remove item from its queues. */ 2072 ( void ) uxListRemove( &pxSegment->xQueueItem ); 2073 } 2074 2075 ulSequenceNumber += ulDataLength; 2076 } 2077 2078 return ulBytesConfirmed; 2079 } 2080 #endif /* ipconfigUSE_TCP_WIN == 1 */ 2081 /*-----------------------------------------------------------*/ 2082 2083 #if ( ipconfigUSE_TCP_WIN == 1 ) 2084 2085 /** 2086 * @brief See if there are segments that need a fast retransmission. 2087 * 2088 * @param[in] pxWindow The descriptor of the TCP sliding windows. 2089 * @param[in] ulFirst The sequence number of the first segment that must be checked. 2090 * 2091 * @return The number of segments that need a fast retransmission. 2092 */ prvTCPWindowFastRetransmit(TCPWindow_t * pxWindow,uint32_t ulFirst)2093 static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t * pxWindow, 2094 uint32_t ulFirst ) 2095 { 2096 const ListItem_t * pxIterator; 2097 const ListItem_t * pxEnd; 2098 TCPSegment_t * pxSegment; 2099 uint32_t ulCount = 0U; 2100 2101 /* A higher Tx block has been acknowledged. Now iterate through the 2102 * xWaitQueue to find a possible condition for a FAST retransmission. */ 2103 2104 /* MISRA Ref 11.3.1 [Misaligned access] */ 2105 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 2106 /* coverity[misra_c_2012_rule_11_3_violation] */ 2107 pxEnd = ( ( const ListItem_t * ) &( pxWindow->xWaitQueue.xListEnd ) ); 2108 2109 pxIterator = listGET_NEXT( pxEnd ); 2110 2111 while( pxIterator != pxEnd ) 2112 { 2113 /* Get the owner, which is a TCP segment. */ 2114 pxSegment = ( ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) ); 2115 2116 /* Hop to the next item before the current gets unlinked. */ 2117 pxIterator = listGET_NEXT( pxIterator ); 2118 2119 /* Fast retransmission: 2120 * When 3 packets with a higher sequence number have been acknowledged 2121 * by the peer, it is very unlikely a current packet will ever arrive. 2122 * It will be retransmitted far before the RTO. */ 2123 if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) 2124 { 2125 if( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) 2126 { 2127 pxSegment->u.bits.ucDupAckCount++; 2128 2129 if( pxSegment->u.bits.ucDupAckCount == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) 2130 { 2131 pxSegment->u.bits.ucTransmitCount = ( uint8_t ) pdFALSE; 2132 2133 /* Not clearing 'ucDupAckCount' yet as more SACK's might come in 2134 * which might lead to a second fast rexmit. */ 2135 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) ) ) 2136 { 2137 FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %u < %u\n", 2138 ( unsigned ) ( pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ), 2139 ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ) ) ); 2140 FreeRTOS_flush_logging(); 2141 } 2142 2143 /* Remove it from xWaitQueue. */ 2144 ( void ) uxListRemove( &pxSegment->xQueueItem ); 2145 2146 /* Add this segment to the priority queue so it gets 2147 * retransmitted immediately. */ 2148 vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) ); 2149 ulCount++; 2150 } 2151 } 2152 } 2153 } 2154 2155 return ulCount; 2156 } 2157 #endif /* ipconfigUSE_TCP_WIN == 1 */ 2158 /*-----------------------------------------------------------*/ 2159 2160 #if ( ipconfigUSE_TCP_WIN == 1 ) 2161 2162 /** 2163 * @brief Receive a normal ACK. 2164 * 2165 * @param[in] pxWindow Window in which a data is receive. 2166 * @param[in] ulSequenceNumber The sequence number of the ACK. 2167 * 2168 * @return The location where the packet should be added. 2169 */ ulTCPWindowTxAck(TCPWindow_t * pxWindow,uint32_t ulSequenceNumber)2170 uint32_t ulTCPWindowTxAck( TCPWindow_t * pxWindow, 2171 uint32_t ulSequenceNumber ) 2172 { 2173 uint32_t ulFirstSequence; 2174 uint32_t ulReturn; 2175 2176 /* Receive a normal ACK. */ 2177 2178 ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber; 2179 2180 if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE ) 2181 { 2182 ulReturn = 0U; 2183 } 2184 else 2185 { 2186 ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber ); 2187 } 2188 2189 return ulReturn; 2190 } 2191 #endif /* ipconfigUSE_TCP_WIN == 1 */ 2192 /*-----------------------------------------------------------*/ 2193 2194 #if ( ipconfigUSE_TCP_WIN == 1 ) 2195 2196 /** 2197 * @brief Receive a SACK option. 2198 * 2199 * @param[in] pxWindow Window in which the data is received. 2200 * @param[in] ulFirst Index of starting position of options. 2201 * @param[in] ulLast Index of end position of the options. 2202 * 2203 * @return returns the number of bytes which have been acked starting from 2204 * the head position. 2205 */ ulTCPWindowTxSack(TCPWindow_t * pxWindow,uint32_t ulFirst,uint32_t ulLast)2206 uint32_t ulTCPWindowTxSack( TCPWindow_t * pxWindow, 2207 uint32_t ulFirst, 2208 uint32_t ulLast ) 2209 { 2210 uint32_t ulAckCount; 2211 uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber; 2212 2213 /* Receive a SACK option. */ 2214 ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast ); 2215 ( void ) prvTCPWindowFastRetransmit( pxWindow, ulFirst ); 2216 2217 if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) ) 2218 { 2219 FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %u to %u (ack = %u)\n", 2220 pxWindow->usPeerPortNumber, 2221 pxWindow->usOurPortNumber, 2222 ( unsigned ) ( ulFirst - pxWindow->tx.ulFirstSequenceNumber ), 2223 ( unsigned ) ( ulLast - pxWindow->tx.ulFirstSequenceNumber ), 2224 ( unsigned ) ( pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ) ); 2225 FreeRTOS_flush_logging(); 2226 } 2227 2228 return ulAckCount; 2229 } 2230 #endif /* ipconfigUSE_TCP_WIN == 1 */ 2231 /*-----------------------------------------------------------*/ 2232 2233 #endif /* ipconfigUSE_TCP == 1 */ 2234