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_Transmission.c 30 * @brief Module which prepares the packet to be sent through 31 * a socket for FreeRTOS+TCP. 32 * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing 33 * schemes. 34 * 35 * Endianness: in this module all ports and IP addresses are stored in 36 * host byte-order, except fields in the IP-packets 37 */ 38 39 /* Standard includes. */ 40 #include <stdint.h> 41 #include <stdio.h> 42 43 /* FreeRTOS includes. */ 44 #include "FreeRTOS.h" 45 #include "task.h" 46 #include "queue.h" 47 #include "semphr.h" 48 49 /* FreeRTOS+TCP includes. */ 50 #include "FreeRTOS_IP.h" 51 #include "FreeRTOS_Sockets.h" 52 #include "FreeRTOS_IP_Private.h" 53 #include "NetworkInterface.h" 54 #include "NetworkBufferManagement.h" 55 #include "FreeRTOS_ARP.h" 56 #include "FreeRTOSIPConfigDefaults.h" 57 58 #include "FreeRTOS_TCP_IP.h" 59 #include "FreeRTOS_TCP_Reception.h" 60 #include "FreeRTOS_TCP_Transmission.h" 61 #include "FreeRTOS_TCP_State_Handling.h" 62 #include "FreeRTOS_TCP_Utils.h" 63 64 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */ 65 #if ipconfigUSE_TCP == 1 66 67 /* 68 * Let ARP look-up the MAC-address of the peer and initialise the first SYN 69 * packet. 70 */ 71 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t * pxSocket ); 72 73 /*------------------------------------------------------------------------*/ 74 75 /** 76 * @brief Check if the outgoing connection is already prepared, if not 77 * call prvTCPPrepareConnect() to continue the preparation. 78 * @param[in] pxSocket The socket that wants to connect. 79 * @return Returns pdTRUE if the connection is prepared, i.e. the MAC- 80 * address of the peer is already known. */ prvTCPMakeSurePrepared(FreeRTOS_Socket_t * pxSocket)81 static BaseType_t prvTCPMakeSurePrepared( FreeRTOS_Socket_t * pxSocket ) 82 { 83 BaseType_t xReturn = pdTRUE; 84 85 if( pxSocket->u.xTCP.bits.bConnPrepared == pdFALSE_UNSIGNED ) 86 { 87 if( prvTCPPrepareConnect( pxSocket ) != pdTRUE ) 88 { 89 /* The preparation of a connection ( ARP resolution ) is not yet ready. */ 90 xReturn = pdFALSE; 91 } 92 } 93 94 return xReturn; 95 } 96 /*-----------------------------------------------------------*/ 97 98 /** 99 * @brief prvTCPSendPacket() will be called when the socket time-out has been reached. 100 * 101 * @param[in] pxSocket The socket owning the connection. 102 * 103 * @return Number of bytes to be sent. 104 * 105 * @note It is only called by xTCPSocketCheck(). 106 */ prvTCPSendPacket(FreeRTOS_Socket_t * pxSocket)107 int32_t prvTCPSendPacket( FreeRTOS_Socket_t * pxSocket ) 108 { 109 int32_t lResult = 0; 110 UBaseType_t uxOptionsLength, uxIntermediateResult = 0; 111 NetworkBufferDescriptor_t * pxNetworkBuffer; 112 113 if( pxSocket->u.xTCP.eTCPState != eCONNECT_SYN ) 114 { 115 /* The connection is in a state other than SYN. */ 116 pxNetworkBuffer = NULL; 117 118 /* prvTCPSendRepeated() will only create a network buffer if necessary, 119 * i.e. when data must be sent to the peer. */ 120 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer ); 121 122 if( pxNetworkBuffer != NULL ) 123 { 124 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); 125 } 126 } 127 else 128 { 129 if( pxSocket->u.xTCP.ucRepCount >= 3U ) 130 { 131 /* The connection is in the SYN status. The packet will be repeated 132 * to most 3 times. When there is no response, the socket get the 133 * status 'eCLOSE_WAIT'. */ 134 FreeRTOS_debug_printf( ( "Connect: giving up %xip:%u\n", 135 ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, /* IP address of remote machine. */ 136 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */ 137 vTCPStateChange( pxSocket, eCLOSE_WAIT ); 138 } 139 else if( prvTCPMakeSurePrepared( pxSocket ) == pdTRUE ) 140 { 141 ProtocolHeaders_t * pxProtocolHeaders; 142 143 /* Or else, if the connection has been prepared, or can be prepared 144 * now, proceed to send the packet with the SYN flag. 145 * prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if 146 * the Ethernet address of the peer or the gateway is found. */ 147 148 /* MISRA Ref 11.3.1 [Misaligned access] */ 149 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 150 /* coverity[misra_c_2012_rule_11_3_violation] */ 151 pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) ); 152 153 /* About to send a SYN packet. Call prvSetSynAckOptions() to set 154 * the proper options: The size of MSS and whether SACK's are 155 * allowed. */ 156 uxOptionsLength = prvSetSynAckOptions( pxSocket, &( pxProtocolHeaders->xTCPHeader ) ); 157 158 /* Return the number of bytes to be sent. */ 159 uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength; 160 lResult = ( int32_t ) uxIntermediateResult; 161 162 /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and 163 * uxOptionsLength is always a multiple of 4. The complete expression 164 * would be: 165 * ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */ 166 pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); 167 168 /* Repeat Count is used for a connecting socket, to limit the number 169 * of tries. */ 170 pxSocket->u.xTCP.ucRepCount++; 171 172 /* Send the SYN message to make a connection. The messages is 173 * stored in the socket field 'xPacket'. It will be wrapped in a 174 * pseudo network buffer descriptor before it will be sent. */ 175 prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE ); 176 } 177 else 178 { 179 /* Nothing to do. */ 180 } 181 } 182 183 /* Return the total number of bytes sent. */ 184 return lResult; 185 } 186 /*-----------------------------------------------------------*/ 187 188 /** 189 * @brief prvTCPSendRepeated will try to send a series of messages, as 190 * long as there is data to be sent and as long as the transmit 191 * window isn't full. 192 * 193 * @param[in] pxSocket The socket owning the connection. 194 * @param[in,out] ppxNetworkBuffer Pointer to pointer to the network buffer. 195 * 196 * @return Total number of bytes sent. 197 */ prvTCPSendRepeated(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t ** ppxNetworkBuffer)198 int32_t prvTCPSendRepeated( FreeRTOS_Socket_t * pxSocket, 199 NetworkBufferDescriptor_t ** ppxNetworkBuffer ) 200 { 201 UBaseType_t uxIndex; 202 int32_t lResult = 0; 203 UBaseType_t uxOptionsLength = 0U; 204 int32_t xSendLength; 205 206 for( uxIndex = 0U; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ ) 207 { 208 /* prvTCPPrepareSend() might allocate a network buffer if there is data 209 * to be sent. */ 210 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength ); 211 212 if( xSendLength <= 0 ) 213 { 214 break; 215 } 216 217 /* And return the packet to the peer. */ 218 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER ); 219 220 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) 221 { 222 *ppxNetworkBuffer = NULL; 223 } 224 #endif /* ipconfigZERO_COPY_TX_DRIVER */ 225 226 lResult += xSendLength; 227 } 228 229 /* Return the total number of bytes sent. */ 230 return lResult; 231 } 232 /*-----------------------------------------------------------*/ 233 234 /** 235 * @brief Return (or send) a packet to the peer. The data is stored in pxBuffer, 236 * which may either point to a real network buffer or to a TCP socket field 237 * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass 238 * the data to the NIC. 239 * 240 * @param[in] pxSocket The socket owning the connection. 241 * @param[in] pxDescriptor The network buffer descriptor carrying the packet. 242 * @param[in] ulLen Length of the packet being sent. 243 * @param[in] xReleaseAfterSend pdTRUE if the ownership of the descriptor is 244 * transferred to the network interface. 245 */ prvTCPReturnPacket(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxDescriptor,uint32_t ulLen,BaseType_t xReleaseAfterSend)246 void prvTCPReturnPacket( FreeRTOS_Socket_t * pxSocket, 247 NetworkBufferDescriptor_t * pxDescriptor, 248 uint32_t ulLen, 249 BaseType_t xReleaseAfterSend ) 250 { 251 const NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor; 252 BaseType_t xIsIPv6 = pdFALSE; 253 254 if( pxNetworkBuffer != NULL ) 255 { 256 #if ( ipconfigUSE_IPv6 != 0 ) 257 if( uxIPHeaderSizePacket( pxNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER ) 258 { 259 xIsIPv6 = pdTRUE; 260 } 261 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 262 } 263 else if( pxSocket != NULL ) 264 { 265 #if ( ipconfigUSE_IPv6 != 0 ) 266 if( uxIPHeaderSizeSocket( pxSocket ) == ipSIZE_OF_IPv6_HEADER ) 267 { 268 xIsIPv6 = pdTRUE; 269 } 270 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 271 } 272 else 273 { 274 /* prvTCPReturnPacket_IPVx() needs either a network buffer, or a socket. */ 275 configASSERT( pdFALSE ); 276 } 277 278 #if ( ipconfigUSE_IPv6 != 0 ) 279 if( xIsIPv6 == pdTRUE ) 280 { 281 prvTCPReturnPacket_IPV6( pxSocket, pxDescriptor, ulLen, xReleaseAfterSend ); 282 } 283 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 284 285 #if ( ipconfigUSE_IPv4 != 0 ) 286 if( xIsIPv6 == pdFALSE ) 287 { 288 prvTCPReturnPacket_IPV4( pxSocket, pxDescriptor, ulLen, xReleaseAfterSend ); 289 } 290 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 291 } 292 /*-----------------------------------------------------------*/ 293 294 /** 295 * @brief Called by prvTCPReturnPacket(), this function will set the the window 296 * size on this side: 'xTCPHeader.usWindow'. 297 * @param[in] pxSocket The socket on which the packet is being sent. 298 * @param[in] pxNetworkBuffer The network buffer carrying the outgoing message. 299 * @param[in] uxIPHeaderSize The size of the IP-header, which depends on the IP-type. 300 */ prvTCPReturn_CheckTCPWindow(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer,size_t uxIPHeaderSize)301 void prvTCPReturn_CheckTCPWindow( FreeRTOS_Socket_t * pxSocket, 302 const NetworkBufferDescriptor_t * pxNetworkBuffer, 303 size_t uxIPHeaderSize ) 304 { 305 /* Calculate the space in the RX buffer in order to advertise the 306 * size of this socket's reception window. */ 307 const TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); 308 uint32_t ulFrontSpace, ulSpace, ulWinSize; 309 ProtocolHeaders_t * pxProtocolHeaders; 310 311 /* MISRA Ref 11.3.1 [Misaligned access] */ 312 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 313 /* coverity[misra_c_2012_rule_11_3_violation] */ 314 pxProtocolHeaders = ( ( ProtocolHeaders_t * ) 315 &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSize ] ) ); 316 317 if( pxSocket->u.xTCP.rxStream != NULL ) 318 { 319 /* An RX stream was created already, see how much space is 320 * available. */ 321 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); 322 } 323 else 324 { 325 /* No RX stream has been created, the full stream size is 326 * available. */ 327 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize; 328 } 329 330 /* Take the minimum of the RX buffer space and the RX window size. */ 331 ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace ); 332 333 if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) ) 334 { 335 /* The low-water mark was reached, meaning there was little 336 * space left. The socket will wait until the application has read 337 * or flushed the incoming data, and 'zero-window' will be 338 * advertised. */ 339 ulSpace = 0U; 340 } 341 342 /* If possible, advertise an RX window size of at least 1 MSS, otherwise 343 * the peer might start 'zero window probing', i.e. sending small packets 344 * (1, 2, 4, 8... bytes). */ 345 if( ( ulSpace < pxSocket->u.xTCP.usMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usMSS ) ) 346 { 347 ulSpace = pxSocket->u.xTCP.usMSS; 348 } 349 350 /* Avoid overflow of the 16-bit win field. */ 351 #if ( ipconfigUSE_TCP_WIN != 0 ) 352 { 353 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor ); 354 } 355 #else 356 { 357 ulWinSize = ulSpace; 358 } 359 #endif 360 361 if( ulWinSize > 0xfffcU ) 362 { 363 ulWinSize = 0xfffcU; 364 } 365 366 pxProtocolHeaders->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize ); 367 368 /* The new window size has been advertised, switch off the flag. */ 369 pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED; 370 371 /* Later on, when deciding to delay an ACK, a precise estimate is needed 372 * of the free RX space. At this moment, 'ulHighestRxAllowed' would be the 373 * highest sequence number minus 1 that the socket will accept. */ 374 pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace; 375 } 376 /*-----------------------------------------------------------*/ 377 378 /** 379 * @brief Called by prvTCPReturnPacket(), this function sets the sequence and ack numbers 380 * in the TCP-header. 381 * @param[in] pxSocket The socket on which the packet is being sent. 382 * @param[in] pxNetworkBuffer The network buffer carrying the outgoing message. 383 * @param[in] uxIPHeaderSize The size of the IP-header, which depends on the IP-type. 384 * @param[in] ulLen The size of the packet minus the size of the Ethernet header. 385 * 386 */ prvTCPReturn_SetSequenceNumber(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer,size_t uxIPHeaderSize,uint32_t ulLen)387 void prvTCPReturn_SetSequenceNumber( FreeRTOS_Socket_t * pxSocket, 388 const NetworkBufferDescriptor_t * pxNetworkBuffer, 389 size_t uxIPHeaderSize, 390 uint32_t ulLen ) 391 { 392 ProtocolHeaders_t * pxProtocolHeaders; 393 const TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); 394 395 /* MISRA Ref 11.3.1 [Misaligned access] */ 396 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 397 /* coverity[misra_c_2012_rule_11_3_violation] */ 398 pxProtocolHeaders = ( ( ProtocolHeaders_t * ) 399 &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSize ] ) ); 400 #if ( ipconfigTCP_KEEP_ALIVE == 1 ) 401 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) 402 { 403 /* Sending a keep-alive packet, send the current sequence number 404 * minus 1, which will be recognised as a keep-alive packet and 405 * responded to by acknowledging the last byte. */ 406 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED; 407 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED; 408 409 pxProtocolHeaders->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1U; 410 pxProtocolHeaders->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxProtocolHeaders->xTCPHeader.ulSequenceNumber ); 411 } 412 else 413 #endif /* if ( ipconfigTCP_KEEP_ALIVE == 1 ) */ 414 { 415 pxProtocolHeaders->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber ); 416 417 if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_FIN ) != 0U ) 418 { 419 /* Suppress FIN in case this packet carries earlier data to be 420 * retransmitted. */ 421 uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + uxIPHeaderSizeSocket( pxSocket ) ) ); 422 423 if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber ) 424 { 425 pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_FLAG_FIN ); 426 FreeRTOS_debug_printf( ( "Suppress FIN for %u + %u < %u\n", 427 ( unsigned int ) ( pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ), 428 ( unsigned int ) ulDataLen, 429 ( unsigned int ) ( pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) ) ); 430 } 431 } 432 } 433 434 /* Tell which sequence number is expected next time */ 435 pxProtocolHeaders->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber ); 436 } 437 /*-----------------------------------------------------------*/ 438 439 /** 440 * @brief Create the TCP window for the given socket. 441 * 442 * @param[in] pxSocket The socket for which the window is being created. 443 * 444 * @note The SYN event is very important: the sequence numbers, which have a kind of 445 * random starting value, are being synchronized. The sliding window manager 446 * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment 447 * Size (MSS). 448 */ prvTCPCreateWindow(FreeRTOS_Socket_t * pxSocket)449 void prvTCPCreateWindow( FreeRTOS_Socket_t * pxSocket ) 450 { 451 uint32_t ulRxWindowSize = ( uint32_t ) pxSocket->u.xTCP.uxRxWinSize; 452 uint32_t ulTxWindowSize = ( uint32_t ) pxSocket->u.xTCP.uxTxWinSize; 453 454 if( xTCPWindowLoggingLevel != 0 ) 455 { 456 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %u Water %u <= %u <= %u\n", 457 ( unsigned ) ( pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS ), 458 ( unsigned ) pxSocket->u.xTCP.uxLittleSpace, 459 ( unsigned ) pxSocket->u.xTCP.uxEnoughSpace, 460 ( unsigned ) pxSocket->u.xTCP.uxRxStreamSize ) ); 461 } 462 463 vTCPWindowCreate( 464 &pxSocket->u.xTCP.xTCPWindow, 465 ulRxWindowSize * ipconfigTCP_MSS, 466 ulTxWindowSize * ipconfigTCP_MSS, 467 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber, 468 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, 469 ( uint32_t ) pxSocket->u.xTCP.usMSS ); 470 } 471 /*-----------------------------------------------------------*/ 472 473 /** 474 * @brief Let ARP look-up the MAC-address of the peer and initialise the first SYN 475 * packet. 476 * 477 * @param[in] pxSocket The socket owning the TCP connection. The first packet shall 478 * be created in this socket. 479 * 480 * @return pdTRUE: if the packet was successfully created and the first SYN can be sent. 481 * Else pdFALSE. 482 * 483 * @note Connecting sockets have a special state: eCONNECT_SYN. In this phase, 484 * the Ethernet address of the target will be found using ARP. In case the 485 * target IP address is not within the netmask, the hardware address of the 486 * gateway will be used. 487 */ prvTCPPrepareConnect(FreeRTOS_Socket_t * pxSocket)488 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t * pxSocket ) 489 { 490 BaseType_t xReturn = pdTRUE; 491 492 switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */ 493 { 494 #if ( ipconfigUSE_IPv4 != 0 ) 495 case pdFALSE_UNSIGNED: 496 xReturn = prvTCPPrepareConnect_IPV4( pxSocket ); 497 break; 498 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 499 500 #if ( ipconfigUSE_IPv6 != 0 ) 501 case pdTRUE_UNSIGNED: 502 xReturn = prvTCPPrepareConnect_IPV6( pxSocket ); 503 break; 504 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 505 506 default: /* LCOV_EXCL_LINE */ 507 /* MISRA 16.4 Compliance */ 508 break; /* LCOV_EXCL_LINE */ 509 } 510 511 return xReturn; 512 } 513 /*-----------------------------------------------------------*/ 514 515 #if ( ipconfigUSE_TCP_WIN != 0 ) 516 517 /** 518 * @brief Get the window scaling factor for the TCP connection. 519 * 520 * @param[in] pxSocket The socket owning the TCP connection. 521 * 522 * @return The scaling factor. 523 */ prvWinScaleFactor(const FreeRTOS_Socket_t * pxSocket)524 static uint8_t prvWinScaleFactor( const FreeRTOS_Socket_t * pxSocket ) 525 { 526 size_t uxWinSize; 527 uint8_t ucFactor; 528 529 530 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */ 531 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usMSS; 532 ucFactor = 0U; 533 534 while( uxWinSize > 0xffffU ) 535 { 536 /* Divide by two and increase the binary factor by 1. */ 537 uxWinSize >>= 1; 538 ucFactor++; 539 } 540 541 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %u MSS %u Factor %u\n", 542 ( unsigned ) pxSocket->u.xTCP.uxRxWinSize, 543 pxSocket->u.xTCP.usMSS, 544 ucFactor ) ); 545 546 return ucFactor; 547 } 548 549 #endif /* if ( ipconfigUSE_TCP_WIN != 0 ) */ 550 /*-----------------------------------------------------------*/ 551 552 /** 553 * @brief When opening a TCP connection, while SYN's are being sent, the parties may 554 * communicate what MSS (Maximum Segment Size) they intend to use, whether Selective 555 * ACK's ( SACK ) are supported, and the size of the reception window ( WSOPT ). 556 * 557 * @param[in] pxSocket The socket being used for communication. It is used to set 558 * the MSS. 559 * @param[in,out] pxTCPHeader The TCP packet header being used in the SYN transmission. 560 * The MSS and corresponding options shall be set in this 561 * header itself. 562 * 563 * @return The option length after the TCP header was updated. 564 * 565 * @note MSS is the net size of the payload, an is always smaller than MTU. 566 */ prvSetSynAckOptions(FreeRTOS_Socket_t * pxSocket,TCPHeader_t * pxTCPHeader)567 UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t * pxSocket, 568 TCPHeader_t * pxTCPHeader ) 569 { 570 uint16_t usMSS = pxSocket->u.xTCP.usMSS; 571 UBaseType_t uxOptionsLength; 572 573 /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */ 574 575 pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) tcpTCP_OPT_MSS; 576 pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) tcpTCP_OPT_MSS_LEN; 577 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 ); 578 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffU ); 579 580 #if ( ipconfigUSE_TCP_WIN != 0 ) 581 { 582 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket ); 583 584 pxTCPHeader->ucOptdata[ 4 ] = tcpTCP_OPT_NOOP; 585 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT ); 586 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( tcpTCP_OPT_WSOPT_LEN ); 587 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor; 588 uxOptionsLength = 8U; 589 } 590 #else 591 { 592 uxOptionsLength = 4U; 593 } 594 #endif /* if ( ipconfigUSE_TCP_WIN != 0 ) */ 595 596 #if ( ipconfigUSE_TCP_WIN != 0 ) 597 { 598 pxTCPHeader->ucOptdata[ uxOptionsLength ] = tcpTCP_OPT_NOOP; 599 pxTCPHeader->ucOptdata[ uxOptionsLength + 1U ] = tcpTCP_OPT_NOOP; 600 pxTCPHeader->ucOptdata[ uxOptionsLength + 2U ] = tcpTCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */ 601 pxTCPHeader->ucOptdata[ uxOptionsLength + 3U ] = 2U; /* 2: length of this option. */ 602 uxOptionsLength += 4U; 603 } 604 #endif /* ipconfigUSE_TCP_WIN == 0 */ 605 return uxOptionsLength; /* bytes, not words. */ 606 } 607 608 /** 609 * @brief Check if the size of a network buffer is big enough to hold the outgoing message. 610 * Allocate a new bigger network buffer when necessary. 611 * 612 * @param[in] pxSocket Socket whose buffer is being resized. 613 * @param[in] pxNetworkBuffer The network buffer whose size is being increased. 614 * @param[in] lDataLen Length of the data to be put in the buffer. 615 * @param[in] uxOptionsLength Length of options. 616 * 617 * @return If the resizing is successful: The new buffer with the size being asked for 618 * with old data copied in it. 619 * Else, NULL. 620 * 621 * @note The old network buffer will be released if the resizing is successful and 622 * cannot be used any longer. 623 */ prvTCPBufferResize(const FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxNetworkBuffer,int32_t lDataLen,UBaseType_t uxOptionsLength)624 NetworkBufferDescriptor_t * prvTCPBufferResize( const FreeRTOS_Socket_t * pxSocket, 625 NetworkBufferDescriptor_t * pxNetworkBuffer, 626 int32_t lDataLen, 627 UBaseType_t uxOptionsLength ) 628 { 629 NetworkBufferDescriptor_t * pxReturn; 630 size_t uxNeeded; 631 BaseType_t xResize; 632 633 if( xBufferAllocFixedSize != pdFALSE ) 634 { 635 /* Network buffers are created with a fixed size and can hold the largest 636 * MTU. */ 637 uxNeeded = ( size_t ) ipTOTAL_ETHERNET_FRAME_SIZE; 638 639 /* and therefore, the buffer won't be too small. 640 * Only ask for a new network buffer in case none was supplied. */ 641 if( pxNetworkBuffer == NULL ) 642 { 643 xResize = pdTRUE; 644 } 645 else 646 { 647 xResize = pdFALSE; 648 } 649 } 650 else 651 { 652 /* Network buffers are created with a variable size. See if it must 653 * grow. */ 654 uxNeeded = ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength; 655 uxNeeded += ( size_t ) lDataLen; 656 657 if( uxNeeded < sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ) 658 { 659 uxNeeded = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ); 660 } 661 662 /* In case we were called from a TCP timer event, a buffer must be 663 * created. Otherwise, test 'xDataLength' of the provided buffer. */ 664 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < uxNeeded ) ) 665 { 666 xResize = pdTRUE; 667 } 668 else 669 { 670 xResize = pdFALSE; 671 } 672 } 673 674 if( xResize != pdFALSE ) 675 { 676 /* The caller didn't provide a network buffer or the provided buffer is 677 * too small. As we must send-out a data packet, a buffer will be created 678 * here. */ 679 pxReturn = pxGetNetworkBufferWithDescriptor( uxNeeded, 0U ); 680 681 if( pxReturn != NULL ) 682 { 683 /* Set the actual packet size, in case the returned buffer is larger. */ 684 pxReturn->xDataLength = uxNeeded; 685 686 /* Copy the existing data to the new created buffer. */ 687 if( pxNetworkBuffer != NULL ) 688 { 689 /* Either from the previous buffer... */ 690 ( void ) memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ); 691 692 /* ...and release it. */ 693 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); 694 } 695 else 696 { 697 /* Or from the socket field 'xTCP.xPacket'. */ 698 ( void ) memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); 699 } 700 } 701 } 702 else 703 { 704 /* xResize is false, the network buffer provided was big enough. */ 705 configASSERT( pxNetworkBuffer != NULL ); /* LCOV_EXCL_BR_LINE this branch will not be covered, since it would never be NULL. to tell lint: when xResize is false, pxNetworkBuffer is not NULL. */ 706 pxReturn = pxNetworkBuffer; 707 708 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen; 709 } 710 711 return pxReturn; 712 } 713 714 /*-----------------------------------------------------------*/ 715 716 /** 717 * @brief Called by prvTCPReturnPacket(), this function makes sure that the network buffer 718 * has 'pxEndPoint' set properly. 719 * @param[in] pxSocket The socket on which the packet is being sent. 720 * @param[in] pxNetworkBuffer The network buffer carrying the outgoing message. 721 * @param[in] uxIPHeaderSize The size of the IP-header, which depends on the IP-type. 722 */ prvTCPReturn_SetEndPoint(const FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxNetworkBuffer,size_t uxIPHeaderSize)723 void prvTCPReturn_SetEndPoint( const FreeRTOS_Socket_t * pxSocket, 724 NetworkBufferDescriptor_t * pxNetworkBuffer, 725 size_t uxIPHeaderSize ) 726 { 727 #if ( ipconfigUSE_IPv4 != 0 ) 728 const IPHeader_t * pxIPHeader = NULL; 729 #endif 730 #if ( ipconfigUSE_IPv6 != 0 ) 731 const IPHeader_IPv6_t * pxIPHeader_IPv6 = NULL; 732 #endif 733 734 if( ( pxSocket != NULL ) && ( pxSocket->pxEndPoint != NULL ) ) 735 { 736 pxNetworkBuffer->pxEndPoint = pxSocket->pxEndPoint; 737 } 738 else 739 { 740 FreeRTOS_printf( ( "prvTCPReturnPacket: No pxEndPoint yet?\n" ) ); 741 742 switch( uxIPHeaderSize ) 743 { 744 #if ( ipconfigUSE_IPv4 != 0 ) 745 case ipSIZE_OF_IPv4_HEADER: 746 747 /*_RB_ Was FreeRTOS_FindEndPointOnIP_IPv4() but changed to FreeRTOS_FindEndPointOnNetMask() 748 * as it is using the destination address. I'm confused here as sometimes the addresses are swapped. */ 749 /* MISRA Ref 11.3.1 [Misaligned access] */ 750 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 751 /* coverity[misra_c_2012_rule_11_3_violation] */ 752 pxIPHeader = ( ( IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) ); 753 pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnNetMask( pxIPHeader->ulDestinationIPAddress, 8 ); 754 755 if( pxNetworkBuffer->pxEndPoint == NULL ) 756 { 757 FreeRTOS_printf( ( "prvTCPReturnPacket: no such end-point %xip => %xip\n", 758 ( unsigned int ) FreeRTOS_ntohl( pxIPHeader->ulSourceIPAddress ), 759 ( unsigned int ) FreeRTOS_ntohl( pxIPHeader->ulDestinationIPAddress ) ) ); 760 } 761 break; 762 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 763 764 #if ( ipconfigUSE_IPv6 != 0 ) 765 case ipSIZE_OF_IPv6_HEADER: 766 /* MISRA Ref 11.3.1 [Misaligned access] */ 767 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 768 /* coverity[misra_c_2012_rule_11_3_violation] */ 769 pxIPHeader_IPv6 = ( ( IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) ); 770 pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv6( &( pxIPHeader_IPv6->xDestinationAddress ) ); 771 772 if( pxNetworkBuffer->pxEndPoint == NULL ) 773 { 774 FreeRTOS_printf( ( "prvTCPReturnPacket: no such end-point %pip => %pip\n", 775 ( void * ) pxIPHeader_IPv6->xSourceAddress.ucBytes, 776 ( void * ) pxIPHeader_IPv6->xDestinationAddress.ucBytes ) ); 777 } 778 break; 779 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 780 781 default: 782 /* Shouldn't reach here */ 783 pxNetworkBuffer->pxEndPoint = NULL; 784 break; 785 } 786 787 if( pxNetworkBuffer->pxEndPoint != NULL ) 788 { 789 FreeRTOS_printf( ( "prvTCPReturnPacket: packet's end-point %02x-%02x\n", 790 pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes[ 4 ], 791 pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes[ 5 ] ) ); 792 } 793 } 794 } 795 /*-----------------------------------------------------------*/ 796 797 /** 798 * @brief Prepare an outgoing message, in case anything has to be sent. 799 * 800 * @param[in] pxSocket The socket owning the connection. 801 * @param[in,out] ppxNetworkBuffer Pointer to the pointer to the network buffer. 802 * @param[in] uxOptionsLength The length of the TCP options. 803 * 804 * @return Length of the data to be sent if everything is correct. Else, -1 805 * is returned in case of any error. 806 */ prvTCPPrepareSend(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t ** ppxNetworkBuffer,UBaseType_t uxOptionsLength)807 int32_t prvTCPPrepareSend( FreeRTOS_Socket_t * pxSocket, 808 NetworkBufferDescriptor_t ** ppxNetworkBuffer, 809 UBaseType_t uxOptionsLength ) 810 { 811 int32_t lDataLen; 812 uint8_t * pucEthernetBuffer, * pucSendData; 813 ProtocolHeaders_t * pxProtocolHeaders; 814 size_t uxOffset; 815 uint32_t ulDataGot, ulDistance; 816 TCPWindow_t * pxTCPWindow; 817 NetworkBufferDescriptor_t * pxNewBuffer; 818 int32_t lStreamPos; 819 UBaseType_t uxIntermediateResult = 0; 820 821 if( ( *ppxNetworkBuffer ) != NULL ) 822 { 823 /* A network buffer descriptor was already supplied */ 824 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer; 825 } 826 else 827 { 828 /* For now let it point to the last packet header */ 829 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; 830 } 831 832 /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */ 833 834 /* MISRA Ref 11.3.1 [Misaligned access] */ 835 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 836 /* coverity[misra_c_2012_rule_11_3_violation] */ 837 pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) ); 838 pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); 839 lDataLen = 0; 840 lStreamPos = 0; 841 pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_ACK; 842 843 if( pxSocket->u.xTCP.txStream != NULL ) 844 { 845 /* ulTCPWindowTxGet will return the amount of data which may be sent 846 * along with the position in the txStream. 847 * Why check for MSS > 1 ? 848 * Because some TCP-stacks (like uIP) use it for flow-control. */ 849 if( pxSocket->u.xTCP.usMSS > 1U ) 850 { 851 lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos ); 852 } 853 854 if( lDataLen > 0 ) 855 { 856 /* Check if the current network buffer is big enough, if not, 857 * resize it. */ 858 pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength ); 859 860 if( pxNewBuffer != NULL ) 861 { 862 *ppxNetworkBuffer = pxNewBuffer; 863 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer; 864 865 /* Map the byte stream onto ProtocolHeaders_t struct for easy 866 * access to the fields. */ 867 868 /* MISRA Ref 11.3.1 [Misaligned access] */ 869 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 870 /* coverity[misra_c_2012_rule_11_3_violation] */ 871 pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) ); 872 873 pucSendData = &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength ] ); 874 875 /* Translate the position in txStream to an offset from the tail 876 * marker. */ 877 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos ); 878 879 /* Here data is copied from the txStream in 'peek' mode. Only 880 * when the packets are acked, the tail marker will be updated. */ 881 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE ); 882 883 #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) 884 { 885 if( ulDataGot != ( uint32_t ) lDataLen ) 886 { 887 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %d offs %u only %u != %d\n", 888 ( int ) lStreamPos, ( unsigned ) uxOffset, ( unsigned ) ulDataGot, ( int ) lDataLen ) ); 889 } 890 } 891 #endif 892 893 /* If the owner of the socket requests a closure, add the FIN 894 * flag to the last packet. */ 895 if( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) 896 { 897 ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead ); 898 899 if( ulDistance == ulDataGot ) 900 { 901 #if ( ipconfigHAS_DEBUG_PRINTF == 1 ) 902 { 903 /* the order of volatile accesses is undefined 904 * so such workaround */ 905 size_t uxHead = pxSocket->u.xTCP.txStream->uxHead; 906 size_t uxMid = pxSocket->u.xTCP.txStream->uxMid; 907 size_t uxTail = pxSocket->u.xTCP.txStream->uxTail; 908 909 FreeRTOS_debug_printf( ( "CheckClose %u <= %u (%u <= %u <= %u)\n", 910 ( unsigned ) ulDataGot, ( unsigned ) ulDistance, 911 ( unsigned ) uxTail, ( unsigned ) uxMid, ( unsigned ) uxHead ) ); 912 } 913 #endif /* if ( ipconfigHAS_DEBUG_PRINTF == 1 ) */ 914 915 /* Although the socket sends a FIN, it will stay in 916 * ESTABLISHED until all current data has been received or 917 * delivered. */ 918 pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN; 919 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen; 920 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED; 921 } 922 } 923 } 924 else 925 { 926 lDataLen = -1; 927 } 928 } 929 } 930 931 if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.eTCPState == eESTABLISHED ) ) 932 { 933 /* See if the socket owner wants to shutdown this connection. */ 934 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) && 935 ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) ) 936 { 937 pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED; 938 pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN; 939 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED; 940 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; 941 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber; 942 vTCPStateChange( pxSocket, eFIN_WAIT_1 ); 943 } 944 945 #if ( ipconfigTCP_KEEP_ALIVE != 0 ) 946 { 947 if( pxSocket->u.xTCP.ucKeepRepCount > 3U ) /*_RB_ Magic number. */ 948 { 949 FreeRTOS_debug_printf( ( "keep-alive: giving up %xip:%u\n", 950 ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, /* IP address of remote machine. */ 951 pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */ 952 vTCPStateChange( pxSocket, eCLOSE_WAIT ); 953 lDataLen = -1; 954 } 955 956 if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) ) 957 { 958 /* If there is no data to be sent, and no window-update message, 959 * we might want to send a keep-alive message. */ 960 TickType_t xAge = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime; 961 TickType_t xMax; 962 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * ( TickType_t ) configTICK_RATE_HZ ); 963 964 if( pxSocket->u.xTCP.ucKeepRepCount != 0U ) 965 { 966 xMax = 3U * configTICK_RATE_HZ; 967 } 968 969 if( xAge > xMax ) 970 { 971 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount(); 972 973 if( xTCPWindowLoggingLevel != 0 ) 974 { 975 FreeRTOS_debug_printf( ( "keep-alive: %xip:%u count %u\n", 976 ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, 977 pxSocket->u.xTCP.usRemotePort, 978 pxSocket->u.xTCP.ucKeepRepCount ) ); 979 } 980 981 pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED; 982 pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500U ) ); 983 pxSocket->u.xTCP.ucKeepRepCount++; 984 } 985 } 986 } 987 #endif /* ipconfigTCP_KEEP_ALIVE */ 988 } 989 990 if( lDataLen >= 0 ) 991 { 992 /* Anything to send, a change of the advertised window size, or maybe send a 993 * keep-alive message? */ 994 if( ( lDataLen > 0 ) || 995 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) || 996 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) ) 997 { 998 pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_FLAG_PSH ); 999 pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); /*_RB_ "2" needs comment. */ 1000 1001 pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_ACK; 1002 1003 if( lDataLen != 0L ) 1004 { 1005 pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_PSH; 1006 } 1007 1008 uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength; 1009 lDataLen += ( int32_t ) uxIntermediateResult; 1010 } 1011 } 1012 1013 return lDataLen; 1014 } 1015 /*-----------------------------------------------------------*/ 1016 1017 1018 /** 1019 * @brief The API FreeRTOS_send() adds data to the TX stream. Add 1020 * this data to the windowing system to it can be transmitted. 1021 * 1022 * @param[in] pxSocket The socket owning the connection. 1023 */ prvTCPAddTxData(FreeRTOS_Socket_t * pxSocket)1024 void prvTCPAddTxData( FreeRTOS_Socket_t * pxSocket ) 1025 { 1026 int32_t lCount, lLength; 1027 1028 /* A txStream has been created already, see if the socket has new data for 1029 * the sliding window. 1030 * 1031 * uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It 1032 * contains new Tx data which has not been passed to the sliding window yet. 1033 * The oldest data not-yet-confirmed can be found at rxTail. */ 1034 lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream ); 1035 1036 if( lLength > 0 ) 1037 { 1038 /* All data between txMid and rxHead will now be passed to the sliding 1039 * window manager, so it can start transmitting them. 1040 * 1041 * Hand over the new data to the sliding window handler. It will be 1042 * split-up in chunks of 1460 bytes each (or less, depending on 1043 * ipconfigTCP_MSS). */ 1044 lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow, 1045 ( uint32_t ) lLength, 1046 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid, 1047 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH ); 1048 1049 /* Move the rxMid pointer forward up to rxHead. */ 1050 if( lCount > 0 ) 1051 { 1052 vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount ); 1053 } 1054 } 1055 } 1056 /*-----------------------------------------------------------*/ 1057 1058 1059 /** 1060 * @brief Set the TCP options (if any) for the outgoing packet. 1061 * 1062 * @param[in] pxSocket The socket owning the connection. 1063 * @param[in] pxNetworkBuffer The network buffer holding the packet. 1064 * 1065 * @return Length of the TCP options after they are set. 1066 */ prvSetOptions(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer)1067 UBaseType_t prvSetOptions( FreeRTOS_Socket_t * pxSocket, 1068 const NetworkBufferDescriptor_t * pxNetworkBuffer ) 1069 { 1070 /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */ 1071 1072 /* MISRA Ref 11.3.1 [Misaligned access] */ 1073 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1074 /* coverity[misra_c_2012_rule_11_3_violation] */ 1075 ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * ) 1076 &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( pxNetworkBuffer ) ] ) ); 1077 TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader; 1078 const TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; 1079 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength; 1080 1081 #if ( ipconfigUSE_TCP_WIN == 1 ) 1082 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/ 1083 const void * pvCopySource; 1084 void * pvCopyDest; 1085 1086 if( uxOptionsLength != 0U ) 1087 { 1088 /* TCP options must be sent because a packet which is out-of-order 1089 * was received. */ 1090 if( xTCPWindowLoggingLevel >= 0 ) 1091 { 1092 FreeRTOS_debug_printf( ( "SACK[%u,%u]: optlen %u sending %u - %u\n", 1093 pxSocket->usLocalPort, 1094 pxSocket->u.xTCP.usRemotePort, 1095 ( unsigned ) uxOptionsLength, 1096 ( unsigned ) ( FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ), 1097 ( unsigned ) ( FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) ) ); 1098 } 1099 1100 /* 1101 * Use helper variables for memcpy() source & dest to remain 1102 * compliant with MISRA Rule 21.15. These should be 1103 * optimized away. 1104 */ 1105 pvCopySource = pxTCPWindow->ulOptionsData; 1106 pvCopyDest = pxTCPHeader->ucOptdata; 1107 ( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) uxOptionsLength ); 1108 1109 /* The header length divided by 4, goes into the higher nibble, 1110 * effectively a shift-left 2. */ 1111 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); 1112 } 1113 else 1114 #endif /* ipconfigUSE_TCP_WIN */ 1115 1116 if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) ) 1117 { 1118 /* TCP options must be sent because the MSS has changed. */ 1119 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED; 1120 1121 if( xTCPWindowLoggingLevel >= 0 ) 1122 { 1123 FreeRTOS_debug_printf( ( "MSS: sending %u\n", pxSocket->u.xTCP.usMSS ) ); 1124 } 1125 1126 pxTCPHeader->ucOptdata[ 0 ] = tcpTCP_OPT_MSS; 1127 pxTCPHeader->ucOptdata[ 1 ] = tcpTCP_OPT_MSS_LEN; 1128 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usMSS ) >> 8 ); 1129 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usMSS ) & 0xffU ); 1130 uxOptionsLength = 4U; 1131 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); 1132 } 1133 else 1134 { 1135 /* Nothing. */ 1136 } 1137 1138 return uxOptionsLength; 1139 } 1140 /*-----------------------------------------------------------*/ 1141 1142 1143 /** 1144 * @brief Called from prvTCPHandleState(). There is data to be sent. If 1145 * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be 1146 * checked if it would better be postponed for efficiency. 1147 * 1148 * @param[in] pxSocket The socket owning the TCP connection. 1149 * @param[in] ppxNetworkBuffer Pointer to pointer to the network buffer. 1150 * @param[in] ulReceiveLength The length of the received buffer. 1151 * @param[in] xByteCount Length of the data to be sent. 1152 * 1153 * @return The number of bytes actually sent. 1154 */ prvSendData(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t ** ppxNetworkBuffer,uint32_t ulReceiveLength,BaseType_t xByteCount)1155 BaseType_t prvSendData( FreeRTOS_Socket_t * pxSocket, 1156 NetworkBufferDescriptor_t ** ppxNetworkBuffer, 1157 uint32_t ulReceiveLength, 1158 BaseType_t xByteCount ) 1159 { 1160 /* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */ 1161 1162 /* MISRA Ref 11.3.1 [Misaligned access] */ 1163 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1164 /* coverity[misra_c_2012_rule_11_3_violation] */ 1165 const ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * ) 1166 &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( *ppxNetworkBuffer ) ] ) ); 1167 const TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader; 1168 const TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; 1169 /* Find out what window size we may advertised. */ 1170 int32_t lRxSpace; 1171 BaseType_t xSendLength = xByteCount; 1172 uint32_t ulRxBufferSpace; 1173 1174 #if ( ipconfigUSE_TCP_WIN == 1 ) 1175 /* Two steps to please MISRA. */ 1176 size_t uxSize = uxIPHeaderSizePacket( *ppxNetworkBuffer ) + ipSIZE_OF_TCP_HEADER; 1177 BaseType_t xSizeWithoutData = ( BaseType_t ) uxSize; 1178 1179 int32_t lMinLength; 1180 #endif 1181 1182 /* Set the time-out field, so that we'll be called by the IP-task in case no 1183 * next message will be received. */ 1184 ulRxBufferSpace = pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber; 1185 lRxSpace = ( int32_t ) ulRxBufferSpace; 1186 1187 #if ipconfigUSE_TCP_WIN == 1 1188 { 1189 /* An ACK may be delayed if the peer has space for at least 2 x MSS. */ 1190 lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usMSS ); 1191 1192 /* In case we're receiving data continuously, we might postpone sending 1193 * an ACK to gain performance. */ 1194 /* lint e9007 is OK because 'uxIPHeaderSizeSocket()' has no side-effects. */ 1195 if( ( ulReceiveLength > 0U ) && /* Data was sent to this socket. */ 1196 ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */ 1197 ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */ 1198 ( xSendLength == xSizeWithoutData ) && /* No Tx data or options to be sent. */ 1199 ( pxSocket->u.xTCP.eTCPState == eESTABLISHED ) && /* Connection established. */ 1200 ( pxTCPHeader->ucTCPFlags == tcpTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */ 1201 { 1202 uint32_t ulCurMSS = ( uint32_t ) pxSocket->u.xTCP.usMSS; 1203 1204 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer ) 1205 { 1206 /* There was still a delayed in queue, delete it. */ 1207 if( pxSocket->u.xTCP.pxAckMessage != NULL ) 1208 { 1209 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); 1210 } 1211 1212 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer; 1213 } 1214 1215 if( ulReceiveLength < ulCurMSS ) /* Received a small message. */ 1216 { 1217 pxSocket->u.xTCP.usTimeout = ( uint16_t ) tcpDELAYED_ACK_SHORT_DELAY_MS; 1218 } 1219 else 1220 { 1221 /* Normally a delayed ACK should wait 200 ms for a next incoming 1222 * packet. Only wait 20 ms here to gain performance. A slow ACK 1223 * for full-size message. */ 1224 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_TICKS( tcpDELAYED_ACK_LONGER_DELAY_MS ); 1225 1226 if( pxSocket->u.xTCP.usTimeout < 1U ) /* LCOV_EXCL_BR_LINE, the second branch will never be hit */ 1227 { 1228 pxSocket->u.xTCP.usTimeout = 1U; /* LCOV_EXCL_LINE, this line will not be reached */ 1229 } 1230 } 1231 1232 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) ) 1233 { 1234 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %u SEQ %u (len %u) tmout %u d %d\n", 1235 pxSocket->usLocalPort, 1236 pxSocket->u.xTCP.usRemotePort, 1237 ( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ), 1238 ( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ), 1239 ( unsigned ) xSendLength, 1240 pxSocket->u.xTCP.usTimeout, 1241 ( int ) lRxSpace ) ); 1242 } 1243 1244 *ppxNetworkBuffer = NULL; 1245 xSendLength = 0; 1246 } 1247 else if( pxSocket->u.xTCP.pxAckMessage != NULL ) 1248 { 1249 /* As an ACK is not being delayed, remove any earlier delayed ACK 1250 * message. */ 1251 if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer ) 1252 { 1253 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); 1254 } 1255 1256 pxSocket->u.xTCP.pxAckMessage = NULL; 1257 } 1258 else 1259 { 1260 /* The ack will not be postponed, and there was no stored ack ( in 'pxAckMessage' ). */ 1261 } 1262 } 1263 #else /* if ipconfigUSE_TCP_WIN == 1 */ 1264 { 1265 /* Remove compiler warnings. */ 1266 ( void ) ulReceiveLength; 1267 ( void ) pxTCPHeader; 1268 ( void ) lRxSpace; 1269 } 1270 #endif /* ipconfigUSE_TCP_WIN */ 1271 1272 if( xSendLength != 0 ) 1273 { 1274 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) ) 1275 { 1276 FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %u SEQ %u (len %u)\n", 1277 pxSocket->usLocalPort, 1278 pxSocket->u.xTCP.usRemotePort, 1279 ( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ), 1280 ( unsigned ) ( pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ), 1281 ( unsigned ) xSendLength ) ); 1282 } 1283 1284 /* Set the parameter 'xReleaseAfterSend' to the value of 1285 * ipconfigZERO_COPY_TX_DRIVER. */ 1286 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER ); 1287 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) 1288 { 1289 /* The driver has taken ownership of the Network Buffer. */ 1290 *ppxNetworkBuffer = NULL; 1291 } 1292 #endif 1293 } 1294 1295 return xSendLength; 1296 } 1297 /*-----------------------------------------------------------*/ 1298 1299 /** 1300 * @brief Common code for sending a TCP protocol control packet (i.e. no options, no 1301 * payload, just flags). 1302 * 1303 * @param[in] pxNetworkBuffer The network buffer received from the peer. 1304 * @param[in] ucTCPFlags The flags to determine what kind of packet this is. 1305 * 1306 * @return pdFAIL always indicating that the packet was not consumed. 1307 */ prvTCPSendSpecialPacketHelper(NetworkBufferDescriptor_t * pxNetworkBuffer,uint8_t ucTCPFlags)1308 BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t * pxNetworkBuffer, 1309 uint8_t ucTCPFlags ) 1310 { 1311 BaseType_t xReturn = pdTRUE; 1312 1313 #if ( ipconfigIGNORE_UNKNOWN_PACKETS == 1 ) 1314 /* Configured to ignore unknown packets just suppress a compiler warning. */ 1315 ( void ) pxNetworkBuffer; 1316 ( void ) ucTCPFlags; 1317 #else 1318 { 1319 switch( uxIPHeaderSizePacket( pxNetworkBuffer ) ) 1320 { 1321 #if ( ipconfigUSE_IPv4 != 0 ) 1322 case ipSIZE_OF_IPv4_HEADER: 1323 xReturn = prvTCPSendSpecialPktHelper_IPV4( pxNetworkBuffer, ucTCPFlags ); 1324 break; 1325 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 1326 1327 #if ( ipconfigUSE_IPv6 != 0 ) 1328 case ipSIZE_OF_IPv6_HEADER: 1329 xReturn = prvTCPSendSpecialPktHelper_IPV6( pxNetworkBuffer, ucTCPFlags ); 1330 break; 1331 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 1332 1333 default: 1334 xReturn = pdFAIL; 1335 break; 1336 } 1337 } 1338 #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */ 1339 1340 /* The packet was not consumed. */ 1341 return xReturn; 1342 } 1343 /*-----------------------------------------------------------*/ 1344 1345 /** 1346 * @brief A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2, 1347 * case #3. In summary, an RST was received with a sequence number that is 1348 * unexpected but still within the window. 1349 * 1350 * @param[in] pxNetworkBuffer The network buffer descriptor with the packet. 1351 * 1352 * @return Returns the value back from #prvTCPSendSpecialPacketHelper. 1353 */ prvTCPSendChallengeAck(NetworkBufferDescriptor_t * pxNetworkBuffer)1354 BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t * pxNetworkBuffer ) 1355 { 1356 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, tcpTCP_FLAG_ACK ); 1357 } 1358 /*-----------------------------------------------------------*/ 1359 1360 /** 1361 * @brief Send a RST (Reset) to peer in case the packet cannot be handled. 1362 * 1363 * @param[in] pxNetworkBuffer The network buffer descriptor with the packet. 1364 * 1365 * @return Returns the value back from #prvTCPSendSpecialPacketHelper. 1366 */ prvTCPSendReset(NetworkBufferDescriptor_t * pxNetworkBuffer)1367 BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t * pxNetworkBuffer ) 1368 { 1369 return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, 1370 ( uint8_t ) tcpTCP_FLAG_ACK | ( uint8_t ) tcpTCP_FLAG_RST ); 1371 } 1372 /*-----------------------------------------------------------*/ 1373 1374 #endif /* ipconfigUSE_TCP == 1 */ 1375