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