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