Hello, Damien Zammit, le mar. 22 juil. 2025 09:23:42 +0000, a ecrit: > 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.
Applied, thanks! Samuel > --- > Makefile | 2 +- > rumpnet/Makefile | 42 ++ > rumpnet/if_hdr.h | 104 +++++ > rumpnet/ioccom-rump.h | 82 ++++ > rumpnet/main.c | 149 +++++++ > rumpnet/net-rump.c | 928 ++++++++++++++++++++++++++++++++++++++++++ > rumpnet/net-rump.h | 24 ++ > 7 files changed, 1330 insertions(+), 1 deletion(-) > create mode 100644 rumpnet/Makefile > create mode 100644 rumpnet/if_hdr.h > create mode 100644 rumpnet/ioccom-rump.h > create mode 100644 rumpnet/main.c > create mode 100644 rumpnet/net-rump.c > create mode 100644 rumpnet/net-rump.h > > 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..b71d2110 > --- /dev/null > +++ b/rumpnet/if_hdr.h > @@ -0,0 +1,104 @@ > +/* > + * 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.distribut...@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_ > + > +/* > + * Header for network interface drivers. > + */ > +struct ifnet { > + short if_unit; /* unit number */ > + short if_flags; /* up/down, broadcast, etc. */ > + short if_timer; /* time until if_watchdog called */ > + short if_mtu; /* maximum transmission unit */ > + short if_header_size; /* length of header */ > + short if_header_format; /* format of hardware header */ > + short if_address_size; /* length of hardware address */ > + short if_alloc_size; /* size of read buffer to allocate */ > + char *if_address; /* pointer to hardware address */ > +// struct ifqueue if_snd; /* output queue */ > +// if_filter_list_t port_list; > +// pthread_mutex_t if_rcv_port_list_lock;/* lock for input filter list */ > +// pthread_mutex_t if_snd_port_list_lock;/* lock for output filter list */ > +/* statistics */ > + int if_ipackets; /* packets received */ > + int if_ierrors; /* input errors */ > + int if_opackets; /* packets sent */ > + int if_oerrors; /* output errors */ > + int if_collisions; /* collisions on csma interfaces */ > + int if_rcvdrops; /* packets received but dropped */ > +}; > + > +#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 > */ > + > +/* internal flags only: */ > +#define IFF_CANTCHANGE (IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING) > + > +#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 > -- > 2.45.2 > > > > -- Samuel "...Deep Hack Mode--that mysterious and frightening state of consciousness where Mortal Users fear to tread." (By Matt Welsh)