2 * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include <ipxe/netdevice.h>
23 #include <ipxe/ethernet.h>
24 #include <ipxe/if_ether.h>
26 #include <ipxe/timer.h>
27 #include <ipxe/retry.h>
28 #include <ipxe/linux.h>
29 #include <ipxe/linux_api.h>
30 #include <ipxe/slirp.h>
34 * Linux Slirp network driver
38 /** Maximum number of open file descriptors */
39 #define SLIRP_MAX_FDS 128
41 /** A Slirp network interface */
43 /** The libslirp device object */
45 /** Polling file descriptor list */
46 struct pollfd pollfds
[SLIRP_MAX_FDS
];
47 /** Number of file descriptors */
51 /** A Slirp alarm timer */
53 /** Slirp network interface */
54 struct slirp_nic
*slirp
;
56 struct retry_timer timer
;
57 /** Callback function */
58 void ( __asmcall
* callback
) ( void *opaque
);
59 /** Opaque value for callback function */
63 /** Default MAC address */
64 static const uint8_t slirp_default_mac
[ETH_ALEN
] =
65 { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
67 /******************************************************************************
71 ******************************************************************************
78 * @v len Length of data
79 * @v device Device opaque pointer
80 * @ret len Consumed length (or negative on error)
82 static ssize_t __asmcall
slirp_send_packet ( const void *buf
, size_t len
,
84 struct net_device
*netdev
= device
;
85 struct io_buffer
*iobuf
;
87 /* Allocate I/O buffer */
88 iobuf
= alloc_iob ( len
);
92 /* Populate I/O buffer */
93 memcpy ( iob_put ( iobuf
, len
), buf
, len
);
95 /* Hand off to network stack */
96 netdev_rx ( netdev
, iobuf
);
102 * Print an error message
104 * @v msg Error message
105 * @v device Device opaque pointer
107 static void __asmcall
slirp_guest_error ( const char *msg
, void *device
) {
108 struct net_device
*netdev
= device
;
109 struct slirp_nic
*slirp
= netdev
->priv
;
111 DBGC ( slirp
, "SLIRP %p error: %s\n", slirp
, msg
);
117 * @v device Device opaque pointer
118 * @ret clock_ns Clock time in nanoseconds
120 static int64_t __asmcall
slirp_clock_get_ns ( void *device __unused
) {
124 return ( time
* ( 1000000 / TICKS_PER_MS
) );
128 * Handle timer expiry
130 * @v timer Retry timer
131 * @v over Failure indicator
133 static void slirp_expired ( struct retry_timer
*timer
, int over __unused
) {
134 struct slirp_alarm
*alarm
=
135 container_of ( timer
, struct slirp_alarm
, timer
);
136 struct slirp_nic
*slirp
= alarm
->slirp
;
138 /* Notify callback */
139 DBGC ( slirp
, "SLIRP %p timer fired\n", slirp
);
140 alarm
->callback ( alarm
->opaque
);
146 * @v callback Timer callback
147 * @v opaque Timer opaque pointer
148 * @v device Device opaque pointer
151 static void * __asmcall
152 slirp_timer_new ( void ( __asmcall
* callback
) ( void *opaque
),
153 void *opaque
, void *device
) {
154 struct net_device
*netdev
= device
;
155 struct slirp_nic
*slirp
= netdev
->priv
;
156 struct slirp_alarm
*alarm
;
159 alarm
= malloc ( sizeof ( *alarm
) );
161 DBGC ( slirp
, "SLIRP %p could not allocate timer\n", slirp
);
165 /* Initialise timer */
166 memset ( alarm
, 0, sizeof ( *alarm
) );
167 alarm
->slirp
= slirp
;
168 timer_init ( &alarm
->timer
, slirp_expired
, NULL
);
169 alarm
->callback
= callback
;
170 alarm
->opaque
= opaque
;
171 DBGC ( slirp
, "SLIRP %p timer %p has callback %p (%p)\n",
172 slirp
, alarm
, alarm
->callback
, alarm
->opaque
);
181 * @v device Device opaque pointer
183 static void __asmcall
slirp_timer_free ( void *timer
, void *device
) {
184 struct net_device
*netdev
= device
;
185 struct slirp_nic
*slirp
= netdev
->priv
;
186 struct slirp_alarm
*alarm
= timer
;
188 /* Ignore timers that failed to allocate */
193 stop_timer ( &alarm
->timer
);
197 DBGC ( slirp
, "SLIRP %p timer %p freed\n", slirp
, alarm
);
201 * Set timer expiry time
204 * @v expire Expiry time
205 * @v device Device opaque pointer
207 static void __asmcall
slirp_timer_mod ( void *timer
, int64_t expire
,
209 struct net_device
*netdev
= device
;
210 struct slirp_nic
*slirp
= netdev
->priv
;
211 struct slirp_alarm
*alarm
= timer
;
213 unsigned long timeout
;
215 /* Ignore timers that failed to allocate */
219 /* (Re)start timer */
220 timeout_ms
= ( expire
- ( currticks() / TICKS_PER_MS
) );
221 if ( timeout_ms
< 0 )
223 timeout
= ( timeout_ms
* TICKS_PER_MS
);
224 start_timer_fixed ( &alarm
->timer
, timeout
);
225 DBGC ( slirp
, "SLIRP %p timer %p set for %ld ticks\n",
226 slirp
, alarm
, timeout
);
230 * Register file descriptor for polling
232 * @v fd File descriptor
233 * @v device Device opaque pointer
235 static void __asmcall
slirp_register_poll_fd ( int fd
, void *device
) {
236 struct net_device
*netdev
= device
;
237 struct slirp_nic
*slirp
= netdev
->priv
;
239 DBGC ( slirp
, "SLIRP %p registered FD %d\n", slirp
, fd
);
243 * Unregister file descriptor
245 * @v fd File descriptor
246 * @v device Device opaque pointer
248 static void __asmcall
slirp_unregister_poll_fd ( int fd
, void *device
) {
249 struct net_device
*netdev
= device
;
250 struct slirp_nic
*slirp
= netdev
->priv
;
252 DBGC ( slirp
, "SLIRP %p unregistered FD %d\n", slirp
, fd
);
256 * Notify that new events are ready
258 * @v device Device opaque pointer
260 static void __asmcall
slirp_notify ( void *device
) {
261 struct net_device
*netdev
= device
;
262 struct slirp_nic
*slirp
= netdev
->priv
;
264 DBGC2 ( slirp
, "SLIRP %p notified\n", slirp
);
267 /** Slirp callbacks */
268 static struct slirp_callbacks slirp_callbacks
= {
269 .send_packet
= slirp_send_packet
,
270 .guest_error
= slirp_guest_error
,
271 .clock_get_ns
= slirp_clock_get_ns
,
272 .timer_new
= slirp_timer_new
,
273 .timer_free
= slirp_timer_free
,
274 .timer_mod
= slirp_timer_mod
,
275 .register_poll_fd
= slirp_register_poll_fd
,
276 .unregister_poll_fd
= slirp_unregister_poll_fd
,
277 .notify
= slirp_notify
,
280 /******************************************************************************
282 * Network device interface
284 ******************************************************************************
288 * Open network device
290 * @v netdev Network device
291 * @ret rc Return status code
293 static int slirp_open ( struct net_device
*netdev
) {
294 struct slirp_nic
*slirp
= netdev
->priv
;
297 DBGC ( slirp
, "SLIRP %p opened\n", slirp
);
303 * Close network device
305 * @v netdev Network device
307 static void slirp_close ( struct net_device
*netdev
) {
308 struct slirp_nic
*slirp
= netdev
->priv
;
311 DBGC ( slirp
, "SLIRP %p closed\n", slirp
);
317 * @v netdev Network device
318 * @v iobuf I/O buffer
319 * @ret rc Return status code
321 static int slirp_transmit ( struct net_device
*netdev
,
322 struct io_buffer
*iobuf
) {
323 struct slirp_nic
*slirp
= netdev
->priv
;
325 /* Transmit packet */
326 linux_slirp_input ( slirp
->slirp
, iobuf
->data
, iob_len ( iobuf
) );
327 netdev_tx_complete ( netdev
, iobuf
);
333 * Add polling file descriptor
335 * @v fd File descriptor
336 * @v events Events of interest
337 * @v device Device opaque pointer
338 * @ret index File descriptor index
340 static int __asmcall
slirp_add_poll ( int fd
, int events
, void *device
) {
341 struct net_device
*netdev
= device
;
342 struct slirp_nic
*slirp
= netdev
->priv
;
343 struct pollfd
*pollfd
;
346 /* Fail if too many descriptors are registered */
347 if ( slirp
->numfds
>= SLIRP_MAX_FDS
) {
348 DBGC ( slirp
, "SLIRP %p too many file descriptors\n", slirp
);
352 /* Populate polling file descriptor */
353 index
= slirp
->numfds
++;
354 pollfd
= &slirp
->pollfds
[index
];
357 if ( events
& SLIRP_EVENT_IN
)
358 pollfd
->events
|= POLLIN
;
359 if ( events
& SLIRP_EVENT_OUT
)
360 pollfd
->events
|= POLLOUT
;
361 if ( events
& SLIRP_EVENT_PRI
)
362 pollfd
->events
|= POLLPRI
;
363 if ( events
& SLIRP_EVENT_ERR
)
364 pollfd
->events
|= POLLERR
;
365 if ( events
& SLIRP_EVENT_HUP
)
366 pollfd
->events
|= ( POLLHUP
| POLLRDHUP
);
367 DBGCP ( slirp
, "SLIRP %p polling FD %d event mask %#04x(%#04x)\n",
368 slirp
, fd
, events
, pollfd
->events
);
374 * Get returned events for a file descriptor
376 * @v index File descriptor index
377 * @v device Device opaque pointer
378 * @ret events Returned events
380 static int __asmcall
slirp_get_revents ( int index
, void *device
) {
381 struct net_device
*netdev
= device
;
382 struct slirp_nic
*slirp
= netdev
->priv
;
386 /* Ignore failed descriptors */
391 revents
= slirp
->pollfds
[index
].revents
;
393 if ( revents
& POLLIN
)
394 events
|= SLIRP_EVENT_IN
;
395 if ( revents
& POLLOUT
)
396 events
|= SLIRP_EVENT_OUT
;
397 if ( revents
& POLLPRI
)
398 events
|= SLIRP_EVENT_PRI
;
399 if ( revents
& POLLERR
)
400 events
|= SLIRP_EVENT_ERR
;
401 if ( revents
& ( POLLHUP
| POLLRDHUP
) )
402 events
|= SLIRP_EVENT_HUP
;
404 DBGC2 ( slirp
, "SLIRP %p polled FD %d events %#04x(%#04x)\n",
405 slirp
, slirp
->pollfds
[index
].fd
, events
, revents
);
412 * Poll for completed and received packets
414 * @v netdev Network device
416 static void slirp_poll ( struct net_device
*netdev
) {
417 struct slirp_nic
*slirp
= netdev
->priv
;
418 uint32_t timeout
= 0;
422 /* Rebuild polling file descriptor list */
424 linux_slirp_pollfds_fill ( slirp
->slirp
, &timeout
,
425 slirp_add_poll
, netdev
);
427 /* Poll descriptors */
428 ready
= linux_poll ( slirp
->pollfds
, slirp
->numfds
, 0 );
429 error
= ( ready
== -1 );
430 linux_slirp_pollfds_poll ( slirp
->slirp
, error
, slirp_get_revents
,
433 /* Record polling errors */
435 DBGC ( slirp
, "SLIRP %p poll failed: %s\n",
436 slirp
, linux_strerror ( linux_errno
) );
437 netdev_rx_err ( netdev
, NULL
, -ELINUX ( linux_errno
) );
441 /** Network device operations */
442 static struct net_device_operations slirp_operations
= {
444 .close
= slirp_close
,
445 .transmit
= slirp_transmit
,
449 /******************************************************************************
451 * Linux driver interface
453 ******************************************************************************
459 * @v linux Linux device
460 * @v request Device creation request
461 * @ret rc Return status code
463 static int slirp_probe ( struct linux_device
*linux
,
464 struct linux_device_request
*request
) {
465 struct net_device
*netdev
;
466 struct slirp_nic
*slirp
;
467 struct slirp_config config
;
470 /* Allocate device */
471 netdev
= alloc_etherdev ( sizeof ( *slirp
) );
476 netdev_init ( netdev
, &slirp_operations
);
477 linux_set_drvdata ( linux
, netdev
);
478 snprintf ( linux
->dev
.name
, sizeof ( linux
->dev
.name
), "host" );
479 netdev
->dev
= &linux
->dev
;
480 memcpy ( netdev
->hw_addr
, slirp_default_mac
, ETH_ALEN
);
481 slirp
= netdev
->priv
;
482 memset ( slirp
, 0, sizeof ( *slirp
) );
484 /* Apply requested settings */
485 linux_apply_settings ( &request
->settings
,
486 netdev_settings ( netdev
) );
488 /* Initialise default configuration (matching qemu) */
489 memset ( &config
, 0, sizeof ( config
) );
491 config
.in_enabled
= true;
492 config
.vnetwork
.s_addr
= htonl ( 0x0a000200 ); /* 10.0.2.0 */
493 config
.vnetmask
.s_addr
= htonl ( 0xffffff00 ); /* 255.255.255.0 */
494 config
.vhost
.s_addr
= htonl ( 0x0a000202 ); /* 10.0.2.2 */
495 config
.in6_enabled
= true;
496 config
.vdhcp_start
.s_addr
= htonl ( 0x0a00020f ); /* 10.0.2.15 */
497 config
.vnameserver
.s_addr
= htonl ( 0x0a000203 ); /* 10.0.2.3 */
499 /* Instantiate device */
500 slirp
->slirp
= linux_slirp_new ( &config
, &slirp_callbacks
, netdev
);
501 if ( ! slirp
->slirp
) {
502 DBGC ( slirp
, "SLIRP could not instantiate\n" );
507 /* Register network device */
508 if ( ( rc
= register_netdev ( netdev
) ) != 0 )
511 /* Set link up since there is no concept of link state */
512 netdev_link_up ( netdev
);
516 unregister_netdev ( netdev
);
518 linux_slirp_cleanup ( slirp
->slirp
);
520 netdev_nullify ( netdev
);
521 netdev_put ( netdev
);
529 * @v linux Linux device
531 static void slirp_remove ( struct linux_device
*linux
) {
532 struct net_device
*netdev
= linux_get_drvdata ( linux
);
533 struct slirp_nic
*slirp
= netdev
->priv
;
535 /* Unregister network device */
536 unregister_netdev ( netdev
);
538 /* Shut down device */
539 linux_slirp_cleanup ( slirp
->slirp
);
541 /* Free network device */
542 netdev_nullify ( netdev
);
543 netdev_put ( netdev
);
547 struct linux_driver slirp_driver __linux_driver
= {
549 .probe
= slirp_probe
,
550 .remove
= slirp_remove
,