xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_TCP_Transmission.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
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