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 * @file FreeRTOS_TCP_IP.c 30 * @brief Module which handles the TCP connections for FreeRTOS+TCP. 31 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing 32 * schemes. 33 * 34 * Endianness: in this module all ports and IP addresses are stored in 35 * host byte-order, except fields in the IP-packets 36 */ 37 38 /* Standard includes. */ 39 #include <stdint.h> 40 #include <stdio.h> 41 42 /* FreeRTOS includes. */ 43 #include "FreeRTOS.h" 44 #include "task.h" 45 #include "queue.h" 46 #include "semphr.h" 47 48 /* FreeRTOS+TCP includes. */ 49 #include "FreeRTOS_IP.h" 50 #include "FreeRTOS_Sockets.h" 51 #include "FreeRTOS_IP_Private.h" 52 #include "FreeRTOS_UDP_IP.h" 53 #include "FreeRTOS_DHCP.h" 54 #include "NetworkInterface.h" 55 #include "NetworkBufferManagement.h" 56 #include "FreeRTOS_ARP.h" 57 58 #include "FreeRTOS_TCP_Reception.h" 59 #include "FreeRTOS_TCP_Transmission.h" 60 #include "FreeRTOS_TCP_State_Handling.h" 61 #include "FreeRTOS_TCP_Utils.h" 62 63 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */ 64 #if ipconfigUSE_TCP == 1 65 66 67 68 /** @brief When closing a socket an event is posted to the Network Event Queue. 69 * If the queue is full, then the event is not posted and the socket 70 * can be orphaned. To prevent this, the below variable is used to keep 71 * track of any socket which needs to be closed. This variable can be 72 * accessed by the IP task only. Thus, preventing any race condition. 73 */ 74 /* MISRA Ref 8.9.1 [File scoped variables] */ 75 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ 76 /* coverity[misra_c_2012_rule_8_9_violation] */ 77 static FreeRTOS_Socket_t * xSocketToClose = NULL; 78 79 /** @brief When a connection is coming in on a reusable socket, and the 80 * SYN phase times out, the socket must be put back into eTCP_LISTEN 81 * mode, so it can accept a new connection again. 82 * This variable can be accessed by the IP task only. Thus, preventing any 83 * race condition. 84 */ 85 /* MISRA Ref 8.9.1 [File scoped variables] */ 86 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ 87 /* coverity[misra_c_2012_rule_8_9_violation] */ 88 _static FreeRTOS_Socket_t * xSocketToListen = NULL; 89 90 #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) 91 92 /* 93 * For logging and debugging: make a string showing the TCP flags. 94 */ 95 const char * prvTCPFlagMeaning( UBaseType_t xFlags ); 96 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ 97 98 99 /*-----------------------------------------------------------*/ 100 101 102 /** @brief Close the socket another time. 103 * 104 * @param[in] pxSocket The socket to be checked. 105 */ 106 /* coverity[single_use] */ vSocketCloseNextTime(FreeRTOS_Socket_t * pxSocket)107 void vSocketCloseNextTime( FreeRTOS_Socket_t * pxSocket ) 108 { 109 if( ( xSocketToClose != NULL ) && ( xSocketToClose != pxSocket ) ) 110 { 111 ( void ) vSocketClose( xSocketToClose ); 112 } 113 114 xSocketToClose = pxSocket; 115 } 116 /*-----------------------------------------------------------*/ 117 118 /** @brief Postpone a call to FreeRTOS_listen() to avoid recursive calls. 119 * 120 * @param[in] pxSocket The socket to be checked. 121 */ 122 /* coverity[single_use] */ vSocketListenNextTime(FreeRTOS_Socket_t * pxSocket)123 void vSocketListenNextTime( FreeRTOS_Socket_t * pxSocket ) 124 { 125 if( ( xSocketToListen != NULL ) && ( xSocketToListen != pxSocket ) ) 126 { 127 ( void ) FreeRTOS_listen( ( Socket_t ) xSocketToListen, ( BaseType_t ) ( xSocketToListen->u.xTCP.usBacklog ) ); 128 } 129 130 xSocketToListen = pxSocket; 131 } 132 /*-----------------------------------------------------------*/ 133 134 /** 135 * @brief As soon as a TCP socket timer expires, this function will be called 136 * (from xTCPTimerCheck). It can send a delayed ACK or new data. 137 * 138 * @param[in] pxSocket socket to be checked. 139 * 140 * @return 0 on success, a negative error code on failure. A negative value will be 141 * returned in case the hang-protection has put the socket in a wait-close state. 142 * 143 * @note Sequence of calling (normally) : 144 * IP-Task: 145 * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c ) 146 * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket() 147 * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages ) 148 * prvTCPSendRepeated() // Send at most 8 messages on a row 149 * prvTCPReturnPacket() // Prepare for returning 150 * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx ) 151 */ xTCPSocketCheck(FreeRTOS_Socket_t * pxSocket)152 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t * pxSocket ) 153 { 154 BaseType_t xResult = 0; 155 BaseType_t xReady = pdFALSE; 156 157 if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) ) 158 { 159 /* The API FreeRTOS_send() might have added data to the TX stream. Add 160 * this data to the windowing system so it can be transmitted. */ 161 prvTCPAddTxData( pxSocket ); 162 } 163 164 #if ( ipconfigUSE_TCP_WIN == 1 ) 165 { 166 if( pxSocket->u.xTCP.pxAckMessage != NULL ) 167 { 168 /* The first task of this regular socket check is to send-out delayed 169 * ACK's. */ 170 if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED ) 171 { 172 /* Earlier data was received but not yet acknowledged. This 173 * function is called when the TCP timer for the socket expires, the 174 * ACK may be sent now. */ 175 if( pxSocket->u.xTCP.eTCPState != eCLOSED ) 176 { 177 if( ( xTCPWindowLoggingLevel > 1 ) && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) 178 { 179 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %u SEQ %u (len %u)\n", 180 pxSocket->usLocalPort, 181 pxSocket->u.xTCP.usRemotePort, 182 ( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ), 183 ( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ), 184 ( unsigned ) ( uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER ) ) ); 185 } 186 187 prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ( uint32_t ) ( uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER ), ipconfigZERO_COPY_TX_DRIVER ); 188 189 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) 190 { 191 /* The ownership has been passed to the SEND routine, 192 * clear the pointer to it. */ 193 pxSocket->u.xTCP.pxAckMessage = NULL; 194 } 195 #endif /* ipconfigZERO_COPY_TX_DRIVER */ 196 } 197 198 if( prvTCPNextTimeout( pxSocket ) > 1U ) 199 { 200 /* Tell the code below that this function is ready. */ 201 xReady = pdTRUE; 202 } 203 } 204 else 205 { 206 /* The user wants to perform an active shutdown(), skip sending 207 * the delayed ACK. The function prvTCPSendPacket() will send the 208 * FIN along with the ACK's. */ 209 } 210 211 if( pxSocket->u.xTCP.pxAckMessage != NULL ) 212 { 213 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); 214 pxSocket->u.xTCP.pxAckMessage = NULL; 215 } 216 } 217 } 218 #endif /* ipconfigUSE_TCP_WIN */ 219 220 if( xReady == pdFALSE ) 221 { 222 /* The second task of this regular socket check is sending out data. */ 223 if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) || 224 ( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN ) ) 225 { 226 ( void ) prvTCPSendPacket( pxSocket ); 227 } 228 229 /* Set the time-out for the next wakeup for this socket. */ 230 ( void ) prvTCPNextTimeout( pxSocket ); 231 232 #if ( ipconfigTCP_HANG_PROTECTION == 1 ) 233 { 234 /* In all (non-connected) states in which keep-alive messages can not be sent 235 * the anti-hang protocol will close sockets that are 'hanging'. */ 236 xResult = prvTCPStatusAgeCheck( pxSocket ); 237 } 238 #endif 239 } 240 241 return xResult; 242 } 243 /*-----------------------------------------------------------*/ 244 245 /** 246 * @brief 'Touch' the socket to keep it alive/updated. 247 * 248 * @param[in] pxSocket The socket to be updated. 249 * 250 * @note This is used for anti-hanging protection and TCP keep-alive messages. 251 * Called in two places: after receiving a packet and after a state change. 252 * The socket's alive timer may be reset. 253 */ prvTCPTouchSocket(struct xSOCKET * pxSocket)254 void prvTCPTouchSocket( struct xSOCKET * pxSocket ) 255 { 256 #if ( ipconfigTCP_HANG_PROTECTION == 1 ) 257 { 258 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount(); 259 } 260 #endif 261 262 #if ( ipconfigTCP_KEEP_ALIVE == 1 ) 263 { 264 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED; 265 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED; 266 pxSocket->u.xTCP.ucKeepRepCount = 0U; 267 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount(); 268 } 269 #endif 270 271 ( void ) pxSocket; 272 } 273 /*-----------------------------------------------------------*/ 274 275 /** 276 * @brief Changing to a new state. Centralised here to do specific actions such as 277 * resetting the alive timer, calling the user's OnConnect handler to notify 278 * that a socket has got (dis)connected, and setting bit to unblock a call to 279 * FreeRTOS_select(). 280 * 281 * @param[in] pxSocket The socket whose state we are trying to change. 282 * @param[in] eTCPState The state to which we want to change to. 283 */ vTCPStateChange(FreeRTOS_Socket_t * pxSocket,enum eTCP_STATE eTCPState)284 void vTCPStateChange( FreeRTOS_Socket_t * pxSocket, 285 enum eTCP_STATE eTCPState ) 286 { 287 FreeRTOS_Socket_t * xParent = pxSocket; 288 BaseType_t bBefore = tcpNOW_CONNECTED( ( BaseType_t ) pxSocket->u.xTCP.eTCPState ); /* Was it connected ? */ 289 BaseType_t bAfter = tcpNOW_CONNECTED( ( BaseType_t ) eTCPState ); /* Is it connected now ? */ 290 291 eIPTCPState_t xPreviousState = pxSocket->u.xTCP.eTCPState; 292 293 #if ( ipconfigUSE_CALLBACKS == 1 ) 294 FreeRTOS_Socket_t * xConnected = NULL; 295 #endif 296 297 if( ( ( xPreviousState == eCONNECT_SYN ) || 298 ( xPreviousState == eSYN_FIRST ) || 299 ( xPreviousState == eSYN_RECEIVED ) ) && 300 ( eTCPState == eCLOSE_WAIT ) ) 301 { 302 /* A socket was in the connecting phase but something 303 * went wrong and it should be closed. */ 304 FreeRTOS_debug_printf( ( "Move from %s to %s\n", 305 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ), 306 FreeRTOS_GetTCPStateName( eTCPState ) ) ); 307 308 /* Set the flag to show that it was connected before and that the 309 * status has changed now. This will cause the control flow to go 310 * in the below if condition.*/ 311 bBefore = pdTRUE; 312 } 313 314 /* Has the connected status changed? */ 315 if( bBefore != bAfter ) 316 { 317 /* if bPassQueued is true, this socket is an orphan until it gets connected. */ 318 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) 319 { 320 /* Find it's parent if the reuse bit is not set. */ 321 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) 322 { 323 xParent = pxSocket->u.xTCP.pxPeerSocket; 324 configASSERT( xParent != NULL ); 325 } 326 } 327 328 /* Is the socket connected now ? */ 329 if( bAfter != pdFALSE ) 330 { 331 /* if bPassQueued is true, this socket is an orphan until it gets connected. */ 332 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) 333 { 334 if( xParent != NULL ) 335 { 336 /* The child socket has got connected. See if the parent 337 * ( the listening socket ) should be signalled, or if a 338 * call-back must be made, in which case 'xConnected' will 339 * be set to the parent socket. */ 340 341 if( xParent->u.xTCP.pxPeerSocket == NULL ) 342 { 343 xParent->u.xTCP.pxPeerSocket = pxSocket; 344 } 345 346 xParent->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT; 347 348 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) 349 { 350 /* Library support FreeRTOS_select(). Receiving a new 351 * connection is being translated as a READ event. */ 352 if( ( xParent->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U ) 353 { 354 xParent->xEventBits |= ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT; 355 } 356 } 357 #endif 358 359 #if ( ipconfigUSE_CALLBACKS == 1 ) 360 { 361 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) ) && 362 ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) ) 363 { 364 /* The listening socket does not become connected itself, in stead 365 * a child socket is created. 366 * Postpone a call the OnConnect event until the end of this function. */ 367 xConnected = xParent; 368 } 369 } 370 #endif 371 } 372 373 /* Don't need to access the parent socket anymore, so the 374 * reference 'pxPeerSocket' may be cleared. */ 375 pxSocket->u.xTCP.pxPeerSocket = NULL; 376 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED; 377 378 /* When true, this socket may be returned in a call to accept(). */ 379 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED; 380 } 381 else 382 { 383 /* An active connect() has succeeded. In this case there is no 384 * ( listening ) parent socket. Signal the now connected socket. */ 385 386 pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_CONNECT; 387 388 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) 389 { 390 if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U ) 391 { 392 pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_WRITE ) << SOCKET_EVENT_BIT_COUNT; 393 } 394 } 395 #endif 396 } 397 } 398 else /* bAfter == pdFALSE, connection is closed. */ 399 { 400 /* Notify/wake-up the socket-owner by setting the event bits. */ 401 xParent->xEventBits |= ( EventBits_t ) eSOCKET_CLOSED; 402 403 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) 404 { 405 if( ( xParent->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U ) 406 { 407 xParent->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT; 408 } 409 } 410 #endif 411 } 412 413 #if ( ipconfigUSE_CALLBACKS == 1 ) 414 { 415 if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) ) && ( xConnected == NULL ) ) 416 { 417 /* The 'connected' state has changed, call the user handler. */ 418 xConnected = pxSocket; 419 } 420 } 421 #endif /* ipconfigUSE_CALLBACKS */ 422 423 if( prvTCPSocketIsActive( pxSocket->u.xTCP.eTCPState ) == 0 ) 424 { 425 /* Now the socket isn't in an active state anymore so it 426 * won't need further attention of the IP-task. 427 * Setting time-out to zero means that the socket won't get checked during 428 * timer events. */ 429 pxSocket->u.xTCP.usTimeout = 0U; 430 } 431 } 432 433 /* Fill in the new state. */ 434 pxSocket->u.xTCP.eTCPState = eTCPState; 435 436 if( ( eTCPState == eCLOSED ) || 437 ( eTCPState == eCLOSE_WAIT ) ) 438 { 439 /* Socket goes to status eCLOSED because of a RST. 440 * When nobody owns the socket yet, delete it. */ 441 vTaskSuspendAll(); 442 { 443 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) || 444 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) 445 { 446 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) 447 { 448 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED; 449 pxSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED; 450 } 451 452 ( void ) xTaskResumeAll(); 453 454 FreeRTOS_printf( ( "vTCPStateChange: Closing socket\n" ) ); 455 456 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) 457 { 458 configASSERT( xIsCallingFromIPTask() != pdFALSE ); 459 vSocketCloseNextTime( pxSocket ); 460 } 461 } 462 else 463 { 464 ( void ) xTaskResumeAll(); 465 } 466 } 467 } 468 469 if( ( eTCPState == eCLOSE_WAIT ) && ( pxSocket->u.xTCP.bits.bReuseSocket == pdTRUE_UNSIGNED ) ) 470 { 471 switch( xPreviousState ) 472 { 473 case eSYN_FIRST: /* 3 (server) Just created, must ACK the SYN request */ 474 case eSYN_RECEIVED: /* 4 (server) waiting for a confirming connection request */ 475 FreeRTOS_debug_printf( ( "Restoring a reuse socket port %u\n", pxSocket->usLocalPort ) ); 476 477 /* Go back into listening mode. Set the TCP status to 'eCLOSED', 478 * otherwise FreeRTOS_listen() will refuse the action. */ 479 pxSocket->u.xTCP.eTCPState = eCLOSED; 480 481 /* vSocketListenNextTime() makes sure that FreeRTOS_listen() will be called 482 * before the IP-task handles any new message. */ 483 vSocketListenNextTime( pxSocket ); 484 break; 485 486 default: 487 /* Nothing to do. */ 488 break; 489 } 490 } 491 492 /* Touch the alive timers because moving to another state. */ 493 prvTCPTouchSocket( pxSocket ); 494 495 #if ( ipconfigHAS_DEBUG_PRINTF == 1 ) 496 { 497 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) ) 498 { 499 char pcBuffer[ 40 ]; 500 501 switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */ 502 { 503 #if ( ipconfigUSE_IPv4 != 0 ) 504 case pdFALSE_UNSIGNED: 505 { 506 uint32_t ulIPAddress = FreeRTOS_ntohl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 ); 507 FreeRTOS_inet_ntop( FREERTOS_AF_INET4, 508 ( const uint8_t * ) &ulIPAddress, 509 pcBuffer, 510 sizeof( pcBuffer ) ); 511 } 512 break; 513 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 514 515 #if ( ipconfigUSE_IPv6 != 0 ) 516 case pdTRUE_UNSIGNED: 517 FreeRTOS_inet_ntop( FREERTOS_AF_INET6, 518 pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, 519 pcBuffer, 520 sizeof( pcBuffer ) ); 521 break; 522 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 523 524 default: /* LCOV_EXCL_LINE */ 525 /* MISRA 16.4 Compliance */ 526 break; /* LCOV_EXCL_LINE */ 527 } 528 529 FreeRTOS_debug_printf( ( "Socket %u -> [%s]:%u State %s->%s\n", 530 pxSocket->usLocalPort, 531 pcBuffer, 532 pxSocket->u.xTCP.usRemotePort, 533 FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ), 534 FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) ); 535 } 536 } 537 #endif /* ipconfigHAS_DEBUG_PRINTF */ 538 539 #if ( ipconfigUSE_CALLBACKS == 1 ) 540 { 541 if( xConnected != NULL ) 542 { 543 /* The 'connected' state has changed, call the OnConnect handler of the parent. */ 544 xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter ); 545 } 546 } 547 #endif 548 549 if( xParent != NULL ) 550 { 551 vSocketWakeUpUser( xParent ); 552 } 553 } 554 /*-----------------------------------------------------------*/ 555 556 557 /** 558 * @brief Calculate after how much time this socket needs to be checked again. 559 * 560 * @param[in] pxSocket The socket to be checked. 561 * 562 * @return The number of clock ticks before the timer expires. 563 */ prvTCPNextTimeout(struct xSOCKET * pxSocket)564 TickType_t prvTCPNextTimeout( struct xSOCKET * pxSocket ) 565 { 566 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS; 567 568 if( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN ) 569 { 570 /* The socket is actively connecting to a peer. */ 571 if( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) 572 { 573 /* Ethernet address has been found, use progressive timeout for 574 * active connect(). */ 575 if( pxSocket->u.xTCP.ucRepCount < 3U ) 576 { 577 ulDelayMs = ( ( ( uint32_t ) 3000U ) << ( pxSocket->u.xTCP.ucRepCount - 1U ) ); 578 } 579 else 580 { 581 ulDelayMs = 11000U; 582 } 583 } 584 else 585 { 586 /* Still in the ARP phase: check every half second. */ 587 ulDelayMs = 500U; 588 } 589 590 FreeRTOS_debug_printf( ( "Connect[%xip:%u]: next timeout %u: %u ms\n", 591 ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, pxSocket->u.xTCP.usRemotePort, 592 pxSocket->u.xTCP.ucRepCount, ( unsigned ) ulDelayMs ) ); 593 pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs ); 594 } 595 else if( pxSocket->u.xTCP.usTimeout == 0U ) 596 { 597 /* Let the sliding window mechanism decide what time-out is appropriate. */ 598 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs ); 599 600 if( ulDelayMs == 0U ) 601 { 602 if( xResult != ( BaseType_t ) 0 ) 603 { 604 ulDelayMs = 1U; 605 } 606 else 607 { 608 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS; 609 } 610 } 611 else 612 { 613 /* ulDelayMs contains the time to wait before a re-transmission. */ 614 } 615 616 pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs ); /* LCOV_EXCL_BR_LINE ulDelayMs will not be smaller than 1 */ 617 } 618 else 619 { 620 /* field '.usTimeout' has already been set (by the 621 * keep-alive/delayed-ACK mechanism). */ 622 } 623 624 /* Return the number of clock ticks before the timer expires. */ 625 return ( TickType_t ) pxSocket->u.xTCP.usTimeout; 626 } 627 /*-----------------------------------------------------------*/ 628 629 /** 630 * @brief Process the received TCP packet. 631 * 632 * @param[in] pxDescriptor The descriptor in which the TCP packet is held. 633 * 634 * @return If the processing of the packet was successful, then pdPASS is returned 635 * or else pdFAIL. 636 * 637 * @note FreeRTOS_TCP_IP has only 2 public functions, this is the second one: 638 * xProcessReceivedTCPPacket() 639 * prvTCPHandleState() 640 * prvTCPPrepareSend() 641 * prvTCPReturnPacket() 642 * xNetworkInterfaceOutput() // Sends data to the NIC 643 * prvTCPSendRepeated() 644 * prvTCPReturnPacket() // Prepare for returning 645 * xNetworkInterfaceOutput() // Sends data to the NIC 646 */ xProcessReceivedTCPPacket(NetworkBufferDescriptor_t * pxDescriptor)647 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t * pxDescriptor ) 648 { 649 /* Function might modify the parameter. */ 650 const NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor; 651 652 configASSERT( pxNetworkBuffer != NULL ); 653 configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL ); 654 655 BaseType_t xResult; 656 657 /* MISRA Ref 11.3.1 [Misaligned access] */ 658 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 659 /* coverity[misra_c_2012_rule_11_3_violation] */ 660 switch( ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer )->usFrameType ) 661 { 662 #if ( ipconfigUSE_IPv4 != 0 ) 663 case ipIPv4_FRAME_TYPE: 664 xResult = xProcessReceivedTCPPacket_IPV4( pxDescriptor ); 665 break; 666 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 667 668 #if ( ipconfigUSE_IPv6 != 0 ) 669 case ipIPv6_FRAME_TYPE: 670 xResult = xProcessReceivedTCPPacket_IPV6( pxDescriptor ); 671 break; 672 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 673 674 default: 675 /* Shouldn't reach here */ 676 xResult = pdFAIL; 677 break; 678 } 679 680 return xResult; 681 } 682 /*-----------------------------------------------------------*/ 683 684 685 /** 686 * @brief In the API accept(), the user asks is there is a new client? As API's can 687 * not walk through the xBoundTCPSocketsList the IP-task will do this. 688 * 689 * @param[in] pxSocket The socket for which the bound socket list will be iterated. 690 * 691 * @return if there is a new client, then pdTRUE is returned or else, pdFALSE. 692 */ xTCPCheckNewClient(FreeRTOS_Socket_t * pxSocket)693 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t * pxSocket ) 694 { 695 TickType_t uxLocalPort = ( TickType_t ) FreeRTOS_htons( pxSocket->usLocalPort ); 696 const ListItem_t * pxIterator; 697 FreeRTOS_Socket_t * pxFound; 698 BaseType_t xResult = pdFALSE; 699 700 /* MISRA Ref 11.3.1 [Misaligned access] */ 701 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 702 /* coverity[misra_c_2012_rule_11_3_violation] */ 703 const ListItem_t * pxEndTCP = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) ); 704 705 /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one 706 * who has access. */ 707 for( pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); 708 pxIterator != pxEndTCP; 709 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) 710 { 711 if( listGET_LIST_ITEM_VALUE( pxIterator ) == ( configLIST_VOLATILE TickType_t ) uxLocalPort ) 712 { 713 pxFound = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) ); 714 715 if( ( pxFound->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) 716 { 717 pxSocket->u.xTCP.pxPeerSocket = pxFound; 718 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) ); 719 xResult = pdTRUE; 720 break; 721 } 722 } 723 } 724 725 return xResult; 726 } 727 /*-----------------------------------------------------------*/ 728 729 730 #endif /* ipconfigUSE_TCP == 1 */ 731 732 /* Provide access to private members for testing. */ 733 #ifdef FREERTOS_ENABLE_UNIT_TESTS 734 #include "freertos_tcp_test_access_tcp_define.h" 735 #endif 736 737 /* Provide access to private members for verification. */ 738 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION 739 #include "aws_freertos_tcp_verification_access_tcp_define.h" 740 #endif 741