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)


Reply via email to