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