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