xref: /FreeRTOS-Plus-TCP-v3.1.0/source/portable/NetworkInterface/libslirp/MBuffNetifBackendLibslirp.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /* libc */
29 #include <stdlib.h>
30 #include <sys/types.h>
31 
32 /* QEMU Slirp Library */
33 #include <libslirp.h>
34 
35 #if defined( _WIN32 )
36     #include <process.h>
37     #include <WinSock2.h>
38 #else
39     #include <poll.h>
40     #include <pthread.h>
41     #include <signal.h>
42     #include <unistd.h>
43     #include "wait_for_event.h"
44 #endif
45 
46 #include "errno.h"
47 
48 #include "FreeRTOS.h"
49 #include "message_buffer.h"
50 #include "FreeRTOSIPConfig.h"
51 #include "FreeRTOS_IP.h"
52 
53 #ifndef IF_MTU_DEFAULT
54     #define IF_MTU_DEFAULT    1500U
55 #endif
56 
57 #ifndef IF_MRU_DEFAULT
58     #define IF_MRU_DEFAULT    1500U
59 #endif
60 
61 #define NETWORK_BUFFER_LEN    ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER )
62 
63 #define xSEND_BUFFER_SIZE     ( 32U * NETWORK_BUFFER_LEN )
64 #define xRECV_BUFFER_SIZE     ( 32U * NETWORK_BUFFER_LEN )
65 #define xNUM_TIMERS           ( 10U )
66 
67 #if defined( _WIN32 )
68     typedef uintptr_t         Thread_t;
69     typedef HANDLE            Mutex_t;
70     #define THREAD_RETURN      unsigned
71     #define THREAD_FUNC_DEF    __stdcall
72     static LARGE_INTEGER xClockFrequency;
73     typedef size_t            nfds_t;
74 #else
75     typedef pthread_t         Thread_t;
76     typedef pthread_mutex_t   Mutex_t;
77     #define THREAD_RETURN    void *
78     #define THREAD_FUNC_DEF
79 #endif /* if defined( _WIN32 ) */
80 
81 #if !defined( slirp_ssize_t ) && defined( SSIZE_MAX )
82     typedef ssize_t slirp_ssize_t;
83 #endif
84 
85 typedef struct
86 {
87     /* "Hardware" buffers */
88     MessageBufferHandle_t xSendMsgBuffer;
89     MessageBufferHandle_t xRecvMsgBuffer;
90     StaticMessageBuffer_t xSendMsgBufferStatic;
91     StaticMessageBuffer_t xRecvMsgBufferStatic;
92     uint8_t pucTxBuffer[ xSEND_BUFFER_SIZE ];
93     uint8_t pucRxBuffer[ xRECV_BUFFER_SIZE ];
94 
95     BaseType_t xExitFlag;
96 
97     /* libslirp context */
98     struct Slirp * pxSlirp;
99 
100     /* File handle storage */
101     nfds_t nfds;
102     size_t xPollFdArraySize;
103     struct pollfd * pxPollFdArray;
104 
105     /* Event used to signal when data is ready in xSendMsgBuffer */
106     void * pvSendEvent;
107 
108     /*
109      * Mutex to arbitrate access to libslirp api between
110      * vTransmitThread and  vReceiveThread
111      */
112     Mutex_t xMutex;
113     Thread_t xTxThread;
114     Thread_t xRxThread;
115 } SlirpBackendContext_t;
116 
117 static int64_t llSlirp_ClockGetNanoSeconds( void * pvOpaque );
118 static slirp_ssize_t xSlirp_WriteCallback( const void * pvBuffer,
119                                            size_t uxLen,
120                                            void * pvOpaque );
121 static void vSlirpGuestError( const char * msg,
122                               void * pvOpaque );
123 
124 /*
125  * Stub functions for unimplemented timer feature
126  * Should not be called.
127  */
128 static void * pvSlirp_TimerNew( SlirpTimerCb cb,
129                                 void * pvCallbackContext,
130                                 void * pvOpaque );
131 static void vSlirp_TimerFree( void * pvTimer,
132                               void * pvOpaque );
133 static void vSlirp_TimerModify( void * pvTimer,
134                                 int64_t expire_time,
135                                 void * pvOpaque );
136 
137 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
138     static void * pvSlirpTimerNewOpaque( SlirpTimerId xTimerId,
139                                          void * cb_opaque,
140                                          void * pvOpaque );
141 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
142 
143 /*
144  * Other empty callbacks. Not used for linux port.
145  */
146 static void vSlirp_RegisterPollFd( int lFd,
147                                    void * pvCallbackContext );
148 static void vSlirp_UnRegisterPollFd( int lFd,
149                                      void * pvCallbackContext );
150 static void vSlirp_Notify( void * pvCallbackContext );
151 
152 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
153     static void vSlirp_InitCompleted( Slirp * pxSlirp,
154                                       void * pvCallbackContext );
155 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
156 
157 /* Receive and Transmit threads */
158 static THREAD_RETURN THREAD_FUNC_DEF vReceiveThread( void * pvParameters );
159 static THREAD_RETURN THREAD_FUNC_DEF vTransmitThread( void * pvParameters );
160 
161 /**
162  * @brief Initialize the slirp posix backend.
163  *
164  * @param[out] pxSendMsgBuffer Location to store the handle of the send message buffer.
165  * @param[out] pxRecvMsgBuffer Location to store the handle of the receive message buffer.
166  * @param[in] pvSendEvent Pointer of the event struct which the implemenbtation should pend on to receive frames.
167  * @param[out] ppvBackendContext Location to store an implementation specific void pointer.
168  */
vMBuffNetifBackendInit(MessageBufferHandle_t * pxSendMsgBuffer,MessageBufferHandle_t * pxRecvMsgBuffer,void * pvSendEvent,void ** ppvBackendContext)169 void vMBuffNetifBackendInit( MessageBufferHandle_t * pxSendMsgBuffer,
170                              MessageBufferHandle_t * pxRecvMsgBuffer,
171                              void * pvSendEvent,
172                              void ** ppvBackendContext )
173 {
174     BaseType_t xErrorFlag = pdFALSE;
175     void * pvContextBuffer = NULL;
176     SlirpBackendContext_t * pxCtx = NULL;
177 
178     static const struct SlirpCb xSlirpCallbacks =
179     {
180         .send_packet          = xSlirp_WriteCallback,
181         .guest_error          = vSlirpGuestError,
182         .clock_get_ns         = llSlirp_ClockGetNanoSeconds,
183         .timer_new            = pvSlirp_TimerNew,
184         .timer_free           = vSlirp_TimerFree,
185         .timer_mod            = vSlirp_TimerModify,
186         .register_poll_fd     = vSlirp_RegisterPollFd,
187         .unregister_poll_fd   = vSlirp_UnRegisterPollFd,
188         .notify               = vSlirp_Notify,
189 
190         #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
191             .init_completed   = vSlirp_InitCompleted,
192             .timer_new_opaque = pvSlirpTimerNewOpaque,
193         #endif
194     };
195 
196     static struct SlirpConfig xSlirpConfig = { 0U };
197 
198     #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
199         xSlirpConfig.version = 4U;
200     #else
201         xSlirpConfig.version = 3U;
202     #endif
203 
204     xSlirpConfig.restricted = false;
205 
206     /* IPv4 Enabled */
207     xSlirpConfig.in_enabled = true;
208     xSlirpConfig.vnetwork.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 0U );
209     xSlirpConfig.vnetmask.s_addr = FreeRTOS_inet_addr_quick( 255U, 255U, 255U, 0U );
210     xSlirpConfig.vhost.s_addr = FreeRTOS_inet_addr_quick( 10, 0U, 2U, 2U );
211 
212     /* IPv6 disabled */
213     xSlirpConfig.in6_enabled = false;
214 
215     xSlirpConfig.vhostname = NULL;
216     xSlirpConfig.tftp_server_name = NULL;
217     xSlirpConfig.tftp_path = NULL;
218     xSlirpConfig.bootfile = NULL;
219 
220     xSlirpConfig.vdhcp_start.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 15U );
221     xSlirpConfig.vnameserver.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 3U );
222     xSlirpConfig.vdnssearch = NULL;
223     xSlirpConfig.vdomainname = NULL;
224 
225     xSlirpConfig.if_mtu = IF_MTU_DEFAULT;
226     xSlirpConfig.if_mru = IF_MRU_DEFAULT;
227 
228     xSlirpConfig.disable_host_loopback = false;
229     xSlirpConfig.enable_emu = false;
230     xSlirpConfig.disable_dns = false;
231 
232     #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
233         xSlirpConfig.disable_dhcp = false;
234     #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
235 
236     if( ( pxSendMsgBuffer == NULL ) ||
237         ( pxRecvMsgBuffer == NULL ) ||
238         ( pvSendEvent == NULL ) ||
239         ( ppvBackendContext == NULL ) )
240     {
241         fprintf( stderr, "NULL parameter passed to vMBuffNetifBackendInit.\n" );
242     }
243     else
244     {
245         pvContextBuffer = pvPortMalloc( sizeof( SlirpBackendContext_t ) );
246     }
247 
248     if( pvContextBuffer != NULL )
249     {
250         pxCtx = ( SlirpBackendContext_t * ) pvContextBuffer;
251 
252         pxCtx->xSendMsgBuffer = xMessageBufferCreateStatic( xSEND_BUFFER_SIZE,
253                                                             pxCtx->pucTxBuffer,
254                                                             &( pxCtx->xSendMsgBufferStatic ) );
255 
256         if( pxCtx->xSendMsgBuffer == NULL )
257         {
258             xErrorFlag = pdTRUE;
259         }
260 
261         pxCtx->xRecvMsgBuffer = xMessageBufferCreateStatic( xSEND_BUFFER_SIZE,
262                                                             pxCtx->pucRxBuffer,
263                                                             &( pxCtx->xRecvMsgBufferStatic ) );
264 
265         if( pxCtx->xRecvMsgBuffer == NULL )
266         {
267             xErrorFlag = pdTRUE;
268         }
269 
270         /* Copy pointer to event struct */
271         pxCtx->pvSendEvent = pvSendEvent;
272 
273         /* Initialize libslirp */
274         pxCtx->pxSlirp = slirp_new( &xSlirpConfig, &xSlirpCallbacks, pvContextBuffer );
275 
276         if( pxCtx->pxSlirp )
277         {
278             #if defined( _WIN32 )
279                 pxCtx->xMutex = CreateMutex( NULL, FALSE, NULL );
280                 configASSERT( pxCtx->xMutex != ( Mutex_t ) NULL );
281 
282                 pxCtx->xTxThread = _beginthreadex( NULL, 0, vTransmitThread, pvContextBuffer, 0, NULL );
283                 configASSERT( pxCtx->xTxThread != ( Thread_t ) NULL );
284 
285                 pxCtx->xRxThread = _beginthreadex( NULL, 0, vReceiveThread, pvContextBuffer, 0, NULL );
286                 configASSERT( pxCtx->xRxThread != ( Thread_t ) NULL );
287 
288                 ( void ) QueryPerformanceFrequency( &xClockFrequency );
289             #else /* if defined( _WIN32 ) */
290                 int lRslt;
291                 lRslt = pthread_mutex_init( &( pxCtx->xMutex ), NULL );
292                 configASSERT( lRslt == 0U );
293 
294                 lRslt = pthread_create( &( pxCtx->xTxThread ), NULL, vTransmitThread, pvContextBuffer );
295                 configASSERT( lRslt == 0U );
296 
297                 lRslt = pthread_create( &( pxCtx->xRxThread ), NULL, vReceiveThread, pvContextBuffer );
298                 configASSERT( lRslt == 0U );
299             #endif /* if defined( _WIN32 ) */
300         }
301     }
302 
303     /* vTaskDelay(2 * 1000); */
304 
305     if( pvContextBuffer != NULL )
306     {
307         *pxSendMsgBuffer = pxCtx->xSendMsgBuffer;
308         *pxRecvMsgBuffer = pxCtx->xRecvMsgBuffer;
309         *ppvBackendContext = pvContextBuffer;
310     }
311 }
312 
313 /**
314  * @brief Lock the given SlirpBackendContext_t object.
315  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
316  */
vLockSlirpContext(SlirpBackendContext_t * pxCtx)317 static inline void vLockSlirpContext( SlirpBackendContext_t * pxCtx )
318 {
319     int lRslt;
320 
321     configASSERT( pxCtx != NULL );
322 
323     #if defined( _WIN32 )
324         lRslt = WaitForSingleObject( pxCtx->xMutex, INFINITE );
325         configASSERT( lRslt == 0 );
326     #else /* _WIN32 */
327         lRslt = pthread_mutex_lock( &( pxCtx->xMutex ) );
328         configASSERT( lRslt == 0 );
329     #endif /* _WIN32 */
330 }
331 
332 /**
333  * @brief Unlock the given SlirpBackendContext_t object.
334  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
335  */
vUnlockSlirpContext(SlirpBackendContext_t * pxCtx)336 static inline void vUnlockSlirpContext( SlirpBackendContext_t * pxCtx )
337 {
338     int lRslt;
339 
340     #if defined( _WIN32 )
341         lRslt = ( int ) ReleaseMutex( pxCtx->xMutex );
342         configASSERT( lRslt != 0 );
343     #else /* _WIN32 */
344         lRslt = pthread_mutex_unlock( &( pxCtx->xMutex ) );
345         configASSERT( lRslt == 0 );
346     #endif /* _WIN32 */
347 }
348 
349 /**
350  * @brief Deinitialize function for the slirp backend driver.
351  *
352  * @param [in,out] pvBackendContext Context to deinitialize / free.
353  */
vMBuffNetifBackendDeInit(void * pvBackendContext)354 void vMBuffNetifBackendDeInit( void * pvBackendContext )
355 {
356     SlirpBackendContext_t * pxCtx = NULL;
357 
358     if( pvBackendContext != NULL )
359     {
360         pxCtx = ( SlirpBackendContext_t * ) pvBackendContext;
361 
362         pxCtx->xExitFlag = pdTRUE;
363 
364         #if defined( _WIN32 )
365             ( void ) WaitForSingleObject( ( HANDLE ) pxCtx->xTxThread, INFINITE );
366             ( void ) WaitForSingleObject( ( HANDLE ) pxCtx->xRxThread, INFINITE );
367         #else
368             pthread_join( pxCtx->xTxThread, NULL );
369             pthread_join( pxCtx->xRxThread, NULL );
370         #endif
371 
372         vLockSlirpContext( pxCtx );
373 
374         #if defined( _WIN32 )
375             ( void ) CloseHandle( pxCtx->xMutex );
376         #else
377             ( void ) pthread_mutex_destroy( &( pxCtx->xMutex ) );
378         #endif
379 
380         slirp_cleanup( pxCtx->pxSlirp );
381 
382         vMessageBufferDelete( pxCtx->xSendMsgBuffer );
383         vMessageBufferDelete( pxCtx->xRecvMsgBuffer );
384 
385         free( ( void * ) ( pxCtx->pxPollFdArray ) );
386         free( ( void * ) pxCtx );
387         pxCtx = NULL;
388     }
389 }
390 
391 /**
392  * @brief Callback called by libslirp when an incomming frame is available.
393  *
394  * @param [in] pvBuffer Pointer to a buffer containing the incoming frame.
395  * @param [in] uxLen Length of the incoming frame.
396  * @param [in] pvOpaque Opaque context pointer ( points to a SlirpBackendContext_t ).
397  * @return slirp_ssize_t 0U Always.
398  */
xSlirp_WriteCallback(const void * pvBuffer,size_t uxLen,void * pvOpaque)399 static slirp_ssize_t xSlirp_WriteCallback( const void * pvBuffer,
400                                            size_t uxLen,
401                                            void * pvOpaque )
402 {
403     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
404     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
405 
406     if( uxLen > ( NETWORK_BUFFER_LEN ) )
407     {
408         fprintf( stderr, "Dropping RX frame of length: %zu > %zu. Frame received from libslirp is too large.\n", uxLen, ( size_t ) NETWORK_BUFFER_LEN );
409     }
410     else if( uxLen < sizeof( EthernetHeader_t ) )
411     {
412         fprintf( stderr, "Dropping RX frame of length: %zu < %zu. Frame received from libslirp is too small.\n", uxLen, sizeof( EthernetHeader_t ) );
413     }
414     else if( xMessageBufferSpacesAvailable( pxCtx->xRecvMsgBuffer ) < ( uxLen + 4U ) )
415     {
416         fprintf( stderr, "Dropping RX frame of length: %zu. xRecvMsgBuffer is full\n", uxLen );
417     }
418     else
419     {
420         size_t uxBytesSent;
421 
422         uxBytesSent = xMessageBufferSendFromISR( pxCtx->xRecvMsgBuffer,
423                                                  pvBuffer,
424                                                  uxLen,
425                                                  &xHigherPriorityTaskWoken );
426 
427         configASSERT( uxBytesSent == uxLen );
428 
429         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
430     }
431 
432     return 0U;
433 }
434 
435 
436 /**
437  * @brief Checks that pxPollFdArray is large enough to accomodate the specified number of file descriptors.
438  *
439  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
440  * @param [in] xDesiredSize Desired number of file descriptors to store.
441  */
vEnsurePollfdSize(SlirpBackendContext_t * pxCtx,size_t xDesiredSize)442 static void vEnsurePollfdSize( SlirpBackendContext_t * pxCtx,
443                                size_t xDesiredSize )
444 {
445     configASSERT( pxCtx != NULL );
446 
447     if( pxCtx->xPollFdArraySize < xDesiredSize )
448     {
449         size_t xNewSize;
450 
451         if( pxCtx->xPollFdArraySize > 0 )
452         {
453             xNewSize = 2U * pxCtx->xPollFdArraySize;
454         }
455         else
456         {
457             xNewSize = 10U;
458         }
459 
460         if( xDesiredSize > xNewSize )
461         {
462             xNewSize = xDesiredSize;
463         }
464 
465         if( pxCtx->pxPollFdArray == NULL )
466         {
467             pxCtx->pxPollFdArray = ( struct pollfd * ) malloc( xNewSize * sizeof( struct pollfd ) );
468         }
469         else
470         {
471             pxCtx->pxPollFdArray = ( struct pollfd * ) realloc( pxCtx->pxPollFdArray, xNewSize * sizeof( struct pollfd ) );
472         }
473 
474         configASSERT( pxCtx->pxPollFdArray != NULL );
475 
476         pxCtx->xPollFdArraySize = xNewSize;
477     }
478 }
479 
480 /**
481  * @brief Convert from a libslirp poll event flag to a posix poll flag.
482  * @param [in] lSlirpPollFlags libslirp poll event flags to be converted.
483  * @return The equivalent posix poll events.
484  */
lSlirpEventsToNativePollEvents(int lSlirpPollFlags)485 static inline int lSlirpEventsToNativePollEvents( int lSlirpPollFlags )
486 {
487     int lPosixPollFlags = 0U;
488 
489     if( lSlirpPollFlags & SLIRP_POLL_IN )
490     {
491         lPosixPollFlags |= POLLIN;
492     }
493 
494     if( lSlirpPollFlags & SLIRP_POLL_OUT )
495     {
496         lPosixPollFlags |= POLLOUT;
497     }
498 
499     if( lSlirpPollFlags & SLIRP_POLL_PRI )
500     {
501         lPosixPollFlags |= POLLPRI;
502     }
503 
504     if( lSlirpPollFlags & SLIRP_POLL_ERR )
505     {
506         lPosixPollFlags |= POLLERR;
507     }
508 
509     if( lSlirpPollFlags & SLIRP_POLL_HUP )
510     {
511         lPosixPollFlags |= POLLHUP;
512     }
513 
514     return lPosixPollFlags;
515 }
516 
517 /**
518  * @brief Convert from posix poll event flags to libslirp poll event flags.
519  * @param [in] lPosixPollFlags Posix poll event flags to be converted.
520  * @return The equivalent libslirp poll events.
521  */
lNativePollEventsToSlirpEvents(int lPosixPollFlags)522 static inline int lNativePollEventsToSlirpEvents( int lPosixPollFlags )
523 {
524     int lSlirpPollFlags = 0U;
525 
526     if( lPosixPollFlags & POLLIN )
527     {
528         lSlirpPollFlags |= SLIRP_POLL_IN;
529     }
530 
531     if( lPosixPollFlags & POLLOUT )
532     {
533         lSlirpPollFlags |= SLIRP_POLL_OUT;
534     }
535 
536     if( lPosixPollFlags & POLLPRI )
537     {
538         lSlirpPollFlags |= SLIRP_POLL_PRI;
539     }
540 
541     if( lPosixPollFlags & POLLERR )
542     {
543         lSlirpPollFlags |= SLIRP_POLL_ERR;
544     }
545 
546     if( lPosixPollFlags & POLLHUP )
547     {
548         lSlirpPollFlags |= SLIRP_POLL_HUP;
549     }
550 
551     return lSlirpPollFlags;
552 }
553 
554 /**
555  * @brief SlirpAddPollCb implementation passed to libslirp during initialization.
556  * @param [in] fd File descriptor to add to the polling list.
557  * @param [in] lSlirpFlags Flags to be placed in the relevant events field.
558  * @param [in] pvOpaque Opaque pointer to the relevant SlirpBackendContext_t.
559  */
lSlirpAddPollCallback(int lFd,int lSlirpFlags,void * pvOpaque)560 static int lSlirpAddPollCallback( int lFd,
561                                   int lSlirpFlags,
562                                   void * pvOpaque )
563 {
564     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
565 
566     configASSERT( pxCtx != NULL );
567     configASSERT( pxCtx->nfds < INT_MAX );
568 
569     vEnsurePollfdSize( pxCtx, pxCtx->nfds + 1U );
570 
571     pxCtx->pxPollFdArray[ pxCtx->nfds ].fd = lFd;
572     pxCtx->pxPollFdArray[ pxCtx->nfds ].events = lSlirpEventsToNativePollEvents( lSlirpFlags );
573     pxCtx->pxPollFdArray[ pxCtx->nfds ].revents = 0U;
574 
575     pxCtx->nfds++;
576 
577     return ( int ) ( pxCtx->nfds - 1U );
578 }
579 
580 /**
581  * @brief SlirpGetREventsCb implementation passed to libslirp during initialization.
582  * @param [in] lIdx Index returned by lSlirpAddPollCallback for the given file descriptor.
583  * @param [in] pvOpaque Opaque pointer to the relevant SlirpBackendContext_t.
584  * @return An integer with the relevant libslirp polling flags set.
585  */
lSlirpGetREventsCallback(int lIdx,void * pvOpaque)586 static int lSlirpGetREventsCallback( int lIdx,
587                                      void * pvOpaque )
588 {
589     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
590     int rEvents = 0U;
591     nfds_t xIndex;
592 
593     configASSERT( pxCtx );
594 
595     configASSERT( lIdx >= 0 );
596 
597     xIndex = ( nfds_t ) lIdx;
598     configASSERT( xIndex < pxCtx->nfds );
599     configASSERT( xIndex < pxCtx->xPollFdArraySize );
600 
601     rEvents = ( pxCtx->pxPollFdArray[ xIndex ].revents );
602 
603     return lNativePollEventsToSlirpEvents( rEvents );
604 }
605 
606 /**
607  * @brief Posix thread implementation which reads from xSendMsgBuffer and passes outgoing frames to libslirp.
608  * @param [in] pvParameters Opaque pointer to the relevant SlirpBackendContext_t.
609  * @return NULL
610  */
vTransmitThread(void * pvParameters)611 static THREAD_RETURN THREAD_FUNC_DEF vTransmitThread( void * pvParameters )
612 {
613     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvParameters;
614     const time_t xMaxMSToWait = 1000;
615     uint8_t ucFrameSendBuffer[ NETWORK_BUFFER_LEN ];
616 
617     #if !defined( _WIN32 )
618         sigset_t set;
619 
620         /*
621          * disable signals to avoid treating this thread as a FreeRTOS task and putting
622          * it to sleep by the scheduler
623          */
624         sigfillset( &set );
625         pthread_sigmask( SIG_SETMASK, &set, NULL );
626     #endif /* !defined(_WIN32) */
627 
628     configASSERT( pxCtx != NULL );
629 
630     while( pxCtx->xExitFlag == pdFALSE )
631     {
632         /* Wait until notified of something to send. */
633         #if defined( _WIN32 )
634             ( void ) WaitForSingleObject( pxCtx->pvSendEvent, ( DWORD ) xMaxMSToWait );
635         #else
636             event_wait_timed( pxCtx->pvSendEvent, xMaxMSToWait );
637         #endif
638 
639         while( xMessageBufferIsEmpty( pxCtx->xSendMsgBuffer ) == pdFALSE )
640         {
641             BaseType_t xHigherPriorityTaskWoken = pdFALSE;
642             size_t uxFrameLen = xMessageBufferReceiveFromISR( pxCtx->xSendMsgBuffer, ucFrameSendBuffer, sizeof( ucFrameSendBuffer ), &xHigherPriorityTaskWoken );
643 
644             vLockSlirpContext( pxCtx );
645             {
646                 slirp_input( pxCtx->pxSlirp, ucFrameSendBuffer, uxFrameLen );
647             }
648             vUnlockSlirpContext( pxCtx );
649 
650             portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
651         }
652     }
653 
654     return ( THREAD_RETURN ) NULL;
655 }
656 
657 /**
658  * @brief Posix thread implementation which polls file descriptors used by libslirp and forwards
659  *        incoming frames to xRecvMsgBuffer indirectly by calling xSlirp_WriteCallback.
660  * @param [in] pvParameters Opaque pointer to the relevant SlirpBackendContext_t.
661  * @return NULL
662  */
vReceiveThread(void * pvParameters)663 static THREAD_RETURN THREAD_FUNC_DEF vReceiveThread( void * pvParameters )
664 {
665     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvParameters;
666 
667     #if !defined( _WIN32 )
668         sigset_t set;
669 
670         /*
671          * disable signals to avoid treating this thread as a FreeRTOS task and putting
672          * it to sleep by the scheduler
673          */
674         sigfillset( &set );
675         pthread_sigmask( SIG_SETMASK, &set, NULL );
676     #endif /* !defined(_WIN32) */
677 
678     configASSERT( pxCtx != NULL );
679 
680     while( pxCtx->xExitFlag == pdFALSE )
681     {
682         int lPollRslt;
683 
684         uint32_t ulPollerTimeoutMs = 100 * 1000U;
685 
686         vLockSlirpContext( pxCtx );
687         {
688             pxCtx->nfds = 0;
689             slirp_pollfds_fill( pxCtx->pxSlirp, &ulPollerTimeoutMs, lSlirpAddPollCallback, pxCtx );
690         }
691         vUnlockSlirpContext( pxCtx );
692 
693         errno = 0;
694         #if defined( _WIN32 )
695             lPollRslt = WSAPoll( pxCtx->pxPollFdArray, pxCtx->nfds, ( int ) ulPollerTimeoutMs );
696         #else /* _WIN32 */
697             lPollRslt = poll( pxCtx->pxPollFdArray, pxCtx->nfds, ulPollerTimeoutMs );
698         #endif /* _WIN32 */
699 
700         if( lPollRslt > 0 )
701         {
702             lPollRslt = 0;
703         }
704 
705         vLockSlirpContext( pxCtx );
706         {
707             slirp_pollfds_poll( pxCtx->pxSlirp, lPollRslt, lSlirpGetREventsCallback, ( void * ) pxCtx );
708         }
709         vUnlockSlirpContext( pxCtx );
710     }
711 
712     return ( THREAD_RETURN ) NULL;
713 }
714 
715 #if defined( _WIN32 )
716 
717 /**
718  * @brief Callback function passed to libslirp to get the current time in nanoseconds.
719  *
720  * @param [in] pvOpaque Opaque context pointer (unused).
721  * @return int64_t Current time in nanoseconds.
722  */
llSlirp_ClockGetNanoSeconds(void * pvOpaque)723     static int64_t llSlirp_ClockGetNanoSeconds( void * pvOpaque )
724     {
725         LARGE_INTEGER xTime;
726         int64_t lTime;
727 
728         ( void ) pvOpaque;
729 
730         QueryPerformanceCounter( &xTime );
731 
732         lTime = ( xTime.QuadPart * 1000000000 / xClockFrequency.QuadPart );
733 
734         return lTime;
735     }
736 #else /* if defined( _WIN32 ) */
737 
738 /**
739  * @brief Callback function passed to libslirp to get the current time in nanoseconds.
740  *
741  * @param [in] pvOpaque Opaque context pointer (unused).
742  * @return int64_t Current time in nanoseconds.
743  */
llSlirp_ClockGetNanoSeconds(void * pvOpaque)744     static int64_t llSlirp_ClockGetNanoSeconds( void * pvOpaque )
745     {
746         struct timespec ts;
747         int64_t llTimeNs = 0;
748 
749         clock_gettime( CLOCK_MONOTONIC, &ts );
750 
751         ( void ) pvOpaque;
752 
753         llTimeNs = ( ts.tv_sec * 1000000000LL ) + ts.tv_nsec;
754         return llTimeNs;
755     }
756 #endif /* if defined( _WIN32 ) */
757 
758 /**
759  * @brief Callback funciton passed to libslirp to report a runtime error.
760  *
761  * @param [in] msg Error message
762  * @param pvOpaque Opaque context pointer (unused).
763  */
vSlirpGuestError(const char * msg,void * pvOpaque)764 static void vSlirpGuestError( const char * msg,
765                               void * pvOpaque )
766 {
767     fprintf( stderr, "libslirp guest error: %s\n", msg );
768     exit( 1 );
769 }
770 
771 /**
772  * @brief Stub callback function for libslirp timer API.
773  *
774  * @param cb Unused.
775  * @param pvCallbackContext Unused.
776  * @param pvOpaque Unused.
777  * @return void* NULL
778  */
pvSlirp_TimerNew(SlirpTimerCb cb,void * pvCallbackContext,void * pvOpaque)779 static void * pvSlirp_TimerNew( SlirpTimerCb cb,
780                                 void * pvCallbackContext,
781                                 void * pvOpaque )
782 {
783     /* Stub */
784     ( void ) cb;
785     ( void ) pvCallbackContext;
786     ( void ) pvOpaque;
787     configASSERT( 0 );
788     return NULL;
789 }
790 
791 /**
792  * @brief Stub callback function for libslirp timer API.
793  *
794  * @param pvTimer Unused.
795  * @param pvOpaque Unused.
796  */
vSlirp_TimerFree(void * pvTimer,void * pvOpaque)797 static void vSlirp_TimerFree( void * pvTimer,
798                               void * pvOpaque )
799 {
800     /* Stub */
801     ( void ) pvTimer;
802     ( void ) pvOpaque;
803     configASSERT( 0 );
804 }
805 
806 /**
807  * @brief Stub callback function for libslirp timer API.
808  *
809  * @param pvTimer Unused.
810  * @param expire_time Unused.
811  * @param pvOpaque Unused.
812  */
vSlirp_TimerModify(void * pvTimer,int64_t expire_time,void * pvOpaque)813 static void vSlirp_TimerModify( void * pvTimer,
814                                 int64_t expire_time,
815                                 void * pvOpaque )
816 {
817     /* Stub */
818     ( void ) pvTimer;
819     ( void ) expire_time;
820     ( void ) pvOpaque;
821     configASSERT( 0 );
822 }
823 
824 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
825 
826 /**
827  * @brief Stub callback function for libslirp timer API.
828  *
829  * @param xTimerId Unused.
830  * @param cb_opaque Unused.
831  * @param pvOpaque Unused.
832  * @return void* NULL
833  */
pvSlirpTimerNewOpaque(SlirpTimerId xTimerId,void * cb_opaque,void * pvOpaque)834     static void * pvSlirpTimerNewOpaque( SlirpTimerId xTimerId,
835                                          void * cb_opaque,
836                                          void * pvOpaque )
837     {
838         /* Stub */
839         ( void ) xTimerId;
840         ( void ) cb_opaque;
841         ( void ) pvOpaque;
842         configASSERT( 0 );
843         return NULL;
844     }
845 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
846 
847 /**
848  * @brief Called by libslipr when a new file descriptor / socket is opened.
849  *
850  * @param lFd File descriptor to watch.
851  * @param pvOpaque Pointer to driver context.
852  */
vSlirp_RegisterPollFd(int lFd,void * pvOpaque)853 static void vSlirp_RegisterPollFd( int lFd,
854                                    void * pvOpaque )
855 {
856     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
857 
858     configASSERT( pxCtx != NULL );
859 
860     ( void ) lFd;
861 
862     vEnsurePollfdSize( pxCtx, pxCtx->nfds + 1 );
863 }
864 
865 /**
866  * @brief Stub callback function.
867  *
868  * @param lFd Unused.
869  * @param pvOpaque Unused.
870  */
vSlirp_UnRegisterPollFd(int lFd,void * pvOpaque)871 static void vSlirp_UnRegisterPollFd( int lFd,
872                                      void * pvOpaque )
873 {
874     ( void ) lFd;
875     ( void ) pvOpaque;
876 }
877 
878 /**
879  * @brief Stub callback function.
880  *
881  * @param pvOpaque Unused.
882  */
vSlirp_Notify(void * pvOpaque)883 static void vSlirp_Notify( void * pvOpaque )
884 {
885     /* Stub */
886     ( void ) pvOpaque;
887 }
888 
889 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
890 
891 /**
892  * @brief Stub callback function.
893  *
894  * @param pxSlirp Unused.
895  * @param pvOpaque Unused.
896  */
vSlirp_InitCompleted(Slirp * pxSlirp,void * pvOpaque)897     static void vSlirp_InitCompleted( Slirp * pxSlirp,
898                                       void * pvOpaque )
899     {
900         /* Stub */
901         ( void ) pxSlirp;
902         ( void ) pvOpaque;
903     }
904 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
905