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