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