xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_TCP_IP.c (revision b23fa86ac476770d3224c07213bec32f5b1628bd)
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_IP.c
30  * @brief Module which handles the TCP connections for FreeRTOS+TCP.
31  * It depends on  FreeRTOS_TCP_WIN.c, which handles the TCP windowing
32  * schemes.
33  *
34  * Endianness: in this module all ports and IP addresses are stored in
35  * host byte-order, except fields in the IP-packets
36  */
37 
38 /* Standard includes. */
39 #include <stdint.h>
40 #include <stdio.h>
41 
42 /* FreeRTOS includes. */
43 #include "FreeRTOS.h"
44 #include "task.h"
45 #include "queue.h"
46 #include "semphr.h"
47 
48 /* FreeRTOS+TCP includes. */
49 #include "FreeRTOS_IP.h"
50 #include "FreeRTOS_Sockets.h"
51 #include "FreeRTOS_IP_Private.h"
52 #include "FreeRTOS_UDP_IP.h"
53 #include "FreeRTOS_DHCP.h"
54 #include "NetworkInterface.h"
55 #include "NetworkBufferManagement.h"
56 #include "FreeRTOS_ARP.h"
57 
58 #include "FreeRTOS_TCP_Reception.h"
59 #include "FreeRTOS_TCP_Transmission.h"
60 #include "FreeRTOS_TCP_State_Handling.h"
61 #include "FreeRTOS_TCP_Utils.h"
62 
63 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */
64 #if ipconfigUSE_TCP == 1
65 
66 
67 
68 /** @brief When closing a socket an event is posted to the Network Event Queue.
69  *         If the queue is full, then the event is not posted and the socket
70  *         can be orphaned. To prevent this, the below variable is used to keep
71  *         track of any socket which needs to be closed. This variable can be
72  *         accessed by the IP task only. Thus, preventing any race condition.
73  */
74     /* MISRA Ref 8.9.1 [File scoped variables] */
75     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
76     /* coverity[misra_c_2012_rule_8_9_violation] */
77     static FreeRTOS_Socket_t * xSocketToClose = NULL;
78 
79 /** @brief When a connection is coming in on a reusable socket, and the
80  *         SYN phase times out, the socket must be put back into eTCP_LISTEN
81  *         mode, so it can accept a new connection again.
82  *         This variable can be accessed by the IP task only. Thus, preventing any
83  *         race condition.
84  */
85     /* MISRA Ref 8.9.1 [File scoped variables] */
86     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
87     /* coverity[misra_c_2012_rule_8_9_violation] */
88     _static FreeRTOS_Socket_t * xSocketToListen = NULL;
89 
90     #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
91 
92 /*
93  * For logging and debugging: make a string showing the TCP flags.
94  */
95         const char * prvTCPFlagMeaning( UBaseType_t xFlags );
96     #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
97 
98 
99 /*-----------------------------------------------------------*/
100 
101 
102 /** @brief Close the socket another time.
103  *
104  * @param[in] pxSocket The socket to be checked.
105  */
106     /* coverity[single_use] */
vSocketCloseNextTime(FreeRTOS_Socket_t * pxSocket)107     void vSocketCloseNextTime( FreeRTOS_Socket_t * pxSocket )
108     {
109         if( ( xSocketToClose != NULL ) && ( xSocketToClose != pxSocket ) )
110         {
111             ( void ) vSocketClose( xSocketToClose );
112         }
113 
114         xSocketToClose = pxSocket;
115     }
116     /*-----------------------------------------------------------*/
117 
118 /** @brief Postpone a call to FreeRTOS_listen() to avoid recursive calls.
119  *
120  * @param[in] pxSocket The socket to be checked.
121  */
122     /* coverity[single_use] */
vSocketListenNextTime(FreeRTOS_Socket_t * pxSocket)123     void vSocketListenNextTime( FreeRTOS_Socket_t * pxSocket )
124     {
125         if( ( xSocketToListen != NULL ) && ( xSocketToListen != pxSocket ) )
126         {
127             ( void ) FreeRTOS_listen( ( Socket_t ) xSocketToListen, ( BaseType_t ) ( xSocketToListen->u.xTCP.usBacklog ) );
128         }
129 
130         xSocketToListen = pxSocket;
131     }
132     /*-----------------------------------------------------------*/
133 
134 /**
135  * @brief As soon as a TCP socket timer expires, this function will be called
136  *       (from xTCPTimerCheck). It can send a delayed ACK or new data.
137  *
138  * @param[in] pxSocket socket to be checked.
139  *
140  * @return 0 on success, a negative error code on failure. A negative value will be
141  *         returned in case the hang-protection has put the socket in a wait-close state.
142  *
143  * @note Sequence of calling (normally) :
144  *   IP-Task:
145  *      xTCPTimerCheck()                // Check all sockets ( declared in FreeRTOS_Sockets.c )
146  *      xTCPSocketCheck()               // Either send a delayed ACK or call prvTCPSendPacket()
147  *      prvTCPSendPacket()              // Either send a SYN or call prvTCPSendRepeated ( regular messages )
148  *      prvTCPSendRepeated()            // Send at most 8 messages on a row
149  *          prvTCPReturnPacket()        // Prepare for returning
150  *          xNetworkInterfaceOutput()   // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
151  */
xTCPSocketCheck(FreeRTOS_Socket_t * pxSocket)152     BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t * pxSocket )
153     {
154         BaseType_t xResult = 0;
155         BaseType_t xReady = pdFALSE;
156 
157         if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
158         {
159             /* The API FreeRTOS_send() might have added data to the TX stream.  Add
160              * this data to the windowing system so it can be transmitted. */
161             prvTCPAddTxData( pxSocket );
162         }
163 
164         #if ( ipconfigUSE_TCP_WIN == 1 )
165             {
166                 if( pxSocket->u.xTCP.pxAckMessage != NULL )
167                 {
168                     /* The first task of this regular socket check is to send-out delayed
169                      * ACK's. */
170                     if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
171                     {
172                         /* Earlier data was received but not yet acknowledged.  This
173                          * function is called when the TCP timer for the socket expires, the
174                          * ACK may be sent now. */
175                         if( pxSocket->u.xTCP.eTCPState != eCLOSED )
176                         {
177                             if( ( xTCPWindowLoggingLevel > 1 ) && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
178                             {
179                                 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %u SEQ %u (len %u)\n",
180                                                          pxSocket->usLocalPort,
181                                                          pxSocket->u.xTCP.usRemotePort,
182                                                          ( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ),
183                                                          ( unsigned ) ( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ),
184                                                          ( unsigned ) ( uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER ) ) );
185                             }
186 
187                             prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ( uint32_t ) ( uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER ), ipconfigZERO_COPY_TX_DRIVER );
188 
189                             #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
190                                 {
191                                     /* The ownership has been passed to the SEND routine,
192                                      * clear the pointer to it. */
193                                     pxSocket->u.xTCP.pxAckMessage = NULL;
194                                 }
195                             #endif /* ipconfigZERO_COPY_TX_DRIVER */
196                         }
197 
198                         if( prvTCPNextTimeout( pxSocket ) > 1U )
199                         {
200                             /* Tell the code below that this function is ready. */
201                             xReady = pdTRUE;
202                         }
203                     }
204                     else
205                     {
206                         /* The user wants to perform an active shutdown(), skip sending
207                          * the delayed ACK.  The function prvTCPSendPacket() will send the
208                          * FIN along with the ACK's. */
209                     }
210 
211                     if( pxSocket->u.xTCP.pxAckMessage != NULL )
212                     {
213                         vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
214                         pxSocket->u.xTCP.pxAckMessage = NULL;
215                     }
216                 }
217             }
218         #endif /* ipconfigUSE_TCP_WIN */
219 
220         if( xReady == pdFALSE )
221         {
222             /* The second task of this regular socket check is sending out data. */
223             if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) ||
224                 ( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN ) )
225             {
226                 ( void ) prvTCPSendPacket( pxSocket );
227             }
228 
229             /* Set the time-out for the next wakeup for this socket. */
230             ( void ) prvTCPNextTimeout( pxSocket );
231 
232             #if ( ipconfigTCP_HANG_PROTECTION == 1 )
233                 {
234                     /* In all (non-connected) states in which keep-alive messages can not be sent
235                      * the anti-hang protocol will close sockets that are 'hanging'. */
236                     xResult = prvTCPStatusAgeCheck( pxSocket );
237                 }
238             #endif
239         }
240 
241         return xResult;
242     }
243     /*-----------------------------------------------------------*/
244 
245 /**
246  * @brief 'Touch' the socket to keep it alive/updated.
247  *
248  * @param[in] pxSocket The socket to be updated.
249  *
250  * @note This is used for anti-hanging protection and TCP keep-alive messages.
251  *       Called in two places: after receiving a packet and after a state change.
252  *       The socket's alive timer may be reset.
253  */
prvTCPTouchSocket(struct xSOCKET * pxSocket)254     void prvTCPTouchSocket( struct xSOCKET * pxSocket )
255     {
256         #if ( ipconfigTCP_HANG_PROTECTION == 1 )
257             {
258                 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount();
259             }
260         #endif
261 
262         #if ( ipconfigTCP_KEEP_ALIVE == 1 )
263             {
264                 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
265                 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
266                 pxSocket->u.xTCP.ucKeepRepCount = 0U;
267                 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
268             }
269         #endif
270 
271         ( void ) pxSocket;
272     }
273     /*-----------------------------------------------------------*/
274 
275 /**
276  * @brief Changing to a new state. Centralised here to do specific actions such as
277  *        resetting the alive timer, calling the user's OnConnect handler to notify
278  *        that a socket has got (dis)connected, and setting bit to unblock a call to
279  *        FreeRTOS_select().
280  *
281  * @param[in] pxSocket The socket whose state we are trying to change.
282  * @param[in] eTCPState The state to which we want to change to.
283  */
vTCPStateChange(FreeRTOS_Socket_t * pxSocket,enum eTCP_STATE eTCPState)284     void vTCPStateChange( FreeRTOS_Socket_t * pxSocket,
285                           enum eTCP_STATE eTCPState )
286     {
287         FreeRTOS_Socket_t * xParent = pxSocket;
288         BaseType_t bBefore = tcpNOW_CONNECTED( ( BaseType_t ) pxSocket->u.xTCP.eTCPState ); /* Was it connected ? */
289         BaseType_t bAfter = tcpNOW_CONNECTED( ( BaseType_t ) eTCPState );                   /* Is it connected now ? */
290 
291         eIPTCPState_t xPreviousState = pxSocket->u.xTCP.eTCPState;
292 
293         #if ( ipconfigUSE_CALLBACKS == 1 )
294             FreeRTOS_Socket_t * xConnected = NULL;
295         #endif
296 
297         if( ( ( xPreviousState == eCONNECT_SYN ) ||
298               ( xPreviousState == eSYN_FIRST ) ||
299               ( xPreviousState == eSYN_RECEIVED ) ) &&
300             ( eTCPState == eCLOSE_WAIT ) )
301         {
302             /* A socket was in the connecting phase but something
303              * went wrong and it should be closed. */
304             FreeRTOS_debug_printf( ( "Move from %s to %s\n",
305                                      FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
306                                      FreeRTOS_GetTCPStateName( eTCPState ) ) );
307 
308             /* Set the flag to show that it was connected before and that the
309              * status has changed now. This will cause the control flow to go
310              * in the below if condition.*/
311             bBefore = pdTRUE;
312         }
313 
314         /* Has the connected status changed? */
315         if( bBefore != bAfter )
316         {
317             /* if bPassQueued is true, this socket is an orphan until it gets connected. */
318             if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
319             {
320                 /* Find it's parent if the reuse bit is not set. */
321                 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
322                 {
323                     xParent = pxSocket->u.xTCP.pxPeerSocket;
324                     configASSERT( xParent != NULL );
325                 }
326             }
327 
328             /* Is the socket connected now ? */
329             if( bAfter != pdFALSE )
330             {
331                 /* if bPassQueued is true, this socket is an orphan until it gets connected. */
332                 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
333                 {
334                     if( xParent != NULL )
335                     {
336                         /* The child socket has got connected.  See if the parent
337                          * ( the listening socket ) should be signalled, or if a
338                          * call-back must be made, in which case 'xConnected' will
339                          * be set to the parent socket. */
340 
341                         if( xParent->u.xTCP.pxPeerSocket == NULL )
342                         {
343                             xParent->u.xTCP.pxPeerSocket = pxSocket;
344                         }
345 
346                         xParent->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
347 
348                         #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
349                             {
350                                 /* Library support FreeRTOS_select().  Receiving a new
351                                  * connection is being translated as a READ event. */
352                                 if( ( xParent->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U )
353                                 {
354                                     xParent->xEventBits |= ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT;
355                                 }
356                             }
357                         #endif
358 
359                         #if ( ipconfigUSE_CALLBACKS == 1 )
360                             {
361                                 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) ) &&
362                                     ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
363                                 {
364                                     /* The listening socket does not become connected itself, in stead
365                                      * a child socket is created.
366                                      * Postpone a call the OnConnect event until the end of this function. */
367                                     xConnected = xParent;
368                                 }
369                             }
370                         #endif
371                     }
372 
373                     /* Don't need to access the parent socket anymore, so the
374                      * reference 'pxPeerSocket' may be cleared. */
375                     pxSocket->u.xTCP.pxPeerSocket = NULL;
376                     pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
377 
378                     /* When true, this socket may be returned in a call to accept(). */
379                     pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
380                 }
381                 else
382                 {
383                     /* An active connect() has succeeded. In this case there is no
384                      * ( listening ) parent socket. Signal the now connected socket. */
385 
386                     pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_CONNECT;
387 
388                     #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
389                         {
390                             if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_WRITE ) ) != 0U )
391                             {
392                                 pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_WRITE ) << SOCKET_EVENT_BIT_COUNT;
393                             }
394                         }
395                     #endif
396                 }
397             }
398             else /* bAfter == pdFALSE, connection is closed. */
399             {
400                 /* Notify/wake-up the socket-owner by setting the event bits. */
401                 xParent->xEventBits |= ( EventBits_t ) eSOCKET_CLOSED;
402 
403                 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
404                     {
405                         if( ( xParent->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
406                         {
407                             xParent->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT;
408                         }
409                     }
410                 #endif
411             }
412 
413             #if ( ipconfigUSE_CALLBACKS == 1 )
414                 {
415                     if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) ) && ( xConnected == NULL ) )
416                     {
417                         /* The 'connected' state has changed, call the user handler. */
418                         xConnected = pxSocket;
419                     }
420                 }
421             #endif /* ipconfigUSE_CALLBACKS */
422 
423             if( prvTCPSocketIsActive( pxSocket->u.xTCP.eTCPState ) == 0 )
424             {
425                 /* Now the socket isn't in an active state anymore so it
426                  * won't need further attention of the IP-task.
427                  * Setting time-out to zero means that the socket won't get checked during
428                  * timer events. */
429                 pxSocket->u.xTCP.usTimeout = 0U;
430             }
431         }
432 
433         /* Fill in the new state. */
434         pxSocket->u.xTCP.eTCPState = eTCPState;
435 
436         if( ( eTCPState == eCLOSED ) ||
437             ( eTCPState == eCLOSE_WAIT ) )
438         {
439             /* Socket goes to status eCLOSED because of a RST.
440              * When nobody owns the socket yet, delete it. */
441             vTaskSuspendAll();
442             {
443                 if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
444                     ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
445                 {
446                     if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
447                     {
448                         pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
449                         pxSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED;
450                     }
451 
452                     ( void ) xTaskResumeAll();
453 
454                     FreeRTOS_printf( ( "vTCPStateChange: Closing socket\n" ) );
455 
456                     if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
457                     {
458                         configASSERT( xIsCallingFromIPTask() != pdFALSE );
459                         vSocketCloseNextTime( pxSocket );
460                     }
461                 }
462                 else
463                 {
464                     ( void ) xTaskResumeAll();
465                 }
466             }
467         }
468 
469         if( ( eTCPState == eCLOSE_WAIT ) && ( pxSocket->u.xTCP.bits.bReuseSocket == pdTRUE_UNSIGNED ) )
470         {
471             switch( xPreviousState )
472             {
473                 case eSYN_FIRST:    /* 3 (server) Just created, must ACK the SYN request */
474                 case eSYN_RECEIVED: /* 4 (server) waiting for a confirming connection request */
475                     FreeRTOS_debug_printf( ( "Restoring a reuse socket port %u\n", pxSocket->usLocalPort ) );
476 
477                     /* Go back into listening mode. Set the TCP status to 'eCLOSED',
478                      * otherwise FreeRTOS_listen() will refuse the action. */
479                     pxSocket->u.xTCP.eTCPState = eCLOSED;
480 
481                     /* vSocketListenNextTime() makes sure that FreeRTOS_listen() will be called
482                      * before the IP-task handles any new message. */
483                     vSocketListenNextTime( pxSocket );
484                     break;
485 
486                 default:
487                     /* Nothing to do. */
488                     break;
489             }
490         }
491 
492         /* Touch the alive timers because moving to another state. */
493         prvTCPTouchSocket( pxSocket );
494 
495         #if ( ipconfigHAS_DEBUG_PRINTF == 1 )
496             {
497                 if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) )
498                 {
499                     char pcBuffer[ 40 ];
500 
501                     switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */
502                     {
503                         #if ( ipconfigUSE_IPv4 != 0 )
504                             case pdFALSE_UNSIGNED:
505                                {
506                                    uint32_t ulIPAddress = FreeRTOS_ntohl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
507                                    FreeRTOS_inet_ntop( FREERTOS_AF_INET4,
508                                                        ( const uint8_t * ) &ulIPAddress,
509                                                        pcBuffer,
510                                                        sizeof( pcBuffer ) );
511                                }
512                                break;
513                         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
514 
515                         #if ( ipconfigUSE_IPv6 != 0 )
516                             case pdTRUE_UNSIGNED:
517                                 FreeRTOS_inet_ntop( FREERTOS_AF_INET6,
518                                                     pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes,
519                                                     pcBuffer,
520                                                     sizeof( pcBuffer ) );
521                                 break;
522                         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
523 
524                         default:   /* LCOV_EXCL_LINE */
525                             /* MISRA 16.4 Compliance */
526                             break; /* LCOV_EXCL_LINE */
527                     }
528 
529                     FreeRTOS_debug_printf( ( "Socket %u -> [%s]:%u State %s->%s\n",
530                                              pxSocket->usLocalPort,
531                                              pcBuffer,
532                                              pxSocket->u.xTCP.usRemotePort,
533                                              FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
534                                              FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
535                 }
536             }
537         #endif /* ipconfigHAS_DEBUG_PRINTF */
538 
539         #if ( ipconfigUSE_CALLBACKS == 1 )
540             {
541                 if( xConnected != NULL )
542                 {
543                     /* The 'connected' state has changed, call the OnConnect handler of the parent. */
544                     xConnected->u.xTCP.pxHandleConnected( ( Socket_t ) xConnected, bAfter );
545                 }
546             }
547         #endif
548 
549         if( xParent != NULL )
550         {
551             vSocketWakeUpUser( xParent );
552         }
553     }
554     /*-----------------------------------------------------------*/
555 
556 
557 /**
558  * @brief Calculate after how much time this socket needs to be checked again.
559  *
560  * @param[in] pxSocket The socket to be checked.
561  *
562  * @return The number of clock ticks before the timer expires.
563  */
prvTCPNextTimeout(struct xSOCKET * pxSocket)564     TickType_t prvTCPNextTimeout( struct xSOCKET * pxSocket )
565     {
566         TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
567 
568         if( pxSocket->u.xTCP.eTCPState == eCONNECT_SYN )
569         {
570             /* The socket is actively connecting to a peer. */
571             if( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED )
572             {
573                 /* Ethernet address has been found, use progressive timeout for
574                  * active connect(). */
575                 if( pxSocket->u.xTCP.ucRepCount < 3U )
576                 {
577                     ulDelayMs = ( ( ( uint32_t ) 3000U ) << ( pxSocket->u.xTCP.ucRepCount - 1U ) );
578                 }
579                 else
580                 {
581                     ulDelayMs = 11000U;
582                 }
583             }
584             else
585             {
586                 /* Still in the ARP phase: check every half second. */
587                 ulDelayMs = 500U;
588             }
589 
590             FreeRTOS_debug_printf( ( "Connect[%xip:%u]: next timeout %u: %u ms\n",
591                                      ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4, pxSocket->u.xTCP.usRemotePort,
592                                      pxSocket->u.xTCP.ucRepCount, ( unsigned ) ulDelayMs ) );
593             pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs );
594         }
595         else if( pxSocket->u.xTCP.usTimeout == 0U )
596         {
597             /* Let the sliding window mechanism decide what time-out is appropriate. */
598             BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
599 
600             if( ulDelayMs == 0U )
601             {
602                 if( xResult != ( BaseType_t ) 0 )
603                 {
604                     ulDelayMs = 1U;
605                 }
606                 else
607                 {
608                     ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
609                 }
610             }
611             else
612             {
613                 /* ulDelayMs contains the time to wait before a re-transmission. */
614             }
615 
616             pxSocket->u.xTCP.usTimeout = ( uint16_t ) ipMS_TO_MIN_TICKS( ulDelayMs ); /* LCOV_EXCL_BR_LINE ulDelayMs will not be smaller than 1 */
617         }
618         else
619         {
620             /* field '.usTimeout' has already been set (by the
621              * keep-alive/delayed-ACK mechanism). */
622         }
623 
624         /* Return the number of clock ticks before the timer expires. */
625         return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
626     }
627     /*-----------------------------------------------------------*/
628 
629 /**
630  * @brief Process the received TCP packet.
631  *
632  * @param[in] pxDescriptor The descriptor in which the TCP packet is held.
633  *
634  * @return If the processing of the packet was successful, then pdPASS is returned
635  *         or else pdFAIL.
636  *
637  * @note FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
638  *  xProcessReceivedTCPPacket()
639  *      prvTCPHandleState()
640  *          prvTCPPrepareSend()
641  *              prvTCPReturnPacket()
642  *              xNetworkInterfaceOutput()  // Sends data to the NIC
643  *      prvTCPSendRepeated()
644  *          prvTCPReturnPacket()        // Prepare for returning
645  *          xNetworkInterfaceOutput()   // Sends data to the NIC
646  */
xProcessReceivedTCPPacket(NetworkBufferDescriptor_t * pxDescriptor)647     BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t * pxDescriptor )
648     {
649         /* Function might modify the parameter. */
650         const NetworkBufferDescriptor_t * pxNetworkBuffer = pxDescriptor;
651 
652         configASSERT( pxNetworkBuffer != NULL );
653         configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
654 
655         BaseType_t xResult;
656 
657         /* MISRA Ref 11.3.1 [Misaligned access] */
658         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
659         /* coverity[misra_c_2012_rule_11_3_violation] */
660         switch( ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer )->usFrameType )
661         {
662             #if ( ipconfigUSE_IPv4 != 0 )
663                 case ipIPv4_FRAME_TYPE:
664                     xResult = xProcessReceivedTCPPacket_IPV4( pxDescriptor );
665                     break;
666             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
667 
668             #if ( ipconfigUSE_IPv6 != 0 )
669                 case ipIPv6_FRAME_TYPE:
670                     xResult = xProcessReceivedTCPPacket_IPV6( pxDescriptor );
671                     break;
672             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
673 
674             default:
675                 /* Shouldn't reach here */
676                 xResult = pdFAIL;
677                 break;
678         }
679 
680         return xResult;
681     }
682     /*-----------------------------------------------------------*/
683 
684 
685 /**
686  * @brief In the API accept(), the user asks is there is a new client? As API's can
687  *        not walk through the xBoundTCPSocketsList the IP-task will do this.
688  *
689  * @param[in] pxSocket The socket for which the bound socket list will be iterated.
690  *
691  * @return if there is a new client, then pdTRUE is returned or else, pdFALSE.
692  */
xTCPCheckNewClient(FreeRTOS_Socket_t * pxSocket)693     BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t * pxSocket )
694     {
695         TickType_t uxLocalPort = ( TickType_t ) FreeRTOS_htons( pxSocket->usLocalPort );
696         const ListItem_t * pxIterator;
697         FreeRTOS_Socket_t * pxFound;
698         BaseType_t xResult = pdFALSE;
699 
700         /* MISRA Ref 11.3.1 [Misaligned access] */
701         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
702         /* coverity[misra_c_2012_rule_11_3_violation] */
703         const ListItem_t * pxEndTCP = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
704 
705         /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
706          * who has access. */
707         for( pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
708              pxIterator != pxEndTCP;
709              pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
710         {
711             if( listGET_LIST_ITEM_VALUE( pxIterator ) == ( configLIST_VOLATILE TickType_t ) uxLocalPort )
712             {
713                 pxFound = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
714 
715                 if( ( pxFound->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
716                 {
717                     pxSocket->u.xTCP.pxPeerSocket = pxFound;
718                     FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
719                     xResult = pdTRUE;
720                     break;
721                 }
722             }
723         }
724 
725         return xResult;
726     }
727     /*-----------------------------------------------------------*/
728 
729 
730 #endif /* ipconfigUSE_TCP == 1 */
731 
732 /* Provide access to private members for testing. */
733 #ifdef FREERTOS_ENABLE_UNIT_TESTS
734     #include "freertos_tcp_test_access_tcp_define.h"
735 #endif
736 
737 /* Provide access to private members for verification. */
738 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
739     #include "aws_freertos_tcp_verification_access_tcp_define.h"
740 #endif
741