summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2025-07-22 09:23:42 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2025-08-01 00:27:39 +0200
commit1d5c92654b2ebd95bee4f2bc4690b883c468b1a4 (patch)
tree97cd1da043120d6d17a3be843301dde97bca62a4
parentecbc38df9f62ecffd1349b6f3b4fd234dbc08fe4 (diff)
rumpnet: Add device translator for (Intel) NICsHEADmaster
This adds a working rump driver for /dev/wmX cards, which are Intel i8254x Gigabit Ethernet devices. (See man.netbsd.org for "wm(4)") This should be easily extended to support other NICs by contributing some makefile foo to netbsd/rump. TESTED: - On UP+apic it works 100% with hurd-i386. - On SMP it also works 100% with hurd-i386. Example usage: settrans -fgap /dev/rumpnet /hurd/rumpnet settrans -fgap /dev/wm0 /hurd/devnode -M /dev/rumpnet wm0 settrans -fgap /servers/socket/2 /hurd/pfinet -i /dev/wm0 ifup /dev/wm0 TODO: check tcpdump support Requires latest master of librump for nofifofs dynamic lib. Message-ID: <20250722092324.414844-1-damien@zamaudio.com>
-rw-r--r--Makefile2
-rw-r--r--rumpnet/Makefile42
-rw-r--r--rumpnet/if_hdr.h75
-rw-r--r--rumpnet/ioccom-rump.h82
-rw-r--r--rumpnet/main.c149
-rw-r--r--rumpnet/net-rump.c928
-rw-r--r--rumpnet/net-rump.h24
7 files changed, 1301 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 9d9e33c3..c51e8c1c 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ prog-subdirs = auth proc exec term \
rtc
ifeq ($(HAVE_LIBRUMP),yes)
-prog-subdirs += rumpdisk
+prog-subdirs += rumpdisk rumpnet
endif
ifeq ($(HAVE_SUN_RPC),yes)
diff --git a/rumpnet/Makefile b/rumpnet/Makefile
new file mode 100644
index 00000000..579197e1
--- /dev/null
+++ b/rumpnet/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2019, 2023 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+RUMPLIBS=rump rumpuser rumpdev rumpdev_miiphy rumpdev_pci rumpvfs rumpdev_pci_if_wm rumpnet rumpnet_net rumpnet_netinet rumpnet_local rumpdev_bpf
+# If we have a configured tree, include the configuration so that we
+# can conditionally build translators.
+ifneq (,$(wildcard ../config.make))
+ include ../config.make
+endif
+
+ifeq ($(HAVE_LIBRUMP_VFSNOFIFO),yes)
+RUMPLIBS += rumpvfs_nofifofs
+endif
+
+dir := rumpnet
+makemode := server
+
+SRCS = main.c net-rump.c
+LCLHDRS =
+target = rumpnet
+OBJS = $(SRCS:.c=.o)
+CFLAGS = -Wno-unused-function -Wno-unused-variable
+HURDLIBS = machdev ports trivfs shouldbeinlibc iohelp ihash fshelp irqhelp
+LDLIBS += -lpthread -lpciaccess -ldl -lz
+rumpnet-LDLIBS += -Wl,--no-as-needed $(RUMPLIBS:%=-l%) -Wl,--as-needed
+rumpnet.static-LDLIBS += -Wl,--whole-archive $(RUMPLIBS:%=-l%_pic) -Wl,--no-whole-archive
+
+include ../Makeconf
diff --git a/rumpnet/if_hdr.h b/rumpnet/if_hdr.h
new file mode 100644
index 00000000..d49d6df0
--- /dev/null
+++ b/rumpnet/if_hdr.h
@@ -0,0 +1,75 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Taken from (bsd)net/if.h. Modified for MACH kernel.
+ */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the Laboratory may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if.h 7.3 (Berkeley) 6/27/88
+ */
+
+#ifndef _IF_HDR_
+#define _IF_HDR_
+
+#define IFF_UP 0x0001 /* interface is up */
+#define IFF_BROADCAST 0x0002 /* interface can broadcast */
+#define IFF_DEBUG 0x0004 /* turn on debugging */
+#define IFF_LOOPBACK 0x0008 /* is a loopback net */
+#define IFF_POINTOPOINT 0x0010 /* point-to-point link */
+#define IFF_RUNNING 0x0040 /* resources allocated */
+#define IFF_NOARP 0x0080 /* no address resolution protocol */
+#define IFF_PROMISC 0x0100 /* receive all packets */
+#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */
+#define IFF_BRIDGE 0x0100 /* support token ring routing field */
+#define IFF_SNAP 0x0200 /* support extended sap header */
+
+#endif /* _IF_HDR_ */
diff --git a/rumpnet/ioccom-rump.h b/rumpnet/ioccom-rump.h
new file mode 100644
index 00000000..6f41b05b
--- /dev/null
+++ b/rumpnet/ioccom-rump.h
@@ -0,0 +1,82 @@
+/* $NetBSD: ioccom.h,v 1.12 2014/12/10 00:16:05 christos Exp $ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ioccom.h 8.3 (Berkeley) 1/9/95
+ */
+
+#ifndef _SYS_IOCCOM_H_
+#define _SYS_IOCCOM_H_
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word. The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ *
+ * 31 29 28 16 15 8 7 0
+ * +---------------------------------------------------------------+
+ * | I/O | Parameter Length | Command Group | Command |
+ * +---------------------------------------------------------------+
+ */
+#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
+#define IOCPARM_SHIFT 16
+#define IOCGROUP_SHIFT 8
+#define IOCPARM_LEN(x) (((x) >> IOCPARM_SHIFT) & IOCPARM_MASK)
+#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << IOCPARM_SHIFT))
+#define IOCGROUP(x) (((x) >> IOCGROUP_SHIFT) & 0xff)
+
+#define IOCPARM_MAX NBPG /* max size of ioctl args, mult. of NBPG */
+ /* no parameters */
+#define IOC_VOID (unsigned long)0x20000000
+ /* copy parameters out */
+#define IOC_OUT (unsigned long)0x40000000
+ /* copy parameters in */
+#define IOC_IN (unsigned long)0x80000000
+ /* copy parameters in and out */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+ /* mask for IN/OUT/VOID */
+#define IOC_DIRMASK (unsigned long)0xe0000000
+
+#define _IOC(inout, group, num, len) \
+ ((inout) | (((len) & IOCPARM_MASK) << IOCPARM_SHIFT) | \
+ ((group) << IOCGROUP_SHIFT) | (num))
+#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0)
+#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
+#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
+
+#define IOCSNPRINTF(buf, len, cmd) \
+ snprintf((buf), (len), "_IO%s%s('%c', %hhu)", \
+ (((cmd) >> 30) & 1) ? "W" : "", \
+ (((cmd) >> 30) & 2) ? "R" : "", \
+ (char)IOCGROUP(cmd), (unsigned char)(cmd))
+
+
+#endif /* !_SYS_IOCCOM_H_ */
diff --git a/rumpnet/main.c b/rumpnet/main.c
new file mode 100644
index 00000000..4385048f
--- /dev/null
+++ b/rumpnet/main.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 Free Software Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <version.h>
+
+#include <pthread.h>
+#include <mach.h>
+#include <mach/vm_param.h>
+#include "libshouldbeinlibc/wire.h"
+#include "libmachdev/machdev.h"
+#include "net-rump.h"
+
+mach_port_t bootstrap_resume_task = MACH_PORT_NULL;
+
+static const struct argp_option options[] = {
+ {"host-priv-port", 'h', "PORT", 0, "Host private port PORT"},
+ {"device-master-port",'d', "PORT", 0, "Device master port PORT"},
+ {"next-task", 'N', "TASK", 0, "Next bootstrap task TASK"},
+ {0}
+};
+
+
+/* Parse a command line option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ /* We save our parsed values in this structure, hung off STATE->hook.
+ Only after parsing all options successfully will we use these values. */
+ struct
+ {
+ int host_priv;
+ int dev_master;
+ int next_task;
+ } *values = state->hook;
+
+ switch (key)
+ {
+ case 'h':
+ values->host_priv = atoi(arg);
+ break;
+ case 'd':
+ values->dev_master = atoi(arg);
+ break;
+ case 'N':
+ values->next_task = atoi(arg);
+ break;
+
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input;
+ values = malloc (sizeof *values);
+ if (values == 0)
+ return ENOMEM;
+ state->hook = values;
+ memset (values, 0, sizeof *values);
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ /* All options parsed successfully */
+ _hurd_host_priv = values->host_priv;
+ _hurd_device_master = values->dev_master;
+ bootstrap_resume_task = values->next_task;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp_child empty_argp_children[] = {{0}};
+static struct argp rumpnet_argp = {options, parse_opt, 0, 0, empty_argp_children};
+static const struct argp *rumpnet_argp_bootup = &rumpnet_argp;
+
+static void *
+rumpnet_multithread_server(void *arg)
+{
+ do
+ {
+ ports_manage_port_operations_multithread (machdev_device_bucket,
+ machdev_demuxer,
+ 1000 * 60 * 2, /* 2 minute thread */
+ 1000 * 60 * 10, /* 10 minute server */
+ 0);
+ } while (1);
+
+ return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+ mach_port_t bootstrap = MACH_PORT_NULL;
+ int err;
+ pthread_t t;
+
+ setenv ("RUMP_NCPU", "1", 1);
+ setenv ("RUMP_VERBOSE", "1", 1);
+ setenv ("RUMP_HOSTNAME", "HURD0", 1);
+ setenv ("HOSTNAME", "HURD0", 1);
+ setenv ("RUMP_PANIC", "1", 1);
+
+ err = argp_parse (rumpnet_argp_bootup, argc, argv, 0, 0, NULL);
+ if (err)
+ {
+ error(1, err, "Missing parameters for bootstrap");
+ }
+
+ /* Make sure we will not swap out,
+ * because dma buffers for net drivers don't work otherwise.
+ * XXX rump must be using memory for dma that was not allocated with vm_allocate_contiguous (?) */
+ err = wire_task_self ();
+ if (err)
+ error (1, err, "cannot lock all memory");
+
+ rump_register_net ();
+ machdev_trivfs_init (argc, argv, bootstrap_resume_task, "rumpnet", "/dev/rumpnet", &bootstrap);
+ machdev_device_init ();
+ err = pthread_create (&t, NULL, rumpnet_multithread_server, NULL);
+ if (err)
+ return err;
+ pthread_detach (t);
+ machdev_trivfs_server_startup (bootstrap);
+ machdev_trivfs_server_loop (NULL);
+ /* Never reached */
+ return 0;
+}
diff --git a/rumpnet/net-rump.c b/rumpnet/net-rump.c
new file mode 100644
index 00000000..a9627c72
--- /dev/null
+++ b/rumpnet/net-rump.c
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) 2024 Free Software Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <net/if_ether.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <mach.h>
+#include <mach/gnumach.h>
+#include <mach/vm_param.h>
+#include <hurd/machdev.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <device/net_status.h>
+#include <net/ethernet.h>
+
+#define MACH_INCLUDE
+#define _STANDALONE
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumperrno2host.h>
+
+#include "if_hdr.h"
+#include "ioccom-rump.h"
+
+#define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */
+#define SIOCGIFADDR _IOWR('i', 33, struct ifreq) /* get ifnet address */
+#define SIOCGIFBRDADDR _IOWR('i', 35, struct ifreq) /* get broadcast addr */
+#define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */
+#define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */
+#define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */
+
+#define SIOCGLIFADDR _IOWR('i', 29, struct if_laddrreq) /* get IF addr */
+
+#define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */
+#define SIOCGIFFLAGS _IOWR('i', 17, struct ifreq) /* get ifnet flags */
+#define SIOCGIFMETRIC _IOWR('i', 23, struct ifreq) /* get IF metric */
+#define SIOCSIFMETRIC _IOW('i', 24, struct ifreq) /* set IF metric */
+#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */
+#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */
+
+#define IF_NAMESIZE 16
+
+#define NET_RCV_WAIT (60*1000*1000) /* 1 minute */
+#define RUMP_POLLIN 0x0001
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+struct rump_timeval {
+ int64_t tv_sec;
+ int32_t tv_usec;
+};
+
+struct bpf_insn;
+
+/*
+ * Structure for BIOCSETF.
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+#define BIOCGBLEN _IOR('B', 102, u_int)
+#define BIOCSBLEN _IOWR('B', 102, u_int)
+#define BIOCSETF _IOW('B', 103, struct bpf_program)
+#define BIOCFLUSH _IO('B', 104)
+#define BIOCPROMISC _IO('B', 105)
+#define BIOCGDLT _IOR('B', 106, u_int)
+#define BIOCGETIF _IOR('B', 107, struct ifreq)
+#define BIOCSETIF _IOW('B', 108, struct ifreq)
+#define BIOCIMMEDIATE _IOW('B', 112, u_int)
+#define BIOCSTCPF _IOW('B', 114, struct bpf_program)
+#define BIOCSUDPF _IOW('B', 115, struct bpf_program)
+#define BIOCGHDRCMPLT _IOR('B', 116, u_int)
+#define BIOCSHDRCMPLT _IOW('B', 117, u_int)
+#define BIOCSDLT _IOW('B', 118, u_int)
+#define BIOCGDIRECTION _IOR('B', 120, u_int)
+#define BIOCSDIRECTION _IOW('B', 121, u_int)
+#define BIOCSRTIMEOUT _IOW('B', 122, struct rump_timeval)
+#define BIOCGFEEDBACK _IOR('B', 124, u_int)
+#define BIOCSFEEDBACK _IOW('B', 125, u_int)
+#define BIOCLOCK _IO('B', 126)
+#define BIOCSETWF _IOW('B', 127, struct bpf_program)
+
+#define BPF_D_IN 0
+#define BPF_D_INOUT 1
+#define BPF_D_OUT 2
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#define SIZEOF_BPF_HDR 18
+#define SIZEOF_MTU 1500
+#define SIZEOF_ETH_FRAME (ETH_HLEN + SIZEOF_MTU)
+
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_BUFSIZE 131072
+
+struct bpf_hdr {
+ int32_t usec;
+ int32_t sec;
+ uint32_t bh_caplen; /* length of captured portion */
+ uint32_t bh_datalen; /* original length of packet */
+ uint16_t bh_hdrlen; /* length of this struct + alignment padding */
+};
+
+int socket_aflink = -1;
+
+struct dl_addr {
+ uint8_t dl_type; /* interface type */
+ uint8_t dl_nlen; /* interface name length, no trailing 0 reqd. */
+ uint8_t dl_alen; /* link level address length */
+ uint8_t dl_slen; /* link layer selector length */
+ char dl_data[24]; /*
+ * minimum work area, can be larger; contains
+ * both if name and ll address; big enough for
+ * IFNAMSIZ plus 8byte ll addr.
+ */
+};
+
+struct sockaddr_dl {
+ uint8_t sdl_len; /* Total length of sockaddr */
+ uint8_t sdl_family; /* AF_LINK */
+ uint16_t sdl_index; /* if != 0, system given index for interface */
+ struct dl_addr sdl_addr;
+#define sdl_type sdl_addr.dl_type
+#define sdl_nlen sdl_addr.dl_nlen
+#define sdl_alen sdl_addr.dl_alen
+#define sdl_slen sdl_addr.dl_slen
+#define sdl_data sdl_addr.dl_data
+};
+
+struct if_laddrreq {
+ char iflr_name[IF_NAMESIZE];
+ unsigned int flags;
+#define IFLR_PREFIX 0x8000 /* in: prefix given out: kernel fills id */
+#define IFLR_ACTIVE 0x4000 /* in/out: link-layer address activation */
+#define IFLR_FACTORY 0x2000 /* in/out: factory link-layer address */
+ unsigned int prefixlen; /* in/out */
+ struct sockaddr_storage addr; /* in/out */
+ struct sockaddr_storage dstaddr; /* out */
+};
+
+#define satosdl(__sa) ((struct sockaddr_dl *)(__sa))
+#define LLADDR(s) ((char *)((s)->sdl_data + (s)->sdl_nlen))
+
+struct ifreq {
+ char ifr_name[IF_NAMESIZE];
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr_storage ifru_space;
+ short ifru_flags;
+ int ifru_addrflags;
+ int ifru_metric;
+ int ifru_mtu;
+ int ifru_dlt;
+ u_int ifru_value;
+ void * ifru_data;
+ struct {
+ uint32_t b_buflen;
+ void *b_buf;
+ } ifru_b;
+ } ifr_ifru;
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_space ifr_ifru.ifru_space /* sockaddr_storage */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_addrflags ifr_ifru.ifru_addrflags /* addr flags */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+#define ifr_dlt ifr_ifru.ifru_dlt /* data link type (DLT_*) */
+#define ifr_value ifr_ifru.ifru_value /* generic value */
+#define ifr_media ifr_ifru.ifru_metric /* media options (overload) */
+#define ifr_data ifr_ifru.ifru_data /* for use by interface
+ * XXX deprecated
+ */
+#define ifr_buf ifr_ifru.ifru_b.b_buf /* new interface ioctls */
+#define ifr_buflen ifr_ifru.ifru_b.b_buflen
+#define ifr_index ifr_ifru.ifru_value /* interface index, BSD */
+#define ifr_ifindex ifr_index /* interface index, linux */
+};
+
+struct bpf_insn bpf_allow_all[] = {
+ BPF_STMT(BPF_RET+BPF_K, BPF_BUFSIZE), /* accept */
+};
+
+/* One of these is associated with each instance of a device. */
+struct net_data
+{
+ struct port_info port; /* device port */
+ struct machdev_emul_device device; /* generic device structure */
+ struct ifreq *dev; /* rump network device structure */
+ uint8_t hw_address[ETH_ALEN]; /* MAC address of device */
+ mach_port_t dest; /* destination port for recieving packets */
+ int bpf_fd; /* bpf file descriptor for communication with device */
+ struct net_data *next;
+};
+
+static struct net_data *nd_head;
+
+/* Forward declarations. */
+
+static void *rcv_process (void *arg);
+
+static struct machdev_device_emulation_ops rump_net_emulation_ops;
+
+static mach_msg_type_t header_type =
+{
+ .msgt_name = MACH_MSG_TYPE_BYTE,
+ .msgt_size = 8,
+ .msgt_number = NET_HDW_HDR_MAX,
+ .msgt_inline = TRUE,
+ .msgt_longform = FALSE,
+ .msgt_deallocate = FALSE,
+ .msgt_unused = 0
+};
+
+static mach_msg_type_t packet_type =
+{
+ .msgt_name = MACH_MSG_TYPE_BYTE,
+ .msgt_size = 8,
+ .msgt_number = 0,
+ .msgt_inline = TRUE,
+ .msgt_longform = FALSE,
+ .msgt_deallocate = FALSE
+};
+
+static struct net_data *search_nd (struct ifreq *dev)
+{
+ struct net_data *nd = nd_head;
+
+ while (nd)
+ {
+ if (strncmp(nd->dev->ifr_name, dev->ifr_name, IF_NAMESIZE) == 0)
+ return nd;
+ nd = nd->next;
+ }
+ return NULL;
+}
+
+/* Return a send right associated with network device ND. */
+static mach_port_t
+dev_to_port (void *nd)
+{
+ return (nd
+ ? ports_get_send_right (nd)
+ : MACH_PORT_NULL);
+}
+
+void socket_init(void)
+{
+ int err;
+
+ socket_aflink = rump_sys_socket(RUMP_AF_LINK, SOCK_DGRAM, 0);
+ if (socket_aflink < 0)
+ mach_print("ERROR rump_sys_socket(RUMP_AF_LINK)\n");
+}
+
+static int
+get_hwaddr(const char *ifname, uint8_t *mac)
+{
+ struct if_laddrreq iflr;
+ struct sockaddr_dl *sdl;
+
+ memset(&iflr, 0, sizeof(iflr));
+ strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));
+ iflr.addr.ss_family = RUMP_AF_LINK;
+
+ sdl = satosdl(&iflr.addr);
+ sdl->sdl_alen = ETH_ALEN;
+
+ if (rump_sys_ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1)
+ {
+ mach_print("ERROR siocglifaddr failed\n");
+ return -1;
+ }
+
+ memcpy(mac, LLADDR(sdl), ETH_ALEN);
+ return 0;
+}
+
+static int
+cmp_hwaddr(uint8_t *hwaddr, uint8_t *devaddr)
+{
+ return memcmp(hwaddr, devaddr, ETH_ALEN);
+}
+
+static int
+cmp_hwbroadcast(uint8_t *hw)
+{
+ uint8_t all[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ return memcmp(hw, all, ETH_ALEN);
+}
+
+struct ifreq *
+search_interface(const char *ifname)
+{
+ struct ifreq ifr;
+ struct ifreq *dev = NULL;
+ char *last_slash, *name;
+
+ memset(&ifr, 0, sizeof(ifr));
+ last_slash = strrchr(ifname, '/');
+ if (!last_slash)
+ name = ifname;
+ else
+ name = last_slash + 1;
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ {
+ mach_print("ERROR: cannot malloc\n");
+ return NULL;
+ }
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (rump_sys_ioctl(socket_aflink, SIOCGIFFLAGS, &ifr) == -1)
+ {
+ mach_print("siocgifflags failed: ");
+ mach_print(name);
+ mach_print("\n");
+ goto errexit;
+ }
+ *dev = ifr;
+ goto exit;
+
+errexit:
+ free(dev);
+ dev = NULL;
+exit:
+ return dev;
+}
+
+static io_return_t
+init_interface(struct net_data *nd)
+{
+ unsigned int flag, buf_size;
+ io_return_t err;
+ struct bpf_program p;
+ pthread_t rcv_thread;
+ /* use minimal 1 microsecond timeout, (0 does not work) */
+ struct rump_timeval timeout = { 0, 1 };
+
+ if (get_hwaddr(nd->dev->ifr_name, nd->hw_address))
+ {
+ mach_print("ERROR can't get mac address\n");
+ return rump_errno2host(errno);
+ }
+
+ /* Hardcode MTU to 1500 */
+ nd->dev->ifr_mtu = SIZEOF_MTU;
+ if (rump_sys_ioctl(socket_aflink, SIOCSIFMTU, nd->dev) == -1)
+ {
+ mach_print("ERROR siocsifmtu\n");
+ return rump_errno2host(errno);
+ }
+
+ nd->bpf_fd = rump_sys_open("/dev/bpf", RUMP_O_RDWR);
+ if (nd->bpf_fd < 0)
+ {
+ mach_print("ERROR rump_sys_open(/dev/bpf)\n");
+ return rump_errno2host(errno);
+ }
+
+ buf_size = BPF_BUFSIZE;
+ /* ignore return value */
+ rump_sys_ioctl (nd->bpf_fd, BIOCSBLEN, &buf_size);
+
+ err = rump_sys_ioctl (nd->bpf_fd, BIOCSETIF, nd->dev);
+ if (err < 0)
+ {
+ mach_print("ERROR: biocsetif failed, buf_size too big?\n");
+ errno = rump_errno2host(err);
+ return errno;
+ }
+
+ flag = 0;
+ err = rump_sys_ioctl (nd->bpf_fd, BIOCIMMEDIATE, &flag);
+ if (err < 0)
+ {
+ mach_print("ERROR: biocimmediate failed\n");
+ errno = rump_errno2host(err);
+ return errno;
+ }
+
+ /* We need this timeout for blocking requests to flush even if not full */
+ err = rump_sys_ioctl (nd->bpf_fd, BIOCSRTIMEOUT, &timeout);
+ if (err < 0)
+ {
+ mach_print("ERROR: biocsrtimeout failed\n");
+ errno = rump_errno2host(err);
+ return errno;
+ }
+
+ /* only capture incoming packets, but still allows sending packets */
+ flag = BPF_D_IN;
+ err = rump_sys_ioctl (nd->bpf_fd, BIOCSDIRECTION, &flag);
+ if (err < 0)
+ {
+ mach_print("ERROR: biocsdirection failed\n");
+ errno = rump_errno2host(err);
+ return -1;
+ }
+
+ p.bf_len = sizeof(bpf_allow_all) / sizeof(bpf_allow_all[0]);
+ p.bf_insns = bpf_allow_all;
+
+ err = rump_sys_ioctl (nd->bpf_fd, BIOCSETF, &p);
+ if (err < 0)
+ {
+ mach_print("ERROR: biocsetf failed\n");
+ errno = rump_errno2host(err);
+ return errno;
+ }
+
+ err = pthread_create(&rcv_thread, 0, rcv_process, nd);
+ if (err != 0)
+ {
+ mach_print("ERROR: pthread_create(rcv)\n");
+ return err;
+ }
+ pthread_detach(rcv_thread);
+
+ return 0;
+}
+
+int
+up_interface(struct ifreq *dev)
+{
+ int retval;
+
+ if (rump_sys_ioctl(socket_aflink, SIOCGIFFLAGS, dev) == 0)
+ {
+ if ((dev->ifr_flags & IFF_UP))
+ retval = 0;
+ else
+ {
+ dev->ifr_flags |= IFF_UP | IFF_RUNNING;
+ if (rump_sys_ioctl(socket_aflink, SIOCSIFFLAGS, dev) == 0)
+ retval = 0;
+ else
+ retval = rump_errno2host(errno);
+ }
+ }
+ else
+ retval = rump_errno2host(errno);
+
+ return retval;
+}
+
+static io_return_t
+deliver_msg(struct net_rcv_msg *msg, mach_port_t p)
+{
+ mach_msg_return_t err;
+
+ msg->msg_hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+ /* remember message sizes must be rounded up */
+ msg->msg_hdr.msgh_local_port = MACH_PORT_NULL;
+ msg->msg_hdr.msgh_kind = MACH_MSGH_KIND_NORMAL;
+ msg->msg_hdr.msgh_id = NET_RCV_MSG_ID;
+
+ msg->msg_hdr.msgh_remote_port = p;
+ err = mach_msg ((mach_msg_header_t *)msg,
+ MACH_SEND_MSG,
+ msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ return err;
+}
+
+static io_return_t
+netif_rx_handle (uint8_t *data, int len, mach_port_t dest)
+{
+ int pack_size;
+ struct net_rcv_msg net_msg;
+ struct ether_header *eh;
+ struct packet_header *ph;
+ size_t align = sizeof (uintptr_t);
+
+ pack_size = len - sizeof (struct ethhdr);
+ /* remember message sizes must be rounded up */
+ net_msg.msg_hdr.msgh_size =
+ (((mach_msg_size_t) (offsetof (struct net_rcv_msg, packet)
+ + sizeof (struct packet_header)
+ + pack_size)) + align-1) & ~(align-1);
+
+ /* Copy packet into message buffer. */
+ eh = (struct ether_header *) (net_msg.header);
+ ph = (struct packet_header *) (net_msg.packet);
+ memcpy (eh, data, sizeof (struct ether_header));
+ /* packet is prefixed with a struct packet_header,
+ see include/device/net_status.h. */
+ memcpy (ph + 1, data + sizeof (struct ether_header), pack_size);
+ ph->type = eh->ether_type;
+ ph->length = pack_size + sizeof (struct packet_header);
+
+ net_msg.sent = FALSE; /* Mark packet as received. */
+
+ net_msg.header_type = header_type;
+ net_msg.packet_type = packet_type;
+ net_msg.net_rcv_msg_packet_count = ph->length;
+ return deliver_msg (&net_msg, dest);
+}
+
+static io_return_t
+rumpnet_device_open (mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, const char *name, device_t *devp,
+ mach_msg_type_name_t *devicePoly)
+{
+ io_return_t err = D_SUCCESS;
+ struct ifreq *dev;
+ struct net_data *nd;
+
+ /* Search for the device. */
+ dev = search_interface (name);
+ if (!dev)
+ {
+ fprintf (stderr, "after search_interface: cannot find %s\n", name);
+ return D_NO_SUCH_DEVICE;
+ }
+
+ /* Allocate and initialize device data if this is the first open. */
+ nd = search_nd (dev);
+ if (!nd)
+ {
+ err = machdev_create_device_port (sizeof (*nd), &nd);
+ if (err)
+ {
+ fprintf (stderr, "after machdev_create_device_port: cannot create a port\n");
+ goto out;
+ }
+
+ nd->dev = dev;
+ nd->device.emul_data = nd;
+ nd->device.emul_ops = &rump_net_emulation_ops;
+ nd->next = nd_head;
+ nd_head = nd;
+
+ if ((err = init_interface(nd) < 0))
+ {
+ mach_print ("after init_interface: cannot init the device\n");
+ goto out;
+ }
+ if ((err = up_interface(dev) < 0))
+ {
+ mach_print ("after up_interface: cannot bring up the device\n");
+ goto out;
+ }
+
+out:
+ if (err)
+ {
+ if (nd)
+ {
+ ports_destroy_right (nd);
+ nd = NULL;
+ }
+ }
+ }
+
+ if (nd)
+ {
+ *devp = ports_get_right (nd);
+ *devicePoly = MACH_MSG_TYPE_MAKE_SEND;
+ }
+ return err;
+}
+
+static io_return_t
+send_packet (struct net_data *nd, io_buf_ptr_t buf, unsigned int bytes)
+{
+ io_return_t err;
+ struct iovec iov;
+ int result;
+
+ iov.iov_base = buf;
+ iov.iov_len = bytes;
+
+ result = rump_sys_writev (nd->bpf_fd, &iov, 1);
+ if (result < 0)
+ {
+ errno = EIO;
+ mach_print("ERROR: rump_sys_writev(bpf)\n");
+ return -1;
+ }
+
+ return result;
+}
+
+static io_return_t
+receive_packets (struct net_data *nd)
+{
+ io_return_t err;
+ int i;
+ int fragment;
+ int pkt_length;
+ int read_length;
+ int todo;
+ int buf_size = BPF_BUFSIZE;
+ struct pollfd pfd;
+ size_t buf_inc;
+ struct bpf_hdr *bp = NULL;
+ struct ethhdr *hdr = NULL;
+ bool own_traffic = true;
+ rpc_phys_addr_t pap;
+ /* reusable packet buffer */
+ static vm_address_t bpf_pkt_addr = 0;
+ static uint8_t *bpf_pkt = NULL;
+
+ pfd.fd = nd->bpf_fd;
+ pfd.events = RUMP_POLLIN;
+
+ if (!bpf_pkt_addr)
+ {
+ err = vm_allocate (mach_task_self (), &bpf_pkt_addr, buf_size, TRUE);
+ if (err != KERN_SUCCESS)
+ {
+ mach_print("ERROR: cannot vm_allocate\n");
+ errno = ENOMEM;
+ return -1;
+ }
+ bpf_pkt = (uint8_t *)bpf_pkt_addr;
+
+ {
+ volatile uint8_t dummy_read __attribute__ ((unused));
+ int npages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ int i;
+
+ /* Fault-in the memory pages by reading a single byte of each */
+ for (i = 0; i < npages; i++)
+ dummy_read = ((volatile uint8_t *)bpf_pkt)[i * PAGE_SIZE];
+ }
+ }
+
+poll_again:
+ switch (rump_sys_poll(&pfd, 1, NET_RCV_WAIT))
+ {
+ case 0:
+ case -1:
+ goto poll_again;
+ default:
+ break;
+ }
+
+ read_length = rump_sys_read (nd->bpf_fd, bpf_pkt, buf_size);
+ if (read_length >= 0 && read_length < SIZEOF_BPF_HDR)
+ goto poll_again;
+ else if (read_length < 0)
+ {
+ switch (rump_errno2host(errno))
+ {
+ case EAGAIN:
+ case EINTR:
+ goto poll_again;
+
+ case ENXIO:
+ case EIO:
+ default:
+ {
+ mach_print("ERROR: rump_sys_read(bpf)\n");
+ vm_deallocate (mach_task_self (), bpf_pkt_addr, buf_size);
+ bpf_pkt_addr = 0;
+ return -2; /* device gone */
+ }
+ }
+ }
+
+ todo = read_length;
+
+ while (own_traffic || (todo > 0))
+ {
+ bp = (struct bpf_hdr *)bpf_pkt;
+ hdr = (struct ethhdr *)(bpf_pkt + bp->bh_hdrlen);
+ fragment = bp->bh_datalen - bp->bh_caplen;
+ pkt_length = bp->bh_caplen;
+ buf_inc = BPF_WORDALIGN(pkt_length + bp->bh_hdrlen);
+ todo -= buf_inc;
+
+ if (fragment)
+ {
+ mach_print("fragment rcvd, try again\n");
+ return 0;
+ }
+
+ if (!cmp_hwaddr(hdr->h_source, nd->hw_address))
+ {
+ own_traffic = true;
+ mach_print("seeing our own traffic\n");
+ }
+ else
+ {
+ /* rcv this packet */
+ own_traffic = false;
+ err = netif_rx_handle((uint8_t *)hdr, pkt_length, nd->dest);
+ /* Ignore errors due to:
+ * not enough bandwidth in software stack to handle all packets
+ */
+ }
+
+ /* Check for last packet in bpf buffer */
+ if (todo > 0)
+ bpf_pkt += buf_inc;
+ else
+ bpf_pkt = (uint8_t *)bpf_pkt_addr;
+ }
+ return 0;
+}
+
+static void *
+rcv_process(void *arg)
+{
+ io_return_t err;
+ struct net_data *nd = (struct net_data *)arg;
+ int length;
+
+ for (;;)
+ {
+ err = receive_packets (nd);
+ if (err == -1)
+ {
+ mach_print("ERROR: cannot rcv any packets, giving up\n");
+ return NULL;
+ }
+ else if (err == -2)
+ {
+ mach_print("ERROR: device gone, retry\n");
+ sleep(2);
+ }
+ }
+}
+
+static io_return_t
+rumpnet_device_write (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, io_buf_ptr_t data, unsigned int count,
+ int *bytes_written)
+{
+ struct net_data *nd = (struct net_data *)d;
+ error_t err;
+
+ err = send_packet(nd, data, count);
+ if (err < 0)
+ return errno;
+ *bytes_written = err;
+
+ if (*bytes_written != count)
+ {
+ mach_print("ERROR: bytes_written != count\n");
+ return D_IO_ERROR;
+ }
+
+ vm_deallocate (mach_task_self (), (vm_address_t) data, count);
+
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *count)
+{
+ struct net_data *nd = (struct net_data *)d;
+ io_return_t err;
+
+ switch (flavor)
+ {
+ case NET_FLAGS:
+ {
+ if (*count != 1)
+ return D_INVALID_SIZE;
+
+ err = rump_sys_ioctl(socket_aflink, SIOCGIFFLAGS, nd->dev);
+ if (err < 0)
+ return D_IO_ERROR;
+
+ *(int *) status = nd->dev->ifr_flags;
+ }
+ break;
+
+ case NET_STATUS:
+ {
+ struct net_status *ns = (struct net_status *)status;
+
+ if (*count < NET_STATUS_COUNT)
+ return D_INVALID_OPERATION;
+
+ ns->min_packet_size = ETH_HLEN;
+ ns->max_packet_size = SIZEOF_ETH_FRAME;
+ ns->header_format = HDR_ETHERNET;
+ ns->header_size = ETH_HLEN;
+ ns->address_size = ETH_ALEN;
+ ns->flags = nd->dev->ifr_flags;
+ ns->mapped_size = 0;
+
+ *count = NET_STATUS_COUNT;
+ }
+ break;
+
+ case NET_ADDRESS:
+ {
+ err = rump_sys_ioctl(socket_aflink, SIOCGIFFLAGS, nd->dev);
+ if (err < 0)
+ return D_IO_ERROR;
+
+ err = get_hwaddr(nd->dev->ifr_name, nd->hw_address);
+ if (err)
+ return D_IO_ERROR;
+
+ status[0] =
+ ((nd->hw_address[0] << 24) |
+ (nd->hw_address[1] << 16) |
+ (nd->hw_address[2] << 8) |
+ (nd->hw_address[3]));
+
+ status[1] =
+ ((nd->hw_address[4] << 24) |
+ (nd->hw_address[5] << 16));
+
+ *count = 2;
+ }
+ break;
+
+ default:
+ return D_INVALID_OPERATION;
+ }
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t count)
+{
+ io_return_t err;
+ struct net_data *nd = (struct net_data *)d;
+
+ if (flavor != NET_FLAGS)
+ {
+ mach_print("Some other flavor\n");
+ return D_INVALID_OPERATION;
+ }
+
+ if (count != 1)
+ return D_INVALID_SIZE;
+
+ err = rump_sys_ioctl(socket_aflink, SIOCGIFFLAGS, nd->dev);
+ if (err < 0)
+ return D_IO_ERROR;
+
+ nd->dev->ifr_flags = *((int *)status);
+
+ err = rump_sys_ioctl(socket_aflink, SIOCSIFFLAGS, nd->dev);
+ if (err < 0)
+ return D_IO_ERROR;
+
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_set_filter (void *d, mach_port_t port, int priority,
+ filter_t * filter, unsigned filter_count)
+{
+// return net_set_filter (&((struct net_data *) d)->ifnet.port_list,
+// port, priority, filter, filter_count);
+ struct net_data *nd = (struct net_data *)d;
+ nd->dest = port;
+
+ return D_SUCCESS;
+}
+
+static void rumpnet_init (void)
+{
+ rump_init();
+ socket_init();
+}
+
+static struct machdev_device_emulation_ops rump_net_emulation_ops =
+{
+ rumpnet_init,
+ NULL,
+ NULL,
+ dev_to_port,
+ rumpnet_device_open,
+ NULL,
+ rumpnet_device_write,
+ NULL,
+ NULL,
+ NULL,
+ device_set_status,
+ device_get_status,
+ device_set_filter,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void rump_register_net(void)
+{
+ machdev_register (&rump_net_emulation_ops);
+}
diff --git a/rumpnet/net-rump.h b/rumpnet/net-rump.h
new file mode 100644
index 00000000..327b80e8
--- /dev/null
+++ b/rumpnet/net-rump.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 Free Software Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _RUMP_NET_H_
+#define _RUMP_NET_H_
+
+void rump_register_net(void);
+
+#endif