[acpi] Expose system MAC address via ${sysmac} setting
[ipxe.git] / src / drivers / linux / slirp.c
1 /*
2 * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 */
19
20 #include <stdio.h>
21 #include <errno.h>
22 #include <ipxe/netdevice.h>
23 #include <ipxe/ethernet.h>
24 #include <ipxe/if_ether.h>
25 #include <ipxe/in.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>
31
32 /** @file
33 *
34 * Linux Slirp network driver
35 *
36 */
37
38 /** Maximum number of open file descriptors */
39 #define SLIRP_MAX_FDS 128
40
41 /** A Slirp network interface */
42 struct slirp_nic {
43 /** The libslirp device object */
44 struct Slirp *slirp;
45 /** Polling file descriptor list */
46 struct pollfd pollfds[SLIRP_MAX_FDS];
47 /** Number of file descriptors */
48 unsigned int numfds;
49 };
50
51 /** A Slirp alarm timer */
52 struct slirp_alarm {
53 /** Slirp network interface */
54 struct slirp_nic *slirp;
55 /** Retry timer */
56 struct retry_timer timer;
57 /** Callback function */
58 void ( __asmcall * callback ) ( void *opaque );
59 /** Opaque value for callback function */
60 void *opaque;
61 };
62
63 /** Default MAC address */
64 static const uint8_t slirp_default_mac[ETH_ALEN] =
65 { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
66
67 /******************************************************************************
68 *
69 * Slirp interface
70 *
71 ******************************************************************************
72 */
73
74 /**
75 * Send packet
76 *
77 * @v buf Data buffer
78 * @v len Length of data
79 * @v device Device opaque pointer
80 * @ret len Consumed length (or negative on error)
81 */
82 static ssize_t __asmcall slirp_send_packet ( const void *buf, size_t len,
83 void *device ) {
84 struct net_device *netdev = device;
85 struct io_buffer *iobuf;
86
87 /* Allocate I/O buffer */
88 iobuf = alloc_iob ( len );
89 if ( ! iobuf )
90 return -1;
91
92 /* Populate I/O buffer */
93 memcpy ( iob_put ( iobuf, len ), buf, len );
94
95 /* Hand off to network stack */
96 netdev_rx ( netdev, iobuf );
97
98 return len;
99 }
100
101 /**
102 * Print an error message
103 *
104 * @v msg Error message
105 * @v device Device opaque pointer
106 */
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;
110
111 DBGC ( slirp, "SLIRP %p error: %s\n", slirp, msg );
112 }
113
114 /**
115 * Get virtual clock
116 *
117 * @v device Device opaque pointer
118 * @ret clock_ns Clock time in nanoseconds
119 */
120 static int64_t __asmcall slirp_clock_get_ns ( void *device __unused ) {
121 int64_t time;
122
123 time = currticks();
124 return ( time * ( 1000000 / TICKS_PER_MS ) );
125 }
126
127 /**
128 * Handle timer expiry
129 *
130 * @v timer Retry timer
131 * @v over Failure indicator
132 */
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;
137
138 /* Notify callback */
139 DBGC ( slirp, "SLIRP %p timer fired\n", slirp );
140 alarm->callback ( alarm->opaque );
141 }
142
143 /**
144 * Create a new timer
145 *
146 * @v callback Timer callback
147 * @v opaque Timer opaque pointer
148 * @v device Device opaque pointer
149 * @ret timer Timer
150 */
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;
157
158 /* Allocate timer */
159 alarm = malloc ( sizeof ( *alarm ) );
160 if ( ! alarm ) {
161 DBGC ( slirp, "SLIRP %p could not allocate timer\n", slirp );
162 return NULL;
163 }
164
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 );
173
174 return alarm;
175 }
176
177 /**
178 * Delete a timer
179 *
180 * @v timer Timer
181 * @v device Device opaque pointer
182 */
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;
187
188 /* Ignore timers that failed to allocate */
189 if ( ! alarm )
190 return;
191
192 /* Stop timer */
193 stop_timer ( &alarm->timer );
194
195 /* Free timer */
196 free ( alarm );
197 DBGC ( slirp, "SLIRP %p timer %p freed\n", slirp, alarm );
198 }
199
200 /**
201 * Set timer expiry time
202 *
203 * @v timer Timer
204 * @v expire Expiry time
205 * @v device Device opaque pointer
206 */
207 static void __asmcall slirp_timer_mod ( void *timer, int64_t expire,
208 void *device ) {
209 struct net_device *netdev = device;
210 struct slirp_nic *slirp = netdev->priv;
211 struct slirp_alarm *alarm = timer;
212 int64_t timeout_ms;
213 unsigned long timeout;
214
215 /* Ignore timers that failed to allocate */
216 if ( ! alarm )
217 return;
218
219 /* (Re)start timer */
220 timeout_ms = ( expire - ( currticks() / TICKS_PER_MS ) );
221 if ( timeout_ms < 0 )
222 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 );
227 }
228
229 /**
230 * Register file descriptor for polling
231 *
232 * @v fd File descriptor
233 * @v device Device opaque pointer
234 */
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;
238
239 DBGC ( slirp, "SLIRP %p registered FD %d\n", slirp, fd );
240 }
241
242 /**
243 * Unregister file descriptor
244 *
245 * @v fd File descriptor
246 * @v device Device opaque pointer
247 */
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;
251
252 DBGC ( slirp, "SLIRP %p unregistered FD %d\n", slirp, fd );
253 }
254
255 /**
256 * Notify that new events are ready
257 *
258 * @v device Device opaque pointer
259 */
260 static void __asmcall slirp_notify ( void *device ) {
261 struct net_device *netdev = device;
262 struct slirp_nic *slirp = netdev->priv;
263
264 DBGC2 ( slirp, "SLIRP %p notified\n", slirp );
265 }
266
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,
278 };
279
280 /******************************************************************************
281 *
282 * Network device interface
283 *
284 ******************************************************************************
285 */
286
287 /**
288 * Open network device
289 *
290 * @v netdev Network device
291 * @ret rc Return status code
292 */
293 static int slirp_open ( struct net_device *netdev ) {
294 struct slirp_nic *slirp = netdev->priv;
295
296 /* Nothing to do */
297 DBGC ( slirp, "SLIRP %p opened\n", slirp );
298
299 return 0;
300 }
301
302 /**
303 * Close network device
304 *
305 * @v netdev Network device
306 */
307 static void slirp_close ( struct net_device *netdev ) {
308 struct slirp_nic *slirp = netdev->priv;
309
310 /* Nothing to do */
311 DBGC ( slirp, "SLIRP %p closed\n", slirp );
312 }
313
314 /**
315 * Transmit packet
316 *
317 * @v netdev Network device
318 * @v iobuf I/O buffer
319 * @ret rc Return status code
320 */
321 static int slirp_transmit ( struct net_device *netdev,
322 struct io_buffer *iobuf ) {
323 struct slirp_nic *slirp = netdev->priv;
324
325 /* Transmit packet */
326 linux_slirp_input ( slirp->slirp, iobuf->data, iob_len ( iobuf ) );
327 netdev_tx_complete ( netdev, iobuf );
328
329 return 0;
330 }
331
332 /**
333 * Add polling file descriptor
334 *
335 * @v fd File descriptor
336 * @v events Events of interest
337 * @v device Device opaque pointer
338 * @ret index File descriptor index
339 */
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;
344 unsigned int index;
345
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 );
349 return -1;
350 }
351
352 /* Populate polling file descriptor */
353 index = slirp->numfds++;
354 pollfd = &slirp->pollfds[index];
355 pollfd->fd = fd;
356 pollfd->events = 0;
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 );
369
370 return index;
371 }
372
373 /**
374 * Get returned events for a file descriptor
375 *
376 * @v index File descriptor index
377 * @v device Device opaque pointer
378 * @ret events Returned events
379 */
380 static int __asmcall slirp_get_revents ( int index, void *device ) {
381 struct net_device *netdev = device;
382 struct slirp_nic *slirp = netdev->priv;
383 int revents;
384 int events;
385
386 /* Ignore failed descriptors */
387 if ( index < 0 )
388 return 0;
389
390 /* Collect events */
391 revents = slirp->pollfds[index].revents;
392 events = 0;
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;
403 if ( events ) {
404 DBGC2 ( slirp, "SLIRP %p polled FD %d events %#04x(%#04x)\n",
405 slirp, slirp->pollfds[index].fd, events, revents );
406 }
407
408 return events;
409 }
410
411 /**
412 * Poll for completed and received packets
413 *
414 * @v netdev Network device
415 */
416 static void slirp_poll ( struct net_device *netdev ) {
417 struct slirp_nic *slirp = netdev->priv;
418 uint32_t timeout = 0;
419 int ready;
420 int error;
421
422 /* Rebuild polling file descriptor list */
423 slirp->numfds = 0;
424 linux_slirp_pollfds_fill ( slirp->slirp, &timeout,
425 slirp_add_poll, netdev );
426
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,
431 netdev );
432
433 /* Record polling errors */
434 if ( error ) {
435 DBGC ( slirp, "SLIRP %p poll failed: %s\n",
436 slirp, linux_strerror ( linux_errno ) );
437 netdev_rx_err ( netdev, NULL, -ELINUX ( linux_errno ) );
438 }
439 }
440
441 /** Network device operations */
442 static struct net_device_operations slirp_operations = {
443 .open = slirp_open,
444 .close = slirp_close,
445 .transmit = slirp_transmit,
446 .poll = slirp_poll,
447 };
448
449 /******************************************************************************
450 *
451 * Linux driver interface
452 *
453 ******************************************************************************
454 */
455
456 /**
457 * Probe device
458 *
459 * @v linux Linux device
460 * @v request Device creation request
461 * @ret rc Return status code
462 */
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;
468 int rc;
469
470 /* Allocate device */
471 netdev = alloc_etherdev ( sizeof ( *slirp ) );
472 if ( ! netdev ) {
473 rc = -ENOMEM;
474 goto err_alloc;
475 }
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 ) );
483
484 /* Apply requested settings */
485 linux_apply_settings ( &request->settings,
486 netdev_settings ( netdev ) );
487
488 /* Initialise default configuration (matching qemu) */
489 memset ( &config, 0, sizeof ( config ) );
490 config.version = 1;
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 */
498
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" );
503 rc = -ENODEV;
504 goto err_new;
505 }
506
507 /* Register network device */
508 if ( ( rc = register_netdev ( netdev ) ) != 0 )
509 goto err_register;
510
511 /* Set link up since there is no concept of link state */
512 netdev_link_up ( netdev );
513
514 return 0;
515
516 unregister_netdev ( netdev );
517 err_register:
518 linux_slirp_cleanup ( slirp->slirp );
519 err_new:
520 netdev_nullify ( netdev );
521 netdev_put ( netdev );
522 err_alloc:
523 return rc;
524 }
525
526 /**
527 * Remove device
528 *
529 * @v linux Linux device
530 */
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;
534
535 /* Unregister network device */
536 unregister_netdev ( netdev );
537
538 /* Shut down device */
539 linux_slirp_cleanup ( slirp->slirp );
540
541 /* Free network device */
542 netdev_nullify ( netdev );
543 netdev_put ( netdev );
544 }
545
546 /** Slirp driver */
547 struct linux_driver slirp_driver __linux_driver = {
548 .name = "slirp",
549 .probe = slirp_probe,
550 .remove = slirp_remove,
551 .can_probe = 1,
552 };