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