xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_TCP_Transmission_IPv4.c (revision 67b9e1c2813792625500f9e8c091822b325f3fe7)
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_IPv4.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 /* *INDENT-OFF* */
66 #if( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_TCP == 1 )
67 /* *INDENT-ON* */
68 
69 /*------------------------------------------------------------------------*/
70 
71 
72 /**
73  * @brief  Return (or send) a packet to the peer. The data is stored in pxBuffer,
74  *         which may either point to a real network buffer or to a TCP socket field
75  *         called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
76  *         the data to the NIC.
77  *
78  * @param[in] pxSocket The socket owning the connection.
79  * @param[in] pxDescriptor The network buffer descriptor carrying the packet.
80  * @param[in] ulLen Length of the packet being sent.
81  * @param[in] xReleaseAfterSend pdTRUE if the ownership of the descriptor is
82  *                               transferred to the network interface.
83  */
prvTCPReturnPacket_IPV4(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxDescriptor,uint32_t ulLen,BaseType_t xReleaseAfterSend)84 void prvTCPReturnPacket_IPV4( FreeRTOS_Socket_t * pxSocket,
85                               NetworkBufferDescriptor_t * pxDescriptor,
86                               uint32_t ulLen,
87                               BaseType_t xReleaseAfterSend )
88 {
89     TCPPacket_t * pxTCPPacket = NULL;
90     ProtocolHeaders_t * pxProtocolHeaders = NULL;
91     IPHeader_t * pxIPHeader = NULL;
92     BaseType_t xDoRelease = xReleaseAfterSend;
93     EthernetHeader_t * pxEthernetHeader = NULL;
94     NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor;
95     NetworkBufferDescriptor_t xTempBuffer;
96     /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
97     MACAddress_t xMACAddress;
98     const void * pvCopySource = NULL;
99     void * pvCopyDest = NULL;
100     const size_t uxIPHeaderSize = ipSIZE_OF_IPv4_HEADER;
101     uint32_t ulDestinationIPAddress;
102 
103     do
104     {
105         /* For sending, a pseudo network buffer will be used, as explained above. */
106 
107         if( pxNetworkBuffer == NULL )
108         {
109             pxNetworkBuffer = &xTempBuffer;
110 
111             ( void ) memset( &xTempBuffer, 0, sizeof( xTempBuffer ) );
112             #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
113                 {
114                     pxNetworkBuffer->pxNextBuffer = NULL;
115                 }
116             #endif
117             pxNetworkBuffer->pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
118             pxNetworkBuffer->xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
119             xDoRelease = pdFALSE;
120         }
121 
122         #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
123             {
124                 if( xDoRelease == pdFALSE )
125                 {
126                     /* A zero-copy network driver wants to pass the packet buffer
127                      * to DMA, so a new buffer must be created. */
128                     pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( size_t ) pxNetworkBuffer->xDataLength );
129 
130                     if( pxNetworkBuffer != NULL )
131                     {
132                         xDoRelease = pdTRUE;
133                     }
134                     else
135                     {
136                         FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
137                     }
138                 }
139             }
140         #endif /* ipconfigZERO_COPY_TX_DRIVER */
141 
142         /* MISRA Ref 11.3.1 [Misaligned access] */
143         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
144         /* coverity[misra_c_2012_rule_11_3_violation] */
145         pxIPHeader = ( ( IPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
146 
147         #ifndef __COVERITY__
148             if( pxNetworkBuffer != NULL ) /* LCOV_EXCL_BR_LINE the 2nd branch will never be reached */
149         #endif
150         {
151             /* Map the Ethernet buffer onto a TCPPacket_t struct for easy access to the fields. */
152 
153             /* MISRA Ref 11.3.1 [Misaligned access] */
154             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
155             /* coverity[misra_c_2012_rule_11_3_violation] */
156             pxTCPPacket = ( TCPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
157             pxEthernetHeader = ( EthernetHeader_t * ) &( pxTCPPacket->xEthernetHeader );
158             /* MISRA Ref 11.3.1 [Misaligned access] */
159             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
160             /* coverity[misra_c_2012_rule_11_3_violation] */
161             pxProtocolHeaders = ( ProtocolHeaders_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSize ] );
162 
163             if( pxNetworkBuffer->pxEndPoint == NULL )
164             {
165                 prvTCPReturn_SetEndPoint( pxSocket, pxNetworkBuffer, uxIPHeaderSize );
166 
167                 if( pxNetworkBuffer->pxEndPoint == NULL )
168                 {
169                     if( xDoRelease != pdFALSE )
170                     {
171                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
172                     }
173 
174                     pxNetworkBuffer = NULL;
175                     break;
176                 }
177             }
178 
179             /* Fill the packet, using hton translations. */
180             if( pxSocket != NULL )
181             {
182                 prvTCPReturn_CheckTCPWindow( pxSocket, pxNetworkBuffer, uxIPHeaderSize );
183                 prvTCPReturn_SetSequenceNumber( pxSocket, pxNetworkBuffer, uxIPHeaderSize, ulLen );
184                 pxIPHeader->ulDestinationIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
185                 pxIPHeader->ulSourceIPAddress = pxNetworkBuffer->pxEndPoint->ipv4_settings.ulIPAddress;
186             }
187             else
188             {
189                 /* Sending data without a socket, probably replying with a RST flag
190                  * Just swap the two sequence numbers. */
191                 vFlip_32( pxProtocolHeaders->xTCPHeader.ulSequenceNumber, pxProtocolHeaders->xTCPHeader.ulAckNr );
192                 vFlip_32( pxIPHeader->ulDestinationIPAddress, pxIPHeader->ulSourceIPAddress );
193             }
194 
195             pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
196             pxIPHeader->usLength = FreeRTOS_htons( ulLen );
197 
198             /* Just an increasing number. */
199             pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
200             usPacketIdentifier++;
201 
202             /* The stack doesn't support fragments, so the fragment offset field must always be zero.
203              * The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go.
204              */
205             #if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 )
206                 pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT;
207             #else
208                 pxIPHeader->usFragmentOffset = 0U;
209             #endif
210 
211             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
212                 {
213                     /* calculate the IP header checksum, in case the driver won't do that. */
214                     pxIPHeader->usHeaderChecksum = 0x00U;
215                     pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), uxIPHeaderSize );
216                     pxIPHeader->usHeaderChecksum = ( uint16_t ) ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
217 
218                     /* calculate the TCP checksum for an outgoing packet. */
219                     ( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
220                 }
221             #endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
222 
223             vFlip_16( pxProtocolHeaders->xTCPHeader.usSourcePort, pxProtocolHeaders->xTCPHeader.usDestinationPort );
224 
225             /* Important: tell NIC driver how many bytes must be sent. */
226             pxNetworkBuffer->xDataLength = ( size_t ) ulLen;
227             pxNetworkBuffer->xDataLength += ipSIZE_OF_ETH_HEADER;
228 
229             #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
230                 {
231                     pxNetworkBuffer->pxNextBuffer = NULL;
232                 }
233             #endif
234 
235             pvCopySource = &pxEthernetHeader->xSourceAddress;
236             ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
237             eARPLookupResult_t eResult;
238 
239             eResult = eARPGetCacheEntry( &ulDestinationIPAddress, &xMACAddress, &( pxNetworkBuffer->pxEndPoint ) );
240 
241             if( eResult == eARPCacheHit )
242             {
243                 pvCopySource = &xMACAddress;
244             }
245             else
246             {
247                 pvCopySource = &pxEthernetHeader->xSourceAddress;
248             }
249 
250             /* Fill in the destination MAC addresses. */
251             pvCopyDest = &pxEthernetHeader->xDestinationAddress;
252             ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxEthernetHeader->xDestinationAddress ) );
253 
254             /*
255              * Use helper variables for memcpy() to remain
256              * compliant with MISRA Rule 21.15.  These should be
257              * optimized away.
258              */
259             /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
260             pvCopySource = pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes;
261             pvCopyDest = &pxEthernetHeader->xSourceAddress;
262             ( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
263 
264             #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
265                 {
266                     if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
267                     {
268                         BaseType_t xIndex;
269 
270                         for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
271                         {
272                             pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
273                         }
274 
275                         pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
276                     }
277                 }
278             #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
279 
280             /* Send! */
281             iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
282 
283             configASSERT( pxNetworkBuffer->pxEndPoint->pxNetworkInterface != NULL );
284             configASSERT( pxNetworkBuffer->pxEndPoint->pxNetworkInterface->pfOutput != NULL );
285 
286             NetworkInterface_t * pxInterface = pxNetworkBuffer->pxEndPoint->pxNetworkInterface;
287             ( void ) pxInterface->pfOutput( pxInterface, pxNetworkBuffer, xDoRelease );
288 
289             if( xDoRelease == pdFALSE )
290             {
291                 /* Swap-back some fields, as pxBuffer probably points to a socket field
292                  * containing the packet header. */
293                 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
294 
295                 pxIPHeader->ulSourceIPAddress = pxIPHeader->ulDestinationIPAddress;
296 
297                 ( void ) memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
298             }
299             else
300             {
301                 /* Nothing to do: the buffer has been passed to DMA and will be released after use */
302             }
303         } /* if( pxNetworkBuffer != NULL ) */
304     } while( ipFALSE_BOOL );
305 }
306 /*-----------------------------------------------------------*/
307 
308 /**
309  * @brief Let ARP look-up the MAC-address of the peer and initialise the first SYN
310  *        packet.
311  *
312  * @param[in] pxSocket The socket owning the TCP connection. The first packet shall
313  *               be created in this socket.
314  *
315  * @return pdTRUE: if the packet was successfully created and the first SYN can be sent.
316  *         Else pdFALSE.
317  *
318  * @note Connecting sockets have a special state: eCONNECT_SYN. In this phase,
319  *       the Ethernet address of the target will be found using ARP. In case the
320  *       target IP address is not within the netmask, the hardware address of the
321  *       gateway will be used.
322  */
prvTCPPrepareConnect_IPV4(FreeRTOS_Socket_t * pxSocket)323 BaseType_t prvTCPPrepareConnect_IPV4( FreeRTOS_Socket_t * pxSocket )
324 {
325     TCPPacket_t * pxTCPPacket;
326     IPHeader_t * pxIPHeader;
327     eARPLookupResult_t eReturned;
328     uint32_t ulRemoteIP;
329     MACAddress_t xEthAddress;
330     BaseType_t xReturn = pdTRUE;
331     uint32_t ulInitialSequenceNumber = 0;
332 
333     #if ( ipconfigHAS_PRINTF != 0 )
334         {
335             /* Only necessary for nicer logging. */
336             ( void ) memset( xEthAddress.ucBytes, 0, sizeof( xEthAddress.ucBytes ) );
337         }
338     #endif /* ipconfigHAS_PRINTF != 0 */
339 
340     ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
341     /* Determine the ARP cache status for the requested IP address. */
342     eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ), &( pxSocket->pxEndPoint ) );
343 
344     switch( eReturned )
345     {
346         case eARPCacheHit:    /* An ARP table lookup found a valid entry. */
347             break;            /* We can now prepare the SYN packet. */
348 
349         case eARPCacheMiss:   /* An ARP table lookup did not find a valid entry. */
350         case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
351         default:
352             /* Count the number of times it could not find the ARP address. */
353             pxSocket->u.xTCP.ucRepCount++;
354 
355             FreeRTOS_debug_printf( ( "ARP for %xip (using %xip): rc=%d %02x-%02x-%02x-%02x-%02x-%02x\n",
356                                      ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
357                                      ( unsigned ) FreeRTOS_htonl( ulRemoteIP ),
358                                      eReturned,
359                                      xEthAddress.ucBytes[ 0 ],
360                                      xEthAddress.ucBytes[ 1 ],
361                                      xEthAddress.ucBytes[ 2 ],
362                                      xEthAddress.ucBytes[ 3 ],
363                                      xEthAddress.ucBytes[ 4 ],
364                                      xEthAddress.ucBytes[ 5 ] ) );
365 
366             /* And issue a (new) ARP request */
367             FreeRTOS_OutputARPRequest( ulRemoteIP );
368             xReturn = pdFALSE;
369             break;
370     }
371 
372     if( xReturn != pdFALSE )
373     {
374         /* Get a difficult-to-predict initial sequence number for this 4-tuple. */
375         ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( pxSocket->xLocalAddress.ulIP_IPv4,
376                                                                       pxSocket->usLocalPort,
377                                                                       pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
378                                                                       pxSocket->u.xTCP.usRemotePort );
379 
380         /* Check for a random number generation error. */
381         if( ulInitialSequenceNumber == 0U )
382         {
383             xReturn = pdFALSE;
384         }
385     }
386 
387     if( xReturn != pdFALSE )
388     {
389         uint16_t usLength;
390 
391         /* The MAC-address of the peer (or gateway) has been found,
392          * now prepare the initial TCP packet and some fields in the socket. Map
393          * the buffer onto the TCPPacket_t struct to easily access it's field. */
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         pxTCPPacket = ( ( TCPPacket_t * ) pxSocket->u.xTCP.xPacket.u.ucLastPacket );
399         pxIPHeader = &pxTCPPacket->xIPHeader;
400 
401         /* reset the retry counter to zero. */
402         pxSocket->u.xTCP.ucRepCount = 0U;
403 
404         /* And remember that the connect/SYN data are prepared. */
405         pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
406 
407         /* Now that the Ethernet address is known, the initial packet can be
408          * prepared. */
409         ( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
410 
411         /* Write the Ethernet address in Source, because it will be swapped by
412          * prvTCPReturnPacket(). */
413         ( void ) memcpy( ( void * ) ( &pxTCPPacket->xEthernetHeader.xSourceAddress ), ( const void * ) ( &xEthAddress ), sizeof( xEthAddress ) );
414 
415         /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
416         pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
417 
418         pxIPHeader->ucVersionHeaderLength = 0x45U;
419         usLength = ( uint16_t ) ( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
420         pxIPHeader->usLength = FreeRTOS_htons( usLength );
421         pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
422 
423         pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
424 
425         /* Addresses and ports will be stored swapped because prvTCPReturnPacket
426          * will swap them back while replying. */
427         pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
428 
429         pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
430         pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
431 
432         /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
433          * isn't known yet. */
434         pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0U;
435 
436         /* Start with ISN (Initial Sequence Number). */
437         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber;
438 
439         /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
440          * the high nibble of the TCP offset field. */
441         pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50U;
442 
443         /* Only set the SYN flag. */
444         pxTCPPacket->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_SYN;
445 
446         /* Set the value of usMSS for this socket. */
447         prvSocketSetMSS( pxSocket );
448 
449         /* The initial sequence numbers at our side are known.  Later
450          * vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
451          * first wait for a SYN+ACK reply. */
452         prvTCPCreateWindow( pxSocket );
453     }
454 
455     return xReturn;
456 }
457 /*-----------------------------------------------------------*/
458 
459 
460 /**
461  * @brief Common code for sending a TCP protocol control packet (i.e. no options, no
462  *        payload, just flags).
463  *
464  * @param[in] pxNetworkBuffer The network buffer received from the peer.
465  * @param[in] ucTCPFlags The flags to determine what kind of packet this is.
466  *
467  * @return pdFAIL always indicating that the packet was not consumed.
468  */
prvTCPSendSpecialPktHelper_IPV4(NetworkBufferDescriptor_t * pxNetworkBuffer,uint8_t ucTCPFlags)469 BaseType_t prvTCPSendSpecialPktHelper_IPV4( NetworkBufferDescriptor_t * pxNetworkBuffer,
470                                             uint8_t ucTCPFlags )
471 {
472     #if ( ipconfigIGNORE_UNKNOWN_PACKETS == 1 )
473         /* Configured to ignore unknown packets just suppress a compiler warning. */
474         ( void ) pxNetworkBuffer;
475         ( void ) ucTCPFlags;
476     #else
477         {
478             /* Map the ethernet buffer onto the TCPPacket_t struct for easy access to the fields. */
479 
480             /* MISRA Ref 11.3.1 [Misaligned access] */
481 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
482             /* coverity[misra_c_2012_rule_11_3_violation] */
483             TCPPacket_t * pxTCPPacket = ( ( TCPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
484             const uint32_t ulSendLength =
485                 ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER; /* Plus 0 options. */
486 
487             uint8_t ucFlagsReceived = pxTCPPacket->xTCPHeader.ucTCPFlags;
488             pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags;
489             pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER ) << 2;
490 
491             if( ( ucFlagsReceived & tcpTCP_FLAG_SYN ) != 0U )
492             {
493                 /* A synchronize packet is received. It counts as 1 pseudo byte of data,
494                  * so increase the variable with 1. Before sending a reply, the values of
495                  * 'ulSequenceNumber' and 'ulAckNr' will be swapped. */
496                 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
497                 ulSequenceNumber++;
498                 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( ulSequenceNumber );
499             }
500 
501             prvTCPReturnPacket( NULL, pxNetworkBuffer, ulSendLength, pdFALSE );
502         }
503     #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
504 
505     /* The packet was not consumed. */
506     return pdFAIL;
507 }
508 /*-----------------------------------------------------------*/
509 
510 /* *INDENT-OFF* */
511 #endif /* ( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_TCP == 1 ) */
512 /* *INDENT-ON* */
513