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