xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_TCP_State_Handling.c (revision 2d3f4daa567ffe71aeda2e0f6d0bc02850db0627)
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_State_Handling.c
30  * @brief Module which handles the TCP protocol state transition for FreeRTOS+TCP.
31  *
32  * Endianness: in this module all ports and IP addresses are stored in
33  * host byte-order, except fields in the IP-packets
34  */
35 
36 /* Standard includes. */
37 #include <stdint.h>
38 #include <stdio.h>
39 
40 /* FreeRTOS includes. */
41 #include "FreeRTOS.h"
42 #include "task.h"
43 #include "queue.h"
44 #include "semphr.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_UDP_IP.h"
51 #include "FreeRTOS_DHCP.h"
52 #include "NetworkInterface.h"
53 #include "NetworkBufferManagement.h"
54 #include "FreeRTOS_ARP.h"
55 
56 #include "FreeRTOS_TCP_Reception.h"
57 #include "FreeRTOS_TCP_Transmission.h"
58 #include "FreeRTOS_TCP_State_Handling.h"
59 #include "FreeRTOS_TCP_Utils.h"
60 
61 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
62 #if ipconfigUSE_TCP == 1
63 
64 /*
65  *  Called to handle the closure of a TCP connection.
66  */
67     static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t * pxSocket,
68                                        const NetworkBufferDescriptor_t * pxNetworkBuffer );
69 
70 /*
71  * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
72  * eCONNECT_SYN.
73  */
74     static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t * pxSocket,
75                                             const NetworkBufferDescriptor_t * pxNetworkBuffer,
76                                             uint32_t ulReceiveLength,
77                                             UBaseType_t uxOptionsLength );
78 
79 /*
80  * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
81  */
82     static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t * pxSocket,
83                                             NetworkBufferDescriptor_t ** ppxNetworkBuffer,
84                                             uint32_t ulReceiveLength,
85                                             UBaseType_t uxOptionsLength );
86 
87 
88 /**
89  * @brief Check whether the socket is active or not.
90  *
91  * @param[in] eStatus The status of the socket.
92  *
93  * @return pdTRUE if the socket must be checked. Non-active sockets
94  *         are waiting for user action, either connect() or close().
95  */
prvTCPSocketIsActive(eIPTCPState_t eStatus)96     BaseType_t prvTCPSocketIsActive( eIPTCPState_t eStatus )
97     {
98         BaseType_t xResult;
99 
100         switch( eStatus )
101         {
102             case eCLOSED:
103             case eCLOSE_WAIT:
104             case eFIN_WAIT_2:
105             case eCLOSING:
106             case eTIME_WAIT:
107                 xResult = pdFALSE;
108                 break;
109 
110             case eTCP_LISTEN:
111             case eCONNECT_SYN:
112             case eSYN_FIRST:
113             case eSYN_RECEIVED:
114             case eESTABLISHED:
115             case eFIN_WAIT_1:
116             case eLAST_ACK:
117             default:
118                 xResult = pdTRUE;
119                 break;
120         }
121 
122         return xResult;
123     }
124 /*-----------------------------------------------------------*/
125 
126 
127 
128     #if ( ipconfigTCP_HANG_PROTECTION == 1 )
129 
130 /**
131  * @brief Some of the TCP states may only last a certain amount of time.
132  *        This function checks if the socket is 'hanging', i.e. staying
133  *        too long in the same state.
134  *
135  * @param[in] pxSocket the socket to be checked.
136  *
137  * @return pdFALSE if no checks are needed, pdTRUE if checks were done, or negative
138  *         in case the socket has reached a critical time-out. The socket will go to
139  *         the eCLOSE_WAIT state.
140  */
prvTCPStatusAgeCheck(FreeRTOS_Socket_t * pxSocket)141         BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t * pxSocket )
142         {
143             BaseType_t xResult;
144 
145             eIPTCPState_t eState = pxSocket->u.xTCP.eTCPState;
146 
147             switch( eState )
148             {
149                 case eESTABLISHED:
150 
151                     /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
152                      *  state ESTABLISHED can be protected using keep-alive messages. */
153                     xResult = pdFALSE;
154                     break;
155 
156                 case eCLOSED:
157                 case eTCP_LISTEN:
158                 case eCLOSE_WAIT:
159                     /* These 3 states may last for ever, up to the owner. */
160                     xResult = pdFALSE;
161                     break;
162 
163                 case eCONNECT_SYN:
164                 case eSYN_FIRST:
165                 case eSYN_RECEIVED:
166                 case eFIN_WAIT_1:
167                 case eFIN_WAIT_2:
168                 case eCLOSING:
169                 case eLAST_ACK:
170                 case eTIME_WAIT:
171                 default:
172 
173                     /* All other (non-connected) states will get anti-hanging
174                      * protection. */
175                     xResult = pdTRUE;
176                     break;
177             }
178 
179             if( xResult != pdFALSE )
180             {
181                 /* How much time has past since the last active moment which is
182                  * defined as A) a state change or B) a packet has arrived. */
183                 TickType_t xAge = xTaskGetTickCount() - pxSocket->u.xTCP.xLastActTime;
184 
185                 /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
186                 if( xAge > ( ( TickType_t ) ipconfigTCP_HANG_PROTECTION_TIME * ( TickType_t ) configTICK_RATE_HZ ) )
187                 {
188                     #if ( ipconfigHAS_DEBUG_PRINTF == 1 )
189                         {
190                             FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %xip:%u status %s\n",
191                                                      pxSocket->usLocalPort,
192                                                      ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
193                                                      pxSocket->u.xTCP.usRemotePort,
194                                                      FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.eTCPState ) ) );
195                         }
196                     #endif /* ipconfigHAS_DEBUG_PRINTF */
197 
198                     /* Move to eCLOSE_WAIT, user may close the socket. */
199                     vTCPStateChange( pxSocket, eCLOSE_WAIT );
200 
201                     /* When 'bPassQueued' true, this socket is an orphan until it
202                      * gets connected. */
203                     if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
204                     {
205                         /* vTCPStateChange() has called vSocketCloseNextTime()
206                          * in case the socket is not yet owned by the application.
207                          * Return a negative value to inform the caller that
208                          * the socket will be closed in the next cycle. */
209                         xResult = -1;
210                     }
211                 }
212             }
213 
214             return xResult;
215         }
216         /*-----------------------------------------------------------*/
217 
218     #endif /* if ( ipconfigTCP_HANG_PROTECTION == 1 ) */
219 
220 /**
221  * @brief prvTCPHandleFin() will be called to handle connection closure. The
222  *        closure starts when either a FIN has been received and accepted,
223  *        or when the socket has sent a FIN flag to the peer. Before being
224  *        called, it has been checked that both reception and transmission
225  *        are complete.
226  *
227  * @param[in] pxSocket Socket owning the the connection.
228  * @param[in] pxNetworkBuffer The network buffer carrying the TCP packet.
229  *
230  * @return Length of the packet to be sent.
231  */
prvTCPHandleFin(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer)232     static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t * pxSocket,
233                                        const NetworkBufferDescriptor_t * pxNetworkBuffer )
234     {
235         /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
236 
237         /* MISRA Ref 11.3.1 [Misaligned access] */
238         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
239         /* coverity[misra_c_2012_rule_11_3_violation] */
240         ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
241                                                   &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( pxNetworkBuffer ) ] ) );
242         TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
243         uint8_t ucIntermediateResult = 0, ucTCPFlags = pxTCPHeader->ucTCPFlags;
244         TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
245         BaseType_t xSendLength = 0;
246         uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
247 
248         if( ( ucTCPFlags & tcpTCP_FLAG_FIN ) != 0U )
249         {
250             pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1U;
251         }
252 
253         if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
254         {
255             /* We haven't yet replied with a FIN, do so now. */
256             pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
257             pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
258         }
259         else
260         {
261             /* We did send a FIN already, see if it's ACK'd. */
262             if( ulAckNr == ( pxTCPWindow->tx.ulFINSequenceNumber + 1U ) )
263             {
264                 pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
265             }
266         }
267 
268         if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
269         {
270             pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
271             pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_ACK | ( uint8_t ) tcpTCP_FLAG_FIN;
272 
273             /* And wait for the final ACK. */
274             vTCPStateChange( pxSocket, eLAST_ACK );
275         }
276         else
277         {
278             /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
279             pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1U;
280 
281             if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
282             {
283                 /* We have sent out a FIN but the peer hasn't replied with a FIN
284                  * yet. Do nothing for the moment. */
285                 pxTCPHeader->ucTCPFlags = 0U;
286             }
287             else
288             {
289                 if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
290                 {
291                     /* This is the third of the three-way hand shake: the last
292                      * ACK. */
293                     pxTCPHeader->ucTCPFlags = tcpTCP_FLAG_ACK;
294                 }
295                 else
296                 {
297                     /* The other party started the closure, so we just wait for the
298                      * last ACK. */
299                     pxTCPHeader->ucTCPFlags = 0U;
300                 }
301 
302                 /* And wait for the user to close this socket. */
303                 vTCPStateChange( pxSocket, eCLOSE_WAIT );
304             }
305         }
306 
307         pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
308 
309         if( pxTCPHeader->ucTCPFlags != 0U )
310         {
311             ucIntermediateResult = ( uint8_t ) ( uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
312             xSendLength = ( BaseType_t ) ucIntermediateResult;
313         }
314 
315         pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
316 
317         if( xTCPWindowLoggingLevel != 0 )
318         {
319             FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %u, cur/nxt %u/%u) ourSeqNr %u | Rx %u\n",
320                                      ( unsigned ) ( ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber ),
321                                      ( unsigned ) ( pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ),
322                                      ( unsigned ) ( pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ),
323                                      ( unsigned ) ( pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ),
324                                      ( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) ) );
325         }
326 
327         return xSendLength;
328     }
329     /*-----------------------------------------------------------*/
330 
331 
332 /**
333  * @brief prvHandleSynReceived(): called from prvTCPHandleState(). Called
334  *        from the states: eSYN_RECEIVED and eCONNECT_SYN. If the flags
335  *        received are correct, the socket will move to eESTABLISHED.
336  *
337  * @param[in] pxSocket The socket handling the connection.
338  * @param[in] pxNetworkBuffer The pointer to the network buffer carrying
339  *                             the packet.
340  * @param[in] ulReceiveLength Length in bytes of the data received.
341  * @param[in] uxOptionsLength Length of the TCP options in bytes.
342  *
343  * @return Length of the data to be sent.
344  */
prvHandleSynReceived(FreeRTOS_Socket_t * pxSocket,const NetworkBufferDescriptor_t * pxNetworkBuffer,uint32_t ulReceiveLength,UBaseType_t uxOptionsLength)345     static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t * pxSocket,
346                                             const NetworkBufferDescriptor_t * pxNetworkBuffer,
347                                             uint32_t ulReceiveLength,
348                                             UBaseType_t uxOptionsLength )
349     {
350         /* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
351 
352         /* MISRA Ref 11.3.1 [Misaligned access] */
353         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
354         /* coverity[misra_c_2012_rule_11_3_violation] */
355         ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
356                                                   &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
357         TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
358         TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
359         uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
360         uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
361         BaseType_t xSendLength = 0;
362         UBaseType_t uxIntermediateResult = 0U;
363 
364         /* Either expect a ACK or a SYN+ACK. */
365         uint8_t ucExpect = tcpTCP_FLAG_ACK;
366         const uint8_t ucFlagsMask = tcpTCP_FLAG_ACK | tcpTCP_FLAG_RST | tcpTCP_FLAG_SYN | tcpTCP_FLAG_FIN;
367 
368         if( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN )
369         {
370             ucExpect |= tcpTCP_FLAG_SYN;
371         }
372 
373         if( ( ucTCPFlags & ucFlagsMask ) != ucExpect )
374         {
375             /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
376             /* eSYN_RECEIVED: flags ACK  expected, not SYN. */
377             FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
378                                      ( pxSocket->u.xTCP.eTCPState == ( uint8_t ) eSYN_RECEIVED ) ? "eSYN_RECEIVED" : "eCONNECT_SYN",
379                                      ucExpect, ucTCPFlags ) );
380 
381             /* In case pxSocket is not yet owned by the application, a closure
382              * of the socket will be scheduled for the next cycle. */
383             vTCPStateChange( pxSocket, eCLOSE_WAIT );
384 
385             /* Send RST with the expected sequence and ACK numbers,
386              * otherwise the packet will be ignored. */
387             pxTCPWindow->ulOurSequenceNumber = FreeRTOS_htonl( pxTCPHeader->ulAckNr );
388             pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
389 
390             pxTCPHeader->ucTCPFlags |= tcpTCP_FLAG_RST;
391 
392             uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
393             xSendLength = ( BaseType_t ) uxIntermediateResult;
394 
395             pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
396         }
397         else
398         {
399             pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
400             pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
401 
402             if( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN )
403             {
404                 /* Map the Last packet onto the ProtocolHeader_t struct for easy access to the fields. */
405 
406                 /* MISRA Ref 11.3.1 [Misaligned access] */
407                 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
408                 /* coverity[misra_c_2012_rule_11_3_violation] */
409                 ProtocolHeaders_t * pxLastHeaders = ( ( ProtocolHeaders_t * )
410                                                       &( pxSocket->u.xTCP.xPacket.u.ucLastPacket[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
411 
412                 /* Clear the SYN flag in lastPacket. */
413                 pxLastHeaders->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_ACK;
414                 pxProtocolHeaders->xTCPHeader.ucTCPFlags = tcpTCP_FLAG_ACK;
415 
416                 /* This socket was the one connecting actively so now perform the
417                  * synchronisation. */
418                 vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
419                                 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usMSS );
420                 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1U;
421                 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1U;
422                 pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
423                 pxTCPWindow->ulNextTxSequenceNumber++;
424             }
425             else if( ulReceiveLength == 0U )
426             {
427                 pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
428             }
429             else
430             {
431                 /* Nothing. */
432             }
433 
434             /* The SYN+ACK has been confirmed, increase the next sequence number by
435              * 1. */
436             pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U;
437 
438             #if ( ipconfigUSE_TCP_WIN == 1 )
439                 {
440                     char pcBuffer[ 40 ]; /* Space to print an IP-address. */
441                     ( void ) FreeRTOS_inet_ntop( ( pxSocket->bits.bIsIPv6 != 0U ) ? FREERTOS_AF_INET6 : FREERTOS_AF_INET,
442                                                  ( void * ) pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes,
443                                                  pcBuffer,
444                                                  sizeof( pcBuffer ) );
445                     FreeRTOS_debug_printf( ( "TCP: %s %u => %s port %u set ESTAB (scaling %u)\n",
446                                              ( pxSocket->u.xTCP.eTCPState == ( uint8_t ) eCONNECT_SYN ) ? "active" : "passive",
447                                              pxSocket->usLocalPort,
448                                              pcBuffer,
449                                              pxSocket->u.xTCP.usRemotePort,
450                                              ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
451                 }
452             #endif /* ipconfigUSE_TCP_WIN */
453 
454             if( ( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0U ) )
455             {
456                 pxTCPHeader->ucTCPFlags = tcpTCP_FLAG_ACK;
457 
458                 uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ( size_t ) ipSIZE_OF_TCP_HEADER + uxOptionsLength;
459                 xSendLength = ( BaseType_t ) uxIntermediateResult;
460                 pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
461             }
462 
463             #if ( ipconfigUSE_TCP_WIN != 0 )
464                 {
465                     if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
466                     {
467                         /* The other party did not send a scaling factor.
468                          * A shifting factor in this side must be canceled. */
469                         pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
470                         pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
471                     }
472                 }
473             #endif /* ipconfigUSE_TCP_WIN */
474 
475             /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
476              * connection is established. */
477             vTCPStateChange( pxSocket, eESTABLISHED );
478         }
479 
480         return xSendLength;
481     }
482     /*-----------------------------------------------------------*/
483 
484 /**
485  * @brief prvHandleEstablished(): called from prvTCPHandleState()
486  *        Called if the status is eESTABLISHED. Data reception has been handled
487  *        earlier. Here the ACK's from peer will be checked, and if a FIN is received,
488  *        the code will check if it may be accepted, i.e. if all expected data has been
489  *        completely received.
490  *
491  * @param[in] pxSocket The socket owning the connection.
492  * @param[in,out] ppxNetworkBuffer Pointer to pointer to the network buffer.
493  * @param[in] ulReceiveLength The length of the received packet.
494  * @param[in] uxOptionsLength Length of TCP options.
495  *
496  * @return The send length of the packet to be sent.
497  */
prvHandleEstablished(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t ** ppxNetworkBuffer,uint32_t ulReceiveLength,UBaseType_t uxOptionsLength)498     static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t * pxSocket,
499                                             NetworkBufferDescriptor_t ** ppxNetworkBuffer,
500                                             uint32_t ulReceiveLength,
501                                             UBaseType_t uxOptionsLength )
502     {
503         /* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */
504 
505         /* MISRA Ref 11.3.1 [Misaligned access] */
506         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
507         /* coverity[misra_c_2012_rule_11_3_violation] */
508         ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
509                                                   &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
510         TCPHeader_t * pxTCPHeader = &pxProtocolHeaders->xTCPHeader;
511         TCPWindow_t * pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
512         uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
513         uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount, ulIntermediateResult = 0;
514         BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
515         int32_t lDistance, lSendResult;
516         uint16_t usWindow;
517         UBaseType_t uxIntermediateResult = 0;
518 
519         /* Remember the window size the peer is advertising. */
520         usWindow = FreeRTOS_ntohs( pxTCPHeader->usWindow );
521         pxSocket->u.xTCP.ulWindowSize = ( uint32_t ) usWindow;
522         #if ( ipconfigUSE_TCP_WIN != 0 )
523             {
524                 pxSocket->u.xTCP.ulWindowSize =
525                     ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
526             }
527         #endif /* ipconfigUSE_TCP_WIN */
528 
529         if( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_ACK ) == 0U )
530         {
531             /* RFC793: If ACK bit is not set at this state, the segment should
532              * be dropped
533              */
534         }
535         else
536         {
537             ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPHeader->ulAckNr ) );
538 
539             /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
540              * starting at 'tx.ulCurrentSequenceNumber'.  Advance the tail pointer in
541              * txStream. */
542             if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0U ) )
543             {
544                 /* Just advancing the tail index, 'ulCount' bytes have been
545                  * confirmed, and because there is new space in the txStream, the
546                  * user/owner should be woken up. */
547                 /* _HT_ : only in case the socket's waiting? */
548                 if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0U, NULL, ( size_t ) ulCount, pdFALSE ) != 0U )
549                 {
550                     pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_SEND;
551 
552                     #if ipconfigSUPPORT_SELECT_FUNCTION == 1
553                         {
554                             if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U )
555                             {
556                                 pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_WRITE ) << SOCKET_EVENT_BIT_COUNT;
557                             }
558                         }
559                     #endif
560 
561                     /* In case the socket owner has installed an OnSent handler,
562                      * call it now. */
563                     #if ( ipconfigUSE_CALLBACKS == 1 )
564                         {
565                             if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
566                             {
567                                 pxSocket->u.xTCP.pxHandleSent( ( Socket_t ) pxSocket, ulCount );
568                             }
569                         }
570                     #endif /* ipconfigUSE_CALLBACKS == 1  */
571                 }
572             }
573 
574             /* If this socket has a stream for transmission, add the data to the
575              * outgoing segment(s). */
576             if( pxSocket->u.xTCP.txStream != NULL )
577             {
578                 prvTCPAddTxData( pxSocket );
579             }
580 
581             pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
582 
583             if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_FIN ) != 0U ) )
584             {
585                 /* Peer is requesting to stop, see if we're really finished. */
586                 xMayClose = pdTRUE;
587 
588                 /* Checks are only necessary if we haven't sent a FIN yet. */
589                 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
590                 {
591                     /* xTCPWindowTxDone returns true when all Tx queues are empty. */
592                     bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
593                     bTxDone = xTCPWindowTxDone( pxTCPWindow );
594 
595                     if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
596                     {
597                         /* Refusing FIN: Rx incomplete 1 optlen 4 tx done 1. */
598                         FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %d tx done %d\n",
599                                                  pxSocket->usLocalPort,
600                                                  pxSocket->u.xTCP.usRemotePort,
601                                                  ( int ) bRxComplete,
602                                                  ( int ) bTxDone ) );
603                         xMayClose = pdFALSE;
604                     }
605                     else
606                     {
607                         ulIntermediateResult = ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber;
608                         lDistance = ( int32_t ) ulIntermediateResult;
609 
610                         if( lDistance > 1 )
611                         {
612                             FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %d (cur %u high %u)\n",
613                                                      ( int ) lDistance,
614                                                      ( unsigned ) ( pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ),
615                                                      ( unsigned ) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) ) );
616 
617                             xMayClose = pdFALSE;
618                         }
619                     }
620                 }
621 
622                 if( xTCPWindowLoggingLevel > 0 )
623                 {
624                     FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %d (Rx %u Len %d, Tx %u)\n",
625                                              ( int ) xMayClose,
626                                              ( unsigned ) ( ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ),
627                                              ( unsigned ) ulReceiveLength,
628                                              ( unsigned ) ( pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) ) );
629                 }
630 
631                 if( xMayClose != pdFALSE )
632                 {
633                     pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
634                     xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
635                 }
636             }
637 
638             if( xMayClose == pdFALSE )
639             {
640                 pxTCPHeader->ucTCPFlags = tcpTCP_FLAG_ACK;
641 
642                 if( ulReceiveLength != 0U )
643                 {
644                     uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
645                     xSendLength = ( BaseType_t ) uxIntermediateResult;
646                     /* TCP-offset equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
647                     pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
648 
649                     if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
650                     {
651                         pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
652                     }
653                 }
654 
655                 /* Now get data to be transmitted. */
656 
657                 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
658                  * can not send-out both TCP options and also a full packet. Sending
659                  * options (SACK) is always more urgent than sending data, which can be
660                  * sent later. */
661                 if( uxOptionsLength == 0U )
662                 {
663                     /* prvTCPPrepareSend might allocate a bigger network buffer, if
664                      * necessary. */
665                     lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
666 
667                     if( lSendResult > 0 )
668                     {
669                         xSendLength = ( BaseType_t ) lSendResult;
670                     }
671                 }
672             }
673         }
674 
675         return xSendLength;
676     }
677     /*-----------------------------------------------------------*/
678 
679 
680 /**
681  * @brief Check incoming packets for valid data and handle the state of the
682  *        TCP connection and respond according to the situation.
683  *
684  * @param[in] pxSocket The socket whose connection state is being handled.
685  * @param[in] ppxNetworkBuffer The network buffer descriptor holding the
686  *            packet received from the peer.
687  *
688  * @return If the data is correct and some packet was sent to the peer, then
689  *         the number of bytes sent is returned, or else a negative value is
690  *         returned indicating an error.
691  *
692  * @note prvTCPHandleState() is the most important function of this TCP stack
693  * We've tried to keep it (relatively short) by putting a lot of code in
694  * the static functions above:
695  *
696  *      prvCheckRxData()
697  *      prvStoreRxData()
698  *      prvSetOptions()
699  *      prvHandleSynReceived()
700  *      prvHandleEstablished()
701  *      prvSendData()
702  *
703  * As these functions are declared static, and they're called from one location
704  * only, most compilers will inline them, thus avoiding a call and return.
705  */
prvTCPHandleState(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t ** ppxNetworkBuffer)706     BaseType_t prvTCPHandleState( FreeRTOS_Socket_t * pxSocket,
707                                   NetworkBufferDescriptor_t ** ppxNetworkBuffer )
708     {
709         /* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */
710 
711         /* MISRA Ref 11.3.1 [Misaligned access] */
712         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
713         /* coverity[misra_c_2012_rule_11_3_violation] */
714         ProtocolHeaders_t * pxProtocolHeaders = ( ( ProtocolHeaders_t * )
715                                                   &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( *ppxNetworkBuffer ) ] ) );
716         TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->xTCPHeader );
717         BaseType_t xSendLength = 0;
718         uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
719         uint8_t * pucRecvData;
720         uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
721 
722         /* uxOptionsLength: the size of the options to be sent (always a multiple of
723          * 4 bytes)
724          * 1. in the SYN phase, we shall communicate the MSS
725          * 2. in case of a SACK, Selective ACK, ack a segment which comes in
726          * out-of-order. */
727         UBaseType_t uxOptionsLength = 0U;
728         uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
729         TCPWindow_t * pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
730         UBaseType_t uxIntermediateResult = 0;
731         uint32_t ulSum;
732 
733         /* First get the length and the position of the received data, if any.
734          * pucRecvData will point to the first byte of the TCP payload. */
735         ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
736 
737         if( pxSocket->u.xTCP.eTCPState >= eESTABLISHED )
738         {
739             if( pxTCPWindow->rx.ulCurrentSequenceNumber == ( ulSequenceNumber + 1U ) )
740             {
741                 /* This is most probably a keep-alive message from peer.  Setting
742                  * 'bWinChange' doesn't cause a window-size-change, the flag is used
743                  * here to force sending an immediate ACK. */
744                 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
745             }
746         }
747 
748         /* Keep track of the highest sequence number that might be expected within
749          * this connection. */
750         ulSum = ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber;
751 
752         if( ( ( int32_t ) ulSum ) > 0 )
753         {
754             pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
755         }
756 
757         /* Storing data may result in a fatal error if malloc() fails. */
758         if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
759         {
760             xSendLength = -1;
761         }
762         else
763         {
764             eIPTCPState_t eState;
765 
766             uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
767 
768             if( ( pxSocket->u.xTCP.eTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_CTRL ) == ( uint8_t ) tcpTCP_FLAG_SYN ) )
769             {
770                 FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
771 
772                 /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
773                  * 'SYN+ACK' didn't arrive.  Step back to the previous state in which
774                  * a first incoming SYN is handled.  The SYN was counted already so
775                  * decrease it first. */
776                 vTCPStateChange( pxSocket, eSYN_FIRST );
777             }
778 
779             if( ( ( ucTCPFlags & tcpTCP_FLAG_FIN ) != 0U ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
780             {
781                 /* It's the first time a FIN has been received, remember its
782                  * sequence number. */
783                 pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
784                 pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
785 
786                 /* Was peer the first one to send a FIN? */
787                 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
788                 {
789                     /* If so, don't send the-last-ACK. */
790                     pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
791                 }
792             }
793 
794             eState = ( eIPTCPState_t ) pxSocket->u.xTCP.eTCPState;
795 
796             switch( eState )
797             {
798                 case eCLOSED: /* (server + client) no connection state at all. */
799 
800                     /* Nothing to do for a closed socket, except waiting for the
801                      * owner. */
802                     break;
803 
804                 case eTCP_LISTEN: /* (server) waiting for a connection request from
805                                    * any remote TCP and port. */
806 
807                     /* The listen state was handled in xProcessReceivedTCPPacket().
808                      * Should not come here. */
809                     break;
810 
811                 case eSYN_FIRST: /* (server) Just received a SYN request for a server
812                                   * socket. */
813 
814                     /* A new socket has been created, reply with a SYN+ACK.
815                      * Acknowledge with seq+1 because the SYN is seen as pseudo data
816                      * with len = 1. */
817                     uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPHeader );
818                     pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_SYN | ( uint8_t ) tcpTCP_FLAG_ACK;
819 
820                     uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
821                     xSendLength = ( BaseType_t ) uxIntermediateResult;
822 
823                     /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and
824                      * uxOptionsLength is a multiple of 4.  The complete expression is:
825                      * ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
826                     pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
827                     vTCPStateChange( pxSocket, eSYN_RECEIVED );
828 
829                     pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1U;
830                     pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1U;
831                     pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U;
832                     pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U; /* because we send a TCP_SYN. */
833                     break;
834 
835                 case eCONNECT_SYN:  /* (client) also called SYN_SENT: we've just send a
836                                      * SYN, expect a SYN+ACK and send a ACK now. */
837                 /* Fall through */
838                 case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
839                                      * expect a ACK and do nothing. */
840                     xSendLength = prvHandleSynReceived( pxSocket, *( ppxNetworkBuffer ), ulReceiveLength, uxOptionsLength );
841                     break;
842 
843                 case eESTABLISHED: /* (server + client) an open connection, data
844                                     * received can be delivered to the user. The normal
845                                     * state for the data transfer phase of the connection
846                                     * The closing states are also handled here with the
847                                     * use of some flags. */
848                     xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
849                     break;
850 
851                 case eLAST_ACK:   /* (server + client) waiting for an acknowledgement
852                                    * of the connection termination request previously
853                                    * sent to the remote TCP (which includes an
854                                    * acknowledgement of its connection termination
855                                    * request). */
856                 /* Fall through */
857                 case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
858                                    * or an acknowledgement of the connection termination request previously sent. */
859                 /* Fall through */
860                 case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
861                     xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
862                     break;
863 
864                 case eCLOSE_WAIT: /* (server + client) waiting for a connection
865                                    * termination request from the local user.  Nothing to
866                                    * do, connection is closed, wait for owner to close
867                                    * this socket. */
868                     break;
869 
870                 case eCLOSING: /* (server + client) waiting for a connection
871                                 * termination request acknowledgement from the remote
872                                 * TCP. */
873                     break;
874 
875                 case eTIME_WAIT: /* (either server or client) waiting for enough time
876                                   * to pass to be sure the remote TCP received the
877                                   * acknowledgement of its connection termination
878                                   * request. [According to RFC 793 a connection can stay
879                                   * in TIME-WAIT for a maximum of four minutes known as
880                                   * a MSL (maximum segment lifetime).]  These states are
881                                   * implemented implicitly by settings flags like
882                                   * 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
883                     break;
884 
885                 default:
886                     /* No more known states. */
887                     break;
888             }
889         }
890 
891         if( xSendLength > 0 )
892         {
893             xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
894         }
895 
896         return xSendLength;
897     }
898     /*-----------------------------------------------------------*/
899 
900 /**
901  * @brief Handle 'listen' event on the given socket.
902  *
903  * @param[in] pxSocket The socket on which the listen occurred.
904  * @param[in] pxNetworkBuffer The network buffer carrying the packet.
905  *
906  * @return If a new socket/duplicate socket is created, then the pointer to
907  *         that socket is returned or else, a NULL pointer is returned.
908  */
prvHandleListen(FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxNetworkBuffer)909     FreeRTOS_Socket_t * prvHandleListen( FreeRTOS_Socket_t * pxSocket,
910                                          NetworkBufferDescriptor_t * pxNetworkBuffer )
911     {
912         FreeRTOS_Socket_t * pxNewSocket = NULL;
913 
914         switch( uxIPHeaderSizePacket( pxNetworkBuffer ) )
915         {
916             #if ( ipconfigUSE_IPv4 != 0 )
917                 case ipSIZE_OF_IPv4_HEADER:
918                     pxNewSocket = prvHandleListen_IPV4( pxSocket, pxNetworkBuffer );
919                     break;
920             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
921 
922             #if ( ipconfigUSE_IPv6 != 0 )
923                 case ipSIZE_OF_IPv6_HEADER:
924                     pxNewSocket = prvHandleListen_IPV6( pxSocket, pxNetworkBuffer );
925                     break;
926             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
927 
928             default:
929                 /* Shouldn't reach here */
930                 /* MISRA 16.4 Compliance */
931                 break;
932         }
933 
934         return pxNewSocket;
935     }
936     /*-----------------------------------------------------------*/
937 
938 
939 /**
940  * @brief Duplicates a socket after a listening socket receives a connection and bind
941  *        the new socket to the same port as the listening socket.
942  *        Also, let the new socket inherit all properties from the listening socket.
943  *
944  * @param[in] pxNewSocket Pointer to the new socket.
945  * @param[in] pxSocket Pointer to the socket being duplicated.
946  *
947  * @return If all steps all successful, then pdTRUE is returned. Else, pdFALSE.
948  */
prvTCPSocketCopy(FreeRTOS_Socket_t * pxNewSocket,FreeRTOS_Socket_t * pxSocket)949     BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t * pxNewSocket,
950                                  FreeRTOS_Socket_t * pxSocket )
951     {
952         struct freertos_sockaddr xAddress;
953         BaseType_t xResult;
954 
955         pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
956         pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
957         pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
958         pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
959         pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
960         pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
961         pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
962         pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
963         pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
964 
965         #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
966             {
967                 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
968             }
969         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
970 
971         #if ( ipconfigUSE_CALLBACKS == 1 )
972             {
973                 /* In case call-backs are used, copy them from parent to child. */
974                 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
975                 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
976                 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
977             }
978         #endif /* ipconfigUSE_CALLBACKS */
979 
980         #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
981             {
982                 /* Child socket of listening sockets will inherit the Socket Set
983                  * Otherwise the owner has no chance of including it into the set. */
984                 if( pxSocket->pxSocketSet != NULL )
985                 {
986                     pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
987                     pxNewSocket->xSelectBits = pxSocket->xSelectBits | ( ( EventBits_t ) eSELECT_READ ) | ( ( EventBits_t ) eSELECT_EXCEPT );
988                 }
989             }
990         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
991 
992         /* And bind it to the same local port as its parent. */
993         /*TODO xAddress.sin_address.ulIP_IPv4 = *ipLOCAL_IP_ADDRESS_POINTER; */
994         xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
995 
996         #if ( ipconfigTCP_HANG_PROTECTION == 1 )
997             {
998                 /* Only when there is anti-hanging protection, a socket may become an
999                  * orphan temporarily.  Once this socket is really connected, the owner of
1000                  * the server socket will be notified. */
1001 
1002                 /* When bPassQueued is true, the socket is an orphan until it gets
1003                  * connected. */
1004                 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
1005                 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
1006             }
1007         #else
1008             {
1009                 /* A reference to the new socket may be stored and the socket is marked
1010                  * as 'passable'. */
1011 
1012                 /* When bPassAccept is true, this socket may be returned in a call to
1013                  * accept(). */
1014                 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
1015 
1016                 if( pxSocket->u.xTCP.pxPeerSocket == NULL )
1017                 {
1018                     pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
1019                 }
1020             }
1021         #endif /* if ( ipconfigTCP_HANG_PROTECTION == 1 ) */
1022 
1023         pxSocket->u.xTCP.usChildCount++;
1024 
1025         FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
1026                                  pxSocket->usLocalPort,
1027                                  pxSocket->u.xTCP.usChildCount,
1028                                  pxSocket->u.xTCP.usBacklog,
1029                                  ( pxSocket->u.xTCP.usChildCount == 1U ) ? "" : "ren" ) );
1030 
1031         /* Now bind the child socket to the same port as the listening socket. */
1032         if( vSocketBind( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
1033         {
1034             FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
1035             ( void ) vSocketClose( pxNewSocket );
1036             xResult = pdFALSE;
1037         }
1038         else
1039         {
1040             xResult = pdTRUE;
1041         }
1042 
1043         return xResult;
1044     }
1045     /*-----------------------------------------------------------*/
1046 
1047     #if ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
1048 
FreeRTOS_GetTCPStateName(UBaseType_t ulState)1049         const char * FreeRTOS_GetTCPStateName( UBaseType_t ulState )
1050         {
1051             static const char * const pcStateNames[] =
1052             {
1053                 "eCLOSED",
1054                 "eTCP_LISTEN",
1055                 "eCONNECT_SYN",
1056                 "eSYN_FIRST",
1057                 "eSYN_RECEIVED",
1058                 "eESTABLISHED",
1059                 "eFIN_WAIT_1",
1060                 "eFIN_WAIT_2",
1061                 "eCLOSE_WAIT",
1062                 "eCLOSING",
1063                 "eLAST_ACK",
1064                 "eTIME_WAIT",
1065                 "eUNKNOWN",
1066             };
1067             BaseType_t xIndex = ( BaseType_t ) ulState;
1068 
1069             if( ( xIndex < 0 ) || ( xIndex >= ARRAY_SIZE( pcStateNames ) ) )
1070             {
1071                 /* The last item is called 'eUNKNOWN' */
1072                 xIndex = ARRAY_SIZE( pcStateNames );
1073                 xIndex--;
1074             }
1075 
1076             return pcStateNames[ xIndex ];
1077         }
1078 
1079     #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
1080     /*-----------------------------------------------------------*/
1081 
1082 #endif /* ipconfigUSE_TCP == 1 */
1083