xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_Sockets.c (revision 574b646147a48c508a8bfc82181fd89ea89c8c17)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_Sockets.c
30  * @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
31  *        Sockets are used by the application processes to interact with the IP-task which in turn
32  *        interacts with the hardware.
33  */
34 
35 /* Standard includes. */
36 #include <stdint.h>
37 #include <stdio.h>
38 
39 /* FreeRTOS includes. */
40 #include "FreeRTOS.h"
41 #include "task.h"
42 #include "queue.h"
43 #include "semphr.h"
44 
45 /* FreeRTOS+TCP includes. */
46 #include "FreeRTOS_UDP_IP.h"
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IPv4_Sockets.h"
50 #include "FreeRTOS_IPv6_Sockets.h"
51 #include "FreeRTOS_IP_Private.h"
52 #include "FreeRTOS_DNS.h"
53 #include "NetworkBufferManagement.h"
54 #include "FreeRTOS_Routing.h"
55 
56 #if ( ipconfigUSE_TCP_MEM_STATS != 0 )
57     #include "tcp_mem_stats.h"
58 #endif
59 
60 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
61  * port number. */
62 /** @brief Set the port number for the socket in the xBoundSocketListItem. */
63 #define socketSET_SOCKET_PORT( pxSocket, usPort )    listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
64 /** @brief Get the port number for the socket in the xBoundSocketListItem. */
65 #define socketGET_SOCKET_PORT( pxSocket )            listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
66 
67 /** @brief Test if a socket it bound which means it is either included in
68  *         xBoundUDPSocketsList or xBoundTCPSocketsList
69  */
70 #define socketSOCKET_IS_BOUND( pxSocket )            ( listLIST_ITEM_CONTAINER( &( pxSocket )->xBoundSocketListItem ) != NULL )
71 
72 /** @brief If FreeRTOS_sendto() is called on a socket that is not bound to a port
73  *         number then, depending on the FreeRTOSIPConfig.h settings, it might be
74  *         that a port number is automatically generated for the socket.
75  *         Automatically generated port numbers will be between
76  *         socketAUTO_PORT_ALLOCATION_START_NUMBER and 0xffff.
77  *
78  * @note Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of
79  *       the range 49152-65535. However, ephemeral port selection algorithms should
80  *       use the whole range 1024-65535" excluding those already in use (inbound
81  *       or outbound).
82  */
83 #if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER )
84     #define socketAUTO_PORT_ALLOCATION_START_NUMBER    ( ( uint16_t ) 0x0400 )
85 #endif
86 
87 /** @brief Maximum value of port number which can be auto assigned. */
88 #define socketAUTO_PORT_ALLOCATION_MAX_NUMBER    ( ( uint16_t ) 0xffff )
89 
90 /** @brief A block time of 0 simply means "don't block". */
91 #define socketDONT_BLOCK                         ( ( TickType_t ) 0 )
92 
93 /** @brief TCP timer period in milliseconds. */
94 #if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
95     #define ipTCP_TIMER_PERIOD_MS    ( 1000U )
96 #endif
97 
98 /* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */
99 #define sock20_PERCENT     20U         /**< 20% of the defined limit. */
100 #define sock80_PERCENT     80U         /**< 80% of the defined limit. */
101 #define sock100_PERCENT    100U        /**< 100% of the defined limit. */
102 
103 #if ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
104 
105 /**
106  * @brief A buffer for prvSocketProps to return socket property in string.
107  */
108     static char pucSocketProps[ 92 ];
109 #endif
110 
111 /*-----------------------------------------------------------*/
112 
113 /*
114  * Allocate the next port number from the private allocation range.
115  * TCP and UDP each have their own series of port numbers
116  * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP
117  */
118 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol );
119 
120 /*
121  * Return the list item from within pxList that has an item value of
122  * xWantedItemValue.  If there is no such list item return NULL.
123  */
124 static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
125                                                        TickType_t xWantedItemValue );
126 
127 /*
128  * Return pdTRUE only if pxSocket is valid and bound, as far as can be
129  * determined.
130  */
131 static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
132                                   BaseType_t xProtocol,
133                                   BaseType_t xIsBound );
134 
135 #if ( ipconfigUSE_TCP == 1 )
136 
137 /*
138  * Internal function prvSockopt_so_buffer(): sets FREERTOS_SO_SNDBUF or
139  * FREERTOS_SO_RCVBUF properties of a socket.
140  */
141     static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
142                                             int32_t lOptionName,
143                                             const void * pvOptionValue );
144 #endif /* ipconfigUSE_TCP == 1 */
145 
146 /*
147  * Before creating a socket, check the validity of the parameters used
148  * and find the size of the socket space, which is different for UDP and TCP
149  */
150 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
151                                           BaseType_t xType,
152                                           BaseType_t xProtocol,
153                                           size_t * pxSocketSize );
154 
155 static BaseType_t prvSocketBindAdd( FreeRTOS_Socket_t * pxSocket,
156                                     const struct freertos_sockaddr * pxAddress,
157                                     List_t * pxSocketList,
158                                     BaseType_t xInternal );
159 
160 static NetworkBufferDescriptor_t * prvRecvFromWaitForPacket( FreeRTOS_Socket_t const * pxSocket,
161                                                              BaseType_t xFlags,
162                                                              EventBits_t * pxEventBits );
163 
164 static int32_t prvSendUDPPacket( const FreeRTOS_Socket_t * pxSocket,
165                                  NetworkBufferDescriptor_t * pxNetworkBuffer,
166                                  size_t uxTotalDataLength,
167                                  BaseType_t xFlags,
168                                  const struct freertos_sockaddr * pxDestinationAddress,
169                                  TickType_t xTicksToWait,
170                                  size_t uxPayloadOffset );
171 
172 #if ( ipconfigUSE_TCP == 1 )
173     static FreeRTOS_Socket_t * prvAcceptWaitClient( FreeRTOS_Socket_t * pxParentSocket,
174                                                     struct freertos_sockaddr * pxAddress,
175                                                     socklen_t * pxAddressLength );
176 #endif /* ( ipconfigUSE_TCP == 1 ) */
177 
178 #if ( ipconfigUSE_TCP == 1 )
179 
180 /*
181  * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream'
182  */
183     static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
184                                                 BaseType_t xIsInputStream );
185 #endif /* ipconfigUSE_TCP == 1 */
186 
187 #if ( ipconfigUSE_TCP == 1 )
188 
189 /*
190  * Called from FreeRTOS_send(): some checks which will be done before
191  * sending a TCP packed.
192  */
193     static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
194                                     size_t uxDataLength );
195 #endif /* ipconfigUSE_TCP */
196 
197 #if ( ipconfigUSE_TCP == 1 )
198 
199 /*
200  * When a child socket gets closed, make sure to update the child-count of the parent
201  */
202     static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete );
203 #endif /* ipconfigUSE_TCP == 1 */
204 
205 #if ( ipconfigUSE_TCP == 1 )
206 
207 /*
208  * Called from FreeRTOS_connect(): make some checks and if allowed, send a
209  * message to the IP-task to start connecting to a remote socket
210  */
211     static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
212                                           struct freertos_sockaddr const * pxAddress );
213 #endif /* ipconfigUSE_TCP */
214 
215 #if ( ipconfigUSE_TCP == 1 )
216 
217 /*
218  * Check if it makes any sense to wait for a connect event.
219  * It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
220  */
221     static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket );
222 #endif /* ipconfigUSE_TCP */
223 
224 /** @brief Check if a socket is already bound to a 'random' port number,
225  * if not, try bind it to port 0.
226  */
227 static BaseType_t prvMakeSureSocketIsBound( FreeRTOS_Socket_t * pxSocket );
228 
229 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
230 
231 /* Executed by the IP-task, it will check all sockets belonging to a set */
232     static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet );
233 
234 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
235 
236 #if ( ipconfigUSE_TCP == 1 )
237 
238 /** @brief This routine will wait for data to arrive in the stream buffer.
239  */
240     static BaseType_t prvRecvWait( const FreeRTOS_Socket_t * pxSocket,
241                                    EventBits_t * pxEventBits,
242                                    BaseType_t xFlags );
243 #endif /* ( ipconfigUSE_TCP == 1 ) */
244 
245 #if ( ipconfigUSE_TCP == 1 )
246 
247 /** @brief Read the data from the stream buffer.
248  */
249     static BaseType_t prvRecvData( FreeRTOS_Socket_t * pxSocket,
250                                    void * pvBuffer,
251                                    size_t uxBufferLength,
252                                    BaseType_t xFlags );
253 #endif /* ( ipconfigUSE_TCP == 1 ) */
254 
255 #if ( ipconfigUSE_TCP == 1 )
256 
257 /**
258  * @brief This function tries to send TCP-data in a loop with a time-out.
259  */
260     static BaseType_t prvTCPSendLoop( FreeRTOS_Socket_t * pxSocket,
261                                       const void * pvBuffer,
262                                       size_t uxDataLength,
263                                       BaseType_t xFlags );
264 #endif /* ( ipconfigUSE_TCP == 1 ) */
265 
266 #if ( ipconfigUSE_CALLBACKS == 1 )
267 
268 /**
269  * @brief Set a callback function for either a TCP or a UDP socket.
270  */
271     BaseType_t prvSetOptionCallback( FreeRTOS_Socket_t * pxSocket,
272                                      int32_t lOptionName,
273                                      const void * pvOptionValue );
274 #endif /* ( ipconfigUSE_CALLBACKS == 1 ) */
275 
276 #if ( ipconfigUSE_TCP != 0 )
277 
278 /**
279  * @brief Handle the socket option FREERTOS_SO_WIN_PROPERTIES.
280  */
281     static BaseType_t prvSetOptionTCPWindows( FreeRTOS_Socket_t * pxSocket,
282                                               const void * pvOptionValue );
283 #endif /* ( ipconfigUSE_TCP != 0 ) */
284 
285 #if ( ipconfigUSE_TCP != 0 )
286 
287 /**
288  * @brief Handle the socket option FREERTOS_SO_SET_LOW_HIGH_WATER.
289  */
290     static BaseType_t prvSetOptionLowHighWater( FreeRTOS_Socket_t * pxSocket,
291                                                 const void * pvOptionValue );
292 #endif /* ( ipconfigUSE_TCP != 0 ) */
293 
294 #if ( ipconfigUSE_TCP != 0 )
295 
296 /**
297  * @brief Handle the socket option FREERTOS_SO_SET_FULL_SIZE.
298  */
299     static BaseType_t prvSetOptionSetFullSize( FreeRTOS_Socket_t * pxSocket,
300                                                const void * pvOptionValue );
301 
302 #endif /* ( ipconfigUSE_TCP != 0 ) */
303 
304 #if ( ipconfigUSE_TCP != 0 )
305 
306 /** @brief Handle the socket option FREERTOS_SO_STOP_RX. */
307     static BaseType_t prvSetOptionStopRX( FreeRTOS_Socket_t * pxSocket,
308                                           const void * pvOptionValue );
309 
310 #endif /* ( ipconfigUSE_TCP != 0 ) */
311 
312 /** @brief Handle the socket options FREERTOS_SO_RCVTIMEO and
313  *         FREERTOS_SO_SNDTIMEO.
314  */
315 static void prvSetOptionTimeout( FreeRTOS_Socket_t * pxSocket,
316                                  const void * pvOptionValue,
317                                  BaseType_t xForSend );
318 
319 #if ( ipconfigUSE_TCP != 0 )
320 
321 /** @brief Handle the socket options FREERTOS_SO_CLOSE_AFTER_SEND.
322  */
323     static BaseType_t prvSetOptionCloseAfterSend( FreeRTOS_Socket_t * pxSocket,
324                                                   const void * pvOptionValue );
325 #endif /* ( ipconfigUSE_TCP != 0 ) */
326 
327 #if ( ipconfigUSE_TCP != 0 )
328 
329 /**
330  * @brief Handle the socket options FREERTOS_SO_REUSE_LISTEN_SOCKET.
331  */
332     static BaseType_t prvSetOptionReuseListenSocket( FreeRTOS_Socket_t * pxSocket,
333                                                      const void * pvOptionValue );
334 
335     static void prvInitialiseTCPFields( FreeRTOS_Socket_t * pxSocket,
336                                         size_t uxSocketSize );
337 #endif /* ipconfigUSE_TCP == 1 */
338 
339 
340 
341 static int32_t prvRecvFrom_CopyPacket( uint8_t * pucEthernetBuffer,
342                                        void * pvBuffer,
343                                        size_t uxBufferLength,
344                                        BaseType_t xFlags,
345                                        int32_t lDataLength );
346 
347 static int32_t prvSendTo_ActualSend( const FreeRTOS_Socket_t * pxSocket,
348                                      const void * pvBuffer,
349                                      size_t uxTotalDataLength,
350                                      BaseType_t xFlags,
351                                      const struct freertos_sockaddr * pxDestinationAddress,
352                                      size_t uxPayloadOffset );
353 
354 #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 )
355 
356 /** @brief The application can attach callback functions to a socket. In this function,
357  *         called by lTCPAddRxdata(), the TCP reception handler will be called. */
358     static void vTCPAddRxdata_Callback( FreeRTOS_Socket_t * pxSocket,
359                                         const uint8_t * pcData,
360                                         uint32_t ulByteCount );
361 #endif
362 
363 #if ( ipconfigUSE_TCP == 1 )
364     static void vTCPAddRxdata_Stored( FreeRTOS_Socket_t * pxSocket );
365 #endif
366 
367 #if ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
368 /** @brief A helper function of vTCPNetStat(), see below. */
369     static void vTCPNetStat_TCPSocket( const FreeRTOS_Socket_t * pxSocket );
370 #endif
371 
372 /*-----------------------------------------------------------*/
373 
374 /** @brief The list that contains mappings between sockets and port numbers.
375  *         Accesses to this list must be protected by critical sections of
376  *         some kind.
377  */
378 List_t xBoundUDPSocketsList;
379 
380 #if ipconfigUSE_TCP == 1
381 
382 /** @brief The list that contains mappings between sockets and port numbers.
383  *         Accesses to this list must be protected by critical sections of
384  *         some kind.
385  */
386     List_t xBoundTCPSocketsList;
387 
388 #endif /* ipconfigUSE_TCP == 1 */
389 
390 /*-----------------------------------------------------------*/
391 
392 /**
393  * @brief Check whether the socket is valid or not.
394  *
395  * @param[in] pxSocket The socket being checked.
396  * @param[in] xProtocol The protocol for which the socket was created.
397  * @param[in] xIsBound pdTRUE when the socket should be bound, otherwise pdFALSE.
398  *
399  * @return If the socket is valid, then pdPASS is returned or else, pdFAIL
400  *         is returned.
401  */
prvValidSocket(const FreeRTOS_Socket_t * pxSocket,BaseType_t xProtocol,BaseType_t xIsBound)402 static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
403                                   BaseType_t xProtocol,
404                                   BaseType_t xIsBound )
405 {
406     BaseType_t xReturn;
407 
408     if( xSocketValid( pxSocket ) == pdFALSE )
409     {
410         xReturn = pdFALSE;
411     }
412     else if( ( xIsBound != pdFALSE ) && !socketSOCKET_IS_BOUND( pxSocket ) )
413     {
414         /* The caller expects the socket to be bound, but it isn't. */
415         xReturn = pdFALSE;
416     }
417     else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol )
418     {
419         /* Socket has a wrong type (UDP != TCP). */
420         xReturn = pdFALSE;
421     }
422     else
423     {
424         xReturn = pdTRUE;
425     }
426 
427     return xReturn;
428 }
429 /*-----------------------------------------------------------*/
430 
431 /**
432  * @brief Initialise the bound TCP/UDP socket lists.
433  */
vNetworkSocketsInit(void)434 void vNetworkSocketsInit( void )
435 {
436     vListInitialise( &xBoundUDPSocketsList );
437 
438     #if ( ipconfigUSE_TCP == 1 )
439         {
440             vListInitialise( &xBoundTCPSocketsList );
441         }
442     #endif /* ipconfigUSE_TCP == 1 */
443 }
444 /*-----------------------------------------------------------*/
445 
446 /**
447  * @brief Determine the socket size for the given protocol.
448  *
449  * @param[in] xDomain The domain for which the size of socket is being determined.
450  * @param[in] xType Is this a datagram socket or a stream socket.
451  * @param[in] xProtocol The protocol being used.
452  * @param[out] pxSocketSize Pointer to a variable in which the size shall be returned
453  *                           if all checks pass.
454  *
455  * @return pdPASS if socket size was determined and put in the parameter pxSocketSize
456  *         correctly, else pdFAIL.
457  */
prvDetermineSocketSize(BaseType_t xDomain,BaseType_t xType,BaseType_t xProtocol,size_t * pxSocketSize)458 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
459                                           BaseType_t xType,
460                                           BaseType_t xProtocol,
461                                           size_t * pxSocketSize )
462 {
463     BaseType_t xReturn = pdPASS;
464     FreeRTOS_Socket_t const * pxSocket = NULL;
465 
466     /* Asserts must not appear before it has been determined that the network
467      * task is ready - otherwise the asserts will fail. */
468     if( xIPIsNetworkTaskReady() == pdFALSE )
469     {
470         xReturn = pdFAIL;
471     }
472     else
473     {
474         /* Only Ethernet is currently supported. */
475         #if ( ( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_IPv6 == 0 ) )
476             {
477                 if( xDomain != FREERTOS_AF_INET )
478                 {
479                     xReturn = pdFAIL;
480                 }
481 
482                 configASSERT( xDomain == FREERTOS_AF_INET );
483             }
484         #elif ( ( ipconfigUSE_IPv4 == 0 ) && ( ipconfigUSE_IPv6 != 0 ) )
485             {
486                 if( xDomain != FREERTOS_AF_INET6 )
487                 {
488                     xReturn = pdFAIL;
489                 }
490 
491                 configASSERT( xDomain == FREERTOS_AF_INET6 );
492             }
493         #else /* if ( ( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_IPv6 == 0 ) ) */
494             {
495                 if( ( xDomain != FREERTOS_AF_INET ) && ( xDomain != FREERTOS_AF_INET6 ) )
496                 {
497                     xReturn = pdFAIL;
498                 }
499 
500                 configASSERT( ( xDomain == FREERTOS_AF_INET ) || ( xDomain == FREERTOS_AF_INET6 ) );
501             }
502         #endif /* if ( ( ipconfigUSE_IPv4 != 0 ) && ( ipconfigUSE_IPv6 == 0 ) ) */
503 
504         /* Check if the UDP socket-list has been initialised. */
505         configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) );
506         #if ( ipconfigUSE_TCP == 1 )
507             {
508                 /* Check if the TCP socket-list has been initialised. */
509                 configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) );
510             }
511         #endif /* ipconfigUSE_TCP == 1 */
512 
513         if( xProtocol == FREERTOS_IPPROTO_UDP )
514         {
515             if( xType != FREERTOS_SOCK_DGRAM )
516             {
517                 xReturn = pdFAIL;
518                 configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
519             }
520 
521             /* In case a UDP socket is created, do not allocate space for TCP data. */
522             *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP );
523         }
524 
525         #if ( ipconfigUSE_TCP == 1 )
526             else if( xProtocol == FREERTOS_IPPROTO_TCP )
527             {
528                 if( xType != FREERTOS_SOCK_STREAM )
529                 {
530                     xReturn = pdFAIL;
531                     configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
532                 }
533 
534                 *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP );
535             }
536         #endif /* ipconfigUSE_TCP == 1 */
537         else
538         {
539             xReturn = pdFAIL;
540             configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
541         }
542     }
543 
544     /* In case configASSERT() is not used */
545     ( void ) xDomain;
546     ( void ) pxSocket; /* Was only used for sizeof. */
547     return xReturn;
548 }
549 /*-----------------------------------------------------------*/
550 
551 #if ( ipconfigUSE_TCP == 1 )
552 
553 /**
554  * @brief Called by FreeRTOS_socket(), it will initialise some essential TCP
555  *        fields in the socket.
556  * @param[in] pxSocket the TCP socket to be initialised.
557  * @param[in] uxSocketSize The calculated size of the socket, only used to
558  *                          gather memory usage statistics.
559  */
prvInitialiseTCPFields(FreeRTOS_Socket_t * pxSocket,size_t uxSocketSize)560     static void prvInitialiseTCPFields( FreeRTOS_Socket_t * pxSocket,
561                                         size_t uxSocketSize )
562     {
563         ( void ) uxSocketSize;
564         /* Lint wants at least a comment, in case the macro is empty. */
565         iptraceMEM_STATS_CREATE( tcpSOCKET_TCP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
566         /* StreamSize is expressed in number of bytes */
567         /* Round up buffer sizes to nearest multiple of MSS */
568         pxSocket->u.xTCP.usMSS = ( uint16_t ) ipconfigTCP_MSS;
569 
570         #if ( ipconfigUSE_IPv6 != 0 )
571             if( pxSocket->bits.bIsIPv6 != 0U )
572             {
573                 uint16_t usDifference = ipSIZE_OF_IPv6_HEADER - ipSIZE_OF_IPv4_HEADER;
574 
575                 if( pxSocket->u.xTCP.usMSS > usDifference )
576                 {
577                     pxSocket->u.xTCP.usMSS = ( uint16_t ) ( pxSocket->u.xTCP.usMSS - usDifference );
578                 }
579             }
580         #endif /* ipconfigUSE_IPv6 != 0 */
581 
582         pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH;
583         pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
584         /* Use half of the buffer size of the TCP windows */
585         #if ( ipconfigUSE_TCP_WIN == 1 )
586             {
587                 pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_size_t( 1U, ( pxSocket->u.xTCP.uxRxStreamSize / 2U ) / ipconfigTCP_MSS );
588                 pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_size_t( 1U, ( pxSocket->u.xTCP.uxTxStreamSize / 2U ) / ipconfigTCP_MSS );
589             }
590         #else
591             {
592                 pxSocket->u.xTCP.uxRxWinSize = 1U;
593                 pxSocket->u.xTCP.uxTxWinSize = 1U;
594             }
595         #endif
596 
597         /* The above values are just defaults, and can be overridden by
598          * calling FreeRTOS_setsockopt().  No buffers will be allocated until a
599          * socket is connected and data is exchanged. */
600     }
601 #endif /* ( ipconfigUSE_TCP == 1 ) */
602 /*-----------------------------------------------------------*/
603 
604 /**
605  * @brief allocate and initialise a socket.
606  *
607  * @param[in] xDomain The domain in which the socket should be created.
608  * @param[in] xType The type of the socket.
609  * @param[in] xProtocol The protocol of the socket.
610  *
611  * @return FREERTOS_INVALID_SOCKET if the allocation failed, or if there was
612  *         a parameter error, otherwise a valid socket.
613  */
FreeRTOS_socket(BaseType_t xDomain,BaseType_t xType,BaseType_t xProtocol)614 Socket_t FreeRTOS_socket( BaseType_t xDomain,
615                           BaseType_t xType,
616                           BaseType_t xProtocol )
617 {
618     FreeRTOS_Socket_t * pxSocket;
619 
620 /* Note that this value will be over-written by the call to prvDetermineSocketSize. */
621     size_t uxSocketSize = 1;
622     EventGroupHandle_t xEventGroup;
623     Socket_t xReturn;
624     BaseType_t xProtocolCpy = xProtocol;
625 
626     configASSERT( ( xDomain == FREERTOS_AF_INET6 ) || ( xDomain == FREERTOS_AF_INET ) );
627 
628     /* Introduce a do-while loop to allow use of break statements. */
629     do
630     {
631         /* The special protocol FREERTOS_SOCK_DEPENDENT_PROTO, which is equivalent
632          * to passing 0 as defined by POSIX, indicates to the socket layer that it
633          * should pick a sensible default protocol based off the given socket type.
634          * If we can't, prvDetermineSocketSize will catch it as an invalid
635          * type/protocol combo.
636          */
637         if( xProtocol == FREERTOS_SOCK_DEPENDENT_PROTO )
638         {
639             switch( xType )
640             {
641                 case FREERTOS_SOCK_DGRAM:
642                     xProtocolCpy = FREERTOS_IPPROTO_UDP;
643                     break;
644 
645                 case FREERTOS_SOCK_STREAM:
646                     xProtocolCpy = FREERTOS_IPPROTO_TCP;
647                     break;
648 
649                 default:
650 
651                     /* incorrect xType. this will be caught by
652                      * prvDetermineSocketSize.
653                      */
654                     break;
655             }
656         }
657 
658         if( prvDetermineSocketSize( xDomain, xType, xProtocolCpy, &uxSocketSize ) == pdFAIL )
659         {
660             /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
661             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
662             /* coverity[misra_c_2012_rule_11_4_violation] */
663             xReturn = FREERTOS_INVALID_SOCKET;
664             break;
665         }
666 
667         /* Allocate the structure that will hold the socket information. The
668         * size depends on the type of socket: UDP sockets need less space. A
669         * define 'pvPortMallocSocket' will used to allocate the necessary space.
670         * By default it points to the FreeRTOS function 'pvPortMalloc()'. */
671 
672         /* MISRA Ref 4.12.1 [Use of dynamic memory]. */
673         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#directive-412. */
674         /* coverity[misra_c_2012_directive_4_12_violation] */
675         pxSocket = ( ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize ) );
676 
677         if( pxSocket == NULL )
678         {
679             /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
680             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
681             /* coverity[misra_c_2012_rule_11_4_violation] */
682             xReturn = FREERTOS_INVALID_SOCKET;
683             iptraceFAILED_TO_CREATE_SOCKET();
684             break;
685         }
686 
687         xEventGroup = xEventGroupCreate();
688 
689         if( xEventGroup == NULL )
690         {
691             vPortFreeSocket( pxSocket );
692 
693             /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
694             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
695             /* coverity[misra_c_2012_rule_11_4_violation] */
696             xReturn = FREERTOS_INVALID_SOCKET;
697             iptraceFAILED_TO_CREATE_EVENT_GROUP();
698         }
699         else
700         {
701             /* Clear the entire space to avoid nulling individual entries. */
702             ( void ) memset( pxSocket, 0, uxSocketSize );
703 
704             pxSocket->xEventGroup = xEventGroup;
705 
706             switch( xDomain ) /* LCOV_EXCL_BR_LINE Exclude this because domain is checked at the begin of this function. */
707             {
708                 #if ( ipconfigUSE_IPv6 != 0 )
709                     case FREERTOS_AF_INET6:
710                         pxSocket->bits.bIsIPv6 = pdTRUE_UNSIGNED;
711                         break;
712                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
713 
714                 #if ( ipconfigUSE_IPv4 != 0 )
715                     case FREERTOS_AF_INET:
716                         pxSocket->bits.bIsIPv6 = pdFALSE_UNSIGNED;
717                         break;
718                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
719 
720                 default: /* LCOV_EXCL_LINE Exclude this because domain is checked at the begin of this function. */
721                     FreeRTOS_debug_printf( ( "FreeRTOS_socket: Undefined xDomain \n" ) );
722 
723                     /* MISRA 16.4 Compliance */
724                     break; /* LCOV_EXCL_LINE Exclude this because domain is checked at the begin of this function. */
725             }
726 
727             /* Initialise the socket's members.  The semaphore will be created
728              * if the socket is bound to an address, for now the pointer to the
729              * semaphore is just set to NULL to show it has not been created. */
730             if( xProtocolCpy == FREERTOS_IPPROTO_UDP )
731             {
732                 iptraceMEM_STATS_CREATE( tcpSOCKET_UDP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
733 
734                 vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
735 
736                 #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
737                     {
738                         pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
739                     }
740                 #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
741             }
742 
743             #if ( ipconfigUSE_TCP == 1 )
744                 else if( xProtocolCpy == FREERTOS_IPPROTO_TCP ) /* LCOV_EXCL_BR_LINE Exclude else case because protocol is checked in prvDetermineSocketSize */
745                 {
746                     prvInitialiseTCPFields( pxSocket, uxSocketSize );
747                 }
748                 else
749                 {
750                     /* MISRA wants to see an unconditional else clause. */
751                 }
752             #endif /* ipconfigUSE_TCP == 1 */
753 
754             vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
755             listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
756 
757             pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
758             pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
759             pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
760             pxSocket->ucProtocol = ( uint8_t ) xProtocolCpy; /* protocol: UDP or TCP */
761 
762             xReturn = pxSocket;
763         }
764     } while( ipFALSE_BOOL );
765 
766     return xReturn;
767 }
768 /*-----------------------------------------------------------*/
769 
770 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
771 
772 /**
773  * @brief Create a socket set.
774  *
775  * @return The new socket set which was created, or NULL when allocation has failed.
776  */
FreeRTOS_CreateSocketSet(void)777     SocketSet_t FreeRTOS_CreateSocketSet( void )
778     {
779         SocketSelect_t * pxSocketSet;
780 
781         /* MISRA Ref 4.12.1 [Use of dynamic memory]. */
782         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#directive-412. */
783         /* coverity[misra_c_2012_directive_4_12_violation] */
784         pxSocketSet = ( ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) ) );
785 
786         if( pxSocketSet != NULL )
787         {
788             ( void ) memset( pxSocketSet, 0, sizeof( *pxSocketSet ) );
789             pxSocketSet->xSelectGroup = xEventGroupCreate();
790 
791             if( pxSocketSet->xSelectGroup == NULL )
792             {
793                 vPortFree( pxSocketSet );
794                 pxSocketSet = NULL;
795             }
796             else
797             {
798                 /* Lint wants at least a comment, in case the macro is empty. */
799                 iptraceMEM_STATS_CREATE( tcpSOCKET_SET, pxSocketSet, sizeof( *pxSocketSet ) + sizeof( StaticEventGroup_t ) );
800             }
801         }
802 
803         return ( SocketSet_t ) pxSocketSet;
804     }
805 
806 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
807 /*-----------------------------------------------------------*/
808 
809 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
810 
811 /**
812  * @brief Delete a given socket set.
813  *
814  * @param[in] xSocketSet The socket set being deleted.
815  */
FreeRTOS_DeleteSocketSet(SocketSet_t xSocketSet)816     void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet )
817     {
818         IPStackEvent_t xCloseEvent;
819 
820 
821         xCloseEvent.eEventType = eSocketSetDeleteEvent;
822         xCloseEvent.pvData = ( void * ) xSocketSet;
823 
824         if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
825         {
826             FreeRTOS_printf( ( "FreeRTOS_DeleteSocketSet: xSendEventStructToIPTask failed\n" ) );
827         }
828     }
829 
830 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
831 /*-----------------------------------------------------------*/
832 
833 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
834 
835 /**
836  * @brief Add a socket to a set.
837  *
838  * @param[in] xSocket The socket being added.
839  * @param[in] xSocketSet The socket set being added to.
840  * @param[in] xBitsToSet The event bits to set, a combination of the values defined
841  *                        in 'eSelectEvent_t', for read, write, exception, etc.
842  */
FreeRTOS_FD_SET(Socket_t xSocket,SocketSet_t xSocketSet,EventBits_t xBitsToSet)843     void FreeRTOS_FD_SET( Socket_t xSocket,
844                           SocketSet_t xSocketSet,
845                           EventBits_t xBitsToSet )
846     {
847         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
848         SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
849 
850 
851         configASSERT( pxSocket != NULL );
852         configASSERT( xSocketSet != NULL );
853 
854         /* Make sure we're not adding bits which are reserved for internal use,
855          * such as eSELECT_CALL_IP */
856         pxSocket->xSelectBits |= xBitsToSet & ( ( EventBits_t ) eSELECT_ALL );
857 
858         if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
859         {
860             /* Adding a socket to a socket set. */
861             pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
862 
863             /* Now have the IP-task call vSocketSelect() to see if the set contains
864              * any sockets which are 'ready' and set the proper bits. */
865             prvFindSelectedSocket( pxSocketSet );
866         }
867     }
868 
869 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
870 /*-----------------------------------------------------------*/
871 
872 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
873 
874 /**
875  * @brief Clear select bits for a socket. If the mask becomes 0,
876  *        remove the socket from the set.
877  *
878  * @param[in] xSocket The socket whose select bits are being cleared.
879  * @param[in] xSocketSet The socket set of the socket.
880  * @param[in] xBitsToClear The bits to be cleared. Every '1' means that the
881  *                corresponding bit will be cleared. See 'eSelectEvent_t' for
882  *                the possible values.
883  */
FreeRTOS_FD_CLR(Socket_t xSocket,SocketSet_t xSocketSet,EventBits_t xBitsToClear)884     void FreeRTOS_FD_CLR( Socket_t xSocket,
885                           SocketSet_t xSocketSet,
886                           EventBits_t xBitsToClear )
887     {
888         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
889 
890         configASSERT( pxSocket != NULL );
891         configASSERT( xSocketSet != NULL );
892 
893         pxSocket->xSelectBits &= ~( xBitsToClear & ( ( EventBits_t ) eSELECT_ALL ) );
894 
895         if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
896         {
897             pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
898         }
899         else
900         {
901             /* disconnect it from the socket set */
902             pxSocket->pxSocketSet = NULL;
903         }
904     }
905 
906 
907 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
908 /*-----------------------------------------------------------*/
909 
910 
911 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
912 
913 /**
914  * @brief Test if a socket belongs to a socket-set and if so, which event bit(s)
915  *        are set.
916  *
917  * @param[in] xSocket The socket of interest.
918  * @param[in] xSocketSet The socket set to which the socket belongs.
919  *
920  * @return If the socket belongs to the socket set: the event bits, otherwise zero.
921  */
FreeRTOS_FD_ISSET(const ConstSocket_t xSocket,const ConstSocketSet_t xSocketSet)922     EventBits_t FreeRTOS_FD_ISSET( const ConstSocket_t xSocket,
923                                    const ConstSocketSet_t xSocketSet )
924     {
925         EventBits_t xReturn;
926         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
927 
928         configASSERT( pxSocket != NULL );
929         configASSERT( xSocketSet != NULL );
930 
931         if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet )
932         {
933             /* Make sure we're not adding bits which are reserved for internal
934              * use. */
935             xReturn = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
936         }
937         else
938         {
939             xReturn = 0;
940         }
941 
942         return xReturn;
943     }
944 
945 
946 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
947 /*-----------------------------------------------------------*/
948 
949 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
950 
951 /**
952  * @brief The select() statement: wait for an event to occur on any of the sockets
953  *        included in a socket set and return its event bits when the event occurs.
954  *
955  * @param[in] xSocketSet The socket set including the sockets on which we are
956  *                        waiting for an event to occur.
957  * @param[in] xBlockTimeTicks Maximum time ticks to wait for an event to occur.
958  *                   If the value is 'portMAX_DELAY' then the function will wait
959  *                   indefinitely for an event to occur.
960  *
961  * @return The event bits (event flags) value for the socket set in which an
962  *          event occurred. If any socket is signalled during the call, using
963  *          FreeRTOS_SignalSocket() or FreeRTOS_SignalSocketFromISR(), then eSELECT_INTR
964  *          is returned.
965  *
966  */
FreeRTOS_select(SocketSet_t xSocketSet,TickType_t xBlockTimeTicks)967     BaseType_t FreeRTOS_select( SocketSet_t xSocketSet,
968                                 TickType_t xBlockTimeTicks )
969     {
970         TimeOut_t xTimeOut;
971         TickType_t xRemainingTime;
972         SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
973         EventBits_t uxResult;
974 
975         configASSERT( xSocketSet != NULL );
976 
977         /* Only in the first round, check for non-blocking */
978         xRemainingTime = xBlockTimeTicks;
979 
980         /* Fetch the current time */
981         vTaskSetTimeOutState( &xTimeOut );
982 
983         for( ; ; )
984         {
985             /* Find a socket which might have triggered the bit
986              * This function might return immediately or block for a limited time */
987             uxResult = xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( ( EventBits_t ) eSELECT_ALL ), pdFALSE, pdFALSE, xRemainingTime );
988 
989             #if ( ipconfigSUPPORT_SIGNALS != 0 )
990                 {
991                     if( ( uxResult & ( ( EventBits_t ) eSELECT_INTR ) ) != 0U )
992                     {
993                         ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
994                         FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) );
995                         break;
996                     }
997                 }
998             #endif /* ipconfigSUPPORT_SIGNALS */
999 
1000             /* Have the IP-task find the socket which had an event */
1001             prvFindSelectedSocket( pxSocketSet );
1002 
1003             uxResult = xEventGroupGetBits( pxSocketSet->xSelectGroup );
1004 
1005             if( uxResult != 0U )
1006             {
1007                 break;
1008             }
1009 
1010             /* Has the timeout been reached? */
1011             if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
1012             {
1013                 break;
1014             }
1015         }
1016 
1017         return ( BaseType_t ) uxResult;
1018     }
1019 
1020 
1021 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
1022 /*-----------------------------------------------------------*/
1023 
1024 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
1025 
1026 /**
1027  * @brief Send a message to the IP-task to have it check all sockets belonging to
1028  *        'pxSocketSet'
1029  *
1030  * @param[in] pxSocketSet The socket set being asked to check.
1031  */
prvFindSelectedSocket(SocketSelect_t * pxSocketSet)1032     static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet )
1033     {
1034         IPStackEvent_t xSelectEvent;
1035 
1036         #if ( ipconfigSELECT_USES_NOTIFY != 0 )
1037             SocketSelectMessage_t xSelectMessage;
1038         #endif
1039 
1040         xSelectEvent.eEventType = eSocketSelectEvent;
1041         #if ( ipconfigSELECT_USES_NOTIFY != 0 )
1042             {
1043                 xSelectMessage.pxSocketSet = pxSocketSet;
1044                 xSelectMessage.xTaskhandle = xTaskGetCurrentTaskHandle();
1045                 xSelectEvent.pvData = &( xSelectMessage );
1046             }
1047         #else
1048             {
1049                 xSelectEvent.pvData = pxSocketSet;
1050 
1051                 /* while the IP-task works on the request, the API will block on
1052                  * 'eSELECT_CALL_IP'.  So clear it first. */
1053                 ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP );
1054             }
1055         #endif /* if ( ipconfigSELECT_USES_NOTIFY != 0 ) */
1056 
1057         /* Now send the socket select event */
1058         if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
1059         {
1060             /* Oops, we failed to wake-up the IP task. No use to wait for it. */
1061             FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) );
1062         }
1063         else
1064         {
1065             /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to
1066              * wakeup the calling API */
1067             #if ( ipconfigSELECT_USES_NOTIFY != 0 )
1068                 {
1069                     ( void ) ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
1070                 }
1071             #else
1072                 {
1073                     ( void ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY );
1074                 }
1075             #endif
1076         }
1077     }
1078 
1079 
1080 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
1081 /*-----------------------------------------------------------*/
1082 
1083 /**
1084  * @brief : called from FreeRTOS_recvfrom(). This function waits for an incoming
1085  *          UDP packet, or until a time-out occurs.
1086  * @param[in] pxSocket  The socket that receives UDP packets.
1087  * @param[in] xFlags  The flags as passed to FreeRTOS_recvfrom().
1088  * @param[in,out] pxEventBits  The last even received in this function,
1089  *                              either eSOCKET_INTR or eSOCKET_RECEIVE.
1090  */
prvRecvFromWaitForPacket(FreeRTOS_Socket_t const * pxSocket,BaseType_t xFlags,EventBits_t * pxEventBits)1091 static NetworkBufferDescriptor_t * prvRecvFromWaitForPacket( FreeRTOS_Socket_t const * pxSocket,
1092                                                              BaseType_t xFlags,
1093                                                              EventBits_t * pxEventBits )
1094 {
1095     BaseType_t xTimed = pdFALSE;
1096     TickType_t xRemainingTime = pxSocket->xReceiveBlockTime;
1097     BaseType_t lPacketCount;
1098     TimeOut_t xTimeOut;
1099     EventBits_t xEventBits = ( EventBits_t ) 0;
1100     NetworkBufferDescriptor_t * pxNetworkBuffer = NULL;
1101 
1102     lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
1103 
1104     while( lPacketCount == 0 )
1105     {
1106         if( xTimed == pdFALSE )
1107         {
1108             /* Check to see if the socket is non blocking on the first
1109              * iteration.  */
1110             if( xRemainingTime == ( TickType_t ) 0 )
1111             {
1112                 #if ( ipconfigSUPPORT_SIGNALS != 0 )
1113                     {
1114                         /* Just check for the interrupt flag. */
1115                         xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
1116                                                           pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
1117                     }
1118                 #endif /* ipconfigSUPPORT_SIGNALS */
1119                 break;
1120             }
1121 
1122             if( ( ( ( UBaseType_t ) xFlags ) & ( ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) ) != 0U )
1123             {
1124                 break;
1125             }
1126 
1127             /* To ensure this part only executes once. */
1128             xTimed = pdTRUE;
1129 
1130             /* Fetch the current time. */
1131             vTaskSetTimeOutState( &xTimeOut );
1132         }
1133 
1134         /* Wait for arrival of data.  While waiting, the IP-task may set the
1135          * 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
1136          * socket, thus unblocking this API call. */
1137         xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( ( EventBits_t ) eSOCKET_RECEIVE ) | ( ( EventBits_t ) eSOCKET_INTR ),
1138                                           pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
1139 
1140         #if ( ipconfigSUPPORT_SIGNALS != 0 )
1141             {
1142                 if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
1143                 {
1144                     if( ( xEventBits & ( EventBits_t ) eSOCKET_RECEIVE ) != 0U )
1145                     {
1146                         /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
1147                         ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
1148                     }
1149 
1150                     break;
1151                 }
1152             }
1153         #else /* if ( ipconfigSUPPORT_SIGNALS != 0 ) */
1154             {
1155                 ( void ) xEventBits;
1156             }
1157         #endif /* ipconfigSUPPORT_SIGNALS */
1158 
1159         lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
1160 
1161         if( lPacketCount != 0 )
1162         {
1163             break;
1164         }
1165 
1166         /* Has the timeout been reached ? */
1167         if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
1168         {
1169             break;
1170         }
1171     } /* while( lPacketCount == 0 ) */
1172 
1173     if( lPacketCount > 0 )
1174     {
1175         taskENTER_CRITICAL();
1176         {
1177             /* The owner of the list item is the network buffer. */
1178             pxNetworkBuffer = ( ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
1179 
1180             if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_PEEK ) == 0U )
1181             {
1182                 /* Remove the network buffer from the list of buffers waiting to
1183                  * be processed by the socket. */
1184                 ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
1185             }
1186         }
1187         taskEXIT_CRITICAL();
1188     }
1189 
1190     *pxEventBits = xEventBits;
1191 
1192     return pxNetworkBuffer;
1193 }
1194 /*-----------------------------------------------------------*/
1195 
1196 /**
1197  * @brief Called by FreeRTOS_recvfrom(). it will copy the received data
1198  *        or just a pointer to the received data in case of zero-copy,
1199  *        to the buffer provided by the caller.
1200  * @param[in] pucEthernetBuffer The packet that was received.
1201  * @param[in] pvBuffer The user-supplied buffer.
1202  * @param[in] uxBufferLength The size of the user-supplied buffer.
1203  * @param[in] xFlags Only 'FREERTOS_ZERO_COPY' will be tested.
1204  * @param[in] lDataLength The number of bytes in the UDP payload.
1205  * @return The number of bytes copied to the use buffer.
1206  */
prvRecvFrom_CopyPacket(uint8_t * pucEthernetBuffer,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags,int32_t lDataLength)1207 static int32_t prvRecvFrom_CopyPacket( uint8_t * pucEthernetBuffer,
1208                                        void * pvBuffer,
1209                                        size_t uxBufferLength,
1210                                        BaseType_t xFlags,
1211                                        int32_t lDataLength )
1212 {
1213     int32_t lReturn = lDataLength;
1214     const void * pvCopySource;
1215 
1216     if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
1217     {
1218         /* The zero copy flag is not set.  Truncate the length if it won't
1219          * fit in the provided buffer. */
1220         if( lReturn > ( int32_t ) uxBufferLength )
1221         {
1222             iptraceRECVFROM_DISCARDING_BYTES( ( uxBufferLength - lReturn ) );
1223             lReturn = ( int32_t ) uxBufferLength;
1224         }
1225 
1226         /* Copy the received data into the provided buffer, then release the
1227          * network buffer. */
1228         pvCopySource = ( const void * ) pucEthernetBuffer;
1229         ( void ) memcpy( pvBuffer, pvCopySource, ( size_t ) lReturn );
1230     }
1231     else
1232     {
1233         /* The zero copy flag was set.  pvBuffer is not a buffer into which
1234          * the received data can be copied, but a pointer that must be set to
1235          * point to the buffer in which the received data has already been
1236          * placed. */
1237         *( ( void ** ) pvBuffer ) = ( void * ) pucEthernetBuffer;
1238     }
1239 
1240     return lReturn;
1241 }
1242 /*-----------------------------------------------------------*/
1243 
1244 /**
1245  * @brief Receive data from a bound socket. In this library, the function
1246  *        can only be used with connection-less sockets (UDP). For TCP sockets,
1247  *        please use FreeRTOS_recv().
1248  *
1249  * @param[in] xSocket The socket to which the data is sent i.e. the
1250  *                     listening socket.
1251  * @param[out] pvBuffer The buffer in which the data being received is to
1252  *                      be stored.
1253  * @param[in] uxBufferLength The length of the buffer.
1254  * @param[in] xFlags The flags to indicate preferences while calling this function.
1255  * @param[out] pxSourceAddress The source address from which the data is being sent.
1256  * @param[out] pxSourceAddressLength The length of the source address structure.
1257  *                  This would always be a constant - 24 (in case of no error) as
1258  *                  FreeRTOS+TCP makes the sizes of IPv4 and IPv6 structures equal
1259  *                  (24-bytes) for compatibility.
1260  *
1261  * @return The number of bytes received. Or else, an error code is returned. When it
1262  *         returns a negative value, the cause can be looked-up in
1263  *         'FreeRTOS_errno_TCP.h'.
1264  */
FreeRTOS_recvfrom(const ConstSocket_t xSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags,struct freertos_sockaddr * pxSourceAddress,socklen_t * pxSourceAddressLength)1265 int32_t FreeRTOS_recvfrom( const ConstSocket_t xSocket,
1266                            void * pvBuffer,
1267                            size_t uxBufferLength,
1268                            BaseType_t xFlags,
1269                            struct freertos_sockaddr * pxSourceAddress,
1270                            socklen_t * pxSourceAddressLength )
1271 {
1272     NetworkBufferDescriptor_t * pxNetworkBuffer;
1273     FreeRTOS_Socket_t const * pxSocket = xSocket;
1274     int32_t lReturn = 0;
1275     EventBits_t xEventBits = ( EventBits_t ) 0;
1276     size_t uxPayloadOffset = 0;
1277     size_t uxPayloadLength;
1278     socklen_t xAddressLength;
1279 
1280     if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
1281     {
1282         lReturn = -pdFREERTOS_ERRNO_EINVAL;
1283     }
1284     else
1285     {
1286         /* The function prototype is designed to maintain the expected Berkeley
1287          * sockets standard, but this implementation does not use all the parameters. */
1288         ( void ) pxSourceAddressLength;
1289 
1290         pxNetworkBuffer = prvRecvFromWaitForPacket( pxSocket, xFlags, &( xEventBits ) );
1291 
1292         if( pxNetworkBuffer != NULL )
1293         {
1294             do
1295             {
1296                 switch( uxIPHeaderSizePacket( pxNetworkBuffer ) )
1297                 {
1298                     #if ( ipconfigUSE_IPv4 != 0 )
1299                         case ipSIZE_OF_IPv4_HEADER:
1300                             uxPayloadOffset = xRecv_Update_IPv4( pxNetworkBuffer, pxSourceAddress );
1301                             break;
1302                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1303 
1304                     #if ( ipconfigUSE_IPv6 != 0 )
1305                         case ipSIZE_OF_IPv6_HEADER:
1306                             uxPayloadOffset = xRecv_Update_IPv6( pxNetworkBuffer, pxSourceAddress );
1307                             break;
1308                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1309 
1310                     default:
1311                         /* MISRA 16.4 Compliance */
1312                         lReturn = -pdFREERTOS_ERRNO_EINVAL;
1313                         break;
1314                 }
1315 
1316                 if( lReturn < 0 )
1317                 {
1318                     break;
1319                 }
1320 
1321                 xAddressLength = sizeof( struct freertos_sockaddr );
1322 
1323                 if( pxSourceAddressLength != NULL )
1324                 {
1325                     *pxSourceAddressLength = xAddressLength;
1326                 }
1327 
1328                 /* The returned value is the length of the payload data, which is
1329                  * calculated at the total packet size minus the headers.
1330                  * The validity of `xDataLength` prvProcessIPPacket has been confirmed
1331                  * in 'prvProcessIPPacket()'. */
1332                 uxPayloadLength = pxNetworkBuffer->xDataLength - uxPayloadOffset;
1333                 lReturn = ( int32_t ) uxPayloadLength;
1334 
1335                 lReturn = prvRecvFrom_CopyPacket( &( pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ] ), pvBuffer, uxBufferLength, xFlags, lReturn );
1336             } while( ipFALSE_BOOL );
1337 
1338             if( ( ( ( UBaseType_t ) xFlags & ( ( ( UBaseType_t ) FREERTOS_MSG_PEEK ) | ( ( UBaseType_t ) FREERTOS_ZERO_COPY ) ) ) == 0U ) ||
1339                 ( lReturn < 0 ) )
1340             {
1341                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1342             }
1343         }
1344 
1345         #if ( ipconfigSUPPORT_SIGNALS != 0 )
1346             else if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
1347             {
1348                 lReturn = -pdFREERTOS_ERRNO_EINTR;
1349                 iptraceRECVFROM_INTERRUPTED();
1350             }
1351         #endif /* ipconfigSUPPORT_SIGNALS */
1352         else
1353         {
1354             lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
1355             iptraceRECVFROM_TIMEOUT();
1356         }
1357     }
1358 
1359     return lReturn;
1360 }
1361 /*-----------------------------------------------------------*/
1362 
1363 /**
1364  * @brief Check if a socket is a valid UDP socket. In case it is not
1365  *        yet bound, bind it to port 0 ( random port ).
1366  * @param[in] pxSocket The socket that must be bound to a port number.
1367  * @return Returns pdTRUE if the socket was already bound, or if the
1368  *         socket has been bound successfully.
1369  */
prvMakeSureSocketIsBound(FreeRTOS_Socket_t * pxSocket)1370 static BaseType_t prvMakeSureSocketIsBound( FreeRTOS_Socket_t * pxSocket )
1371 {
1372     /* Check if this is a valid UDP socket, does not have to be bound yet. */
1373     BaseType_t xReturn = prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdFALSE );
1374 
1375     if( ( xReturn == pdTRUE ) && ( !socketSOCKET_IS_BOUND( pxSocket ) ) )
1376     {
1377         /* The socket is valid but it is not yet bound. */
1378         if( FreeRTOS_bind( pxSocket, NULL, 0U ) != 0 )
1379         {
1380             /* The socket was not yet bound, and binding it has failed. */
1381             xReturn = pdFALSE;
1382         }
1383     }
1384 
1385     return xReturn;
1386 }
1387 /*-----------------------------------------------------------*/
1388 
1389 
1390 /**
1391  * @brief Forward a UDP packet to the IP-task, so it will be sent.
1392  * @param[in] pxSocket  The socket on which a packet is sent.
1393  * @param[in] pxNetworkBuffer  The packet to be sent.
1394  * @param[in] uxTotalDataLength  The total number of payload bytes in the packet.
1395  * @param[in] xFlags  The flag 'FREERTOS_ZERO_COPY' will be checked.
1396  * @param[in] pxDestinationAddress  The address of the destination.
1397  * @param[in] xTicksToWait  Number of ticks to wait, in case the IP-queue is full.
1398  * @param[in] uxPayloadOffset  The number of bytes in the packet before the payload.
1399  * @return The number of bytes sent on success, otherwise zero.
1400  */
prvSendUDPPacket(const FreeRTOS_Socket_t * pxSocket,NetworkBufferDescriptor_t * pxNetworkBuffer,size_t uxTotalDataLength,BaseType_t xFlags,const struct freertos_sockaddr * pxDestinationAddress,TickType_t xTicksToWait,size_t uxPayloadOffset)1401 static int32_t prvSendUDPPacket( const FreeRTOS_Socket_t * pxSocket,
1402                                  NetworkBufferDescriptor_t * pxNetworkBuffer,
1403                                  size_t uxTotalDataLength,
1404                                  BaseType_t xFlags,
1405                                  const struct freertos_sockaddr * pxDestinationAddress,
1406                                  TickType_t xTicksToWait,
1407                                  size_t uxPayloadOffset )
1408 {
1409     int32_t lReturn = 0;
1410     IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
1411 
1412     switch( pxDestinationAddress->sin_family ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is checked before calling. */
1413     {
1414         #if ( ipconfigUSE_IPv6 != 0 )
1415             case FREERTOS_AF_INET6:
1416                 ( void ) xSend_UDP_Update_IPv6( pxNetworkBuffer, pxDestinationAddress );
1417                 break;
1418         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1419 
1420         #if ( ipconfigUSE_IPv4 != 0 )
1421             case FREERTOS_AF_INET4:
1422                 ( void ) xSend_UDP_Update_IPv4( pxNetworkBuffer, pxDestinationAddress );
1423                 break;
1424         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1425 
1426         default:   /* LCOV_EXCL_LINE Exclude this line because default case is checked before calling. */
1427             /* MISRA 16.4 Compliance */
1428             break; /* LCOV_EXCL_LINE Exclude this line because default case is checked before calling. */
1429     }
1430 
1431     pxNetworkBuffer->xDataLength = uxTotalDataLength + uxPayloadOffset;
1432     pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
1433     pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );
1434 
1435     /* The socket options are passed to the IP layer in the
1436      * space that will eventually get used by the Ethernet header. */
1437     pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
1438 
1439     /* Tell the networking task that the packet needs sending. */
1440     xStackTxEvent.pvData = pxNetworkBuffer;
1441 
1442     /* Ask the IP-task to send this packet */
1443     if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS )
1444     {
1445         /* The packet was successfully sent to the IP task. */
1446         lReturn = ( int32_t ) uxTotalDataLength;
1447         #if ( ipconfigUSE_CALLBACKS == 1 )
1448             {
1449                 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) )
1450                 {
1451                     pxSocket->u.xUDP.pxHandleSent( ( FreeRTOS_Socket_t * ) pxSocket, uxTotalDataLength );
1452                 }
1453             }
1454         #endif /* ipconfigUSE_CALLBACKS */
1455     }
1456     else
1457     {
1458         /* If the buffer was allocated in this function, release
1459          * it. */
1460         if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
1461         {
1462             vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1463         }
1464 
1465         iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
1466     }
1467 
1468     return lReturn;
1469 }
1470 /*-----------------------------------------------------------*/
1471 
1472 /**
1473  * @brief Called by FreeRTOS_sendto(), it will actually send a UDP packet.
1474  * @param[in] pxSocket The socket used for sending.
1475  * @param[in] pvBuffer The character buffer as provided by the caller.
1476  * @param[in] uxTotalDataLength The number of byte in the buffer.
1477  * @param[in] xFlags The flags that were passed to FreeRTOS_sendto()
1478  *                    It will test for FREERTOS_MSG_DONTWAIT and for
1479  *                    FREERTOS_ZERO_COPY.
1480  * @param[in] pxDestinationAddress The IP-address to which the packet must be sent.
1481  * @param[in] uxPayloadOffset The calculated UDP payload offset, which depends
1482  *                             on the IP type: IPv4 or IPv6.
1483  * @return The number of bytes stored in the socket for transmission.
1484  */
prvSendTo_ActualSend(const FreeRTOS_Socket_t * pxSocket,const void * pvBuffer,size_t uxTotalDataLength,BaseType_t xFlags,const struct freertos_sockaddr * pxDestinationAddress,size_t uxPayloadOffset)1485 static int32_t prvSendTo_ActualSend( const FreeRTOS_Socket_t * pxSocket,
1486                                      const void * pvBuffer,
1487                                      size_t uxTotalDataLength,
1488                                      BaseType_t xFlags,
1489                                      const struct freertos_sockaddr * pxDestinationAddress,
1490                                      size_t uxPayloadOffset )
1491 {
1492     int32_t lReturn = 0;
1493     TickType_t xTicksToWait = pxSocket->xSendBlockTime;
1494     TimeOut_t xTimeOut;
1495     NetworkBufferDescriptor_t * pxNetworkBuffer;
1496 
1497     if( ( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) != 0U ) ||
1498         ( xIsCallingFromIPTask() != pdFALSE ) )
1499     {
1500         /* The caller wants a non-blocking operation. When called by the IP-task,
1501          * the operation should always be non-blocking. */
1502         xTicksToWait = ( TickType_t ) 0U;
1503     }
1504 
1505     if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
1506     {
1507         /* Zero copy is not set, so obtain a network buffer into
1508          * which the payload will be copied. */
1509         vTaskSetTimeOutState( &xTimeOut );
1510 
1511         /* Block until a buffer becomes available, or until a
1512          * timeout has been reached */
1513         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPayloadOffset + uxTotalDataLength, xTicksToWait );
1514 
1515         if( pxNetworkBuffer != NULL )
1516         {
1517             void * pvCopyDest = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ] );
1518             ( void ) memcpy( pvCopyDest, pvBuffer, uxTotalDataLength );
1519 
1520             if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
1521             {
1522                 /* The entire block time has been used up. */
1523                 xTicksToWait = ( TickType_t ) 0;
1524             }
1525         }
1526     }
1527     else
1528     {
1529         /* When zero copy is used, pvBuffer is a pointer to the
1530          * payload of a buffer that has already been obtained from the
1531          * stack.  Obtain the network buffer pointer from the buffer. */
1532         pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer );
1533     }
1534 
1535     if( pxNetworkBuffer != NULL )
1536     {
1537         pxNetworkBuffer->pxEndPoint = pxSocket->pxEndPoint;
1538         lReturn = prvSendUDPPacket( pxSocket,
1539                                     pxNetworkBuffer,
1540                                     uxTotalDataLength,
1541                                     xFlags,
1542                                     pxDestinationAddress,
1543                                     xTicksToWait,
1544                                     uxPayloadOffset );
1545     }
1546     else
1547     {
1548         /* If errno was available, errno would be set to
1549          * FREERTOS_ENOPKTS.  As it is, the function must return the
1550          * number of transmitted bytes, so the calling function knows
1551          * how  much data was actually sent. */
1552         iptraceNO_BUFFER_FOR_SENDTO();
1553     }
1554 
1555     return lReturn;
1556 }
1557 /*-----------------------------------------------------------*/
1558 
1559 /**
1560  * @brief Send data to a socket. The socket must have already been created by a
1561  *        successful call to FreeRTOS_socket(). It works for UDP-sockets only.
1562  *
1563  * @param[in] xSocket The socket being sent to.
1564  * @param[in] pvBuffer Pointer to the data being sent.
1565  * @param[in] uxTotalDataLength Length (in bytes) of the data being sent.
1566  * @param[in] xFlags Flags used to communicate preferences to the function.
1567  *                    Possibly FREERTOS_MSG_DONTWAIT and/or FREERTOS_ZERO_COPY.
1568  * @param[in] pxDestinationAddress The address to which the data is to be sent.
1569  * @param[in] xDestinationAddressLength This parameter is present to adhere to the
1570  *                  Berkeley sockets standard. Else, it is not used.
1571  *
1572  * @return When positive: the total number of bytes sent, when negative an error
1573  *         has occurred: it can be looked-up in 'FreeRTOS_errno_TCP.h'.
1574  */
FreeRTOS_sendto(Socket_t xSocket,const void * pvBuffer,size_t uxTotalDataLength,BaseType_t xFlags,const struct freertos_sockaddr * pxDestinationAddress,socklen_t xDestinationAddressLength)1575 int32_t FreeRTOS_sendto( Socket_t xSocket,
1576                          const void * pvBuffer,
1577                          size_t uxTotalDataLength,
1578                          BaseType_t xFlags,
1579                          const struct freertos_sockaddr * pxDestinationAddress,
1580                          socklen_t xDestinationAddressLength )
1581 {
1582     int32_t lReturn = 0;
1583     FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1584     size_t uxMaxPayloadLength = 0;
1585     size_t uxPayloadOffset = 0;
1586 
1587     #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
1588         struct freertos_sockaddr xTempDestinationAddress;
1589 
1590         if( ( pxDestinationAddress != NULL ) && ( pxDestinationAddress->sin_family != FREERTOS_AF_INET6 ) && ( pxDestinationAddress->sin_family != FREERTOS_AF_INET ) )
1591         {
1592             ( void ) memcpy( &xTempDestinationAddress, pxDestinationAddress, sizeof( struct freertos_sockaddr ) );
1593 
1594             /* Default to FREERTOS_AF_INET family if either FREERTOS_AF_INET6/FREERTOS_AF_INET
1595              *  is not specified in sin_family, if ipconfigIPv4_BACKWARD_COMPATIBLE is enabled. */
1596             xTempDestinationAddress.sin_family = FREERTOS_AF_INET;
1597             pxDestinationAddress = &xTempDestinationAddress;
1598         }
1599     #endif /* ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
1600 
1601     /* The function prototype is designed to maintain the expected Berkeley
1602      * sockets standard, but this implementation does not use all the
1603      * parameters. */
1604     ( void ) xDestinationAddressLength;
1605     configASSERT( pxDestinationAddress != NULL );
1606     configASSERT( pvBuffer != NULL );
1607 
1608     switch( pxDestinationAddress->sin_family )
1609     {
1610         #if ( ipconfigUSE_IPv6 != 0 )
1611             case FREERTOS_AF_INET6:
1612                 uxMaxPayloadLength = ipconfigNETWORK_MTU - ( ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_UDP_HEADER );
1613                 uxPayloadOffset = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_UDP_HEADER;
1614                 break;
1615         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1616 
1617         #if ( ipconfigUSE_IPv4 != 0 )
1618             case FREERTOS_AF_INET4:
1619                 uxMaxPayloadLength = ipconfigNETWORK_MTU - ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );
1620                 uxPayloadOffset = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER;
1621                 break;
1622         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1623 
1624         default:
1625             FreeRTOS_debug_printf( ( "FreeRTOS_sendto: Undefined sin_family \n" ) );
1626             lReturn = -pdFREERTOS_ERRNO_EINVAL;
1627             break;
1628     }
1629 
1630     if( lReturn == 0 )
1631     {
1632         if( uxTotalDataLength <= ( size_t ) uxMaxPayloadLength )
1633         {
1634             /* If the socket is not already bound to an address, bind it now.
1635              * Passing NULL as the address parameter tells FreeRTOS_bind() to select
1636              * the address to bind to. */
1637             if( prvMakeSureSocketIsBound( pxSocket ) == pdTRUE )
1638             {
1639                 lReturn = prvSendTo_ActualSend( pxSocket, pvBuffer, uxTotalDataLength, xFlags, pxDestinationAddress, uxPayloadOffset );
1640             }
1641             else
1642             {
1643                 /* No comment. */
1644                 iptraceSENDTO_SOCKET_NOT_BOUND();
1645             }
1646         }
1647         else
1648         {
1649             /* The data is longer than the available buffer space. */
1650             iptraceSENDTO_DATA_TOO_LONG();
1651         }
1652     }
1653 
1654     return lReturn;
1655 } /* Tested */
1656 /*-----------------------------------------------------------*/
1657 
1658 /**
1659  * @brief binds a socket to a local port number. If port 0 is provided,
1660  *        a system provided port number will be assigned. This function
1661  *        can be used for both UDP and TCP sockets. The actual binding
1662  *        will be performed by the IP-task to avoid mutual access to the
1663  *        bound-socket-lists (xBoundUDPSocketsList or xBoundTCPSocketsList).
1664  *
1665  * @param[in] xSocket The socket being bound.
1666  * @param[in] pxAddress The address struct carrying the port number to which
1667  *                       this socket is to be bound.
1668  * @param[in] xAddressLength This parameter is not used internally. The
1669  *                       function signature is used to adhere to standard
1670  *                       Berkeley sockets API.
1671  *
1672  * @return The return value is 0 if the bind is successful.
1673  *         If some error occurred, then a negative value is returned.
1674  */
FreeRTOS_bind(Socket_t xSocket,struct freertos_sockaddr const * pxAddress,socklen_t xAddressLength)1675 BaseType_t FreeRTOS_bind( Socket_t xSocket,
1676                           struct freertos_sockaddr const * pxAddress,
1677                           socklen_t xAddressLength )
1678 {
1679     IPStackEvent_t xBindEvent;
1680     FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1681     BaseType_t xReturn = 0;
1682 
1683     #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
1684         struct freertos_sockaddr xTempAddress;
1685 
1686         if( ( pxAddress != NULL ) && ( pxAddress->sin_family != FREERTOS_AF_INET6 ) && ( pxAddress->sin_family != FREERTOS_AF_INET ) )
1687         {
1688             ( void ) memcpy( &xTempAddress, pxAddress, sizeof( struct freertos_sockaddr ) );
1689 
1690             /* Default to FREERTOS_AF_INET family if either FREERTOS_AF_INET6/FREERTOS_AF_INET
1691              *  is not specified in sin_family, if ipconfigIPv4_BACKWARD_COMPATIBLE is enabled. */
1692             xTempAddress.sin_family = FREERTOS_AF_INET;
1693             pxAddress = &xTempAddress;
1694         }
1695     #endif /* ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
1696 
1697     ( void ) xAddressLength;
1698 
1699     configASSERT( xIsCallingFromIPTask() == pdFALSE );
1700 
1701     if( xSocketValid( pxSocket ) == pdFALSE )
1702     {
1703         xReturn = -pdFREERTOS_ERRNO_EINVAL;
1704     }
1705 
1706     /* Once a socket is bound to a port, it can not be bound to a different
1707      * port number */
1708     else if( socketSOCKET_IS_BOUND( pxSocket ) )
1709     {
1710         /* The socket is already bound. */
1711         FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) );
1712         xReturn = -pdFREERTOS_ERRNO_EINVAL;
1713     }
1714     else
1715     {
1716         /* Prepare a messages to the IP-task in order to perform the binding.
1717          * The desired port number will be passed in usLocalPort. */
1718         xBindEvent.eEventType = eSocketBindEvent;
1719         xBindEvent.pvData = xSocket;
1720 
1721         if( pxAddress != NULL )
1722         {
1723             switch( pxAddress->sin_family )
1724             {
1725                 #if ( ipconfigUSE_IPv6 != 0 )
1726                     case FREERTOS_AF_INET6:
1727                         ( void ) memcpy( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, pxAddress->sin_address.xIP_IPv6.ucBytes, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
1728                         pxSocket->bits.bIsIPv6 = pdTRUE_UNSIGNED;
1729                         break;
1730                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1731 
1732                 #if ( ipconfigUSE_IPv4 != 0 )
1733                     case FREERTOS_AF_INET4:
1734                         pxSocket->xLocalAddress.ulIP_IPv4 = FreeRTOS_ntohl( pxAddress->sin_address.ulIP_IPv4 );
1735                         pxSocket->bits.bIsIPv6 = pdFALSE_UNSIGNED;
1736                         break;
1737                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1738 
1739                 default:
1740                     FreeRTOS_debug_printf( ( "FreeRTOS_bind: Undefined sin_family \n" ) );
1741                     break;
1742             }
1743 
1744             pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
1745         }
1746         else
1747         {
1748             /* Caller wants to bind to a random port number. */
1749             pxSocket->usLocalPort = 0U;
1750             ( void ) memset( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, 0, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
1751         }
1752 
1753         /* portMAX_DELAY is used as a the time-out parameter, as binding *must*
1754          * succeed before the socket can be used.  _RB_ The use of an infinite
1755          * block time needs be changed as it could result in the task hanging. */
1756         if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
1757         {
1758             /* Failed to wake-up the IP-task, no use to wait for it */
1759             FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) );
1760             xReturn = -pdFREERTOS_ERRNO_ECANCELED;
1761         }
1762         else
1763         {
1764             /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its
1765              * job. */
1766             ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY );
1767 
1768             if( !socketSOCKET_IS_BOUND( pxSocket ) )
1769             {
1770                 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1771             }
1772         }
1773     }
1774 
1775     return xReturn;
1776 }
1777 /*-----------------------------------------------------------*/
1778 
1779 /**
1780  * @brief : Bind a socket to a port number.
1781  * @param[in] pxSocket  The socket to be bound.
1782  * @param[in] pxAddress  The socket will be bound to this address.
1783  * @param[in] pxSocketList  will either point to xBoundUDPSocketsList or
1784  *                           xBoundTCPSocketsList.
1785  * @param[in] xInternal  pdTRUE if this function is called 'internally', i.e.
1786  *                        by the IP-task.
1787  */
prvSocketBindAdd(FreeRTOS_Socket_t * pxSocket,const struct freertos_sockaddr * pxAddress,List_t * pxSocketList,BaseType_t xInternal)1788 static BaseType_t prvSocketBindAdd( FreeRTOS_Socket_t * pxSocket,
1789                                     const struct freertos_sockaddr * pxAddress,
1790                                     List_t * pxSocketList,
1791                                     BaseType_t xInternal )
1792 {
1793     BaseType_t xReturn = 0;
1794 
1795     /* Check to ensure the port is not already in use.  If the bind is
1796      * called internally, a port MAY be used by more than one socket. */
1797     if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) &&
1798         ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) )
1799     {
1800         FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n",
1801                                  ( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) ? "TC" : "UD",
1802                                  FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1803         xReturn = -pdFREERTOS_ERRNO_EADDRINUSE;
1804     }
1805     else
1806     {
1807         /* Allocate the port number to the socket.
1808          * This macro will set 'xBoundSocketListItem->xItemValue' */
1809         socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port );
1810 
1811         /* And also store it in a socket field 'usLocalPort' in host-byte-order,
1812          * mostly used for logging and debugging purposes */
1813         pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
1814 
1815         #if ( ipconfigUSE_IPv6 != 0 )
1816             if( pxAddress->sin_family == ( uint8_t ) FREERTOS_AF_INET6 )
1817             {
1818                 ( void ) memcpy( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, pxAddress->sin_address.xIP_IPv6.ucBytes, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
1819             }
1820             else
1821         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1822         {
1823             #if ( ipconfigUSE_IPv4 != 0 )
1824                 if( pxAddress->sin_address.ulIP_IPv4 != FREERTOS_INADDR_ANY )
1825                 {
1826                     pxSocket->pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( pxAddress->sin_address.ulIP_IPv4, 7 );
1827                 }
1828                 else
1829             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1830             {
1831                 /* Place holder, do nothing, MISRA compliance */
1832             }
1833         }
1834 
1835         if( pxSocket->pxEndPoint != NULL )
1836         {
1837             pxSocket->xLocalAddress.ulIP_IPv4 = FreeRTOS_ntohl( pxSocket->pxEndPoint->ipv4_settings.ulIPAddress );
1838             /*TODO Check if needed for ipv6 setting */
1839         }
1840         else
1841         #if ( ipconfigUSE_IPv6 != 0 )
1842             if( pxAddress->sin_family == ( uint8_t ) FREERTOS_AF_INET6 )
1843             {
1844                 /* Socket address was set, do nothing for IPv6. */
1845             }
1846             else
1847         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1848         {
1849             ( void ) memset( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, 0, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
1850         }
1851 
1852         /* Add the socket to the list of bound ports. */
1853         {
1854             /* If the network driver can iterate through 'xBoundUDPSocketsList',
1855              * by calling xPortHasUDPSocket() then the IP-task must temporarily
1856              * suspend the scheduler to keep the list in a consistent state. */
1857             #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1858                 {
1859                     vTaskSuspendAll();
1860                 }
1861             #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1862 
1863             /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */
1864             vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) );
1865 
1866             #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1867                 {
1868                     ( void ) xTaskResumeAll();
1869                 }
1870             #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1871         }
1872     }
1873 
1874     return xReturn;
1875 }
1876 /*-----------------------------------------------------------*/
1877 
1878 /**
1879  * @brief Internal version of bind() that should not be called directly.
1880  *        'xInternal' is used for TCP sockets only: it allows to have several
1881  *        (connected) child sockets bound to the same server port.
1882  *
1883  * @param[in] pxSocket The socket is to be bound.
1884  * @param[in] pxBindAddress The port to which this socket should be bound.
1885  * @param[in] uxAddressLength The address length.
1886  * @param[in] xInternal pdTRUE is calling internally, else pdFALSE.
1887  *
1888  * @return If the socket was bound to a port successfully, then a 0 is returned.
1889  *         Or else, an error code is returned.
1890  */
vSocketBind(FreeRTOS_Socket_t * pxSocket,struct freertos_sockaddr * pxBindAddress,size_t uxAddressLength,BaseType_t xInternal)1891 BaseType_t vSocketBind( FreeRTOS_Socket_t * pxSocket,
1892                         struct freertos_sockaddr * pxBindAddress,
1893                         size_t uxAddressLength,
1894                         BaseType_t xInternal )
1895 {
1896     BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
1897     List_t * pxSocketList;
1898     struct freertos_sockaddr * pxAddress = pxBindAddress;
1899 
1900     #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1901         struct freertos_sockaddr xAddress;
1902     #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
1903 
1904     configASSERT( xSocketValid( pxSocket ) == pdTRUE );
1905 
1906     #if ( ipconfigUSE_TCP == 1 )
1907         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1908         {
1909             pxSocketList = &xBoundTCPSocketsList;
1910         }
1911         else
1912     #endif /* ipconfigUSE_TCP == 1 */
1913     {
1914         pxSocketList = &xBoundUDPSocketsList;
1915     }
1916 
1917     /* The function prototype is designed to maintain the expected Berkeley
1918      * sockets standard, but this implementation does not use all the parameters. */
1919     ( void ) uxAddressLength;
1920 
1921     #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1922         {
1923             /* pxAddress will be NULL if sendto() was called on a socket without the
1924              * socket being bound to an address. In this case, automatically allocate
1925              * an address to the socket.  There is a small chance that the allocated
1926              * port will already be in use - if that is the case, then the check below
1927              * [pxListFindListItemWithValue()] will result in an error being returned. */
1928             if( pxAddress == NULL )
1929             {
1930                 pxAddress = &xAddress;
1931                 /* Put the port to zero to be assigned later. */
1932                 pxAddress->sin_port = 0U;
1933             }
1934         }
1935     #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
1936 
1937     /* Sockets must be bound before calling FreeRTOS_sendto() if
1938     * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
1939     configASSERT( pxAddress != NULL );
1940 
1941     #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1942         /* pxAddress is not NULL, no testing needed. */
1943     #else
1944         if( pxAddress != NULL )
1945     #endif
1946     {
1947         /* Add a do-while loop to facilitate use of 'break' statements. */
1948         do
1949         {
1950             if( pxAddress->sin_port == 0U )
1951             {
1952                 pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol );
1953 
1954                 if( pxAddress->sin_port == ( uint16_t ) 0U )
1955                 {
1956                     xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1957                     break;
1958                 }
1959             }
1960 
1961             /* If vSocketBind() is called from the API FreeRTOS_bind() it has been
1962              * confirmed that the socket was not yet bound to a port.  If it is called
1963              * from the IP-task, no such check is necessary. */
1964 
1965             xReturn = prvSocketBindAdd( pxSocket, pxAddress, pxSocketList, xInternal );
1966         } while( ipFALSE_BOOL );
1967     }
1968 
1969     #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 0 )
1970         else
1971         {
1972             xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1973             FreeRTOS_debug_printf( ( "vSocketBind: Socket has no address.\n" ) );
1974         }
1975     #endif
1976 
1977     if( xReturn != 0 )
1978     {
1979         iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1980     }
1981 
1982     return xReturn;
1983 } /* Tested */
1984 /*-----------------------------------------------------------*/
1985 
1986 /**
1987  * @brief Close a socket and free the allocated space. In case of a TCP socket:
1988  *        the connection will not be closed automatically. Subsequent messages
1989  *        for the closed socket will be responded to with a RST. The IP-task
1990  *        will actually close the socket, after receiving a 'eSocketCloseEvent'
1991  *        message.
1992  *
1993  * @param[in] xSocket the socket being closed.
1994  *
1995  * @return There are three distinct values which can be returned:
1996  *         0: If the xSocket is NULL/invalid.
1997  *         1: If the socket was successfully closed (read the brief above).
1998  *        -1: If the socket was valid but could not be closed because the message
1999  *            could not be delivered to the IP-task. Try again later.
2000  */
FreeRTOS_closesocket(Socket_t xSocket)2001 BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
2002 {
2003     BaseType_t xResult;
2004 
2005     #if ( ipconfigUSE_CALLBACKS == 1 )
2006         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2007     #endif /* ipconfigUSE_CALLBACKS == 1 */
2008     IPStackEvent_t xCloseEvent;
2009     xCloseEvent.eEventType = eSocketCloseEvent;
2010     xCloseEvent.pvData = xSocket;
2011 
2012     if( xSocketValid( xSocket ) == pdFALSE )
2013     {
2014         xResult = 0;
2015     }
2016     else
2017     {
2018         #if ( ipconfigUSE_CALLBACKS == 1 )
2019             {
2020                 #if ( ipconfigUSE_TCP == 1 )
2021                     if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2022                     {
2023                         /* Make sure that IP-task won't call the user callback's anymore */
2024                         pxSocket->u.xTCP.pxHandleConnected = NULL;
2025                         pxSocket->u.xTCP.pxHandleReceive = NULL;
2026                         pxSocket->u.xTCP.pxHandleSent = NULL;
2027                     }
2028                     else
2029                 #endif /* ipconfigUSE_TCP == 1 */
2030 
2031                 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
2032                 {
2033                     /* Clear the two UDP handlers. */
2034                     pxSocket->u.xUDP.pxHandleReceive = NULL;
2035                     pxSocket->u.xUDP.pxHandleSent = NULL;
2036                 }
2037             }
2038         #endif /* ipconfigUSE_CALLBACKS == 1 */
2039 
2040         /* Let the IP task close the socket to keep it synchronised with the
2041          * packet handling. */
2042 
2043         /* The timeout value below is only used if this function is called from
2044          * a user task. If this function is called by the IP-task, it may fail
2045          * to close the socket when the event queue is full.
2046          * This should only happen in case of a user call-back. */
2047         if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
2048         {
2049             FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) );
2050             xResult = -1;
2051         }
2052         else
2053         {
2054             xResult = 1;
2055         }
2056     }
2057 
2058     return xResult;
2059 }
2060 
2061 /**
2062  * @brief This is the internal version of FreeRTOS_closesocket(). It will
2063  *        be called by the IPtask only to avoid problems with synchronicity.
2064  *
2065  * @param[in] pxSocket The socket descriptor of the socket being closed.
2066  *
2067  * @return Returns NULL, always.
2068  */
2069 /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
2070 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
2071 /* coverity[misra_c_2012_rule_17_2_violation] */
vSocketClose(FreeRTOS_Socket_t * pxSocket)2072 void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
2073 {
2074     NetworkBufferDescriptor_t * pxNetworkBuffer;
2075 
2076     #if ( ipconfigUSE_TCP == 1 )
2077         {
2078             /* For TCP: clean up a little more. */
2079             if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2080             {
2081                 #if ( ipconfigUSE_TCP_WIN == 1 )
2082                     {
2083                         if( pxSocket->u.xTCP.pxAckMessage != NULL )
2084                         {
2085                             vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
2086                         }
2087 
2088                         /* Free the resources which were claimed by the tcpWin member */
2089                         vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow );
2090                     }
2091                 #endif /* ipconfigUSE_TCP_WIN */
2092 
2093                 /* Free the input and output streams */
2094                 if( pxSocket->u.xTCP.rxStream != NULL )
2095                 {
2096                     iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.rxStream );
2097                     vPortFreeLarge( pxSocket->u.xTCP.rxStream );
2098                 }
2099 
2100                 if( pxSocket->u.xTCP.txStream != NULL )
2101                 {
2102                     iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.txStream );
2103                     vPortFreeLarge( pxSocket->u.xTCP.txStream );
2104                 }
2105 
2106                 /* In case this is a child socket, make sure the child-count of the
2107                  * parent socket is decreased. */
2108                 prvTCPSetSocketCount( pxSocket );
2109             }
2110         }
2111     #endif /* ipconfigUSE_TCP == 1 */
2112 
2113     /* Socket must be unbound first, to ensure no more packets are queued on
2114      * it. */
2115     if( socketSOCKET_IS_BOUND( pxSocket ) )
2116     {
2117         /* If the network driver can iterate through 'xBoundUDPSocketsList',
2118          * by calling xPortHasUDPSocket(), then the IP-task must temporarily
2119          * suspend the scheduler to keep the list in a consistent state. */
2120         #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
2121             {
2122                 vTaskSuspendAll();
2123             }
2124         #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
2125 
2126         ( void ) uxListRemove( &( pxSocket->xBoundSocketListItem ) );
2127 
2128         #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
2129             {
2130                 ( void ) xTaskResumeAll();
2131             }
2132         #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
2133     }
2134 
2135     /* Now the socket is not bound the list of waiting packets can be
2136      * drained. */
2137     if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
2138     {
2139         while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U )
2140         {
2141             pxNetworkBuffer = ( ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
2142             ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
2143             vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
2144         }
2145     }
2146 
2147     if( pxSocket->xEventGroup != NULL )
2148     {
2149         vEventGroupDelete( pxSocket->xEventGroup );
2150     }
2151 
2152     #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 )
2153         {
2154             if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2155             {
2156                 FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%s]: buffers %lu socks %lu\n",
2157                                          prvSocketProps( pxSocket ),
2158                                          uxGetNumberOfFreeNetworkBuffers(),
2159                                          listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) );
2160             }
2161         }
2162     #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
2163 
2164     /* And finally, after all resources have been freed, free the socket space */
2165     iptraceMEM_STATS_DELETE( pxSocket );
2166     vPortFreeSocket( pxSocket );
2167 
2168     return NULL;
2169 } /* Tested */
2170 /*-----------------------------------------------------------*/
2171 
2172 #if ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
prvSocketProps(FreeRTOS_Socket_t * pxSocket)2173     const char * prvSocketProps( FreeRTOS_Socket_t * pxSocket )
2174     {
2175         /* For debugging purposes only: show some properties of a socket:
2176          * IP-addresses and port numbers. */
2177         #if ipconfigUSE_TCP == 1
2178             if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2179             {
2180                 switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
2181                 {
2182                     /* The use of snprintf() is discouraged by the MISRA rules.
2183                      * This code however, is only active when logging is used. */
2184 
2185                     /* The format '%pip' takes an string of 16 bytes as
2186                      * a parameter, which is an IPv6 address.
2187                      * See printf-stdarg.c */
2188 
2189                     #if ( ipconfigUSE_IPv4 != 0 )
2190                         case pdFALSE_UNSIGNED:
2191                             ( void ) snprintf( pucSocketProps, sizeof( pucSocketProps ), "%xip port %u to %xip port %u",
2192                                                ( unsigned ) pxSocket->xLocalAddress.ulIP_IPv4,
2193                                                pxSocket->usLocalPort,
2194                                                ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
2195                                                pxSocket->u.xTCP.usRemotePort );
2196                             break;
2197                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
2198 
2199                     #if ( ipconfigUSE_IPv6 != 0 )
2200                         case pdTRUE_UNSIGNED:
2201                             ( void ) snprintf( pucSocketProps, sizeof( pucSocketProps ), "%pip port %u to %pip port %u",
2202                                                ( void * ) pxSocket->xLocalAddress.xIP_IPv6.ucBytes,
2203                                                pxSocket->usLocalPort,
2204                                                ( void * ) pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes,
2205                                                pxSocket->u.xTCP.usRemotePort );
2206                             break;
2207                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
2208 
2209                     default:
2210                         /* MISRA 16.4 Compliance */
2211                         break;
2212                 }
2213             }
2214             else
2215         #endif /* if ipconfigUSE_TCP == 1 */
2216 
2217         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
2218         {
2219             switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
2220             {
2221                 #if ( ipconfigUSE_IPv4 != 0 )
2222                     case pdFALSE_UNSIGNED:
2223                         ( void ) snprintf( pucSocketProps, sizeof( pucSocketProps ),
2224                                            "%xip port %u",
2225                                            ( unsigned ) pxSocket->xLocalAddress.ulIP_IPv4,
2226                                            pxSocket->usLocalPort );
2227                         break;
2228                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
2229 
2230                 #if ( ipconfigUSE_IPv6 != 0 )
2231                     case pdTRUE_UNSIGNED:
2232                         ( void ) snprintf( pucSocketProps, sizeof( pucSocketProps ),
2233                                            "%pip port %u",
2234                                            ( void * ) pxSocket->xLocalAddress.xIP_IPv6.ucBytes,
2235                                            pxSocket->usLocalPort );
2236                         break;
2237                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
2238 
2239                 default:
2240                     /* MISRA 16.4 Compliance */
2241                     break;
2242             }
2243         }
2244         else
2245         {
2246             /* Protocol not handled. */
2247         }
2248 
2249         return pucSocketProps;
2250     }
2251 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
2252 /*-----------------------------------------------------------*/
2253 
2254 #if ipconfigUSE_TCP == 1
2255 
2256 /**
2257  * @brief When a child socket gets closed, make sure to update the child-count of the
2258  *        parent. When a listening parent socket is closed, make sure to close also
2259  *        all orphaned child-sockets.
2260  *
2261  * @param[in] pxSocketToDelete The socket being closed.
2262  */
2263     /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
2264     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
2265     /* coverity[misra_c_2012_rule_17_2_violation] */
2266     /* coverity[recursive_step] */
prvTCPSetSocketCount(FreeRTOS_Socket_t const * pxSocketToDelete)2267     static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete )
2268     {
2269         const ListItem_t * pxIterator;
2270 
2271         /* MISRA Ref 11.3.1 [Misaligned access] */
2272         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2273         /* coverity[misra_c_2012_rule_11_3_violation] */
2274         const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
2275         FreeRTOS_Socket_t * pxOtherSocket;
2276         uint16_t usLocalPort = pxSocketToDelete->usLocalPort;
2277 
2278         if( pxSocketToDelete->u.xTCP.eTCPState == eTCP_LISTEN )
2279         {
2280             pxIterator = listGET_NEXT( pxEnd );
2281 
2282             while( pxIterator != pxEnd )
2283             {
2284                 pxOtherSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
2285 
2286                 /* This needs to be done here, before calling vSocketClose. */
2287                 pxIterator = listGET_NEXT( pxIterator );
2288 
2289                 if( ( pxOtherSocket->u.xTCP.eTCPState != eTCP_LISTEN ) &&
2290                     ( pxOtherSocket->usLocalPort == usLocalPort ) &&
2291                     ( ( pxOtherSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
2292                       ( pxOtherSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) )
2293                 {
2294                     /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
2295                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
2296                     /* coverity[misra_c_2012_rule_17_2_violation] */
2297                     /* coverity[recursive_step] */
2298                     ( void ) vSocketClose( pxOtherSocket );
2299                 }
2300             }
2301         }
2302         else
2303         {
2304             for( pxIterator = listGET_NEXT( pxEnd );
2305                  pxIterator != pxEnd;
2306                  pxIterator = listGET_NEXT( pxIterator ) )
2307             {
2308                 pxOtherSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
2309 
2310                 if( ( pxOtherSocket->u.xTCP.eTCPState == eTCP_LISTEN ) &&
2311                     ( pxOtherSocket->usLocalPort == usLocalPort ) &&
2312                     ( pxOtherSocket->u.xTCP.usChildCount != 0U ) )
2313                 {
2314                     pxOtherSocket->u.xTCP.usChildCount--;
2315                     FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n",
2316                                              pxOtherSocket->usLocalPort,
2317                                              pxOtherSocket->u.xTCP.usChildCount,
2318                                              pxOtherSocket->u.xTCP.usBacklog,
2319                                              ( pxOtherSocket->u.xTCP.usChildCount == 1U ) ? "" : "ren" ) );
2320                     break;
2321                 }
2322             }
2323         }
2324     }
2325 
2326 
2327 #endif /* ipconfigUSE_TCP == 1 */
2328 
2329 /*-----------------------------------------------------------*/
2330 
2331 #if ( ipconfigUSE_TCP == 1 )
2332 
2333 /**
2334  * @brief Set the value of receive/send buffer after some preliminary checks.
2335  *
2336  * @param[in] pxSocket The socket whose options are being set.
2337  * @param[in] lOptionName The option name: either FREERTOS_SO_SNDBUF or
2338  *                         FREERTOS_SO_SNDBUF.
2339  * @param[in] pvOptionValue The value of the option being set.
2340  *
2341  * @return If there is no error, then 0 is returned. Or a negative errno
2342  *         value is returned.
2343  */
prvSockopt_so_buffer(FreeRTOS_Socket_t * pxSocket,int32_t lOptionName,const void * pvOptionValue)2344     static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
2345                                             int32_t lOptionName,
2346                                             const void * pvOptionValue )
2347     {
2348         uint32_t ulNewValue;
2349         BaseType_t xReturn;
2350 
2351         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2352         {
2353             FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
2354                                      ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
2355             xReturn = -pdFREERTOS_ERRNO_EINVAL;
2356         }
2357         else if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
2358                  ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
2359         {
2360             FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
2361                                      ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
2362             xReturn = -pdFREERTOS_ERRNO_EINVAL;
2363         }
2364         else
2365         {
2366             ulNewValue = *( ( const uint32_t * ) pvOptionValue );
2367 
2368             if( lOptionName == FREERTOS_SO_SNDBUF )
2369             {
2370                 /* Round up to nearest MSS size */
2371                 ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usMSS );
2372                 pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
2373             }
2374             else
2375             {
2376                 pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
2377             }
2378 
2379             xReturn = 0;
2380         }
2381 
2382         return xReturn;
2383     }
2384 #endif /* ipconfigUSE_TCP == 1 */
2385 /*-----------------------------------------------------------*/
2386 
2387 #if ( ipconfigUSE_CALLBACKS == 1 )
2388 
2389 /**
2390  * @brief Set a callback function for either a TCP or a UDP socket.
2391  *        The callback function will be called on-connect, on-send
2392  *        or on-receive.
2393  *
2394  * @param[in] pxSocket The socket whose options are being set.
2395  * @param[in] lOptionName The option name like FREERTOS_SO_xxx_HANDLER.
2396  * @param[in] pvOptionValue A pointer to a 'F_TCP_UDP_Handler_t',
2397  *                           which defines the handler.
2398  *
2399  * @return If there is no error, then 0 is returned. Or a negative errno
2400  *         value is returned.
2401  */
prvSetOptionCallback(FreeRTOS_Socket_t * pxSocket,int32_t lOptionName,const void * pvOptionValue)2402     BaseType_t prvSetOptionCallback( FreeRTOS_Socket_t * pxSocket,
2403                                      int32_t lOptionName,
2404                                      const void * pvOptionValue )
2405     {
2406         BaseType_t xReturn = 0;
2407 
2408         #if ( ipconfigUSE_TCP == 1 )
2409             {
2410                 UBaseType_t uxProtocol;
2411 
2412                 if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
2413                     ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
2414                 {
2415                     uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
2416                 }
2417                 else
2418                 {
2419                     uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
2420                 }
2421 
2422                 if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
2423                 {
2424                     xReturn = -pdFREERTOS_ERRNO_EINVAL;
2425                 }
2426             }
2427         #else /* if ( ipconfigUSE_TCP == 1 ) */
2428             {
2429                 /* No need to check if the socket has the right
2430                  * protocol, because only UDP sockets can be created. */
2431             }
2432         #endif /* ipconfigUSE_TCP */
2433 
2434         if( xReturn == 0 )
2435         {
2436             switch( lOptionName ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is checked before calling. */
2437             {
2438                 #if ipconfigUSE_TCP == 1
2439                     case FREERTOS_SO_TCP_CONN_HANDLER:
2440                         pxSocket->u.xTCP.pxHandleConnected = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPConnected;
2441                         break;
2442 
2443                     case FREERTOS_SO_TCP_RECV_HANDLER:
2444                         pxSocket->u.xTCP.pxHandleReceive = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPReceive;
2445                         break;
2446 
2447                     case FREERTOS_SO_TCP_SENT_HANDLER:
2448                         pxSocket->u.xTCP.pxHandleSent = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPSent;
2449                         break;
2450                 #endif /* ipconfigUSE_TCP */
2451                 case FREERTOS_SO_UDP_RECV_HANDLER:
2452                     pxSocket->u.xUDP.pxHandleReceive = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnUDPReceive;
2453                     break;
2454 
2455                 case FREERTOS_SO_UDP_SENT_HANDLER:
2456                     pxSocket->u.xUDP.pxHandleSent = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnUDPSent;
2457                     break;
2458 
2459                 default:                                /* LCOV_EXCL_LINE Exclude this line because default case is checked before calling. */
2460                     xReturn = -pdFREERTOS_ERRNO_EINVAL; /* LCOV_EXCL_LINE Exclude this line because default case is checked before calling. */
2461                     break;                              /* LCOV_EXCL_LINE Exclude this line because default case is checked before calling. */
2462             }
2463         }
2464 
2465         return xReturn;
2466     }
2467 #endif /* ( ipconfigUSE_CALLBACKS == 1 ) */
2468 /*-----------------------------------------------------------*/
2469 
2470 
2471 #if ( ipconfigUSE_TCP != 0 )
2472 
2473 /**
2474  * @brief Handle the socket option FREERTOS_SO_WIN_PROPERTIES, which sets
2475  *        the sizes of the TCP windows and the sizes of the stream buffers.
2476  *
2477  * @param[in] pxSocket The socket whose options are being set.
2478  * @param[in] pvOptionValue The pointer that is passed by the application.
2479  */
prvSetOptionTCPWindows(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2480     static BaseType_t prvSetOptionTCPWindows( FreeRTOS_Socket_t * pxSocket,
2481                                               const void * pvOptionValue )
2482     {
2483         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2484         const WinProperties_t * pxProps;
2485 
2486         do
2487         {
2488             IPTCPSocket_t * pxTCP = &( pxSocket->u.xTCP );
2489 
2490             if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2491             {
2492                 FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
2493                 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2494             }
2495 
2496             pxProps = ( const WinProperties_t * ) pvOptionValue;
2497 
2498             /* Validity of txStream will be checked by the function below. */
2499             xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ) );
2500 
2501             if( xReturn != 0 )
2502             {
2503                 break; /* will return an error. */
2504             }
2505 
2506             xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ) );
2507 
2508             if( xReturn != 0 )
2509             {
2510                 break; /* will return an error. */
2511             }
2512 
2513             #if ( ipconfigUSE_TCP_WIN == 1 )
2514                 {
2515                     pxTCP->uxRxWinSize = ( uint32_t ) pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
2516                     pxTCP->uxTxWinSize = ( uint32_t ) pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
2517                 }
2518             #else
2519                 {
2520                     pxTCP->uxRxWinSize = 1U;
2521                     pxTCP->uxTxWinSize = 1U;
2522                 }
2523             #endif
2524 
2525             /* In case the socket has already initialised its tcpWin,
2526              * adapt the window size parameters */
2527             if( pxTCP->xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
2528             {
2529                 pxTCP->xTCPWindow.xSize.ulRxWindowLength = ( uint32_t ) ( pxTCP->uxRxWinSize * pxTCP->usMSS );
2530                 pxTCP->xTCPWindow.xSize.ulTxWindowLength = ( uint32_t ) ( pxTCP->uxTxWinSize * pxTCP->usMSS );
2531             }
2532         }
2533         while( ipFALSE_BOOL );
2534 
2535         return xReturn;
2536     }
2537 #endif /* ( ipconfigUSE_TCP != 0 ) */
2538 /*-----------------------------------------------------------*/
2539 
2540 #if ( ipconfigUSE_TCP != 0 )
2541 
2542 /**
2543  * @brief Handle the socket option FREERTOS_SO_SET_LOW_HIGH_WATER, which sets
2544  *        the low- and the high-water values for TCP reception. Useful when
2545  *        streaming music.
2546  *
2547  * @param[in] pxSocket The socket whose options are being set.
2548  * @param[in] pvOptionValue The pointer that is passed by the application.
2549  */
prvSetOptionLowHighWater(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2550     static BaseType_t prvSetOptionLowHighWater( FreeRTOS_Socket_t * pxSocket,
2551                                                 const void * pvOptionValue )
2552     {
2553         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2554         const LowHighWater_t * pxLowHighWater = ( const LowHighWater_t * ) pvOptionValue;
2555 
2556         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2557         {
2558             /* It is not allowed to access 'pxSocket->u.xTCP'. */
2559             FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) );
2560         }
2561         else if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) ||
2562                  ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) )
2563         {
2564             /* Impossible values. */
2565             FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) );
2566         }
2567         else
2568         {
2569             /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */
2570             pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace;
2571             /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */
2572             pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace;
2573             xReturn = 0;
2574         }
2575 
2576         return xReturn;
2577     }
2578 #endif /* ( ipconfigUSE_TCP != 0 ) */
2579 /*-----------------------------------------------------------*/
2580 
2581 #if ( ipconfigUSE_TCP != 0 )
2582 
2583 /**
2584  * @brief Handle the socket option FREERTOS_SO_SET_FULL_SIZE.
2585  *        When enabled, the IP-stack will only send packets when
2586  *        there are at least MSS bytes to send.
2587  *
2588  * @param[in] pxSocket The socket whose options are being set.
2589  * @param[in] pvOptionValue The option name like FREERTOS_SO_xxx_HANDLER.
2590  */
prvSetOptionSetFullSize(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2591     static BaseType_t prvSetOptionSetFullSize( FreeRTOS_Socket_t * pxSocket,
2592                                                const void * pvOptionValue )
2593     {
2594         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2595 
2596         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2597         {
2598             if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2599             {
2600                 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED;
2601             }
2602             else
2603             {
2604                 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED;
2605             }
2606 
2607             if( ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) &&
2608                 ( FreeRTOS_outstanding( pxSocket ) != 0 ) )
2609             {
2610                 /* There might be some data in the TX-stream, less than full-size,
2611                  * which equals a MSS.  Wake-up the IP-task to check this. */
2612                 pxSocket->u.xTCP.usTimeout = 1U;
2613                 ( void ) xSendEventToIPTask( eTCPTimerEvent );
2614             }
2615 
2616             xReturn = 0;
2617         }
2618 
2619         return xReturn;
2620     }
2621 #endif /* ( ipconfigUSE_TCP != 0 ) */
2622 /*-----------------------------------------------------------*/
2623 
2624 #if ( ipconfigUSE_TCP != 0 )
2625 
2626 /**
2627  * @brief Handle the socket option FREERTOS_SO_STOP_RX.
2628  *        Used in applications with streaming audio: tell the peer
2629  *        to stop or continue sending data.
2630  *
2631  * @param[in] pxSocket The TCP socket used for the connection.
2632  * @param[in] pvOptionValue The option name like FREERTOS_SO_xxx_HANDLER.
2633  */
prvSetOptionStopRX(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2634     static BaseType_t prvSetOptionStopRX( FreeRTOS_Socket_t * pxSocket,
2635                                           const void * pvOptionValue )
2636     {
2637         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2638 
2639         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2640         {
2641             if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2642             {
2643                 pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED;
2644             }
2645             else
2646             {
2647                 pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED;
2648             }
2649 
2650             pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
2651             pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bRxStopped */
2652             ( void ) xSendEventToIPTask( eTCPTimerEvent );
2653             xReturn = 0;
2654         }
2655 
2656         return xReturn;
2657     }
2658 #endif /* ( ipconfigUSE_TCP != 0 ) */
2659 /*-----------------------------------------------------------*/
2660 
2661 
2662 /**
2663  * @brief Handle the socket options FREERTOS_SO_RCVTIMEO and
2664  *        FREERTOS_SO_SNDTIMEO.
2665  *        Used in applications with streaming audio: tell the peer
2666  *        to stop or continue sending data.
2667  *
2668  * @param[in] pxSocket The TCP socket used for the connection.
2669  * @param[in] pvOptionValue The option name like FREERTOS_SO_xxx_HANDLER.
2670  * @param[in] xForSend when true, handle 'FREERTOS_SO_SNDTIMEO',
2671  *            otherwise handle the option `FREERTOS_SO_RCVTIMEO`.
2672  */
prvSetOptionTimeout(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue,BaseType_t xForSend)2673 static void prvSetOptionTimeout( FreeRTOS_Socket_t * pxSocket,
2674                                  const void * pvOptionValue,
2675                                  BaseType_t xForSend )
2676 {
2677     TickType_t xBlockTime = *( ( const TickType_t * ) pvOptionValue );
2678 
2679     if( xForSend == pdTRUE )
2680     {
2681         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
2682         {
2683             /* The send time out is capped for the reason stated in the
2684              * comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
2685              * in FreeRTOSIPConfig.h (assuming an official configuration file
2686              * is being used. */
2687             if( xBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
2688             {
2689                 xBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
2690             }
2691         }
2692         else
2693         {
2694             /* For TCP socket, it isn't necessary to limit the blocking time
2695              * because  the FreeRTOS_send() function does not wait for a network
2696              * buffer to become available. */
2697         }
2698 
2699         pxSocket->xSendBlockTime = xBlockTime;
2700     }
2701     else
2702     {
2703         pxSocket->xReceiveBlockTime = xBlockTime;
2704     }
2705 }
2706 /*-----------------------------------------------------------*/
2707 
2708 #if ( ipconfigUSE_TCP != 0 )
2709 
2710 /**
2711  * @brief Handle the socket options FREERTOS_SO_REUSE_LISTEN_SOCKET.
2712  *        When set, a listening socket will turn itself into a child
2713  *        socket when it receives a connection.
2714  *
2715  * @param[in] pxSocket The TCP socket used for the connection.
2716  * @param[in] pvOptionValue The option name like FREERTOS_SO_xxx_HANDLER.
2717  */
prvSetOptionReuseListenSocket(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2718     static BaseType_t prvSetOptionReuseListenSocket( FreeRTOS_Socket_t * pxSocket,
2719                                                      const void * pvOptionValue )
2720     {
2721         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2722 
2723         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2724         {
2725             if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2726             {
2727                 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
2728             }
2729             else
2730             {
2731                 pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED;
2732             }
2733 
2734             xReturn = 0;
2735         }
2736 
2737         return xReturn;
2738     }
2739 #endif /* ( ipconfigUSE_TCP != 0 ) */
2740 /*-----------------------------------------------------------*/
2741 
2742 #if ( ipconfigUSE_TCP != 0 )
2743 
2744 /**
2745  * @brief Handle the socket options FREERTOS_SO_CLOSE_AFTER_SEND.
2746  *        As soon as the last byte has been transmitted, initiate
2747  *        a graceful closure of the TCP connection.
2748  *
2749  * @param[in] pxSocket The TCP socket used for the connection.
2750  * @param[in] pvOptionValue A pointer to a binary value of size
2751  *            BaseType_t.
2752  */
prvSetOptionCloseAfterSend(FreeRTOS_Socket_t * pxSocket,const void * pvOptionValue)2753     static BaseType_t prvSetOptionCloseAfterSend( FreeRTOS_Socket_t * pxSocket,
2754                                                   const void * pvOptionValue )
2755     {
2756         BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2757 
2758         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
2759         {
2760             if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2761             {
2762                 pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED;
2763             }
2764             else
2765             {
2766                 pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED;
2767             }
2768 
2769             xReturn = 0;
2770         }
2771 
2772         return xReturn;
2773     }
2774 #endif /* ( ipconfigUSE_TCP != 0 ) */
2775 /*-----------------------------------------------------------*/
2776 
2777 /* FreeRTOS_setsockopt calls itself, but in a very limited way,
2778  * only when FREERTOS_SO_WIN_PROPERTIES is being set. */
2779 
2780 /**
2781  * @brief Set the socket options for the given socket.
2782  *
2783  * @param[in] xSocket The socket for which the options are to be set.
2784  * @param[in] lLevel Not used. Parameter is used to maintain the Berkeley sockets
2785  *                    standard.
2786  * @param[in] lOptionName The name of the option to be set.
2787  * @param[in] pvOptionValue The value of the option to be set.
2788  * @param[in] uxOptionLength Not used. Parameter is used to maintain the Berkeley
2789  *                            sockets standard.
2790  *
2791  * @return If the option can be set with the given value, then 0 is returned. Else,
2792  *         an error code is returned.
2793  */
FreeRTOS_setsockopt(Socket_t xSocket,int32_t lLevel,int32_t lOptionName,const void * pvOptionValue,size_t uxOptionLength)2794 BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
2795                                 int32_t lLevel,
2796                                 int32_t lOptionName,
2797                                 const void * pvOptionValue,
2798                                 size_t uxOptionLength )
2799 {
2800 /* The standard Berkeley function returns 0 for success. */
2801     BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
2802     FreeRTOS_Socket_t * pxSocket;
2803 
2804     pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2805 
2806     /* The function prototype is designed to maintain the expected Berkeley
2807      * sockets standard, but this implementation does not use all the parameters. */
2808     ( void ) lLevel;
2809     ( void ) uxOptionLength;
2810 
2811     if( xSocketValid( pxSocket ) == pdTRUE )
2812     {
2813         switch( lOptionName )
2814         {
2815             case FREERTOS_SO_RCVTIMEO:
2816                 /* Receive time out. */
2817                 prvSetOptionTimeout( pxSocket, pvOptionValue, pdFALSE );
2818                 xReturn = 0;
2819                 break;
2820 
2821             case FREERTOS_SO_SNDTIMEO:
2822                 prvSetOptionTimeout( pxSocket, pvOptionValue, pdTRUE );
2823                 xReturn = 0;
2824                 break;
2825 
2826                 #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
2827                     case FREERTOS_SO_UDP_MAX_RX_PACKETS:
2828 
2829                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
2830                         {
2831                             break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2832                         }
2833 
2834                         pxSocket->u.xUDP.uxMaxPackets = *( ( const UBaseType_t * ) pvOptionValue );
2835                         xReturn = 0;
2836                         break;
2837                 #endif /* ipconfigUDP_MAX_RX_PACKETS */
2838 
2839             case FREERTOS_SO_UDPCKSUM_OUT:
2840 
2841                 /* Turn calculating of the UDP checksum on/off for this socket. If pvOptionValue
2842                  * is anything else than NULL, the checksum generation will be turned on. */
2843 
2844                 if( pvOptionValue == NULL )
2845                 {
2846                     pxSocket->ucSocketOptions &= ( ( uint8_t ) ~( ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) );
2847                 }
2848                 else
2849                 {
2850                     pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
2851                 }
2852 
2853                 xReturn = 0;
2854                 break;
2855 
2856                 #if ( ipconfigUSE_CALLBACKS == 1 )
2857                     #if ( ipconfigUSE_TCP == 1 )
2858                         case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */
2859                         case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
2860                         case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
2861                     #endif /* ipconfigUSE_TCP */
2862                     case FREERTOS_SO_UDP_RECV_HANDLER:     /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
2863                     case FREERTOS_SO_UDP_SENT_HANDLER:     /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
2864                         xReturn = prvSetOptionCallback( pxSocket, lOptionName, pvOptionValue );
2865                         break;
2866                 #endif /* ipconfigUSE_CALLBACKS */
2867 
2868                 #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
2869 
2870                     /* Each socket has a semaphore on which the using task normally
2871                      * sleeps. */
2872                     case FREERTOS_SO_SET_SEMAPHORE:
2873                         pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue );
2874                         xReturn = 0;
2875                         break;
2876                 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
2877 
2878                 #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 )
2879                     case FREERTOS_SO_WAKEUP_CALLBACK:
2880 
2881                         /* Each socket can have a callback function that is executed
2882                          * when there is an event the socket's owner might want to
2883                          * process. */
2884 
2885                         /* The type cast of the pointer expression "A" to
2886                          * type "B" removes const qualifier from the pointed to type. */
2887 
2888                         /* MISRA Ref 11.8.1 [Function pointer and use of const pointer] */
2889                         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-118 */
2890 
2891                         /* MISRA Ref 11.1.1 [ Conversion between pointer to
2892                          * a function and another type ] */
2893                         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-111 */
2894                         /* coverity[misra_c_2012_rule_11_8_violation] */
2895                         /* coverity[misra_c_2012_rule_11_1_violation] */
2896                         pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue;
2897                         xReturn = 0;
2898                         break;
2899                 #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
2900 
2901                 #if ( ipconfigUSE_TCP != 0 )
2902                     case FREERTOS_SO_SET_LOW_HIGH_WATER:
2903                         xReturn = prvSetOptionLowHighWater( pxSocket, pvOptionValue );
2904                         break;
2905 
2906                     case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */
2907                     case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */
2908                         xReturn = prvSockopt_so_buffer( pxSocket, lOptionName, pvOptionValue );
2909                         break;
2910 
2911                     case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
2912                         xReturn = prvSetOptionTCPWindows( pxSocket, pvOptionValue );
2913                         break;
2914 
2915                     case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */
2916                         xReturn = prvSetOptionReuseListenSocket( pxSocket, pvOptionValue );
2917                         break;
2918 
2919                     case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */
2920                         xReturn = prvSetOptionCloseAfterSend( pxSocket, pvOptionValue );
2921                         break;
2922 
2923                     case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS  */
2924                         xReturn = prvSetOptionSetFullSize( pxSocket, pvOptionValue );
2925                         break;
2926 
2927                     case FREERTOS_SO_STOP_RX: /* Refuse to receive more packets. */
2928                         xReturn = prvSetOptionStopRX( pxSocket, pvOptionValue );
2929                         break;
2930                 #endif /* ipconfigUSE_TCP == 1 */
2931 
2932             default:
2933                 /* No other options are handled. */
2934                 xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
2935                 break;
2936         }
2937     }
2938     else
2939     {
2940         xReturn = -pdFREERTOS_ERRNO_EINVAL;
2941     }
2942 
2943     return xReturn;
2944 } /* Tested */
2945 
2946 /*-----------------------------------------------------------*/
2947 
2948 /**
2949  * @brief Find an available port number per https://tools.ietf.org/html/rfc6056.
2950  *
2951  * @param[in] xProtocol FREERTOS_IPPROTO_TCP/FREERTOS_IPPROTO_UDP.
2952  *
2953  * @return If an available protocol port is found then that port number is returned.
2954  *         Or else, 0 is returned.
2955  */
prvGetPrivatePortNumber(BaseType_t xProtocol)2956 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )
2957 {
2958     const uint16_t usEphemeralPortCount =
2959         socketAUTO_PORT_ALLOCATION_MAX_NUMBER - ( uint16_t ) ( socketAUTO_PORT_ALLOCATION_START_NUMBER - 1U );
2960     uint16_t usIterations = usEphemeralPortCount;
2961     uint32_t ulRandomSeed = 0;
2962     uint16_t usResult = 0;
2963     const List_t * pxList;
2964 
2965     #if ipconfigUSE_TCP == 1
2966         if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP )
2967         {
2968             pxList = &xBoundTCPSocketsList;
2969         }
2970         else
2971     #endif
2972     {
2973         pxList = &xBoundUDPSocketsList;
2974     }
2975 
2976     /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */
2977     ( void ) xProtocol;
2978 
2979     /* Find the next available port using the random seed as a starting
2980      * point. */
2981     do
2982     {
2983         /* Only proceed if the random number generator succeeded. */
2984         if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE )
2985         {
2986             break;
2987         }
2988 
2989         /* Map the random to a candidate port. */
2990         usResult = ( uint16_t ) ( socketAUTO_PORT_ALLOCATION_START_NUMBER +
2991                                   ( ( ( uint16_t ) ulRandomSeed ) % usEphemeralPortCount ) );
2992 
2993         /* Check if there's already an open socket with the same protocol
2994          * and port. */
2995         if( NULL == pxListFindListItemWithValue(
2996                 pxList,
2997                 ( TickType_t ) FreeRTOS_htons( usResult ) ) )
2998         {
2999             usResult = FreeRTOS_htons( usResult );
3000             break;
3001         }
3002         else
3003         {
3004             usResult = 0;
3005         }
3006 
3007         usIterations--;
3008     }
3009     while( usIterations > 0U );
3010 
3011     return usResult;
3012 }
3013 /*-----------------------------------------------------------*/
3014 
3015 /**
3016  * @brief Find a list item associated with the wanted-item.
3017  *
3018  * @param[in] pxList The list through which the search is to be conducted.
3019  * @param[in] xWantedItemValue The wanted item whose association is to be found.
3020  *
3021  * @return The list item holding the value being searched for. If nothing is found,
3022  *         then a NULL is returned.
3023  */
pxListFindListItemWithValue(const List_t * pxList,TickType_t xWantedItemValue)3024 static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
3025                                                        TickType_t xWantedItemValue )
3026 {
3027     const ListItem_t * pxResult = NULL;
3028 
3029     if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) )
3030     {
3031         const ListItem_t * pxIterator;
3032 
3033         /* MISRA Ref 11.3.1 [Misaligned access] */
3034         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
3035         /* coverity[misra_c_2012_rule_11_3_violation] */
3036         const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxList->xListEnd ) );
3037 
3038         for( pxIterator = listGET_NEXT( pxEnd );
3039              pxIterator != pxEnd;
3040              pxIterator = listGET_NEXT( pxIterator ) )
3041         {
3042             if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue )
3043             {
3044                 pxResult = pxIterator;
3045                 break;
3046             }
3047         }
3048     }
3049 
3050     return pxResult;
3051 } /* Tested */
3052 
3053 /*-----------------------------------------------------------*/
3054 
3055 /**
3056  * @brief Find the UDP socket corresponding to the port number.
3057  *
3058  * @param[in] uxLocalPort The port whose corresponding bound UDP socket
3059  *                         is to be found.
3060  *
3061  * @return The socket owning the port if found or else NULL.
3062  */
pxUDPSocketLookup(UBaseType_t uxLocalPort)3063 FreeRTOS_Socket_t * pxUDPSocketLookup( UBaseType_t uxLocalPort )
3064 {
3065     const ListItem_t * pxListItem;
3066     FreeRTOS_Socket_t * pxSocket = NULL;
3067 
3068     /* Looking up a socket is quite simple, find a match with the local port.
3069      *
3070      * See if there is a list item associated with the port number on the
3071      * list of bound sockets. */
3072     pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort );
3073 
3074     if( pxListItem != NULL )
3075     {
3076         /* The owner of the list item is the socket itself. */
3077         pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ) );
3078         configASSERT( pxSocket != NULL );
3079     }
3080 
3081     return pxSocket;
3082 }
3083 
3084 /*-----------------------------------------------------------*/
3085 
3086 #define sockDIGIT_COUNT    ( 3U ) /**< Each nibble is expressed in at most 3 digits such as "192". */
3087 
3088 /**
3089  * @brief Convert the 32-bit representation of the IP-address to the dotted decimal
3090  *        notation after some checks.
3091  *        A safe alternative is FreeRTOS_inet_ntop4().
3092  *
3093  * @param[in] ulIPAddress 32-bit representation of the IP-address.
3094  * @param[out] pcBuffer The buffer where the dotted decimal representation will be
3095  *                      stored if all checks pass. The buffer must be at least 16
3096  *                      bytes long.
3097  *
3098  * @return The pointer returned will be same as pcBuffer and will have the address
3099  *         stored in the location.
3100  */
FreeRTOS_inet_ntoa(uint32_t ulIPAddress,char * pcBuffer)3101 const char * FreeRTOS_inet_ntoa( uint32_t ulIPAddress,
3102                                  char * pcBuffer )
3103 {
3104     socklen_t uxNibble;
3105     socklen_t uxIndex = 0;
3106     const uint8_t * pucAddress = ( const uint8_t * ) &( ulIPAddress );
3107     const char * pcResult = pcBuffer;
3108 
3109     for( uxNibble = 0; uxNibble < ipSIZE_OF_IPv4_ADDRESS; uxNibble++ )
3110     {
3111         uint8_t pucDigits[ sockDIGIT_COUNT ];
3112         uint8_t ucValue = pucAddress[ uxNibble ];
3113         socklen_t uxSource = ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U;
3114 
3115         for( ; ; )
3116         {
3117             pucDigits[ uxSource ] = ucValue % ( uint8_t ) 10U;
3118             ucValue /= ( uint8_t ) 10U;
3119 
3120             if( uxSource == 1U )
3121             {
3122                 break;
3123             }
3124 
3125             uxSource--;
3126         }
3127 
3128         pucDigits[ 0 ] = ucValue;
3129 
3130         /* Skip leading zeros. */
3131         for( uxSource = 0; uxSource < ( ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U ); uxSource++ )
3132         {
3133             if( pucDigits[ uxSource ] != 0U )
3134             {
3135                 break;
3136             }
3137         }
3138 
3139         for( ; uxSource < ( socklen_t ) sockDIGIT_COUNT; uxSource++ )
3140         {
3141             pcBuffer[ uxIndex ] = ( char ) ( pucDigits[ uxSource ] + ( char ) '0' );
3142             uxIndex++;
3143         }
3144 
3145         if( uxNibble < ( ipSIZE_OF_IPv4_ADDRESS - 1U ) )
3146         {
3147             pcBuffer[ uxIndex ] = '.';
3148         }
3149         else
3150         {
3151             pcBuffer[ uxIndex ] = '\0';
3152         }
3153 
3154         uxIndex++;
3155     }
3156 
3157     return pcResult;
3158 }
3159 /*-----------------------------------------------------------*/
3160 
3161 /**
3162  * @brief Convert the dotted decimal format of the IP-address to the 32-bit representation.
3163  *
3164  * @param[in] xAddressFamily The Address family to which the IP-address belongs to. Only
3165  *                            FREERTOS_AF_INET (IPv4) is supported.
3166  * @param[in] pcSource Pointer to the string holding the dotted decimal representation of
3167  *                      the IP-address.
3168  * @param[out] pvDestination The pointer to the address struct/variable where the converted
3169  *                            IP-address will be stored. The buffer must be 4 bytes long
3170  *                            in case of a IPv4 address.
3171  *
3172  * @return If all checks pass, then pdPASS is returned or else pdFAIL is returned.
3173  */
FreeRTOS_inet_pton(BaseType_t xAddressFamily,const char * pcSource,void * pvDestination)3174 BaseType_t FreeRTOS_inet_pton( BaseType_t xAddressFamily,
3175                                const char * pcSource,
3176                                void * pvDestination )
3177 {
3178     BaseType_t xResult;
3179 
3180     /* Printable string to struct sockaddr. */
3181     switch( xAddressFamily )
3182     {
3183         #if ( ipconfigUSE_IPv4 != 0 )
3184             case FREERTOS_AF_INET:
3185                 xResult = FreeRTOS_inet_pton4( pcSource, pvDestination );
3186                 break;
3187         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
3188 
3189         #if ( ipconfigUSE_IPv6 != 0 )
3190             case FREERTOS_AF_INET6:
3191                 xResult = FreeRTOS_inet_pton6( pcSource, pvDestination );
3192                 break;
3193         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
3194 
3195         default:
3196             xResult = -pdFREERTOS_ERRNO_EAFNOSUPPORT;
3197             break;
3198     }
3199 
3200     return xResult;
3201 }
3202 /*-----------------------------------------------------------*/
3203 
3204 /**
3205  * @brief Convert the 32-bit representation of the IP-address to the dotted
3206  *        decimal format based on the Address Family. (Only FREERTOS_AF_INET
3207  *        is allowed).
3208  *
3209  * @param[in] xAddressFamily The address family of the IP-address.
3210  * @param[in] pvSource Pointer to the 32-bit representation of IP-address.
3211  * @param[out] pcDestination The pointer to the character array where the dotted
3212  *                            decimal address will be stored if every check does pass.
3213  * @param[in] uxSize Size of the character array. This value makes sure that the code
3214  *                    doesn't write beyond it's bounds.
3215  *
3216  * @return If every check does pass, then the pointer to the pcDestination is returned
3217  *         holding the dotted decimal format of IP-address. Else, a NULL is returned.
3218  */
FreeRTOS_inet_ntop(BaseType_t xAddressFamily,const void * pvSource,char * pcDestination,socklen_t uxSize)3219 const char * FreeRTOS_inet_ntop( BaseType_t xAddressFamily,
3220                                  const void * pvSource,
3221                                  char * pcDestination,
3222                                  socklen_t uxSize )
3223 {
3224     const char * pcResult;
3225 
3226     /* Printable struct sockaddr to string. */
3227     switch( xAddressFamily )
3228     {
3229         #if ( ipconfigUSE_IPv4 != 0 )
3230             case FREERTOS_AF_INET4:
3231                 pcResult = FreeRTOS_inet_ntop4( pvSource, pcDestination, uxSize );
3232                 break;
3233         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
3234 
3235         #if ( ipconfigUSE_IPv6 != 0 )
3236             case FREERTOS_AF_INET6:
3237                 pcResult = FreeRTOS_inet_ntop6( pvSource, pcDestination, uxSize );
3238                 break;
3239         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
3240 
3241         default:
3242             /* errno should be set to pdFREERTOS_ERRNO_EAFNOSUPPORT. */
3243             pcResult = NULL;
3244             break;
3245     }
3246 
3247     return pcResult;
3248 }
3249 /*-----------------------------------------------------------*/
3250 
3251 /**
3252  * @brief Convert an ASCII character to its corresponding hexadecimal value.
3253  *        Accepted characters are 0-9, a-f, and A-F.
3254  *
3255  * @param[in] cChar The character to be converted.
3256  *
3257  * @return The hexadecimal value, between 0 and 15.
3258  *         When the character is not valid, socketINVALID_HEX_CHAR will be returned.
3259  */
3260 
ucASCIIToHex(char cChar)3261 uint8_t ucASCIIToHex( char cChar )
3262 {
3263     char cValue = cChar;
3264     uint8_t ucNew;
3265 
3266     if( ( cValue >= '0' ) && ( cValue <= '9' ) )
3267     {
3268         cValue = ( char ) ( cValue - ( uint8_t ) '0' );
3269         /* The value will be between 0 and 9. */
3270         ucNew = ( uint8_t ) cValue;
3271     }
3272     else if( ( cValue >= 'a' ) && ( cValue <= 'f' ) )
3273     {
3274         cValue = ( char ) ( cValue - ( uint8_t ) 'a' );
3275         ucNew = ( uint8_t ) cValue;
3276         /* The value will be between 10 and 15. */
3277         ucNew = ( uint8_t ) ( ucNew + ( uint8_t ) 10 );
3278     }
3279     else if( ( cValue >= 'A' ) && ( cValue <= 'F' ) )
3280     {
3281         cValue = ( char ) ( cValue - ( uint8_t ) 'A' );
3282         ucNew = ( uint8_t ) cValue;
3283         /* The value will be between 10 and 15. */
3284         ucNew = ( uint8_t ) ( ucNew + ( uint8_t ) 10 );
3285     }
3286     else
3287     {
3288         /* The character does not represent a valid hex number, return 255. */
3289         ucNew = ( uint8_t ) socketINVALID_HEX_CHAR;
3290     }
3291 
3292     return ucNew;
3293 }
3294 
3295 /*-----------------------------------------------------------*/
3296 
3297 /**
3298  * @brief This function converts a 48-bit MAC address to a human readable string.
3299  *
3300  * @param[in] pucSource A pointer to an array of 6 bytes.
3301  * @param[out] pcTarget A buffer that is 18 bytes long, it will contain the resulting string.
3302  * @param[in] cTen Either an 'A' or an 'a'. It determines whether the hex numbers will use
3303  *                  capital or small letters.
3304  * @param[in] cSeparator The separator that should appear between the bytes, either ':' or '-'.
3305  */
FreeRTOS_EUI48_ntop(const uint8_t * pucSource,char * pcTarget,char cTen,char cSeparator)3306 void FreeRTOS_EUI48_ntop( const uint8_t * pucSource,
3307                           char * pcTarget,
3308                           char cTen,
3309                           char cSeparator )
3310 {
3311     size_t uxIndex;
3312     size_t uxNibble;
3313     size_t uxTarget = 0U;
3314 
3315     for( uxIndex = 0U; uxIndex < ipMAC_ADDRESS_LENGTH_BYTES; uxIndex++ )
3316     {
3317         uint8_t ucByte = pucSource[ uxIndex ];
3318 
3319         for( uxNibble = 0; uxNibble < 2U; uxNibble++ )
3320         {
3321             uint8_t ucNibble;
3322             char cResult;
3323 
3324             if( uxNibble == 0U )
3325             {
3326                 ucNibble = ucByte >> 4;
3327             }
3328             else
3329             {
3330                 ucNibble = ucByte & 0x0FU;
3331             }
3332 
3333             if( ucNibble <= 0x09U )
3334             {
3335                 cResult = '0';
3336                 cResult = ( char ) ( cResult + ucNibble );
3337             }
3338             else
3339             {
3340                 cResult = cTen; /* Either 'a' or 'A' */
3341                 cResult = ( char ) ( cResult + ucNibble );
3342                 cResult = ( char ) ( cResult - ( uint8_t ) 10U );
3343             }
3344 
3345             pcTarget[ uxTarget ] = cResult;
3346             uxTarget++;
3347         }
3348 
3349         if( uxIndex == ( ipMAC_ADDRESS_LENGTH_BYTES - 1U ) )
3350         {
3351             pcTarget[ uxTarget ] = ( char ) 0;
3352             uxTarget++;
3353         }
3354         else
3355         {
3356             pcTarget[ uxTarget ] = cSeparator;
3357             uxTarget++;
3358         }
3359     }
3360 }
3361 /*-----------------------------------------------------------*/
3362 
3363 /**
3364  * @brief This function converts a human readable string, representing an 48-bit MAC address,
3365  *        into a 6-byte address. Valid inputs are e.g. "62:48:5:83:A0:b2" and "0-12-34-fe-dc-ba".
3366  *
3367  * @param[in] pcSource The null terminated string to be parsed.
3368  * @param[out] pucTarget A buffer that is 6 bytes long, it will contain the MAC address.
3369  *
3370  * @return pdTRUE in case the string got parsed correctly, otherwise pdFALSE.
3371  */
FreeRTOS_EUI48_pton(const char * pcSource,uint8_t * pucTarget)3372 BaseType_t FreeRTOS_EUI48_pton( const char * pcSource,
3373                                 uint8_t * pucTarget )
3374 {
3375     BaseType_t xResult = pdFALSE;
3376     size_t uxByteNr = 0U;
3377     size_t uxSourceIndex;
3378     size_t uxNibbleCount = 0U;
3379     size_t uxLength = strlen( pcSource );
3380     uint32_t uxSum = 0U;
3381     uint8_t ucHex;
3382     char cChar;
3383 
3384     /* Ignore the following line from branch coverage since the exits from this loop are
3385      * covered by break statements. The loop is kept as is to future proof the code against
3386      * any changes. LCOV_EXCL_BR_START */
3387     for( uxSourceIndex = 0U; uxSourceIndex <= uxLength; uxSourceIndex++ )
3388     /* LCOV_EXCL_BR_STOP */
3389     {
3390         cChar = pcSource[ uxSourceIndex ];
3391         ucHex = ucASCIIToHex( cChar );
3392 
3393         if( ucHex != socketINVALID_HEX_CHAR )
3394         {
3395             /* A valid nibble was found. Shift it into the accumulator. */
3396             uxSum = uxSum << 4;
3397 
3398             if( uxSum > 0xffU )
3399             {
3400                 /* A hex value was too big. */
3401                 break;
3402             }
3403 
3404             uxSum |= ucHex;
3405             uxNibbleCount++;
3406         }
3407         else
3408         {
3409             if( uxNibbleCount != 2U )
3410             {
3411                 /* Each number should have 2 nibbles. */
3412                 break;
3413             }
3414 
3415             pucTarget[ uxByteNr ] = ( uint8_t ) uxSum;
3416             uxSum = 0U;
3417             uxNibbleCount = 0U;
3418             uxByteNr++;
3419 
3420             if( uxByteNr == ipMAC_ADDRESS_LENGTH_BYTES )
3421             {
3422                 xResult = pdTRUE;
3423                 break;
3424             }
3425 
3426             if( ( cChar != ':' ) && ( cChar != '-' ) )
3427             {
3428                 /* Invalid character. */
3429                 break;
3430             }
3431         }
3432     }
3433 
3434     return xResult;
3435 }
3436 /*-----------------------------------------------------------*/
3437 
3438 #if ( ipconfigUSE_IPv4 != 0 )
3439 
3440 /**
3441  * @brief Convert the IP address from "w.x.y.z" (dotted decimal) format to the 32-bit format.
3442  *
3443  * @param[in] pcIPAddress The character string pointer holding the IP-address in the "W.X.Y.Z"
3444  *                         (dotted decimal) format.
3445  *
3446  * @return The 32-bit representation of IP(v4) address.
3447  */
FreeRTOS_inet_addr(const char * pcIPAddress)3448     uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
3449     {
3450         uint32_t ulReturn = 0U;
3451 
3452         /* inet_pton AF_INET target is a 4-byte 'struct in_addr'. */
3453         if( pdFAIL == FreeRTOS_inet_pton4( pcIPAddress, &( ulReturn ) ) )
3454         {
3455             /* Return 0 if translation failed. */
3456             ulReturn = 0U;
3457         }
3458 
3459         return ulReturn;
3460     }
3461     /*-----------------------------------------------------------*/
3462 #endif /* ipconfigUSE_IPv4 != 0 ) */
3463 
3464 /**
3465  * @brief Function to get the local address and IP port of the given socket.
3466  *
3467  * @param[in] xSocket Socket whose port is to be added to the pxAddress.
3468  * @param[out] pxAddress Structure in which the IP address and the port number
3469  *                        is returned.
3470  *
3471  * @return Size of the freertos_sockaddr structure.
3472  */
FreeRTOS_GetLocalAddress(ConstSocket_t xSocket,struct freertos_sockaddr * pxAddress)3473 size_t FreeRTOS_GetLocalAddress( ConstSocket_t xSocket,
3474                                  struct freertos_sockaddr * pxAddress )
3475 {
3476     const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
3477 
3478     switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
3479     {
3480         #if ( ipconfigUSE_IPv4 != 0 )
3481             case pdFALSE_UNSIGNED:
3482                 pxAddress->sin_family = FREERTOS_AF_INET;
3483                 pxAddress->sin_len = ( uint8_t ) sizeof( *pxAddress );
3484                 /* IP address of local machine. */
3485                 pxAddress->sin_address.ulIP_IPv4 = FreeRTOS_htonl( pxSocket->xLocalAddress.ulIP_IPv4 );
3486 
3487                 /* Local port on this machine. */
3488                 pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
3489                 break;
3490         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
3491 
3492         #if ( ipconfigUSE_IPv6 != 0 )
3493             case pdTRUE_UNSIGNED:
3494                 pxAddress->sin_family = FREERTOS_AF_INET6;
3495                 /* IP address of local machine. */
3496                 ( void ) memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, pxSocket->xLocalAddress.xIP_IPv6.ucBytes, sizeof( pxAddress->sin_address.xIP_IPv6.ucBytes ) );
3497                 /* Local port on this machine. */
3498                 pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
3499                 break;
3500         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
3501 
3502         default:
3503             /* MISRA 16.4 Compliance */
3504             break;
3505     }
3506 
3507     return sizeof( *pxAddress );
3508 }
3509 
3510 /*-----------------------------------------------------------*/
3511 
3512 /**
3513  * @brief Wake up the user of the given socket through event-groups.
3514  *
3515  * @param[in] pxSocket The socket whose user is to be woken up.
3516  */
vSocketWakeUpUser(FreeRTOS_Socket_t * pxSocket)3517 void vSocketWakeUpUser( FreeRTOS_Socket_t * pxSocket )
3518 {
3519 /* _HT_ must work this out, now vSocketWakeUpUser will be called for any important
3520  * event or transition */
3521     #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
3522         {
3523             if( pxSocket->pxUserSemaphore != NULL )
3524             {
3525                 ( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
3526             }
3527         }
3528     #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
3529 
3530     #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
3531         {
3532             if( pxSocket->pxUserWakeCallback != NULL )
3533             {
3534                 pxSocket->pxUserWakeCallback( pxSocket );
3535             }
3536         }
3537     #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
3538 
3539     #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
3540         {
3541             if( pxSocket->pxSocketSet != NULL )
3542             {
3543                 EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & ( ( EventBits_t ) eSELECT_ALL );
3544 
3545                 if( xSelectBits != 0U )
3546                 {
3547                     pxSocket->xSocketBits |= xSelectBits;
3548                     ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits );
3549                 }
3550             }
3551 
3552             pxSocket->xEventBits &= ( EventBits_t ) eSOCKET_ALL;
3553         }
3554     #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
3555 
3556     if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0U ) )
3557     {
3558         ( void ) xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits );
3559     }
3560 
3561     pxSocket->xEventBits = 0U;
3562 }
3563 
3564 /*-----------------------------------------------------------*/
3565 
3566 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
3567 
3568 /**
3569  * @brief This define makes it possible for network interfaces to inspect
3570  *        UDP messages and see if there is any UDP socket bound to a given port
3571  *        number.  This is probably only useful in systems with a minimum of
3572  *        RAM and when lots of anonymous broadcast messages come in.
3573  *
3574  * @param[in] usPortNr the port number to look for.
3575  *
3576  * @return xFound if a socket with the port number is found.
3577  */
xPortHasUDPSocket(uint16_t usPortNr)3578     BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
3579     {
3580         BaseType_t xFound = pdFALSE;
3581 
3582         vTaskSuspendAll();
3583         {
3584             if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) )
3585             {
3586                 xFound = pdTRUE;
3587             }
3588         }
3589         ( void ) xTaskResumeAll();
3590 
3591         return xFound;
3592     }
3593 
3594 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
3595 
3596 /*-----------------------------------------------------------*/
3597 
3598 #if ( ipconfigUSE_TCP == 1 )
3599 
3600 /**
3601  * @brief Check if it makes any sense to wait for a connect event.
3602  *
3603  * @param[in] pxSocket The socket trying to connect.
3604  *
3605  * @return It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
3606  */
bMayConnect(FreeRTOS_Socket_t const * pxSocket)3607     static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket )
3608     {
3609         BaseType_t xResult;
3610 
3611         eIPTCPState_t eState = pxSocket->u.xTCP.eTCPState;
3612 
3613         switch( eState )
3614         {
3615             case eCLOSED:
3616             case eCLOSE_WAIT:
3617                 xResult = 0;
3618                 break;
3619 
3620             case eCONNECT_SYN:
3621                 xResult = -pdFREERTOS_ERRNO_EINPROGRESS;
3622                 break;
3623 
3624             case eTCP_LISTEN:
3625             case eSYN_FIRST:
3626             case eSYN_RECEIVED:
3627             case eESTABLISHED:
3628             case eFIN_WAIT_1:
3629             case eFIN_WAIT_2:
3630             case eCLOSING:
3631             case eLAST_ACK:
3632             case eTIME_WAIT:
3633             default:
3634                 xResult = -pdFREERTOS_ERRNO_EAGAIN;
3635                 break;
3636         }
3637 
3638         return xResult;
3639     }
3640 
3641 
3642 #endif /* ipconfigUSE_TCP */
3643 /*-----------------------------------------------------------*/
3644 
3645 #if ( ipconfigUSE_TCP == 1 )
3646 
3647 /**
3648  * @brief Called from #FreeRTOS_connect(): make some checks and if allowed,
3649  *        send a message to the IP-task to start connecting to a remote socket.
3650  *
3651  * @param[in] pxSocket The socket attempting to connect to a remote port.
3652  * @param[in] pxAddress The address the socket is trying to connect to.
3653  *
3654  * @return 0 on successful checks or a negative error code.
3655  */
prvTCPConnectStart(FreeRTOS_Socket_t * pxSocket,struct freertos_sockaddr const * pxAddress)3656     static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
3657                                           struct freertos_sockaddr const * pxAddress )
3658     {
3659         BaseType_t xResult = 0;
3660 
3661         if( pxAddress == NULL )
3662         {
3663             /* NULL address passed to the function. Invalid value. */
3664             xResult = -pdFREERTOS_ERRNO_EINVAL;
3665         }
3666         else if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE )
3667         {
3668             /* Not a valid socket or wrong type */
3669             xResult = -pdFREERTOS_ERRNO_EBADF;
3670         }
3671         else if( FreeRTOS_issocketconnected( pxSocket ) > 0 )
3672         {
3673             /* The socket is already connected. */
3674             xResult = -pdFREERTOS_ERRNO_EISCONN;
3675         }
3676         else if( !socketSOCKET_IS_BOUND( pxSocket ) )
3677         {
3678             /* Bind the socket to the port that the client task will send from.
3679              * Non-standard, so the error returned is that returned by bind(). */
3680             xResult = FreeRTOS_bind( pxSocket, NULL, 0U );
3681         }
3682         else
3683         {
3684             /* The socket is valid, not yet connected, and already bound to a port number. */
3685         }
3686 
3687         if( xResult == 0 )
3688         {
3689             /* Check if it makes any sense to wait for a connect event, this condition
3690              * might change while sleeping, so it must be checked within each loop */
3691             xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */
3692 
3693             /* Start the connect procedure, kernel will start working on it */
3694             if( xResult == 0 )
3695             {
3696                 pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE;
3697                 pxSocket->u.xTCP.ucRepCount = 0U;
3698 
3699                 switch( pxAddress->sin_family )
3700                 {
3701                     #if ( ipconfigUSE_IPv6 != 0 )
3702                         case FREERTOS_AF_INET6:
3703                             pxSocket->bits.bIsIPv6 = pdTRUE_UNSIGNED;
3704                             FreeRTOS_printf( ( "FreeRTOS_connect: %u to %pip port %u\n",
3705                                                pxSocket->usLocalPort, ( void * ) pxAddress->sin_address.xIP_IPv6.ucBytes,
3706                                                FreeRTOS_ntohs( pxAddress->sin_port ) ) );
3707                             ( void ) memcpy( pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, pxAddress->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
3708                             break;
3709                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
3710 
3711                     #if ( ipconfigUSE_IPv4 != 0 )
3712                         case FREERTOS_AF_INET4:
3713                             pxSocket->bits.bIsIPv6 = pdFALSE_UNSIGNED;
3714                             FreeRTOS_printf( ( "FreeRTOS_connect: %u to %xip:%u\n",
3715                                                pxSocket->usLocalPort, ( unsigned int ) FreeRTOS_ntohl( pxAddress->sin_address.ulIP_IPv4 ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
3716                             pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 = FreeRTOS_ntohl( pxAddress->sin_address.ulIP_IPv4 );
3717                             break;
3718                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
3719 
3720                     default:
3721                         FreeRTOS_debug_printf( ( "FreeRTOS_connect: Undefined sin_family \n" ) );
3722                         break;
3723                 }
3724 
3725                 /* Port on remote machine. */
3726                 pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port );
3727 
3728                 /* (client) internal state: socket wants to send a connect. */
3729                 vTCPStateChange( pxSocket, eCONNECT_SYN );
3730 
3731                 /* To start an active connect. */
3732                 pxSocket->u.xTCP.usTimeout = 1U;
3733 
3734                 if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS )
3735                 {
3736                     xResult = -pdFREERTOS_ERRNO_ECANCELED;
3737                 }
3738             }
3739         }
3740 
3741         return xResult;
3742     }
3743 
3744 
3745 #endif /* ipconfigUSE_TCP */
3746 /*-----------------------------------------------------------*/
3747 
3748 #if ( ipconfigUSE_TCP == 1 )
3749 
3750 /**
3751  * @brief Connect to a remote port.
3752  *
3753  * @param[in] xClientSocket The socket initiating the connection.
3754  * @param[in] pxAddress The address of the remote socket.
3755  * @param[in] xAddressLength This parameter is not used. It is kept in
3756  *                   the function signature to adhere to the Berkeley
3757  *                   sockets standard.
3758  *
3759  * @return 0 is returned on a successful connection, else a negative
3760  *         error code is returned.
3761  */
FreeRTOS_connect(Socket_t xClientSocket,const struct freertos_sockaddr * pxAddress,socklen_t xAddressLength)3762     BaseType_t FreeRTOS_connect( Socket_t xClientSocket,
3763                                  const struct freertos_sockaddr * pxAddress,
3764                                  socklen_t xAddressLength )
3765     {
3766         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xClientSocket;
3767         TickType_t xRemainingTime;
3768         BaseType_t xTimed = pdFALSE;
3769         BaseType_t xResult = -pdFREERTOS_ERRNO_EINVAL;
3770         TimeOut_t xTimeOut;
3771 
3772         ( void ) xAddressLength;
3773 
3774         #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
3775             struct freertos_sockaddr xTempAddress;
3776 
3777             if( ( pxAddress != NULL ) && ( pxAddress->sin_family != FREERTOS_AF_INET6 ) && ( pxAddress->sin_family != FREERTOS_AF_INET ) )
3778             {
3779                 ( void ) memcpy( &xTempAddress, pxAddress, sizeof( struct freertos_sockaddr ) );
3780 
3781                 /* Default to FREERTOS_AF_INET family if either FREERTOS_AF_INET6/FREERTOS_AF_INET
3782                  *  is not specified in sin_family, if ipconfigIPv4_BACKWARD_COMPATIBLE is enabled. */
3783                 xTempAddress.sin_family = FREERTOS_AF_INET;
3784                 pxAddress = &xTempAddress;
3785             }
3786         #endif /* ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
3787 
3788         xResult = prvTCPConnectStart( pxSocket, pxAddress );
3789 
3790         if( xResult == 0 )
3791         {
3792             /* And wait for the result */
3793             for( ; ; )
3794             {
3795                 EventBits_t uxEvents;
3796 
3797                 if( xTimed == pdFALSE )
3798                 {
3799                     /* Only in the first round, check for non-blocking */
3800                     xRemainingTime = pxSocket->xReceiveBlockTime;
3801 
3802                     if( xRemainingTime == ( TickType_t ) 0 )
3803                     {
3804                         /* Not yet connected, correct state, non-blocking. */
3805                         xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK;
3806                         break;
3807                     }
3808 
3809                     /* Don't get here a second time. */
3810                     xTimed = pdTRUE;
3811 
3812                     /* Fetch the current time */
3813                     vTaskSetTimeOutState( &xTimeOut );
3814                 }
3815 
3816                 /* Did it get connected while sleeping ? */
3817                 xResult = FreeRTOS_issocketconnected( pxSocket );
3818 
3819                 /* Returns positive when connected, negative means an error */
3820                 if( xResult < 0 )
3821                 {
3822                     /* Return the error */
3823                     break;
3824                 }
3825 
3826                 if( xResult > 0 )
3827                 {
3828                     /* Socket now connected, return a zero */
3829                     xResult = 0;
3830                     break;
3831                 }
3832 
3833                 /* Is it allowed to sleep more? */
3834                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
3835                 {
3836                     xResult = -pdFREERTOS_ERRNO_ETIMEDOUT;
3837                     break;
3838                 }
3839 
3840                 /* Go sleeping until we get any down-stream event */
3841                 uxEvents = xEventGroupWaitBits( pxSocket->xEventGroup,
3842                                                 ( EventBits_t ) eSOCKET_CONNECT | ( EventBits_t ) eSOCKET_CLOSED,
3843                                                 pdTRUE /*xClearOnExit*/,
3844                                                 pdFALSE /*xWaitAllBits*/,
3845                                                 xRemainingTime );
3846 
3847                 if( ( uxEvents & ( EventBits_t ) eSOCKET_CLOSED ) != 0U )
3848                 {
3849                     xResult = -pdFREERTOS_ERRNO_ENOTCONN;
3850                     FreeRTOS_debug_printf( ( "FreeRTOS_connect() stopped due to an error\n" ) );
3851                     break;
3852                 }
3853             }
3854         }
3855 
3856         return xResult;
3857     }
3858 
3859 #endif /* ipconfigUSE_TCP */
3860 /*-----------------------------------------------------------*/
3861 
3862 #if ( ipconfigUSE_TCP == 1 )
3863 
3864 /**
3865  * @brief Check if a new connection has come in for a socket in listen mode.
3866  *
3867  * @param[in] pxParentSocket  The parent socket, which is in listening mode.
3868  * @param[out] pxAddress  The address of the peer will be filled in 'pxAddress'.
3869  * @param[in] pxAddressLength  The actual size of the space pointed to by 'pxAddress'.
3870  * @return A new connected socket or NULL.
3871  */
prvAcceptWaitClient(FreeRTOS_Socket_t * pxParentSocket,struct freertos_sockaddr * pxAddress,socklen_t * pxAddressLength)3872     static FreeRTOS_Socket_t * prvAcceptWaitClient( FreeRTOS_Socket_t * pxParentSocket,
3873                                                     struct freertos_sockaddr * pxAddress,
3874                                                     socklen_t * pxAddressLength )
3875     {
3876         FreeRTOS_Socket_t * pxClientSocket = NULL;
3877 
3878         /* Is there a new client? */
3879         vTaskSuspendAll();
3880         {
3881             if( pxParentSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
3882             {
3883                 pxClientSocket = pxParentSocket->u.xTCP.pxPeerSocket;
3884             }
3885             else
3886             {
3887                 pxClientSocket = pxParentSocket;
3888             }
3889 
3890             if( pxClientSocket != NULL )
3891             {
3892                 pxParentSocket->u.xTCP.pxPeerSocket = NULL;
3893 
3894                 /* Is it still not taken ? */
3895                 if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED )
3896                 {
3897                     pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED;
3898                 }
3899                 else
3900                 {
3901                     pxClientSocket = NULL;
3902                 }
3903             }
3904         }
3905         ( void ) xTaskResumeAll();
3906 
3907         if( pxClientSocket != NULL )
3908         {
3909             if( pxAddressLength != NULL )
3910             {
3911                 *pxAddressLength = sizeof( struct freertos_sockaddr );
3912             }
3913 
3914             switch( pxClientSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
3915             {
3916                 #if ( ipconfigUSE_IPv4 != 0 )
3917                     case pdFALSE_UNSIGNED:
3918 
3919                         if( pxAddress != NULL )
3920                         {
3921                             pxAddress->sin_family = FREERTOS_AF_INET4;
3922                             /* Copy IP-address and port number. */
3923                             pxAddress->sin_address.ulIP_IPv4 = FreeRTOS_ntohl( pxClientSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
3924                             pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
3925                         }
3926                         break;
3927                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
3928 
3929                 #if ( ipconfigUSE_IPv6 != 0 )
3930                     case pdTRUE_UNSIGNED:
3931 
3932                         if( pxAddress != NULL )
3933                         {
3934                             pxAddress->sin_family = FREERTOS_AF_INET6;
3935                             /* Copy IP-address and port number. */
3936                             ( void ) memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, pxClientSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
3937                             pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
3938                         }
3939                         break;
3940                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
3941 
3942                 default:
3943                     /* MISRA 16.4 Compliance */
3944                     break;
3945             }
3946         }
3947 
3948         return pxClientSocket;
3949     }
3950 #endif /* ( ipconfigUSE_TCP == 1 ) */
3951 /*-----------------------------------------------------------*/
3952 
3953 #if ( ipconfigUSE_TCP == 1 )
3954 
3955 /**
3956  * @brief Accept a connection on an listening socket.
3957  *
3958  * @param[in] xServerSocket The socket in listening mode.
3959  * @param[out] pxAddress The address of the machine trying to connect to this node
3960  *                        is returned in this pointer.
3961  * @param[out] pxAddressLength The length of the address of the remote machine.
3962  *
3963  * @return FreeRTOS_accept: can return a new connected socket if the server socket
3964  *         is in listen mode and receives a connection request. The new socket will
3965  *         be bound already to the same port number as the listening socket.
3966  */
FreeRTOS_accept(Socket_t xServerSocket,struct freertos_sockaddr * pxAddress,socklen_t * pxAddressLength)3967     Socket_t FreeRTOS_accept( Socket_t xServerSocket,
3968                               struct freertos_sockaddr * pxAddress,
3969                               socklen_t * pxAddressLength )
3970     {
3971         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket;
3972         FreeRTOS_Socket_t * pxClientSocket = NULL;
3973         TickType_t xRemainingTime;
3974         BaseType_t xTimed = pdFALSE;
3975         TimeOut_t xTimeOut;
3976         IPStackEvent_t xAskEvent;
3977 
3978         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3979         {
3980             /* Not a valid socket or wrong type */
3981 
3982             /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
3983             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
3984             /* coverity[misra_c_2012_rule_11_4_violation] */
3985             pxClientSocket = FREERTOS_INVALID_SOCKET;
3986         }
3987         else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) &&
3988                  ( pxSocket->u.xTCP.eTCPState != eTCP_LISTEN ) )
3989         {
3990             /* Parent socket is not in listening mode */
3991 
3992             /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
3993             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
3994             /* coverity[misra_c_2012_rule_11_4_violation] */
3995             pxClientSocket = FREERTOS_INVALID_SOCKET;
3996         }
3997         else
3998         {
3999             /* Loop will stop with breaks. */
4000             for( ; ; )
4001             {
4002                 pxClientSocket = prvAcceptWaitClient( pxSocket, pxAddress, pxAddressLength );
4003 
4004                 if( pxClientSocket != NULL )
4005                 {
4006                     if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
4007                     {
4008                         /* Ask to set an event in 'xEventGroup' as soon as a new
4009                          * client gets connected for this listening socket. */
4010                         xAskEvent.eEventType = eTCPAcceptEvent;
4011                         xAskEvent.pvData = pxSocket;
4012                         ( void ) xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY );
4013                     }
4014 
4015                     break;
4016                 }
4017 
4018                 if( xTimed == pdFALSE )
4019                 {
4020                     /* Only in the first round, check for non-blocking */
4021                     xRemainingTime = pxSocket->xReceiveBlockTime;
4022 
4023                     if( xRemainingTime == ( TickType_t ) 0 )
4024                     {
4025                         break;
4026                     }
4027 
4028                     /* Don't get here a second time */
4029                     xTimed = pdTRUE;
4030 
4031                     /* Fetch the current time */
4032                     vTaskSetTimeOutState( &xTimeOut );
4033                 }
4034 
4035                 /* Has the timeout been reached? */
4036                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
4037                 {
4038                     break;
4039                 }
4040 
4041                 /* Put the calling task to 'sleep' until a down-stream event is received. */
4042                 ( void ) xEventGroupWaitBits( pxSocket->xEventGroup,
4043                                               ( EventBits_t ) eSOCKET_ACCEPT,
4044                                               pdTRUE /*xClearOnExit*/,
4045                                               pdFALSE /*xWaitAllBits*/,
4046                                               xRemainingTime );
4047             }
4048         }
4049 
4050         return pxClientSocket;
4051     }
4052 
4053 #endif /* ipconfigUSE_TCP */
4054 /*-----------------------------------------------------------*/
4055 
4056 #if ( ipconfigUSE_TCP == 1 )
4057 
4058 /**
4059  * @brief After all checks have been done in FreeRTOS_recv()
4060  *        read the data from the stream buffer.
4061  *
4062  * @param[in] pxSocket The socket owning the connection.
4063  * @param[out] pvBuffer The buffer to store the incoming data in.
4064  * @param[in] uxBufferLength The length of the buffer so that the function
4065  *                            does not do out of bound access.
4066  * @param[in] xFlags The flags for conveying preference. This routine
4067  *                    will check for 'FREERTOS_ZERO_COPY and/or'.
4068  *
4069  * @return The number of bytes actually received and stored in the pvBuffer.
4070  */
prvRecvData(FreeRTOS_Socket_t * pxSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags)4071     static BaseType_t prvRecvData( FreeRTOS_Socket_t * pxSocket,
4072                                    void * pvBuffer,
4073                                    size_t uxBufferLength,
4074                                    BaseType_t xFlags )
4075     {
4076         BaseType_t xByteCount;
4077 
4078         if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) == 0U )
4079         {
4080             BaseType_t xIsPeek = ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_PEEK ) != 0U ) ? 1L : 0L;
4081 
4082             xByteCount = ( BaseType_t )
4083                          uxStreamBufferGet( pxSocket->u.xTCP.rxStream,
4084                                             0U,
4085                                             ( uint8_t * ) pvBuffer,
4086                                             ( size_t ) uxBufferLength,
4087                                             xIsPeek );
4088 
4089             if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
4090             {
4091                 /* We had reached the low-water mark, now see if the flag
4092                  * can be cleared */
4093                 size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
4094 
4095                 if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
4096                 {
4097                     pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED;
4098                     pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
4099                     pxSocket->u.xTCP.usTimeout = 1U; /* because bLowWater is cleared. */
4100                     ( void ) xSendEventToIPTask( eTCPTimerEvent );
4101                 }
4102             }
4103         }
4104         else
4105         {
4106             /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
4107             xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, ( uint8_t ** ) pvBuffer );
4108         }
4109 
4110         return xByteCount;
4111     }
4112 #endif /* ipconfigUSE_TCP */
4113 /*-----------------------------------------------------------*/
4114 
4115 #if ( ipconfigUSE_TCP == 1 )
4116 
4117 /**
4118  * @brief After FreeRTOS_recv() has checked the validity of the parameters,
4119  *        this routine will wait for data to arrive in the stream buffer.
4120  *
4121  * @param[in] pxSocket The socket owning the connection.
4122  * @param[out] pxEventBits A bit-mask of socket events will be set:
4123  *             eSOCKET_RECEIVE, eSOCKET_CLOSED, and or eSOCKET_INTR.
4124  * @param[in] xFlags flags passed by the user, only 'FREERTOS_MSG_DONTWAIT'
4125  *            is checked in this function.
4126  */
prvRecvWait(const FreeRTOS_Socket_t * pxSocket,EventBits_t * pxEventBits,BaseType_t xFlags)4127     static BaseType_t prvRecvWait( const FreeRTOS_Socket_t * pxSocket,
4128                                    EventBits_t * pxEventBits,
4129                                    BaseType_t xFlags )
4130     {
4131         BaseType_t xByteCount = 0;
4132         TickType_t xRemainingTime;
4133         BaseType_t xTimed = pdFALSE;
4134         TimeOut_t xTimeOut;
4135         EventBits_t xEventBits = ( EventBits_t ) 0U;
4136 
4137         if( pxSocket->u.xTCP.rxStream != NULL )
4138         {
4139             xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
4140         }
4141 
4142         while( xByteCount == 0 )
4143         {
4144             eIPTCPState_t eType = ( eIPTCPState_t ) pxSocket->u.xTCP.eTCPState;
4145 
4146             if( ( eType == eCLOSED ) ||
4147                 ( eType == eCLOSE_WAIT ) || /* (server + client) waiting for a connection termination request from the local user. */
4148                 ( eType == eCLOSING ) )     /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
4149             {
4150                 /* Return -ENOTCONN, unless there was a malloc failure. */
4151                 xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
4152 
4153                 if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
4154                 {
4155                     /* The no-memory error has priority above the non-connected error.
4156                      * Both are fatal and will lead to closing the socket. */
4157                     xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
4158                 }
4159 
4160                 break;
4161             }
4162 
4163             if( xTimed == pdFALSE )
4164             {
4165                 /* Only in the first round, check for non-blocking. */
4166                 xRemainingTime = pxSocket->xReceiveBlockTime;
4167 
4168                 if( xRemainingTime == ( TickType_t ) 0U )
4169                 {
4170                     #if ( ipconfigSUPPORT_SIGNALS != 0 )
4171                         {
4172                             /* Just check for the interrupt flag. */
4173                             xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
4174                                                               pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
4175                         }
4176                     #endif /* ipconfigSUPPORT_SIGNALS */
4177                     break;
4178                 }
4179 
4180                 if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
4181                 {
4182                     break;
4183                 }
4184 
4185                 /* Don't get here a second time. */
4186                 xTimed = pdTRUE;
4187 
4188                 /* Fetch the current time. */
4189                 vTaskSetTimeOutState( &xTimeOut );
4190             }
4191 
4192             /* Has the timeout been reached? */
4193             if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
4194             {
4195                 break;
4196             }
4197 
4198             /* Block until there is a down-stream event. */
4199             xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
4200                                               ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED | ( EventBits_t ) eSOCKET_INTR,
4201                                               pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
4202             #if ( ipconfigSUPPORT_SIGNALS != 0 )
4203                 {
4204                     if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
4205                     {
4206                         break;
4207                     }
4208                 }
4209             #else
4210                 {
4211                     ( void ) xEventBits;
4212                 }
4213             #endif /* ipconfigSUPPORT_SIGNALS */
4214 
4215             if( pxSocket->u.xTCP.rxStream != NULL )
4216             {
4217                 xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
4218             }
4219         } /* while( xByteCount == 0 ) */
4220 
4221         *( pxEventBits ) = xEventBits;
4222 
4223         return xByteCount;
4224     }
4225 /*-----------------------------------------------------------*/
4226 #endif /* ( ipconfigUSE_TCP == 1 ) */
4227 
4228 #if ( ipconfigUSE_TCP == 1 )
4229 
4230 /**
4231  * @brief Read incoming data from a TCP socket. Only after the last
4232  *        byte has been read, a close error might be returned.
4233  *
4234  * @param[in] xSocket The socket owning the connection.
4235  * @param[out] pvBuffer The buffer to store the incoming data in.
4236  * @param[in] uxBufferLength The length of the buffer so that the function
4237  *                            does not do out of bound access.
4238  * @param[in] xFlags The flags for conveying preference. The values
4239  *                    FREERTOS_MSG_DONTWAIT, FREERTOS_ZERO_COPY and/or
4240  *                    FREERTOS_MSG_PEEK can be used.
4241  *
4242  * @return The number of bytes actually received and stored in the pvBuffer.
4243  */
FreeRTOS_recv(Socket_t xSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags)4244     BaseType_t FreeRTOS_recv( Socket_t xSocket,
4245                               void * pvBuffer,
4246                               size_t uxBufferLength,
4247                               BaseType_t xFlags )
4248     {
4249         BaseType_t xByteCount = 0;
4250         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
4251         EventBits_t xEventBits = ( EventBits_t ) 0U;
4252 
4253         /* Check if the socket is valid, has type TCP and if it is bound to a
4254          * port. */
4255         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
4256         {
4257             xByteCount = -pdFREERTOS_ERRNO_EINVAL;
4258         }
4259         else if( ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) != 0U ) &&
4260                  ( pvBuffer == NULL ) )
4261         {
4262             /* In zero-copy mode, pvBuffer is a pointer to a pointer ( not NULL ). */
4263             xByteCount = -pdFREERTOS_ERRNO_EINVAL;
4264         }
4265         else
4266         {
4267             /* The function parameters have been checked, now wait for incoming data. */
4268             xByteCount = prvRecvWait( pxSocket, &( xEventBits ), xFlags );
4269 
4270             #if ( ipconfigSUPPORT_SIGNALS != 0 )
4271                 if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
4272                 {
4273                     if( ( xEventBits & ( ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED ) ) != 0U )
4274                     {
4275                         /* Shouldn't have cleared other flags. */
4276                         xEventBits &= ~( ( EventBits_t ) eSOCKET_INTR );
4277                         ( void ) xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
4278                     }
4279 
4280                     xByteCount = -pdFREERTOS_ERRNO_EINTR;
4281                 }
4282                 else
4283             #endif /* ipconfigSUPPORT_SIGNALS */
4284 
4285             if( xByteCount > 0 )
4286             {
4287                 /* Get the actual data from the buffer, or in case of zero-copy,
4288                  * let *pvBuffer point to the RX-stream of the socket. */
4289                 xByteCount = prvRecvData( pxSocket, pvBuffer, uxBufferLength, xFlags );
4290             }
4291         } /* prvValidSocket() */
4292 
4293         return xByteCount;
4294     }
4295 
4296 
4297 #endif /* ipconfigUSE_TCP */
4298 /*-----------------------------------------------------------*/
4299 
4300 #if ( ipconfigUSE_TCP == 1 )
4301 
4302 /**
4303  * @brief Called from FreeRTOS_send(): some checks which will be done before
4304  *        sending a TCP packed.
4305  *
4306  * @param[in] pxSocket The socket owning the connection.
4307  * @param[in] uxDataLength The length of the data to be sent.
4308  *
4309  * @return 0: representing OK, else a negative error code will be returned.
4310  */
prvTCPSendCheck(FreeRTOS_Socket_t * pxSocket,size_t uxDataLength)4311     static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
4312                                     size_t uxDataLength )
4313     {
4314         int32_t xResult = 1;
4315 
4316         /* Is this a socket of type TCP and is it already bound to a port number ? */
4317         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
4318         {
4319             xResult = -pdFREERTOS_ERRNO_EINVAL;
4320         }
4321         else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
4322         {
4323             xResult = -pdFREERTOS_ERRNO_ENOMEM;
4324         }
4325         else if( ( pxSocket->u.xTCP.eTCPState == eCLOSED ) ||
4326                  ( pxSocket->u.xTCP.eTCPState == eCLOSE_WAIT ) ||
4327                  ( pxSocket->u.xTCP.eTCPState == eCLOSING ) )
4328         {
4329             xResult = -pdFREERTOS_ERRNO_ENOTCONN;
4330         }
4331         else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
4332         {
4333             /* This TCP connection is closing already, the FIN flag has been sent.
4334              * Maybe it is still delivering or receiving data.
4335              * Return OK in order not to get closed/deleted too quickly */
4336             xResult = 0;
4337         }
4338         else if( uxDataLength == 0U )
4339         {
4340             /* send() is being called to send zero bytes */
4341             xResult = 0;
4342         }
4343         else if( pxSocket->u.xTCP.txStream == NULL )
4344         {
4345             /* Create the outgoing stream only when it is needed */
4346             ( void ) prvTCPCreateStream( pxSocket, pdFALSE );
4347 
4348             if( pxSocket->u.xTCP.txStream == NULL )
4349             {
4350                 xResult = -pdFREERTOS_ERRNO_ENOMEM;
4351             }
4352         }
4353         else
4354         {
4355             /* Nothing. */
4356         }
4357 
4358         return xResult;
4359     }
4360 
4361 #endif /* ipconfigUSE_TCP */
4362 /*-----------------------------------------------------------*/
4363 
4364 #if ( ipconfigUSE_TCP == 1 )
4365 
4366 /**
4367  * @brief Get a direct pointer to the circular transmit buffer.
4368  *
4369  * @param[in] xSocket The socket owning the buffer.
4370  * @param[in] pxLength This will contain the number of bytes that may be written.
4371  *
4372  * @return Head of the circular transmit buffer if all checks pass. Or else, NULL
4373  *         is returned.
4374  */
FreeRTOS_get_tx_head(ConstSocket_t xSocket,BaseType_t * pxLength)4375     uint8_t * FreeRTOS_get_tx_head( ConstSocket_t xSocket,
4376                                     BaseType_t * pxLength )
4377     {
4378         uint8_t * pucReturn = NULL;
4379         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4380         StreamBuffer_t * pxBuffer = NULL;
4381 
4382         *pxLength = 0;
4383 
4384         /* Confirm that this is a TCP socket before dereferencing structure
4385          * member pointers. */
4386         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
4387         {
4388             pxBuffer = pxSocket->u.xTCP.txStream;
4389 
4390             if( pxBuffer != NULL )
4391             {
4392                 size_t uxSpace = uxStreamBufferGetSpace( pxBuffer );
4393                 size_t uxRemain = pxBuffer->LENGTH - pxBuffer->uxHead;
4394 
4395                 if( uxRemain <= uxSpace )
4396                 {
4397                     *pxLength = ( BaseType_t ) uxRemain;
4398                 }
4399                 else
4400                 {
4401                     *pxLength = ( BaseType_t ) uxSpace;
4402                 }
4403 
4404                 pucReturn = &( pxBuffer->ucArray[ pxBuffer->uxHead ] );
4405             }
4406         }
4407 
4408         return pucReturn;
4409     }
4410 #endif /* ipconfigUSE_TCP */
4411 /*-----------------------------------------------------------*/
4412 
4413 #if ( ipconfigUSE_TCP == 1 )
4414 
4415 /**
4416  * @brief This internal function will try to send as many bytes as possible to a TCP-socket.
4417  *
4418  * @param[in] pxSocket  The socket owning the connection.
4419  * @param[in] pvBuffer  The buffer containing the data to be sent.
4420  * @param[in] uxDataLength  The number of bytes contained in the buffer.
4421  * @param[in] xFlags  Only the flag 'FREERTOS_MSG_DONTWAIT' will be tested.
4422  *
4423  * @result The number of bytes queued for transmission.
4424  */
prvTCPSendLoop(FreeRTOS_Socket_t * pxSocket,const void * pvBuffer,size_t uxDataLength,BaseType_t xFlags)4425     static BaseType_t prvTCPSendLoop( FreeRTOS_Socket_t * pxSocket,
4426                                       const void * pvBuffer,
4427                                       size_t uxDataLength,
4428                                       BaseType_t xFlags )
4429     {
4430         /* The number of bytes sent. */
4431         BaseType_t xBytesSent = 0;
4432         /* xBytesLeft is the number of bytes that still must be sent. */
4433         BaseType_t xBytesLeft = ( BaseType_t ) uxDataLength;
4434         /* xByteCount is number of bytes that can be sent now. */
4435         BaseType_t xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
4436         TickType_t xRemainingTime;
4437         BaseType_t xTimed = pdFALSE;
4438         TimeOut_t xTimeOut;
4439         const uint8_t * pucSource = ( const uint8_t * ) pvBuffer;
4440 
4441         /* While there are still bytes to be sent. */
4442         while( xBytesLeft > 0 )
4443         {
4444             /* If txStream has space. */
4445             if( xByteCount > 0 )
4446             {
4447                 BaseType_t xCloseAfterSend = pdFALSE;
4448 
4449                 /* Don't send more than necessary. */
4450                 if( xByteCount > xBytesLeft )
4451                 {
4452                     xByteCount = xBytesLeft;
4453                 }
4454 
4455                 if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) &&
4456                     ( xByteCount == xBytesLeft ) )
4457                 {
4458                     xCloseAfterSend = pdTRUE;
4459 
4460                     /* Now suspend the scheduler: sending the last data and
4461                      * setting bCloseRequested must be done together */
4462                     vTaskSuspendAll();
4463                     pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED;
4464 
4465                     /* The flag 'bCloseAfterSend' can be set before sending data
4466                      * using setsockopt()
4467                      *
4468                      * When the last data packet is being sent out, a FIN flag will
4469                      * be included to let the peer know that no more data is to be
4470                      * expected.  The use of 'bCloseAfterSend' is not mandatory, it
4471                      * is just a faster way of transferring files (e.g. when using
4472                      * FTP). */
4473                 }
4474 
4475                 xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0U, pucSource, ( size_t ) xByteCount );
4476 
4477                 if( xCloseAfterSend == pdTRUE )
4478                 {
4479                     /* Now when the IP-task transmits the data, it will also
4480                      * see that bCloseRequested is true and include the FIN
4481                      * flag to start closure of the connection. */
4482                     ( void ) xTaskResumeAll();
4483                 }
4484 
4485                 /* Send a message to the IP-task so it can work on this
4486                 * socket.  Data is sent, let the IP-task work on it. */
4487                 pxSocket->u.xTCP.usTimeout = 1U;
4488 
4489                 if( xIsCallingFromIPTask() == pdFALSE )
4490                 {
4491                     /* Only send a TCP timer event when not called from the
4492                      * IP-task. */
4493                     ( void ) xSendEventToIPTask( eTCPTimerEvent );
4494                 }
4495 
4496                 xBytesLeft -= xByteCount;
4497                 xBytesSent += xByteCount;
4498 
4499                 if( ( xBytesLeft == 0 ) && ( pvBuffer == NULL ) )
4500                 {
4501                     /* pvBuffer can be NULL in case TCP zero-copy transmissions are used. */
4502                     break;
4503                 }
4504 
4505                 /* As there are still bytes left to be sent, increase the
4506                  * data pointer. */
4507                 pucSource = &( pucSource[ xByteCount ] );
4508             } /* if( xByteCount > 0 ) */
4509 
4510             /* Not all bytes have been sent. In case the socket is marked as
4511              * blocking sleep for a while. */
4512             if( xTimed == pdFALSE )
4513             {
4514                 /* Only in the first round, check for non-blocking. */
4515                 xRemainingTime = pxSocket->xSendBlockTime;
4516 
4517                 if( xIsCallingFromIPTask() != pdFALSE )
4518                 {
4519                     /* If this send function is called from within a
4520                      * call-back handler it may not block, otherwise
4521                      * chances would be big to get a deadlock: the IP-task
4522                      * waiting for itself. */
4523                     xRemainingTime = ( TickType_t ) 0U;
4524                 }
4525 
4526                 if( xRemainingTime == ( TickType_t ) 0U )
4527                 {
4528                     break;
4529                 }
4530 
4531                 if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
4532                 {
4533                     break;
4534                 }
4535 
4536                 /* Don't get here a second time. */
4537                 xTimed = pdTRUE;
4538 
4539                 /* Fetch the current time. */
4540                 vTaskSetTimeOutState( &xTimeOut );
4541             }
4542             else
4543             {
4544                 /* Has the timeout been reached? */
4545                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
4546                 {
4547                     break;
4548                 }
4549             }
4550 
4551             /* Go sleeping until a SEND or a CLOSE event is received. */
4552             ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_SEND | ( EventBits_t ) eSOCKET_CLOSED,
4553                                           pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
4554 
4555             xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
4556 
4557             if( xByteCount < 0 )
4558             {
4559                 /* In a meanwhile, the connection has dropped, stop iterating. */
4560                 break;
4561             }
4562 
4563             /* See if in a meanwhile there is space in the TX-stream. */
4564             xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
4565         } /* while( xBytesLeft > 0 ) */
4566 
4567         return xBytesSent;
4568     }
4569 
4570 /**
4571  * @brief Send data using a TCP socket. It is not necessary to have the socket
4572  *        connected already. Outgoing data will be stored and delivered as soon as
4573  *        the socket gets connected.
4574  *
4575  * @param[in] xSocket  The socket owning the connection.
4576  * @param[in] pvBuffer The buffer containing the data. The value of this pointer
4577  *                      may be NULL in case zero-copy transmissions are used.
4578  *                      It is used in combination with 'FreeRTOS_get_tx_head()'.
4579  * @param[in] uxDataLength The length of the data to be added.
4580  * @param[in] xFlags This parameter is not used. (zero or FREERTOS_MSG_DONTWAIT).
4581  *
4582  * @return The number of bytes actually sent. Zero when nothing could be sent
4583  *         or a negative error code in case an error occurred.
4584  */
FreeRTOS_send(Socket_t xSocket,const void * pvBuffer,size_t uxDataLength,BaseType_t xFlags)4585     BaseType_t FreeRTOS_send( Socket_t xSocket,
4586                               const void * pvBuffer,
4587                               size_t uxDataLength,
4588                               BaseType_t xFlags )
4589     {
4590         BaseType_t xByteCount = -pdFREERTOS_ERRNO_EINVAL;
4591         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
4592 
4593         if( pvBuffer != NULL )
4594         {
4595             /* Check if this is a valid TCP socket, affirm that it is not closed or closing,
4596              * affirm that there was not malloc-problem, test if uxDataLength is non-zero,
4597              * and if the connection is not in a confirmed FIN state. */
4598             xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
4599         }
4600 
4601         if( xByteCount > 0 )
4602         {
4603             /* prvTCPSendLoop() will try to send as many bytes as possible,
4604              * returning number of bytes that have been queued for transmission.. */
4605             xByteCount = prvTCPSendLoop( pxSocket, pvBuffer, uxDataLength, xFlags );
4606 
4607             if( xByteCount == 0 )
4608             {
4609                 if( pxSocket->u.xTCP.eTCPState > eESTABLISHED )
4610                 {
4611                     xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
4612                 }
4613                 else
4614                 {
4615                     if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
4616                     {
4617                         FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %xip:%d: no space\n",
4618                                                  pxSocket->usLocalPort,
4619                                                  ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4,
4620                                                  pxSocket->u.xTCP.usRemotePort ) );
4621                     }
4622 
4623                     xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC;
4624                 }
4625             }
4626         }
4627 
4628         return xByteCount;
4629     }
4630 
4631 
4632 #endif /* ipconfigUSE_TCP */
4633 /*-----------------------------------------------------------*/
4634 
4635 #if ( ipconfigUSE_TCP == 1 )
4636 
4637 /**
4638  * @brief Request to put a socket in listen mode.
4639  *
4640  * @param[in] xSocket the socket to be put in listening mode.
4641  * @param[in] xBacklog Maximum number of child sockets.
4642  *
4643  * @return 0 in case of success, or else a negative error code is
4644  *         returned.
4645  */
4646     /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
4647     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
4648     /* coverity[misra_c_2012_rule_17_2_violation] */
4649     /* coverity[recursive_step] */
FreeRTOS_listen(Socket_t xSocket,BaseType_t xBacklog)4650     BaseType_t FreeRTOS_listen( Socket_t xSocket,
4651                                 BaseType_t xBacklog )
4652     {
4653         FreeRTOS_Socket_t * pxSocket;
4654         BaseType_t xResult = 0;
4655 
4656         pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
4657 
4658         /* listen() is allowed for a valid TCP socket in Closed state and already
4659          * bound. */
4660         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
4661         {
4662             xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
4663         }
4664         else if( ( pxSocket->u.xTCP.eTCPState != eCLOSED ) && ( pxSocket->u.xTCP.eTCPState != eCLOSE_WAIT ) )
4665         {
4666             /* Socket is in a wrong state. */
4667             xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
4668         }
4669         else
4670         {
4671             /* Backlog is interpreted here as "the maximum number of child
4672              * sockets. */
4673             pxSocket->u.xTCP.usBacklog = ( uint16_t ) FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog );
4674 
4675             /* This cleaning is necessary only if a listening socket is being
4676              * reused as it might have had a previous connection. */
4677             if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
4678             {
4679                 if( pxSocket->u.xTCP.rxStream != NULL )
4680                 {
4681                     vStreamBufferClear( pxSocket->u.xTCP.rxStream );
4682                 }
4683 
4684                 if( pxSocket->u.xTCP.txStream != NULL )
4685                 {
4686                     vStreamBufferClear( pxSocket->u.xTCP.txStream );
4687                 }
4688 
4689                 ( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
4690                 ( void ) memset( &pxSocket->u.xTCP.xTCPWindow, 0, sizeof( pxSocket->u.xTCP.xTCPWindow ) );
4691                 ( void ) memset( &pxSocket->u.xTCP.bits, 0, sizeof( pxSocket->u.xTCP.bits ) );
4692 
4693                 /* Now set the bReuseSocket flag again, because the bits have
4694                  * just been cleared. */
4695                 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
4696             }
4697 
4698             vTCPStateChange( pxSocket, eTCP_LISTEN );
4699         }
4700 
4701         return xResult;
4702     }
4703 
4704 
4705 #endif /* ipconfigUSE_TCP */
4706 /*-----------------------------------------------------------*/
4707 
4708 #if ( ipconfigUSE_TCP == 1 )
4709 
4710 /**
4711  * @brief Shutdown - This function will shut down the connection in both
4712  *        directions. However, it will first deliver all data queued for
4713  *        transmission, and also it will first wait to receive any missing
4714  *        packets from the peer.
4715  *
4716  * @param[in] xSocket The socket owning the connection.
4717  * @param[in] xHow Not used. Just present to stick to Berkeley standard.
4718  *
4719  * @return 0 on successful shutdown or else a negative error code.
4720  */
FreeRTOS_shutdown(Socket_t xSocket,BaseType_t xHow)4721     BaseType_t FreeRTOS_shutdown( Socket_t xSocket,
4722                                   BaseType_t xHow )
4723     {
4724         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
4725         BaseType_t xResult;
4726 
4727         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
4728         {
4729             /*_RB_ Is this comment correct?  The socket is not of a type that
4730              * supports the listen() operation. */
4731             xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
4732         }
4733         else if( pxSocket->u.xTCP.eTCPState != eESTABLISHED )
4734         {
4735             /* The socket is not connected. */
4736             xResult = -pdFREERTOS_ERRNO_ENOTCONN;
4737         }
4738         else
4739         {
4740             pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED;
4741 
4742             /* Let the IP-task perform the shutdown of the connection. */
4743             pxSocket->u.xTCP.usTimeout = 1U;
4744             ( void ) xSendEventToIPTask( eTCPTimerEvent );
4745             xResult = 0;
4746         }
4747 
4748         ( void ) xHow;
4749 
4750         return xResult;
4751     }
4752 
4753 
4754 #endif /* ipconfigUSE_TCP */
4755 /*-----------------------------------------------------------*/
4756 
4757 #if ( ipconfigUSE_TCP == 1 )
4758 
4759 /**
4760  * @brief A TCP timer has expired, now check all TCP sockets for:
4761  *        - Active connect
4762  *        - Send a delayed ACK
4763  *        - Send new data
4764  *        - Send a keep-alive packet
4765  *        - Check for timeout (in non-connected states only)
4766  *
4767  * @param[in] xWillSleep Whether the calling task is going to sleep.
4768  *
4769  * @return Minimum amount of time before the timer shall expire.
4770  */
xTCPTimerCheck(BaseType_t xWillSleep)4771     TickType_t xTCPTimerCheck( BaseType_t xWillSleep )
4772     {
4773         FreeRTOS_Socket_t * pxSocket;
4774         TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS );
4775         TickType_t xNow = xTaskGetTickCount();
4776         static TickType_t xLastTime = 0U;
4777         TickType_t xDelta = xNow - xLastTime;
4778 
4779         /* MISRA Ref 11.3.1 [Misaligned access] */
4780         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4781         /* coverity[misra_c_2012_rule_11_3_violation] */
4782         const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
4783 
4784         /* MISRA Ref 11.3.1 [Misaligned access] */
4785         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4786         /* coverity[misra_c_2012_rule_11_3_violation] */
4787         const ListItem_t * pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
4788 
4789         xLastTime = xNow;
4790 
4791         if( xDelta == 0U )
4792         {
4793             xDelta = 1U;
4794         }
4795 
4796         while( pxIterator != pxEnd )
4797         {
4798             pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4799             pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator );
4800 
4801             /* Sockets with 'timeout == 0' do not need any regular attention. */
4802             if( pxSocket->u.xTCP.usTimeout == 0U )
4803             {
4804                 continue;
4805             }
4806 
4807             if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout )
4808             {
4809                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta );
4810             }
4811             else
4812             {
4813                 BaseType_t xRc;
4814 
4815                 pxSocket->u.xTCP.usTimeout = 0U;
4816                 xRc = xTCPSocketCheck( pxSocket );
4817 
4818                 /* Within this function, the socket might want to send a delayed
4819                  * ack or send out data or whatever it needs to do. */
4820                 if( xRc < 0 )
4821                 {
4822                     /* Continue because the socket was deleted. */
4823                     continue;
4824                 }
4825             }
4826 
4827             /* In xEventBits the driver may indicate that the socket has
4828              * important events for the user.  These are only done just before the
4829              * IP-task goes to sleep. */
4830             if( pxSocket->xEventBits != 0U )
4831             {
4832                 if( xWillSleep != pdFALSE )
4833                 {
4834                     /* The IP-task is about to go to sleep, so messages can be
4835                      * sent to the socket owners. */
4836                     vSocketWakeUpUser( pxSocket );
4837                 }
4838                 else
4839                 {
4840                     /* Or else make sure this will be called again to wake-up
4841                      * the sockets' owner. */
4842                     xShortest = ( TickType_t ) 0;
4843                 }
4844             }
4845 
4846             if( ( pxSocket->u.xTCP.usTimeout != 0U ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) )
4847             {
4848                 xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout;
4849             }
4850         }
4851 
4852         return xShortest;
4853     }
4854 
4855 
4856 #endif /* ipconfigUSE_TCP */
4857 /*-----------------------------------------------------------*/
4858 
4859 #if ( ipconfigUSE_TCP == 1 )
4860 
4861 /**
4862  * @brief As multiple sockets may be bound to the same local port number
4863  *        looking up a socket is a little more complex: Both a local port,
4864  *        and a remote port and IP address are being used to find a match.
4865  *        For a socket in listening mode, the remote port and IP address
4866  *        are both 0.
4867  *
4868  * @param[in] ulLocalIP Local IP address. Ignored for now.
4869  * @param[in] uxLocalPort Local port number.
4870  * @param[in] xRemoteIP Remote (peer) IP address.
4871  * @param[in] uxRemotePort Remote (peer) port.
4872  *
4873  * @return The socket which was found.
4874  */
pxTCPSocketLookup(uint32_t ulLocalIP,UBaseType_t uxLocalPort,IPv46_Address_t xRemoteIP,UBaseType_t uxRemotePort)4875     FreeRTOS_Socket_t * pxTCPSocketLookup( uint32_t ulLocalIP,
4876                                            UBaseType_t uxLocalPort,
4877                                            IPv46_Address_t xRemoteIP,
4878                                            UBaseType_t uxRemotePort )
4879     {
4880         const ListItem_t * pxIterator;
4881         FreeRTOS_Socket_t * pxResult = NULL, * pxListenSocket = NULL;
4882 
4883         /* MISRA Ref 11.3.1 [Misaligned access] */
4884         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4885         /* coverity[misra_c_2012_rule_11_3_violation] */
4886         const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
4887 
4888         /* __XX__ TODO ulLocalIP is not used, for misra compliance*/
4889         ( void ) ulLocalIP;
4890 
4891         for( pxIterator = listGET_NEXT( pxEnd );
4892              pxIterator != pxEnd;
4893              pxIterator = listGET_NEXT( pxIterator ) )
4894         {
4895             FreeRTOS_Socket_t * pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4896 
4897             if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort )
4898             {
4899                 if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
4900                 {
4901                     /* If this is a socket listening to uxLocalPort, remember it
4902                      * in case there is no perfect match. */
4903                     pxListenSocket = pxSocket;
4904                 }
4905                 else if( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort )
4906                 {
4907                     if( xRemoteIP.xIs_IPv6 != pdFALSE )
4908                     {
4909                         #if ( ipconfigUSE_IPv6 != 0 )
4910                             pxResult = pxTCPSocketLookup_IPv6( pxSocket, &xRemoteIP );
4911                         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
4912                     }
4913                     else
4914                     {
4915                         if( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 == xRemoteIP.xIPAddress.ulIP_IPv4 )
4916                         {
4917                             /* For sockets not in listening mode, find a match with
4918                              * xLocalPort, ulRemoteIP AND xRemotePort. */
4919                             pxResult = pxSocket;
4920                         }
4921                     }
4922 
4923                     if( pxResult != NULL )
4924                     {
4925                         break;
4926                     }
4927                 }
4928                 else
4929                 {
4930                     /* This 'pxSocket' doesn't match. */
4931                 }
4932             }
4933         }
4934 
4935         if( pxResult == NULL )
4936         {
4937             /* An exact match was not found, maybe a listening socket was
4938              * found. */
4939             pxResult = pxListenSocket;
4940         }
4941 
4942         return pxResult;
4943     }
4944 
4945 #endif /* ipconfigUSE_TCP */
4946 /*-----------------------------------------------------------*/
4947 
4948 #if ( ipconfigUSE_TCP == 1 )
4949 
4950 /**
4951  * @brief For the web server: borrow the circular Rx buffer for inspection.
4952  *        HTML driver wants to see if a sequence of 13/10/13/10 is available.
4953  *
4954  * @param[in] xSocket The socket whose Rx stream is to be returned.
4955  *
4956  * @return The Rx stream of the socket if all checks pass, else NULL.
4957  */
FreeRTOS_get_rx_buf(ConstSocket_t xSocket)4958     const struct xSTREAM_BUFFER * FreeRTOS_get_rx_buf( ConstSocket_t xSocket )
4959     {
4960         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4961         const struct xSTREAM_BUFFER * pxReturn = NULL;
4962 
4963 
4964         /* Confirm that this is a TCP socket before dereferencing structure
4965          * member pointers. */
4966         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
4967         {
4968             pxReturn = pxSocket->u.xTCP.rxStream;
4969         }
4970 
4971         return pxReturn;
4972     }
4973 
4974 #endif /* ipconfigUSE_TCP */
4975 /*-----------------------------------------------------------*/
4976 
4977 #if ( ipconfigUSE_TCP == 1 )
4978 
4979 /**
4980  * @brief Create the stream buffer for the given socket.
4981  *
4982  * @param[in] pxSocket the socket to create the stream for.
4983  * @param[in] xIsInputStream Is this input stream? pdTRUE/pdFALSE?
4984  *
4985  * @return The stream buffer.
4986  */
prvTCPCreateStream(FreeRTOS_Socket_t * pxSocket,BaseType_t xIsInputStream)4987     static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
4988                                                 BaseType_t xIsInputStream )
4989     {
4990         StreamBuffer_t * pxBuffer;
4991         size_t uxLength;
4992         size_t uxSize;
4993 
4994         /* Now that a stream is created, the maximum size is fixed before
4995          * creation, it could still be changed with setsockopt(). */
4996         if( xIsInputStream != pdFALSE )
4997         {
4998             size_t uxLittlePerc = sock20_PERCENT;
4999             size_t uxEnoughPerc = sock80_PERCENT;
5000             size_t uxSegmentCount = pxSocket->u.xTCP.uxRxStreamSize / pxSocket->u.xTCP.usMSS;
5001             static const struct Percent
5002             {
5003                 size_t uxPercLittle, uxPercEnough;
5004             }
5005             xPercTable[] =
5006             {
5007                 { 0U,  100U }, /* 1 segment. */
5008                 { 50U, 100U }, /* 2 segments. */
5009                 { 34U, 100U }, /* 3 segments. */
5010                 { 25U, 100U }, /* 4 segments. */
5011             };
5012 
5013             if( ( uxSegmentCount > 0U ) &&
5014                 ( uxSegmentCount <= ARRAY_USIZE( xPercTable ) ) )
5015             {
5016                 uxLittlePerc = xPercTable[ uxSegmentCount - 1U ].uxPercLittle;
5017                 uxEnoughPerc = xPercTable[ uxSegmentCount - 1U ].uxPercEnough;
5018             }
5019 
5020             uxLength = pxSocket->u.xTCP.uxRxStreamSize;
5021 
5022             if( pxSocket->u.xTCP.uxLittleSpace == 0U )
5023             {
5024                 pxSocket->u.xTCP.uxLittleSpace = ( uxLittlePerc * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
5025             }
5026 
5027             if( pxSocket->u.xTCP.uxEnoughSpace == 0U )
5028             {
5029                 pxSocket->u.xTCP.uxEnoughSpace = ( uxEnoughPerc * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
5030             }
5031         }
5032         else
5033         {
5034             uxLength = pxSocket->u.xTCP.uxTxStreamSize;
5035         }
5036 
5037         /* Add an extra 4 (or 8) bytes. */
5038         uxLength += sizeof( size_t );
5039 
5040         /* And make the length a multiple of sizeof( size_t ). */
5041         uxLength &= ~( sizeof( size_t ) - 1U );
5042 
5043         uxSize = ( sizeof( *pxBuffer ) + uxLength ) - sizeof( pxBuffer->ucArray );
5044 
5045         /* MISRA Ref 4.12.1 [Use of dynamic memory]. */
5046         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#directive-412. */
5047         /* coverity[misra_c_2012_directive_4_12_violation] */
5048         pxBuffer = ( ( StreamBuffer_t * ) pvPortMallocLarge( uxSize ) );
5049 
5050         if( pxBuffer == NULL )
5051         {
5052             FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) );
5053             pxSocket->u.xTCP.bits.bMallocError = pdTRUE;
5054             vTCPStateChange( pxSocket, eCLOSE_WAIT );
5055         }
5056         else
5057         {
5058             /* Clear the markers of the stream */
5059             ( void ) memset( pxBuffer, 0, sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
5060             pxBuffer->LENGTH = ( size_t ) uxLength;
5061 
5062             if( xTCPWindowLoggingLevel != 0 )
5063             {
5064                 FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %u bytes (total %u)\n", ( xIsInputStream != 0 ) ? 'R' : 'T', ( unsigned ) uxLength, ( unsigned ) uxSize ) );
5065             }
5066 
5067             if( xIsInputStream != 0 )
5068             {
5069                 iptraceMEM_STATS_CREATE( tcpRX_STREAM_BUFFER, pxBuffer, uxSize );
5070                 pxSocket->u.xTCP.rxStream = pxBuffer;
5071             }
5072             else
5073             {
5074                 iptraceMEM_STATS_CREATE( tcpTX_STREAM_BUFFER, pxBuffer, uxSize );
5075                 pxSocket->u.xTCP.txStream = pxBuffer;
5076             }
5077         }
5078 
5079         return pxBuffer;
5080     }
5081 
5082 
5083 #endif /* ipconfigUSE_TCP */
5084 /*-----------------------------------------------------------*/
5085 
5086 #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 )
5087 
5088 /**
5089  * @brief The application can attach callback functions to a socket. In this function,
5090  *        called by lTCPAddRxdata(), the TCP reception handler will be called.
5091  * @param[in] pxSocket The socket which has received TCP data.
5092  * @param[in] pcData The actual data received.
5093  * @param[in] ulByteCount The number of bytes that were received.
5094  */
vTCPAddRxdata_Callback(FreeRTOS_Socket_t * pxSocket,const uint8_t * pcData,uint32_t ulByteCount)5095     static void vTCPAddRxdata_Callback( FreeRTOS_Socket_t * pxSocket,
5096                                         const uint8_t * pcData,
5097                                         uint32_t ulByteCount )
5098     {
5099         const uint8_t * pucBuffer = pcData;
5100 
5101         /* The socket owner has installed an OnReceive handler. Pass the
5102          * Rx data, without copying from the rxStream, to the user. */
5103         for( ; ; )
5104         {
5105             uint8_t * ucReadPtr = NULL;
5106             uint32_t ulCount;
5107 
5108             if( pucBuffer != NULL )
5109             {
5110                 ucReadPtr = ( uint8_t * ) pucBuffer;
5111                 ulCount = ulByteCount;
5112                 pucBuffer = NULL;
5113             }
5114             else
5115             {
5116                 ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, &( ucReadPtr ) );
5117             }
5118 
5119             if( ulCount == 0U )
5120             {
5121                 break;
5122             }
5123 
5124             /* For advanced users only: here a pointer to the RX-stream of a socket
5125              * is passed to an application hook. */
5126             ( void ) pxSocket->u.xTCP.pxHandleReceive( pxSocket, ucReadPtr, ( size_t ) ulCount );
5127             /* Forward the tail in the RX stream. */
5128             ( void ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0U, NULL, ( size_t ) ulCount, pdFALSE );
5129         }
5130     }
5131 #endif /* #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) */
5132 
5133 #if ( ipconfigUSE_TCP == 1 )
5134 
5135 /**
5136  * @brief Called by lTCPAddRxdata(), the received data has just been added to the
5137  *        RX-stream. When the space is dropped below a threshold, it may set the
5138  *        bit field 'bLowWater'. Also the socket's events bits for READ will be set.
5139  * @param[in] pxSocket the socket that has received new data.
5140  */
vTCPAddRxdata_Stored(FreeRTOS_Socket_t * pxSocket)5141     static void vTCPAddRxdata_Stored( FreeRTOS_Socket_t * pxSocket )
5142     {
5143         /* See if running out of space. */
5144         if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED )
5145         {
5146             size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
5147 
5148             if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace )
5149             {
5150                 pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED;
5151                 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
5152 
5153                 /* bLowWater was reached, send the changed window size. */
5154                 pxSocket->u.xTCP.usTimeout = 1U;
5155                 ( void ) xSendEventToIPTask( eTCPTimerEvent );
5156             }
5157         }
5158 
5159         /* New incoming data is available, wake up the user.   User's
5160          * semaphores will be set just before the IP-task goes asleep. */
5161         pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_RECEIVE;
5162 
5163         #if ipconfigSUPPORT_SELECT_FUNCTION == 1
5164             {
5165                 if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U )
5166                 {
5167                     pxSocket->xEventBits |= ( ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT );
5168                 }
5169             }
5170         #endif
5171     }
5172 #endif /* ipconfigUSE_TCP */
5173 
5174 #if ( ipconfigUSE_TCP == 1 )
5175 
5176 /**
5177  * @brief Add data to the RxStream. When uxOffset > 0, data has come in out-of-order
5178  *        and will be put in front of the head so it can not be popped by the user.
5179  *
5180  * @param[in] pxSocket The socket to whose RxStream data is to be added.
5181  * @param[in] uxOffset Offset of the packet.
5182  * @param[in] pcData The data to be added to the RxStream.
5183  * @param[in] ulByteCount Number of bytes in the data.
5184  *
5185  * @return The number of bytes actually added to the RxStream. Or else, a negative
5186  *         error code is returned.
5187  */
lTCPAddRxdata(FreeRTOS_Socket_t * pxSocket,size_t uxOffset,const uint8_t * pcData,uint32_t ulByteCount)5188     int32_t lTCPAddRxdata( FreeRTOS_Socket_t * pxSocket,
5189                            size_t uxOffset,
5190                            const uint8_t * pcData,
5191                            uint32_t ulByteCount )
5192     {
5193         StreamBuffer_t * pxStream = pxSocket->u.xTCP.rxStream;
5194         int32_t xResult = 0;
5195 
5196         #if ( ipconfigUSE_CALLBACKS == 1 )
5197             BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ) ? pdTRUE : pdFALSE;
5198             const uint8_t * pucBuffer = NULL;
5199         #endif /* ipconfigUSE_CALLBACKS */
5200 
5201         /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount )
5202          * if( pucData != NULL ) copy data the the buffer
5203          * if( pucData == NULL ) no copying, just advance rxHead
5204          * if( uxOffset != 0 ) Just store data which has come out-of-order
5205          * if( uxOffset == 0 ) Also advance rxHead */
5206         if( pxStream == NULL )
5207         {
5208             pxStream = prvTCPCreateStream( pxSocket, pdTRUE );
5209 
5210             if( pxStream == NULL )
5211             {
5212                 xResult = -1;
5213             }
5214         }
5215 
5216         if( xResult >= 0 )
5217         {
5218             #if ( ipconfigUSE_CALLBACKS == 1 )
5219                 {
5220                     if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0U ) && ( uxOffset == 0U ) && ( pcData != NULL ) )
5221                     {
5222                         /* Data can be passed directly to the user because there is
5223                          * no data in the RX-stream, it the new data must be stored
5224                          * at offset zero, and a buffer 'pcData' is provided.
5225                          */
5226                         pucBuffer = pcData;
5227 
5228                         /* Zero-copy for call-back: no need to add the bytes to the
5229                          * stream, only the pointer will be advanced by uxStreamBufferAdd(). */
5230                         pcData = NULL;
5231                     }
5232                 }
5233             #endif /* ipconfigUSE_CALLBACKS */
5234 
5235             xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount );
5236 
5237             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
5238                 {
5239                     if( xResult != ( int32_t ) ulByteCount )
5240                     {
5241                         FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %u: %d/%u bytes (tail %u head %u space %u front %u)\n",
5242                                                  ( unsigned int ) uxOffset,
5243                                                  ( int ) xResult,
5244                                                  ( unsigned int ) ulByteCount,
5245                                                  ( unsigned int ) pxStream->uxTail,
5246                                                  ( unsigned int ) pxStream->uxHead,
5247                                                  ( unsigned int ) uxStreamBufferFrontSpace( pxStream ),
5248                                                  ( unsigned int ) pxStream->uxFront ) );
5249                     }
5250                 }
5251             #endif /* ipconfigHAS_DEBUG_PRINTF */
5252 
5253             if( uxOffset == 0U )
5254             {
5255                 /* Data is being added to rxStream at the head (offs = 0) */
5256                 #if ( ipconfigUSE_CALLBACKS == 1 )
5257                     if( bHasHandler != pdFALSE )
5258                     {
5259                         vTCPAddRxdata_Callback( pxSocket, pucBuffer, ulByteCount );
5260                     }
5261                     else
5262                 #endif /* ipconfigUSE_CALLBACKS */
5263                 {
5264                     vTCPAddRxdata_Stored( pxSocket );
5265                 }
5266             }
5267         }
5268 
5269         return xResult;
5270     }
5271 
5272 
5273 #endif /* ipconfigUSE_TCP */
5274 /*-----------------------------------------------------------*/
5275 
5276 #if ( ipconfigUSE_TCP == 1 )
5277 
5278 /**
5279  * @brief Function to get the remote IP-address and port number.
5280  *
5281  * @param[in] xSocket Socket owning the connection.
5282  * @param[out] pxAddress The address pointer to which the address
5283  *                        is to be added.
5284  *
5285  * @return The size of the address being returned. Or else a negative
5286  *         error code will be returned.
5287  */
5288 
5289 /* Function to get the remote address and IP port */
FreeRTOS_GetRemoteAddress(ConstSocket_t xSocket,struct freertos_sockaddr * pxAddress)5290     BaseType_t FreeRTOS_GetRemoteAddress( ConstSocket_t xSocket,
5291                                           struct freertos_sockaddr * pxAddress )
5292     {
5293         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5294         BaseType_t xResult;
5295 
5296         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5297         {
5298             xResult = -pdFREERTOS_ERRNO_EINVAL;
5299         }
5300         else
5301         {
5302             /* BSD style sockets communicate IP and port addresses in network
5303              * byte order.
5304              * IP address of remote machine. */
5305             switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
5306             {
5307                 #if ( ipconfigUSE_IPv4 != 0 )
5308                     case pdFALSE_UNSIGNED:
5309                         pxAddress->sin_len = ( uint8_t ) sizeof( *pxAddress );
5310                         pxAddress->sin_family = FREERTOS_AF_INET;
5311 
5312                         /* IP address of remote machine. */
5313                         pxAddress->sin_address.ulIP_IPv4 = FreeRTOS_htonl( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
5314 
5315                         /* Port on remote machine. */
5316                         pxAddress->sin_port = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
5317                         break;
5318                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
5319 
5320                 #if ( ipconfigUSE_IPv6 != 0 )
5321                     case pdTRUE_UNSIGNED:
5322                         pxAddress->sin_family = FREERTOS_AF_INET6;
5323 
5324                         /* IP address of remote machine. */
5325                         ( void ) memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, sizeof( pxAddress->sin_address.xIP_IPv6.ucBytes ) );
5326 
5327                         /* Port of remote machine. */
5328                         pxAddress->sin_port = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
5329                         break;
5330                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
5331 
5332                 default:
5333                     /* MISRA 16.4 Compliance */
5334                     break;
5335             }
5336 
5337             xResult = ( BaseType_t ) sizeof( *pxAddress );
5338         }
5339 
5340         return xResult;
5341     }
5342 
5343 
5344 #endif /* ipconfigUSE_TCP */
5345 
5346 
5347 /*-----------------------------------------------------------*/
5348 
5349 #if ( ipconfigUSE_TCP == 1 )
5350 
5351 
5352 /**
5353  * @brief Get the version of IP: either 'ipTYPE_IPv4' or 'ipTYPE_IPv6'.
5354  *
5355  * @param[in] xSocket  The socket to be checked.
5356  *
5357  * @return Either ipTYPE_IPv4 or ipTYPE_IPv6.
5358  */
FreeRTOS_GetIPType(ConstSocket_t xSocket)5359     BaseType_t FreeRTOS_GetIPType( ConstSocket_t xSocket )
5360     {
5361         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5362         BaseType_t xResult = ( BaseType_t ) ipTYPE_IPv4;
5363 
5364         switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
5365         {
5366             #if ( ipconfigUSE_IPv4 != 0 )
5367                 case pdFALSE_UNSIGNED:
5368                     xResult = ( BaseType_t ) ipTYPE_IPv4;
5369                     break;
5370             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
5371 
5372             #if ( ipconfigUSE_IPv6 != 0 )
5373                 case pdTRUE_UNSIGNED:
5374                     xResult = ( BaseType_t ) ipTYPE_IPv6;
5375                     break;
5376             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
5377 
5378             default:
5379                 /* MISRA 16.4 Compliance */
5380                 break;
5381         }
5382 
5383         return xResult;
5384     }
5385 
5386 /**
5387  * @brief Check the number of bytes that may be added to txStream.
5388  *
5389  * @param[in] xSocket The socket to be checked.
5390  *
5391  * @return the number of bytes that may be added to txStream or
5392  *         else a negative error code.
5393  */
FreeRTOS_maywrite(ConstSocket_t xSocket)5394     BaseType_t FreeRTOS_maywrite( ConstSocket_t xSocket )
5395     {
5396         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5397         BaseType_t xResult = 0;
5398 
5399         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5400         {
5401             xResult = -pdFREERTOS_ERRNO_EINVAL;
5402         }
5403         else if( pxSocket->u.xTCP.eTCPState != eESTABLISHED )
5404         {
5405             if( ( pxSocket->u.xTCP.eTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.eTCPState > eESTABLISHED ) )
5406             {
5407                 xResult = -1;
5408             }
5409         }
5410         else if( pxSocket->u.xTCP.txStream == NULL )
5411         {
5412             xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
5413         }
5414         else
5415         {
5416             xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
5417         }
5418 
5419         return xResult;
5420     }
5421 
5422 
5423 #endif /* ipconfigUSE_TCP */
5424 /*-----------------------------------------------------------*/
5425 
5426 #if ( ipconfigUSE_TCP == 1 )
5427 
5428 /**
5429  * @brief Get the number of bytes that can be written in the Tx buffer
5430  *        of the given socket.
5431  *
5432  * @param[in] xSocket the socket to be checked.
5433  *
5434  * @return The bytes that can be written. Or else an error code.
5435  */
FreeRTOS_tx_space(ConstSocket_t xSocket)5436     BaseType_t FreeRTOS_tx_space( ConstSocket_t xSocket )
5437     {
5438         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5439         BaseType_t xReturn;
5440 
5441         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5442         {
5443             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5444         }
5445         else
5446         {
5447             if( pxSocket->u.xTCP.txStream != NULL )
5448             {
5449                 xReturn = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
5450             }
5451             else
5452             {
5453                 xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
5454             }
5455         }
5456 
5457         return xReturn;
5458     }
5459 
5460 
5461 #endif /* ipconfigUSE_TCP */
5462 /*-----------------------------------------------------------*/
5463 
5464 #if ( ipconfigUSE_TCP == 1 )
5465 
5466 /**
5467  * @brief Returns the number of bytes stored in the Tx buffer.
5468  *
5469  * @param[in] xSocket The socket to be checked.
5470  *
5471  * @return The number of bytes stored in the Tx buffer of the socket.
5472  *         Or an error code.
5473  */
FreeRTOS_tx_size(ConstSocket_t xSocket)5474     BaseType_t FreeRTOS_tx_size( ConstSocket_t xSocket )
5475     {
5476         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5477         BaseType_t xReturn;
5478 
5479         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5480         {
5481             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5482         }
5483         else
5484         {
5485             if( pxSocket->u.xTCP.txStream != NULL )
5486             {
5487                 xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.txStream );
5488             }
5489             else
5490             {
5491                 xReturn = 0;
5492             }
5493         }
5494 
5495         return xReturn;
5496     }
5497 
5498 
5499 #endif /* ipconfigUSE_TCP */
5500 /*-----------------------------------------------------------*/
5501 
5502 #if ( ipconfigUSE_TCP == 1 )
5503 
5504 /**
5505  * @brief Is the socket connected.
5506  *
5507  * @param[in] xSocket The socket being checked.
5508  *
5509  * @return pdTRUE if TCP socket is connected.
5510  */
FreeRTOS_issocketconnected(ConstSocket_t xSocket)5511     BaseType_t FreeRTOS_issocketconnected( ConstSocket_t xSocket )
5512     {
5513         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5514         BaseType_t xReturn = pdFALSE;
5515 
5516         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5517         {
5518             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5519         }
5520         else
5521         {
5522             if( pxSocket->u.xTCP.eTCPState >= eESTABLISHED )
5523             {
5524                 if( pxSocket->u.xTCP.eTCPState < eCLOSE_WAIT )
5525                 {
5526                     xReturn = pdTRUE;
5527                 }
5528             }
5529         }
5530 
5531         return xReturn;
5532     }
5533 
5534 
5535 #endif /* ipconfigUSE_TCP */
5536 /*-----------------------------------------------------------*/
5537 
5538 #if ( ipconfigUSE_TCP == 1 )
5539 
5540 /**
5541  * @brief Get the actual value of Maximum Segment Size ( MSS ) being used.
5542  *
5543  * @param[in] xSocket The socket whose MSS is to be returned.
5544  *
5545  * @return the actual size of MSS being used or an error code.
5546  */
FreeRTOS_mss(ConstSocket_t xSocket)5547     BaseType_t FreeRTOS_mss( ConstSocket_t xSocket )
5548     {
5549         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5550         BaseType_t xReturn;
5551 
5552         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5553         {
5554             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5555         }
5556         else
5557         {
5558             /* usMSS is declared as uint16_t to save space.  FreeRTOS_mss()
5559              * will often be used in signed native-size expressions cast it to
5560              * BaseType_t. */
5561             xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usMSS );
5562         }
5563 
5564         return xReturn;
5565     }
5566 
5567 
5568 #endif /* ipconfigUSE_TCP */
5569 /*-----------------------------------------------------------*/
5570 
5571 #if ( ipconfigUSE_TCP == 1 )
5572 
5573 /**
5574  * @brief Get the connection status. The values correspond to the members
5575  *        of the enum 'eIPTCPState_t'.
5576  *
5577  * @param[in] xSocket Socket to get the connection status from.
5578  *
5579  * @return The connection status or an error code.
5580  *
5581  * @note For internal use only.
5582  */
FreeRTOS_connstatus(ConstSocket_t xSocket)5583     BaseType_t FreeRTOS_connstatus( ConstSocket_t xSocket )
5584     {
5585         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5586         BaseType_t xReturn;
5587 
5588         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5589         {
5590             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5591         }
5592         else
5593         {
5594             /* Cast it to BaseType_t. */
5595             xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.eTCPState );
5596         }
5597 
5598         return xReturn;
5599     }
5600 
5601 
5602 #endif /* ipconfigUSE_TCP */
5603 /*-----------------------------------------------------------*/
5604 
5605 #if ( ipconfigUSE_TCP == 1 )
5606 
5607 /**
5608  * @brief Returns the number of bytes which can be read from the RX stream buffer.
5609  *
5610  * @param[in] xSocket the socket to get the number of bytes from.
5611  *
5612  * @return Returns the number of bytes which can be read. Or an error
5613  *         code is returned.
5614  */
FreeRTOS_rx_size(ConstSocket_t xSocket)5615     BaseType_t FreeRTOS_rx_size( ConstSocket_t xSocket )
5616     {
5617         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5618         BaseType_t xReturn;
5619 
5620         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
5621         {
5622             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5623         }
5624         else if( pxSocket->u.xTCP.rxStream != NULL )
5625         {
5626             xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
5627         }
5628         else
5629         {
5630             xReturn = 0;
5631         }
5632 
5633         return xReturn;
5634     }
5635 
5636 
5637 #endif /* ipconfigUSE_TCP */
5638 /*-----------------------------------------------------------*/
5639 
5640 /**
5641  * @brief Check whether a given socket is valid or not. Validity is defined
5642  *        as the socket not being NULL and not being Invalid.
5643  * @param[in] xSocket The socket to be checked.
5644  * @return pdTRUE if the socket is valid, else pdFALSE.
5645  *
5646  */
xSocketValid(const ConstSocket_t xSocket)5647 BaseType_t xSocketValid( const ConstSocket_t xSocket )
5648 {
5649     BaseType_t xReturnValue = pdFALSE;
5650 
5651     /*
5652      * There are two values which can indicate an invalid socket:
5653      * FREERTOS_INVALID_SOCKET and NULL.  In order to compare against
5654      * both values, the code cannot be compliant with rule 11.4,
5655      * hence the Coverity suppression statement below.
5656      */
5657 
5658     /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
5659     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
5660     /* coverity[misra_c_2012_rule_11_4_violation] */
5661     if( ( xSocket != FREERTOS_INVALID_SOCKET ) && ( xSocket != NULL ) )
5662     {
5663         xReturnValue = pdTRUE;
5664     }
5665 
5666     return xReturnValue;
5667 }
5668 /*-----------------------------------------------------------*/
5669 
5670 #if 0
5671 
5672 /**
5673  * @brief Returns the number of packets that are stored in a UDP socket.
5674  *
5675  * @param[in] xSocket the socket to get the number of bytes from.
5676  *
5677  * @return Returns the number of packets that are stored.  Use FreeRTOS_recvfrom()
5678  *         to retrieve those packets.
5679  */
5680     BaseType_t FreeRTOS_udp_rx_size( Socket_t xSocket )
5681     {
5682         BaseType_t xReturn = 0;
5683         const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5684 
5685         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
5686         {
5687             xReturn = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
5688         }
5689         else
5690         {
5691             xReturn = -pdFREERTOS_ERRNO_EINVAL;
5692         }
5693 
5694         return xReturn;
5695     }
5696 #endif /* 0 */
5697 
5698 #if ( ipconfigUSE_TCP == 1 )
5699 
5700 /**
5701  * @brief Get the net status. The IP-task will print a summary of all sockets and
5702  *        their connections.
5703  */
FreeRTOS_netstat(void)5704     void FreeRTOS_netstat( void )
5705     {
5706         IPStackEvent_t xAskEvent;
5707 
5708         /* Ask the IP-task to call vTCPNetStat()
5709          * to avoid accessing xBoundTCPSocketsList
5710          */
5711         xAskEvent.eEventType = eTCPNetStat;
5712         xAskEvent.pvData = ( void * ) NULL;
5713         ( void ) xSendEventStructToIPTask( &xAskEvent, pdMS_TO_TICKS( 1000U ) );
5714     }
5715 
5716 #endif /* ipconfigUSE_TCP */
5717 /*-----------------------------------------------------------*/
5718 
5719 /**
5720  * @brief Set the value of the SocketID of a socket.
5721  * @param[in] xSocket The socket whose ID should be set.
5722  * @param[in] pvSocketID The new value for the SocketID.
5723  * @return Zero if the socket was valid, otherwise -EINVAL.
5724  */
xSocketSetSocketID(const Socket_t xSocket,void * pvSocketID)5725 BaseType_t xSocketSetSocketID( const Socket_t xSocket,
5726                                void * pvSocketID )
5727 {
5728     FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
5729     BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
5730 
5731     if( xSocketValid( pxSocket ) == pdTRUE )
5732     {
5733         xReturn = 0;
5734         pxSocket->pvSocketID = pvSocketID;
5735     }
5736 
5737     return xReturn;
5738 }
5739 /*-----------------------------------------------------------*/
5740 
5741 /**
5742  * @brief Retrieve the SocketID that is associated with a socket.
5743  * @param[in] xSocket The socket whose ID should be returned.
5744  * @return The current value of pvSocketID, or NULL in case
5745  *         the socket pointer is not valid or when the ID was not
5746  *         yet set.
5747  */
pvSocketGetSocketID(const ConstSocket_t xSocket)5748 void * pvSocketGetSocketID( const ConstSocket_t xSocket )
5749 {
5750     const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
5751     void * pvReturn = NULL;
5752 
5753     if( xSocketValid( pxSocket ) == pdTRUE )
5754     {
5755         pvReturn = pxSocket->pvSocketID;
5756     }
5757 
5758     return pvReturn;
5759 }
5760 /*-----------------------------------------------------------*/
5761 
5762 #if ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
5763 
5764 /**
5765  * @brief A helper function of vTCPNetStat(), see below.
5766  *
5767  * @param[in] pxSocket The socket that needs logging.
5768  */
vTCPNetStat_TCPSocket(const FreeRTOS_Socket_t * pxSocket)5769     static void vTCPNetStat_TCPSocket( const FreeRTOS_Socket_t * pxSocket )
5770     {
5771         char pcRemoteIp[ 40 ];
5772         int xIPWidth = 32;
5773 
5774         #if ( ipconfigTCP_KEEP_ALIVE == 1 )
5775             TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
5776         #else
5777             TickType_t age = 0U;
5778         #endif
5779 
5780         char ucChildText[ 16 ] = "";
5781 
5782         if( pxSocket->u.xTCP.eTCPState == ( uint8_t ) eTCP_LISTEN )
5783         {
5784             /* Using function "snprintf". */
5785             const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",
5786                                                  pxSocket->u.xTCP.usChildCount,
5787                                                  pxSocket->u.xTCP.usBacklog );
5788             ( void ) copied_len;
5789             /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */
5790             configASSERT( copied_len >= 0 );                                /* LCOV_EXCL_BR_LINE the 'taken' branch will never execute. See the above comment. */
5791             configASSERT( copied_len < ( int32_t ) sizeof( ucChildText ) ); /* LCOV_EXCL_BR_LINE the 'taken' branch will never execute. See the above comment. */
5792         }
5793 
5794         if( age > 999999U )
5795         {
5796             age = 999999U;
5797         }
5798 
5799         switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE Exclude this line because default case is not counted. */
5800         {
5801             #if ( ipconfigUSE_IPv4 != 0 )
5802                 case pdFALSE_UNSIGNED:
5803                     ( void ) snprintf( pcRemoteIp, sizeof( pcRemoteIp ), "%xip", ( unsigned ) pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 );
5804                     break;
5805             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
5806 
5807             #if ( ipconfigUSE_IPv6 != 0 )
5808                 case pdTRUE_UNSIGNED:
5809                     ( void ) snprintf( pcRemoteIp,
5810                                        sizeof( pcRemoteIp ),
5811                                        "%pip", ( void * ) pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes );
5812                     break;
5813             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
5814 
5815             default:
5816                 /* MISRA 16.4 Compliance */
5817                 break;
5818         }
5819 
5820         FreeRTOS_printf( ( "TCP %5d %-*s:%5d %d/%d %-13.13s %6u %6u%s\n",
5821                            pxSocket->usLocalPort,         /* Local port on this machine */
5822                            xIPWidth,
5823                            pcRemoteIp,                    /* IP address of remote machine */
5824                            pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */
5825                            ( pxSocket->u.xTCP.rxStream != NULL ) ? 1 : 0,
5826                            ( pxSocket->u.xTCP.txStream != NULL ) ? 1 : 0,
5827                            FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.eTCPState ),
5828                            ( unsigned ) ( ( age > 999999U ) ? 999999U : age ), /* Format 'age' for printing */
5829                            pxSocket->u.xTCP.usTimeout,
5830                            ucChildText ) );
5831     }
5832 
5833 #endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
5834 
5835 #if ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
5836 
5837 /**
5838  * @brief Print a summary of all sockets and their connections.
5839  */
vTCPNetStat(void)5840     void vTCPNetStat( void )
5841     {
5842         /* Show a simple listing of all created sockets and their connections */
5843         const ListItem_t * pxIterator;
5844         BaseType_t count = 0;
5845         size_t uxMinimum = uxGetMinimumFreeNetworkBuffers();
5846         size_t uxCurrent = uxGetNumberOfFreeNetworkBuffers();
5847 
5848         if( !listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) )
5849         {
5850             FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) );
5851         }
5852         else
5853         {
5854             /* Casting a "MiniListItem_t" to a "ListItem_t".
5855              * This is safe because only its address is being accessed, not its fields. */
5856             const ListItem_t * pxEndTCP = listGET_END_MARKER( &xBoundTCPSocketsList );
5857             const ListItem_t * pxEndUDP = listGET_END_MARKER( &xBoundUDPSocketsList );
5858 
5859             FreeRTOS_printf( ( "Prot Port IP-Remote       : Port  R/T Status       Alive  tmout Child\n" ) );
5860 
5861             for( pxIterator = listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
5862                  pxIterator != pxEndTCP;
5863                  pxIterator = listGET_NEXT( pxIterator ) )
5864             {
5865                 const FreeRTOS_Socket_t * pxSocket = ( ( const FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
5866                 vTCPNetStat_TCPSocket( pxSocket );
5867                 count++;
5868             }
5869 
5870             for( pxIterator = listGET_HEAD_ENTRY( &xBoundUDPSocketsList );
5871                  pxIterator != pxEndUDP;
5872                  pxIterator = listGET_NEXT( pxIterator ) )
5873             {
5874                 /* Local port on this machine */
5875                 FreeRTOS_printf( ( "UDP Port %5u\n",
5876                                    FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) );
5877                 count++;
5878             }
5879 
5880             FreeRTOS_printf( ( "FreeRTOS_netstat: %d sockets %u < %u < %u buffers free\n",
5881                                ( int ) count,
5882                                ( unsigned ) uxMinimum,
5883                                ( unsigned ) uxCurrent,
5884                                ( unsigned ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) );
5885         }
5886     }
5887 
5888 #endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
5889 /*-----------------------------------------------------------*/
5890 
5891 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
5892 
5893     #if ( ipconfigUSE_TCP == 1 )
5894 
5895 /**
5896  * @brief This internal function will check if a given TCP
5897  *        socket has had any select event, either READ, WRITE,
5898  *        or EXCEPT.
5899  *
5900  * @param[in] pxSocket The socket which needs to be checked.
5901  * @return An event mask of events that are active for this socket.
5902  */
vSocketSelectTCP(FreeRTOS_Socket_t * pxSocket)5903         static EventBits_t vSocketSelectTCP( FreeRTOS_Socket_t * pxSocket )
5904         {
5905             /* Check if the TCP socket has already been accepted by
5906              * the owner.  If not, it is useless to return it from a
5907              * select(). */
5908             BaseType_t bAccepted = pdFALSE;
5909             EventBits_t xSocketBits = 0U;
5910 
5911             if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED )
5912             {
5913                 if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED )
5914                 {
5915                     bAccepted = pdTRUE;
5916                 }
5917             }
5918 
5919             /* Is the set owner interested in READ events? */
5920             if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != ( EventBits_t ) 0U )
5921             {
5922                 if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
5923                 {
5924                     if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
5925                     {
5926                         xSocketBits |= ( EventBits_t ) eSELECT_READ;
5927                     }
5928                 }
5929                 else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
5930                 {
5931                     /* This socket has the re-use flag. After connecting it turns into
5932                      * a connected socket. Set the READ event, so that accept() will be called. */
5933                     xSocketBits |= ( EventBits_t ) eSELECT_READ;
5934                 }
5935                 else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) )
5936                 {
5937                     xSocketBits |= ( EventBits_t ) eSELECT_READ;
5938                 }
5939                 else
5940                 {
5941                     /* Nothing. */
5942                 }
5943             }
5944 
5945             /* Is the set owner interested in EXCEPTION events? */
5946             if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
5947             {
5948                 if( ( pxSocket->u.xTCP.eTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.eTCPState == eCLOSED ) )
5949                 {
5950                     xSocketBits |= ( EventBits_t ) eSELECT_EXCEPT;
5951                 }
5952             }
5953 
5954             /* Is the set owner interested in WRITE events? */
5955             if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
5956             {
5957                 BaseType_t bMatch = pdFALSE;
5958 
5959                 if( bAccepted != 0 )
5960                 {
5961                     if( FreeRTOS_tx_space( pxSocket ) > 0 )
5962                     {
5963                         bMatch = pdTRUE;
5964                     }
5965                 }
5966 
5967                 if( bMatch == pdFALSE )
5968                 {
5969                     if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) &&
5970                         ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) &&
5971                         ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) )
5972                     {
5973                         pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED;
5974                         bMatch = pdTRUE;
5975                     }
5976                 }
5977 
5978                 if( bMatch != pdFALSE )
5979                 {
5980                     xSocketBits |= ( EventBits_t ) eSELECT_WRITE;
5981                 }
5982             }
5983 
5984             return xSocketBits;
5985         }
5986 
5987     #endif /* ( ipconfigUSE_TCP == 1 ) */
5988 
5989 /**
5990  * @brief This internal non-blocking function will check all sockets that belong
5991  *        to a select set.  The events bits of each socket will be updated, and it
5992  *        will check if an ongoing select() call must be interrupted because of an
5993  *        event has occurred.
5994  *
5995  * @param[in] pxSocketSet The socket-set which is to be waited on for change.
5996  */
vSocketSelect(const SocketSelect_t * pxSocketSet)5997     void vSocketSelect( const SocketSelect_t * pxSocketSet )
5998     {
5999         BaseType_t xRound;
6000         EventBits_t xSocketBits, xBitsToClear;
6001 
6002         #if ipconfigUSE_TCP == 1
6003             BaseType_t xLastRound = 1;
6004         #else
6005             BaseType_t xLastRound = 0;
6006         #endif
6007 
6008         /* These flags will be switched on after checking the socket status. */
6009         EventBits_t xGroupBits = 0;
6010 
6011         for( xRound = 0; xRound <= xLastRound; xRound++ )
6012         {
6013             const ListItem_t * pxIterator;
6014             const ListItem_t * pxEnd;
6015 
6016             if( xRound == 0 )
6017             {
6018                 /* MISRA Ref 11.3.1 [Misaligned access] */
6019                 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
6020                 /* coverity[misra_c_2012_rule_11_3_violation] */
6021                 pxEnd = ( ( const ListItem_t * ) &( xBoundUDPSocketsList.xListEnd ) );
6022             }
6023 
6024             #if ipconfigUSE_TCP == 1
6025                 else
6026                 {
6027                     /* MISRA Ref 11.3.1 [Misaligned access] */
6028                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
6029                     /* coverity[misra_c_2012_rule_11_3_violation] */
6030                     pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
6031                 }
6032             #endif /* ipconfigUSE_TCP == 1 */
6033 
6034             for( pxIterator = listGET_NEXT( pxEnd );
6035                  pxIterator != pxEnd;
6036                  pxIterator = listGET_NEXT( pxIterator ) )
6037             {
6038                 FreeRTOS_Socket_t * pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
6039 
6040                 if( pxSocket->pxSocketSet != pxSocketSet )
6041                 {
6042                     /* Socket does not belong to this select group. */
6043                     continue;
6044                 }
6045 
6046                 xSocketBits = 0;
6047 
6048                 #if ( ipconfigUSE_TCP == 1 )
6049                     if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
6050                     {
6051                         xSocketBits |= vSocketSelectTCP( pxSocket );
6052                     }
6053                     else
6054                 #endif /* ipconfigUSE_TCP == 1 */
6055                 {
6056                     /* Select events for UDP are simpler. */
6057                     if( ( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U ) &&
6058                         ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) )
6059                     {
6060                         xSocketBits |= ( EventBits_t ) eSELECT_READ;
6061                     }
6062 
6063                     /* The WRITE and EXCEPT bits are not used for UDP */
6064                 } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */
6065 
6066                 /* Each socket keeps its own event flags, which are looked-up
6067                  * by FreeRTOS_FD_ISSSET() */
6068                 pxSocket->xSocketBits = xSocketBits;
6069 
6070                 /* The ORed value will be used to set the bits in the event
6071                  * group. */
6072                 xGroupBits |= xSocketBits;
6073             } /* for( pxIterator ... ) */
6074         }     /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */
6075 
6076         xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup );
6077 
6078         /* Now set the necessary bits. */
6079         xBitsToClear = ( xBitsToClear & ~xGroupBits ) & ( ( EventBits_t ) eSELECT_ALL );
6080 
6081         #if ( ipconfigSUPPORT_SIGNALS != 0 )
6082             {
6083                 /* Maybe the socketset was signalled, but don't
6084                  * clear the 'eSELECT_INTR' bit here, as it will be used
6085                  * and cleared in FreeRTOS_select(). */
6086                 xBitsToClear &= ~( ( EventBits_t ) eSELECT_INTR );
6087             }
6088         #endif /* ipconfigSUPPORT_SIGNALS */
6089 
6090         if( xBitsToClear != 0U )
6091         {
6092             ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear );
6093         }
6094 
6095         /* Now include eSELECT_CALL_IP to wakeup the caller. */
6096         ( void ) xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | ( EventBits_t ) eSELECT_CALL_IP );
6097     }
6098 
6099 
6100 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
6101 /*-----------------------------------------------------------*/
6102 
6103 #if ( ipconfigSUPPORT_SIGNALS != 0 )
6104 
6105 /**
6106  * @brief Send a signal to the task which reads from this socket.
6107  *        The socket will receive an event of the type 'eSOCKET_INTR'.
6108  *        Any ongoing blocking API ( e.g. FreeRTOS_recv() ) will be terminated
6109  *        and return the value -pdFREERTOS_ERRNO_EINTR ( -4 ).
6110  *
6111  * @param[in] xSocket The socket that will be signalled.
6112  *
6113  * @return If xSocket is an invalid socket (NULL) or if the socket set is invalid (NULL)
6114  *         and/or if event group is invalid/not created, then, -pdFREERTOS_ERRNO_EINVAL
6115  *         is returned. On successful sending of a signal, 0 is returned.
6116  */
FreeRTOS_SignalSocket(Socket_t xSocket)6117     BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket )
6118     {
6119         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
6120         BaseType_t xReturn;
6121 
6122         if( pxSocket == NULL )
6123         {
6124             xReturn = -pdFREERTOS_ERRNO_EINVAL;
6125         }
6126         else
6127         #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
6128             if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) )
6129             {
6130                 ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
6131                 xReturn = 0;
6132             }
6133             else
6134         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
6135         if( pxSocket->xEventGroup != NULL )
6136         {
6137             ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR );
6138             xReturn = 0;
6139         }
6140         else
6141         {
6142             xReturn = -pdFREERTOS_ERRNO_EINVAL;
6143         }
6144 
6145         return xReturn;
6146     }
6147 
6148 #endif /* ipconfigSUPPORT_SIGNALS */
6149 /*-----------------------------------------------------------*/
6150 
6151 #if ( ipconfigSUPPORT_SIGNALS != 0 )
6152 
6153 /**
6154  * @brief The same as 'FreeRTOS_SignalSocket()', except that this function should
6155  *        be called from an ISR context.
6156  *
6157  * @param[in] xSocket The socket that will be signalled.
6158  * @param[in,out] pxHigherPriorityTaskWoken will be set to non-zero in case a higher-
6159  *                priority task has become runnable.
6160  */
FreeRTOS_SignalSocketFromISR(Socket_t xSocket,BaseType_t * pxHigherPriorityTaskWoken)6161     BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket,
6162                                              BaseType_t * pxHigherPriorityTaskWoken )
6163     {
6164         FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
6165         BaseType_t xReturn;
6166         IPStackEvent_t xEvent;
6167 
6168         configASSERT( pxSocket != NULL );
6169         configASSERT( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP );
6170         configASSERT( pxSocket->xEventGroup != NULL );
6171 
6172         xEvent.eEventType = eSocketSignalEvent;
6173         xEvent.pvData = pxSocket;
6174 
6175         /* The IP-task will call FreeRTOS_SignalSocket for this socket. */
6176         xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
6177 
6178         return xReturn;
6179     }
6180 
6181 #endif /* ipconfigSUPPORT_SIGNALS */
6182 /*-----------------------------------------------------------*/
6183 
6184 #if 0
6185     #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
6186         struct pollfd
6187         {
6188             Socket_t fd;         /* file descriptor */
6189             EventBits_t events;  /* requested events */
6190             EventBits_t revents; /* returned events */
6191         };
6192 
6193         typedef BaseType_t nfds_t;
6194 
6195         BaseType_t poll( struct pollfd * fds,
6196                          nfds_t nfds,
6197                          BaseType_t timeout );
6198         BaseType_t poll( struct pollfd * fds,
6199                          nfds_t nfds,
6200                          BaseType_t timeout )
6201         {
6202             BaseType_t index;
6203             SocketSelect_t * pxSocketSet = NULL;
6204             BaseType_t xReturn = 0;
6205 
6206             /* See which socket-sets have been created and bound to the sockets involved. */
6207             for( index = 0; index < nfds; index++ )
6208             {
6209                 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
6210 
6211                 if( pxSocket->pxSocketSet != NULL )
6212                 {
6213                     if( pxSocketSet == NULL )
6214                     {
6215                         /* Use this socket-set. */
6216                         pxSocketSet = pxSocket->pxSocketSet;
6217                         xReturn = 1;
6218                     }
6219                     else if( pxSocketSet == pxSocket->pxSocketSet )
6220                     {
6221                         /* Good: associated with the same socket-set. */
6222                     }
6223                     else
6224                     {
6225                         /* More than one socket-set is found: can not do a select on 2 sets. */
6226                         xReturn = -1;
6227                         break;
6228                     }
6229                 }
6230             }
6231 
6232             if( xReturn == 0 )
6233             {
6234                 /* Create a new socket-set, and attach all sockets to it. */
6235                 pxSocketSet = FreeRTOS_CreateSocketSet();
6236 
6237                 if( pxSocketSet != NULL )
6238                 {
6239                     xReturn = 1;
6240                 }
6241                 else
6242                 {
6243                     xReturn = -2;
6244                 }
6245 
6246                 /* Memory leak: when the last socket closes, there is no more reference to
6247                  * this socket-set.  It should be marked as an automatic or anonymous socket-set,
6248                  * so when closing the last member, its memory will be freed. */
6249             }
6250 
6251             if( xReturn > 0 )
6252             {
6253                 /* Only one socket-set is found.  Connect all sockets to this socket-set. */
6254                 for( index = 0; index < nfds; index++ )
6255                 {
6256                     FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
6257                     EventBits_t xEventBits = fds[ index ].events;
6258 
6259                     FreeRTOS_FD_SET( pxSocket, pxSocketSet, xEventBits );
6260                     FreeRTOS_FD_CLR( pxSocket, pxSocketSet, ( EventBits_t ) ~xEventBits );
6261                 }
6262 
6263                 /* And sleep until an event happens or a time-out. */
6264                 xReturn = FreeRTOS_select( pxSocketSet, timeout );
6265 
6266                 /* Now set the return events, copying from the socked field 'xSocketBits'. */
6267                 for( index = 0; index < nfds; index++ )
6268                 {
6269                     FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
6270 
6271                     fds[ index ].revents = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
6272                 }
6273             }
6274             else
6275             {
6276                 /* -1: Sockets are connected to different socket sets. */
6277                 /* -2: FreeRTOS_CreateSocketSet() failed. */
6278             }
6279 
6280             return xReturn;
6281         }
6282 
6283     #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
6284 #endif /* 0 */
6285