xref: /FreeRTOS-Plus-TCP-v4.0.0/source/portable/NetworkInterface/libslirp/MBuffNetifBackendLibslirp.c (revision c64bef1957a72e35be2f6584dafea00df0ed6f03)
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 /* 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     #elif SLIRP_CHECK_VERSION( 4U, 3U, 0U )
201         xSlirpConfig.version = 3U;
202     #elif SLIRP_CHECK_VERSION( 4U, 2U, 0U )
203         xSlirpConfig.version = 2U;
204     #else
205         xSlirpConfig.version = 1U;
206     #endif
207 
208     xSlirpConfig.restricted = false;
209 
210     /* IPv4 Enabled */
211     xSlirpConfig.in_enabled = true;
212     xSlirpConfig.vnetwork.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 0U );
213     xSlirpConfig.vnetmask.s_addr = FreeRTOS_inet_addr_quick( 255U, 255U, 255U, 0U );
214     xSlirpConfig.vhost.s_addr = FreeRTOS_inet_addr_quick( 10, 0U, 2U, 2U );
215 
216     /* IPv6 disabled */
217     xSlirpConfig.in6_enabled = false;
218 
219     xSlirpConfig.vhostname = NULL;
220     xSlirpConfig.tftp_server_name = NULL;
221     xSlirpConfig.tftp_path = NULL;
222     xSlirpConfig.bootfile = NULL;
223 
224     xSlirpConfig.vdhcp_start.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 15U );
225     xSlirpConfig.vnameserver.s_addr = FreeRTOS_inet_addr_quick( 10U, 0U, 2U, 3U );
226     xSlirpConfig.vdnssearch = NULL;
227     xSlirpConfig.vdomainname = NULL;
228 
229     xSlirpConfig.if_mtu = IF_MTU_DEFAULT;
230     xSlirpConfig.if_mru = IF_MRU_DEFAULT;
231 
232     xSlirpConfig.disable_host_loopback = false;
233     xSlirpConfig.enable_emu = false;
234 
235     #if SLIRP_CHECK_VERSION( 4U, 3U, 0U )
236         xSlirpConfig.disable_dns = false;
237     #endif
238 
239     #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
240         xSlirpConfig.disable_dhcp = false;
241     #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
242 
243     if( ( pxSendMsgBuffer == NULL ) ||
244         ( pxRecvMsgBuffer == NULL ) ||
245         ( pvSendEvent == NULL ) ||
246         ( ppvBackendContext == NULL ) )
247     {
248         fprintf( stderr, "NULL parameter passed to vMBuffNetifBackendInit.\n" );
249     }
250     else
251     {
252         pvContextBuffer = pvPortMalloc( sizeof( SlirpBackendContext_t ) );
253 
254         if( pvContextBuffer == NULL )
255         {
256             FreeRTOS_printf( ( "Failed to allocate memory for pvContextBuffer" ) );
257             configASSERT( 0 );
258         }
259     }
260 
261     if( pvContextBuffer != NULL )
262     {
263         pxCtx = ( SlirpBackendContext_t * ) pvContextBuffer;
264 
265         pxCtx->xSendMsgBuffer = xMessageBufferCreateStatic( xSEND_BUFFER_SIZE,
266                                                             pxCtx->pucTxBuffer,
267                                                             &( pxCtx->xSendMsgBufferStatic ) );
268 
269         if( pxCtx->xSendMsgBuffer == NULL )
270         {
271             xErrorFlag = pdTRUE;
272         }
273 
274         pxCtx->xRecvMsgBuffer = xMessageBufferCreateStatic( xSEND_BUFFER_SIZE,
275                                                             pxCtx->pucRxBuffer,
276                                                             &( pxCtx->xRecvMsgBufferStatic ) );
277 
278         if( pxCtx->xRecvMsgBuffer == NULL )
279         {
280             xErrorFlag = pdTRUE;
281         }
282 
283         /* Copy pointer to event struct */
284         pxCtx->pvSendEvent = pvSendEvent;
285 
286         /* Initialize libslirp */
287         pxCtx->pxSlirp = slirp_new( &xSlirpConfig, &xSlirpCallbacks, pvContextBuffer );
288 
289         if( pxCtx->pxSlirp )
290         {
291             #if defined( _WIN32 )
292                 pxCtx->xMutex = CreateMutex( NULL, FALSE, NULL );
293                 configASSERT( pxCtx->xMutex != ( Mutex_t ) NULL );
294 
295                 pxCtx->xTxThread = _beginthreadex( NULL, 0, vTransmitThread, pvContextBuffer, 0, NULL );
296                 configASSERT( pxCtx->xTxThread != ( Thread_t ) NULL );
297 
298                 pxCtx->xRxThread = _beginthreadex( NULL, 0, vReceiveThread, pvContextBuffer, 0, NULL );
299                 configASSERT( pxCtx->xRxThread != ( Thread_t ) NULL );
300 
301                 ( void ) QueryPerformanceFrequency( &xClockFrequency );
302             #else /* if defined( _WIN32 ) */
303                 int lRslt;
304                 lRslt = pthread_mutex_init( &( pxCtx->xMutex ), NULL );
305                 configASSERT( lRslt == 0U );
306 
307                 lRslt = pthread_create( &( pxCtx->xTxThread ), NULL, vTransmitThread, pvContextBuffer );
308                 configASSERT( lRslt == 0U );
309 
310                 lRslt = pthread_create( &( pxCtx->xRxThread ), NULL, vReceiveThread, pvContextBuffer );
311                 configASSERT( lRslt == 0U );
312             #endif /* if defined( _WIN32 ) */
313         }
314     }
315 
316     /* vTaskDelay(2 * 1000); */
317 
318     if( pvContextBuffer != NULL )
319     {
320         *pxSendMsgBuffer = pxCtx->xSendMsgBuffer;
321         *pxRecvMsgBuffer = pxCtx->xRecvMsgBuffer;
322         *ppvBackendContext = pvContextBuffer;
323     }
324 }
325 
326 /**
327  * @brief Lock the given SlirpBackendContext_t object.
328  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
329  */
vLockSlirpContext(SlirpBackendContext_t * pxCtx)330 static inline void vLockSlirpContext( SlirpBackendContext_t * pxCtx )
331 {
332     int lRslt;
333 
334     configASSERT( pxCtx != NULL );
335 
336     #if defined( _WIN32 )
337         lRslt = WaitForSingleObject( pxCtx->xMutex, INFINITE );
338         configASSERT( lRslt == 0 );
339     #else /* _WIN32 */
340         lRslt = pthread_mutex_lock( &( pxCtx->xMutex ) );
341         configASSERT( lRslt == 0 );
342     #endif /* _WIN32 */
343 }
344 
345 /**
346  * @brief Unlock the given SlirpBackendContext_t object.
347  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
348  */
vUnlockSlirpContext(SlirpBackendContext_t * pxCtx)349 static inline void vUnlockSlirpContext( SlirpBackendContext_t * pxCtx )
350 {
351     int lRslt;
352 
353     #if defined( _WIN32 )
354         lRslt = ( int ) ReleaseMutex( pxCtx->xMutex );
355         configASSERT( lRslt != 0 );
356     #else /* _WIN32 */
357         lRslt = pthread_mutex_unlock( &( pxCtx->xMutex ) );
358         configASSERT( lRslt == 0 );
359     #endif /* _WIN32 */
360 }
361 
362 /**
363  * @brief Deinitialize function for the slirp backend driver.
364  *
365  * @param [in,out] pvBackendContext Context to deinitialize / free.
366  */
vMBuffNetifBackendDeInit(void * pvBackendContext)367 void vMBuffNetifBackendDeInit( void * pvBackendContext )
368 {
369     SlirpBackendContext_t * pxCtx = NULL;
370 
371     if( pvBackendContext != NULL )
372     {
373         pxCtx = ( SlirpBackendContext_t * ) pvBackendContext;
374 
375         pxCtx->xExitFlag = pdTRUE;
376 
377         #if defined( _WIN32 )
378             ( void ) WaitForSingleObject( ( HANDLE ) pxCtx->xTxThread, INFINITE );
379             ( void ) WaitForSingleObject( ( HANDLE ) pxCtx->xRxThread, INFINITE );
380         #else
381             pthread_join( pxCtx->xTxThread, NULL );
382             pthread_join( pxCtx->xRxThread, NULL );
383         #endif
384 
385         vLockSlirpContext( pxCtx );
386 
387         #if defined( _WIN32 )
388             ( void ) CloseHandle( pxCtx->xMutex );
389         #else
390             ( void ) pthread_mutex_destroy( &( pxCtx->xMutex ) );
391         #endif
392 
393         slirp_cleanup( pxCtx->pxSlirp );
394 
395         vMessageBufferDelete( pxCtx->xSendMsgBuffer );
396         vMessageBufferDelete( pxCtx->xRecvMsgBuffer );
397 
398         free( ( void * ) ( pxCtx->pxPollFdArray ) );
399         free( ( void * ) pxCtx );
400         pxCtx = NULL;
401     }
402 }
403 
404 /**
405  * @brief Callback called by libslirp when an incomming frame is available.
406  *
407  * @param [in] pvBuffer Pointer to a buffer containing the incoming frame.
408  * @param [in] uxLen Length of the incoming frame.
409  * @param [in] pvOpaque Opaque context pointer ( points to a SlirpBackendContext_t ).
410  * @return slirp_ssize_t 0U Always.
411  */
xSlirp_WriteCallback(const void * pvBuffer,size_t uxLen,void * pvOpaque)412 static slirp_ssize_t xSlirp_WriteCallback( const void * pvBuffer,
413                                            size_t uxLen,
414                                            void * pvOpaque )
415 {
416     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
417     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
418 
419     if( uxLen > ( NETWORK_BUFFER_LEN ) )
420     {
421         fprintf( stderr, "Dropping RX frame of length: %zu > %zu. Frame received from libslirp is too large.\n", uxLen, ( size_t ) NETWORK_BUFFER_LEN );
422     }
423     else if( uxLen < sizeof( EthernetHeader_t ) )
424     {
425         fprintf( stderr, "Dropping RX frame of length: %zu < %zu. Frame received from libslirp is too small.\n", uxLen, sizeof( EthernetHeader_t ) );
426     }
427     else if( xMessageBufferSpacesAvailable( pxCtx->xRecvMsgBuffer ) < ( uxLen + 4U ) )
428     {
429         fprintf( stderr, "Dropping RX frame of length: %zu. xRecvMsgBuffer is full\n", uxLen );
430     }
431     else
432     {
433         size_t uxBytesSent;
434 
435         uxBytesSent = xMessageBufferSendFromISR( pxCtx->xRecvMsgBuffer,
436                                                  pvBuffer,
437                                                  uxLen,
438                                                  &xHigherPriorityTaskWoken );
439 
440         configASSERT( uxBytesSent == uxLen );
441 
442         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
443     }
444 
445     return 0U;
446 }
447 
448 
449 /**
450  * @brief Checks that pxPollFdArray is large enough to accomodate the specified number of file descriptors.
451  *
452  * @param [in] pxCtx Pointer to the relevant SlirpBackendContext_t.
453  * @param [in] xDesiredSize Desired number of file descriptors to store.
454  */
vEnsurePollfdSize(SlirpBackendContext_t * pxCtx,size_t xDesiredSize)455 static void vEnsurePollfdSize( SlirpBackendContext_t * pxCtx,
456                                size_t xDesiredSize )
457 {
458     configASSERT( pxCtx != NULL );
459 
460     if( pxCtx->xPollFdArraySize < xDesiredSize )
461     {
462         size_t xNewSize;
463 
464         if( pxCtx->xPollFdArraySize > 0 )
465         {
466             xNewSize = 2U * pxCtx->xPollFdArraySize;
467         }
468         else
469         {
470             xNewSize = 10U;
471         }
472 
473         if( xDesiredSize > xNewSize )
474         {
475             xNewSize = xDesiredSize;
476         }
477 
478         if( pxCtx->pxPollFdArray == NULL )
479         {
480             pxCtx->pxPollFdArray = ( struct pollfd * ) malloc( xNewSize * sizeof( struct pollfd ) );
481 
482             if( pxCtx->pxPollFdArray == NULL )
483             {
484                 FreeRTOS_printf( ( "Failed to allocate memory for pxCtx->pxPollFdArray" ) );
485                 configASSERT( 0 );
486             }
487         }
488         else
489         {
490             pxCtx->pxPollFdArray = ( struct pollfd * ) realloc( pxCtx->pxPollFdArray, xNewSize * sizeof( struct pollfd ) );
491         }
492 
493         configASSERT( pxCtx->pxPollFdArray != NULL );
494 
495         pxCtx->xPollFdArraySize = xNewSize;
496     }
497 }
498 
499 /**
500  * @brief Convert from a libslirp poll event flag to a posix poll flag.
501  * @param [in] lSlirpPollFlags libslirp poll event flags to be converted.
502  * @return The equivalent posix poll events.
503  */
lSlirpEventsToNativePollEvents(int lSlirpPollFlags)504 static inline int lSlirpEventsToNativePollEvents( int lSlirpPollFlags )
505 {
506     int lPosixPollFlags = 0U;
507 
508     if( lSlirpPollFlags & SLIRP_POLL_IN )
509     {
510         lPosixPollFlags |= POLLIN;
511     }
512 
513     if( lSlirpPollFlags & SLIRP_POLL_OUT )
514     {
515         lPosixPollFlags |= POLLOUT;
516     }
517 
518     if( lSlirpPollFlags & SLIRP_POLL_PRI )
519     {
520         lPosixPollFlags |= POLLPRI;
521     }
522 
523     if( lSlirpPollFlags & SLIRP_POLL_ERR )
524     {
525         lPosixPollFlags |= POLLERR;
526     }
527 
528     if( lSlirpPollFlags & SLIRP_POLL_HUP )
529     {
530         lPosixPollFlags |= POLLHUP;
531     }
532 
533     #if defined( _WIN32 )
534         lPosixPollFlags &= ~( POLLPRI | POLLERR | POLLHUP );
535     #endif
536 
537     return lPosixPollFlags;
538 }
539 
540 /**
541  * @brief Convert from posix poll event flags to libslirp poll event flags.
542  * @param [in] lPosixPollFlags Posix poll event flags to be converted.
543  * @return The equivalent libslirp poll events.
544  */
lNativePollEventsToSlirpEvents(int lPosixPollFlags)545 static inline int lNativePollEventsToSlirpEvents( int lPosixPollFlags )
546 {
547     int lSlirpPollFlags = 0U;
548 
549     if( lPosixPollFlags & POLLIN )
550     {
551         lSlirpPollFlags |= SLIRP_POLL_IN;
552     }
553 
554     if( lPosixPollFlags & POLLOUT )
555     {
556         lSlirpPollFlags |= SLIRP_POLL_OUT;
557     }
558 
559     if( lPosixPollFlags & POLLPRI )
560     {
561         lSlirpPollFlags |= SLIRP_POLL_PRI;
562     }
563 
564     if( lPosixPollFlags & POLLERR )
565     {
566         lSlirpPollFlags |= SLIRP_POLL_ERR;
567     }
568 
569     if( lPosixPollFlags & POLLHUP )
570     {
571         lSlirpPollFlags |= SLIRP_POLL_HUP;
572     }
573 
574     return lSlirpPollFlags;
575 }
576 
577 /**
578  * @brief SlirpAddPollCb implementation passed to libslirp during initialization.
579  * @param [in] fd File descriptor to add to the polling list.
580  * @param [in] lSlirpFlags Flags to be placed in the relevant events field.
581  * @param [in] pvOpaque Opaque pointer to the relevant SlirpBackendContext_t.
582  */
lSlirpAddPollCallback(int lFd,int lSlirpFlags,void * pvOpaque)583 static int lSlirpAddPollCallback( int lFd,
584                                   int lSlirpFlags,
585                                   void * pvOpaque )
586 {
587     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
588 
589     configASSERT( pxCtx != NULL );
590     configASSERT( pxCtx->nfds < INT_MAX );
591 
592     vEnsurePollfdSize( pxCtx, pxCtx->nfds + 1U );
593 
594     pxCtx->pxPollFdArray[ pxCtx->nfds ].fd = lFd;
595     pxCtx->pxPollFdArray[ pxCtx->nfds ].events = lSlirpEventsToNativePollEvents( lSlirpFlags );
596     pxCtx->pxPollFdArray[ pxCtx->nfds ].revents = 0U;
597 
598     pxCtx->nfds++;
599 
600     return ( int ) ( pxCtx->nfds - 1U );
601 }
602 
603 /**
604  * @brief SlirpGetREventsCb implementation passed to libslirp during initialization.
605  * @param [in] lIdx Index returned by lSlirpAddPollCallback for the given file descriptor.
606  * @param [in] pvOpaque Opaque pointer to the relevant SlirpBackendContext_t.
607  * @return An integer with the relevant libslirp polling flags set.
608  */
lSlirpGetREventsCallback(int lIdx,void * pvOpaque)609 static int lSlirpGetREventsCallback( int lIdx,
610                                      void * pvOpaque )
611 {
612     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
613     int rEvents = 0U;
614     nfds_t xIndex;
615 
616     configASSERT( pxCtx );
617 
618     configASSERT( lIdx >= 0 );
619 
620     xIndex = ( nfds_t ) lIdx;
621     configASSERT( xIndex < pxCtx->nfds );
622     configASSERT( xIndex < pxCtx->xPollFdArraySize );
623 
624     rEvents = ( pxCtx->pxPollFdArray[ xIndex ].revents );
625 
626     return lNativePollEventsToSlirpEvents( rEvents );
627 }
628 
629 /**
630  * @brief Posix thread implementation which reads from xSendMsgBuffer and passes outgoing frames to libslirp.
631  * @param [in] pvParameters Opaque pointer to the relevant SlirpBackendContext_t.
632  * @return NULL
633  */
vTransmitThread(void * pvParameters)634 static THREAD_RETURN THREAD_FUNC_DEF vTransmitThread( void * pvParameters )
635 {
636     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvParameters;
637     const time_t xMaxMSToWait = 1000;
638     uint8_t ucFrameSendBuffer[ NETWORK_BUFFER_LEN ];
639 
640     #if !defined( _WIN32 )
641         sigset_t set;
642 
643         /*
644          * disable signals to avoid treating this thread as a FreeRTOS task and putting
645          * it to sleep by the scheduler
646          */
647         sigfillset( &set );
648         pthread_sigmask( SIG_SETMASK, &set, NULL );
649     #endif /* !defined(_WIN32) */
650 
651     configASSERT( pxCtx != NULL );
652 
653     while( pxCtx->xExitFlag == pdFALSE )
654     {
655         /* Wait until notified of something to send. */
656         #if defined( _WIN32 )
657             ( void ) WaitForSingleObject( pxCtx->pvSendEvent, ( DWORD ) xMaxMSToWait );
658         #else
659             event_wait_timed( pxCtx->pvSendEvent, xMaxMSToWait );
660         #endif
661 
662         while( xMessageBufferIsEmpty( pxCtx->xSendMsgBuffer ) == pdFALSE )
663         {
664             BaseType_t xHigherPriorityTaskWoken = pdFALSE;
665             size_t uxFrameLen = xMessageBufferReceiveFromISR( pxCtx->xSendMsgBuffer, ucFrameSendBuffer, sizeof( ucFrameSendBuffer ), &xHigherPriorityTaskWoken );
666 
667             vLockSlirpContext( pxCtx );
668             {
669                 slirp_input( pxCtx->pxSlirp, ucFrameSendBuffer, uxFrameLen );
670             }
671             vUnlockSlirpContext( pxCtx );
672 
673             portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
674         }
675     }
676 
677     return ( THREAD_RETURN ) NULL;
678 }
679 
680 /**
681  * @brief Posix thread implementation which polls file descriptors used by libslirp and forwards
682  *        incoming frames to xRecvMsgBuffer indirectly by calling xSlirp_WriteCallback.
683  * @param [in] pvParameters Opaque pointer to the relevant SlirpBackendContext_t.
684  * @return NULL
685  */
vReceiveThread(void * pvParameters)686 static THREAD_RETURN THREAD_FUNC_DEF vReceiveThread( void * pvParameters )
687 {
688     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvParameters;
689 
690     #if !defined( _WIN32 )
691         sigset_t set;
692 
693         /*
694          * disable signals to avoid treating this thread as a FreeRTOS task and putting
695          * it to sleep by the scheduler
696          */
697         sigfillset( &set );
698         pthread_sigmask( SIG_SETMASK, &set, NULL );
699     #endif /* !defined(_WIN32) */
700 
701     configASSERT( pxCtx != NULL );
702 
703     while( pxCtx->xExitFlag == pdFALSE )
704     {
705         int lPollRslt;
706 
707         uint32_t ulPollerTimeoutMs = 100 * 1000U;
708 
709         vLockSlirpContext( pxCtx );
710         {
711             pxCtx->nfds = 0;
712             slirp_pollfds_fill( pxCtx->pxSlirp, &ulPollerTimeoutMs, lSlirpAddPollCallback, pxCtx );
713         }
714         vUnlockSlirpContext( pxCtx );
715 
716         errno = 0;
717         #if defined( _WIN32 )
718             lPollRslt = WSAPoll( pxCtx->pxPollFdArray, pxCtx->nfds, ( int ) ulPollerTimeoutMs );
719         #else /* _WIN32 */
720             lPollRslt = poll( pxCtx->pxPollFdArray, pxCtx->nfds, ulPollerTimeoutMs );
721         #endif /* _WIN32 */
722 
723         if( lPollRslt > 0 )
724         {
725             lPollRslt = 0;
726         }
727 
728         vLockSlirpContext( pxCtx );
729         {
730             slirp_pollfds_poll( pxCtx->pxSlirp, lPollRslt, lSlirpGetREventsCallback, ( void * ) pxCtx );
731         }
732         vUnlockSlirpContext( pxCtx );
733     }
734 
735     return ( THREAD_RETURN ) NULL;
736 }
737 
738 #if defined( _WIN32 )
739 
740 /**
741  * @brief Callback function passed to libslirp to get the current time in nanoseconds.
742  *
743  * @param [in] pvOpaque Opaque context pointer (unused).
744  * @return int64_t Current time in nanoseconds.
745  */
llSlirp_ClockGetNanoSeconds(void * pvOpaque)746     static int64_t llSlirp_ClockGetNanoSeconds( void * pvOpaque )
747     {
748         LARGE_INTEGER xTime;
749         int64_t lTime;
750 
751         ( void ) pvOpaque;
752 
753         QueryPerformanceCounter( &xTime );
754 
755         lTime = ( xTime.QuadPart * 1000000000 / xClockFrequency.QuadPart );
756 
757         return lTime;
758     }
759 #else /* if defined( _WIN32 ) */
760 
761 /**
762  * @brief Callback function passed to libslirp to get the current time in nanoseconds.
763  *
764  * @param [in] pvOpaque Opaque context pointer (unused).
765  * @return int64_t Current time in nanoseconds.
766  */
llSlirp_ClockGetNanoSeconds(void * pvOpaque)767     static int64_t llSlirp_ClockGetNanoSeconds( void * pvOpaque )
768     {
769         struct timespec ts;
770         int64_t llTimeNs = 0;
771 
772         clock_gettime( CLOCK_MONOTONIC, &ts );
773 
774         ( void ) pvOpaque;
775 
776         llTimeNs = ( ts.tv_sec * 1000000000LL ) + ts.tv_nsec;
777         return llTimeNs;
778     }
779 #endif /* if defined( _WIN32 ) */
780 
781 /**
782  * @brief Callback funciton passed to libslirp to report a runtime error.
783  *
784  * @param [in] msg Error message
785  * @param pvOpaque Opaque context pointer (unused).
786  */
vSlirpGuestError(const char * msg,void * pvOpaque)787 static void vSlirpGuestError( const char * msg,
788                               void * pvOpaque )
789 {
790     fprintf( stderr, "libslirp guest error: %s\n", msg );
791     exit( 1 );
792 }
793 
794 /**
795  * @brief Stub callback function for libslirp timer API.
796  *
797  * @param cb Unused.
798  * @param pvCallbackContext Unused.
799  * @param pvOpaque Unused.
800  * @return void* NULL
801  */
pvSlirp_TimerNew(SlirpTimerCb cb,void * pvCallbackContext,void * pvOpaque)802 static void * pvSlirp_TimerNew( SlirpTimerCb cb,
803                                 void * pvCallbackContext,
804                                 void * pvOpaque )
805 {
806     /* Stub */
807     ( void ) cb;
808     ( void ) pvCallbackContext;
809     ( void ) pvOpaque;
810     configASSERT( 0 );
811     return NULL;
812 }
813 
814 /**
815  * @brief Stub callback function for libslirp timer API.
816  *
817  * @param pvTimer Unused.
818  * @param pvOpaque Unused.
819  */
vSlirp_TimerFree(void * pvTimer,void * pvOpaque)820 static void vSlirp_TimerFree( void * pvTimer,
821                               void * pvOpaque )
822 {
823     /* Stub */
824     ( void ) pvTimer;
825     ( void ) pvOpaque;
826     configASSERT( 0 );
827 }
828 
829 /**
830  * @brief Stub callback function for libslirp timer API.
831  *
832  * @param pvTimer Unused.
833  * @param expire_time Unused.
834  * @param pvOpaque Unused.
835  */
vSlirp_TimerModify(void * pvTimer,int64_t expire_time,void * pvOpaque)836 static void vSlirp_TimerModify( void * pvTimer,
837                                 int64_t expire_time,
838                                 void * pvOpaque )
839 {
840     /* Stub */
841     ( void ) pvTimer;
842     ( void ) expire_time;
843     ( void ) pvOpaque;
844     configASSERT( 0 );
845 }
846 
847 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
848 
849 /**
850  * @brief Stub callback function for libslirp timer API.
851  *
852  * @param xTimerId Unused.
853  * @param cb_opaque Unused.
854  * @param pvOpaque Unused.
855  * @return void* NULL
856  */
pvSlirpTimerNewOpaque(SlirpTimerId xTimerId,void * cb_opaque,void * pvOpaque)857     static void * pvSlirpTimerNewOpaque( SlirpTimerId xTimerId,
858                                          void * cb_opaque,
859                                          void * pvOpaque )
860     {
861         /* Stub */
862         ( void ) xTimerId;
863         ( void ) cb_opaque;
864         ( void ) pvOpaque;
865         configASSERT( 0 );
866         return NULL;
867     }
868 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
869 
870 /**
871  * @brief Called by libslipr when a new file descriptor / socket is opened.
872  *
873  * @param lFd File descriptor to watch.
874  * @param pvOpaque Pointer to driver context.
875  */
vSlirp_RegisterPollFd(int lFd,void * pvOpaque)876 static void vSlirp_RegisterPollFd( int lFd,
877                                    void * pvOpaque )
878 {
879     SlirpBackendContext_t * pxCtx = ( SlirpBackendContext_t * ) pvOpaque;
880 
881     configASSERT( pxCtx != NULL );
882 
883     ( void ) lFd;
884 
885     vEnsurePollfdSize( pxCtx, pxCtx->nfds + 1 );
886 }
887 
888 /**
889  * @brief Stub callback function.
890  *
891  * @param lFd Unused.
892  * @param pvOpaque Unused.
893  */
vSlirp_UnRegisterPollFd(int lFd,void * pvOpaque)894 static void vSlirp_UnRegisterPollFd( int lFd,
895                                      void * pvOpaque )
896 {
897     ( void ) lFd;
898     ( void ) pvOpaque;
899 }
900 
901 /**
902  * @brief Stub callback function.
903  *
904  * @param pvOpaque Unused.
905  */
vSlirp_Notify(void * pvOpaque)906 static void vSlirp_Notify( void * pvOpaque )
907 {
908     /* Stub */
909     ( void ) pvOpaque;
910 }
911 
912 #if SLIRP_CHECK_VERSION( 4U, 7U, 0U )
913 
914 /**
915  * @brief Stub callback function.
916  *
917  * @param pxSlirp Unused.
918  * @param pvOpaque Unused.
919  */
vSlirp_InitCompleted(Slirp * pxSlirp,void * pvOpaque)920     static void vSlirp_InitCompleted( Slirp * pxSlirp,
921                                       void * pvOpaque )
922     {
923         /* Stub */
924         ( void ) pxSlirp;
925         ( void ) pvOpaque;
926     }
927 #endif /* SLIRP_CHECK_VERSION( 4U, 7U, 0U ) */
928