summaryrefslogtreecommitdiff
path: root/lwip
diff options
context:
space:
mode:
authorJoan Lledó <joanlluislledo@gmail.com>2017-11-13 08:31:46 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2017-12-18 00:01:02 +0100
commitd3594ddad8fdd4f28f2362ad288acd03ed60eb41 (patch)
treef76d7dffd2f6e8de6011b0333481a51c70f3c6d2 /lwip
parent0ca198f1f90071a054287c204a3fd1b4ea315e18 (diff)
lwip: Add LwIP-based TCP/IP translator
* Makefile (prog-subdirs): Add lwip. * config.make.in (HAVE_LIBLWIP, liblwip_CFLAGS, liblwip_LIBS): Define variables. * configure.ac: Check for liblwip. * lwip/: New directory.
Diffstat (limited to 'lwip')
-rw-r--r--lwip/Makefile50
-rw-r--r--lwip/iioctl-ops.c410
-rw-r--r--lwip/io-ops.c554
-rw-r--r--lwip/lwip-hurd.h102
-rw-r--r--lwip/lwip-util.c343
-rw-r--r--lwip/lwip-util.h41
-rw-r--r--lwip/main.c272
-rw-r--r--lwip/mig-decls.h68
-rw-r--r--lwip/mig-mutate.h44
-rw-r--r--lwip/options.c342
-rw-r--r--lwip/options.h81
-rw-r--r--lwip/pfinet-ops.c113
-rw-r--r--lwip/port-objs.c144
-rw-r--r--lwip/port/include/netif/hurdethif.h39
-rw-r--r--lwip/port/include/netif/hurdloopif.h36
-rw-r--r--lwip/port/include/netif/hurdtunif.h65
-rw-r--r--lwip/port/include/netif/ifcommon.h60
-rw-r--r--lwip/port/netif/hurdethif.c573
-rw-r--r--lwip/port/netif/hurdloopif.c112
-rw-r--r--lwip/port/netif/hurdtunif.c721
-rw-r--r--lwip/port/netif/ifcommon.c121
-rw-r--r--lwip/socket-ops.c451
-rw-r--r--lwip/startup-ops.c39
-rw-r--r--lwip/startup.c69
-rw-r--r--lwip/startup.h26
25 files changed, 4876 insertions, 0 deletions
diff --git a/lwip/Makefile b/lwip/Makefile
new file mode 100644
index 00000000..c5f3c8cb
--- /dev/null
+++ b/lwip/Makefile
@@ -0,0 +1,50 @@
+# Copyright (C) 2017 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd 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.
+#
+# The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+
+dir = lwip
+makemode = server
+
+PORTDIR = $(srcdir)/port
+
+SRCS = main.c io-ops.c socket-ops.c pfinet-ops.c iioctl-ops.c port-objs.c \
+ startup-ops.c options.c lwip-util.c startup.c
+IFSRCS = ifcommon.c hurdethif.c hurdloopif.c hurdtunif.c
+MIGSRCS = ioServer.c socketServer.c pfinetServer.c iioctlServer.c \
+ startup_notifyServer.c
+OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o,\
+ $(SRCS) $(IFSRCS) $(MIGSRCS)))
+
+HURDLIBS = trivfs fshelp ports ihash shouldbeinlibc iohelp
+LDLIBS = -lpthread $(liblwip_LIBS)
+
+target = lwip
+
+include ../Makeconf
+
+vpath %.c $(PORTDIR) $(PORTDIR)/netif
+
+CFLAGS += -I$(PORTDIR)/include $(liblwip_CFLAGS)
+
+MIGCOMSFLAGS += -prefix lwip_
+mig-sheader-prefix = lwip_
+io-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+socket-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+iioctl-MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+
+# cpp doesn't automatically make dependencies for -imacros dependencies. argh.
+lwip_io_S.h ioServer.c lwip_socket_S.h socketServer.c: mig-mutate.h
+$(OBJS): config.h
diff --git a/lwip/iioctl-ops.c b/lwip/iioctl-ops.c
new file mode 100644
index 00000000..fcb7e872
--- /dev/null
+++ b/lwip/iioctl-ops.c
@@ -0,0 +1,410 @@
+/*
+ Copyright (C) 2000, 2007, 2017 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Ioctls for network device configuration */
+
+#include <lwip_iioctl_S.h>
+
+#include <lwip/sockets.h>
+#include <device/device.h>
+#include <device/net_status.h>
+
+#include <lwip-hurd.h>
+#include <lwip-util.h>
+#include <netif/ifcommon.h>
+
+/* Get the interface from its name */
+static struct netif *
+get_if (char *name)
+{
+ char ifname[IFNAMSIZ];
+ struct netif *netif;
+
+ memcpy (ifname, name, IFNAMSIZ - 1);
+ ifname[IFNAMSIZ - 1] = 0;
+
+ for (netif = netif_list; netif != 0; netif = netif->next)
+ {
+ if (strcmp (netif_get_state (netif)->devname, ifname) == 0)
+ break;
+ }
+
+ return netif;
+}
+
+enum siocgif_type
+{
+ ADDR,
+ NETMASK,
+ DSTADDR,
+ BRDADDR
+};
+
+#define SIOCGIF(name, type) \
+ kern_return_t \
+ lwip_S_iioctl_siocgif##name (struct sock_user *user, \
+ ifname_t ifnam, \
+ sockaddr_t *addr) \
+ { \
+ return siocgifXaddr (user, ifnam, addr, type); \
+ }
+
+/* Get some sockaddr type of info. */
+static kern_return_t
+siocgifXaddr (struct sock_user *user,
+ ifname_t ifnam, sockaddr_t * addr, enum siocgif_type type)
+{
+ error_t err = 0;
+ struct sockaddr_in *sin = (struct sockaddr_in *) addr;
+ size_t buflen = sizeof (struct sockaddr);
+ struct netif *netif;
+ uint32_t addrs[4];
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (ifnam);
+ if (!netif)
+ return ENODEV;
+
+ if (type == DSTADDR)
+ return EOPNOTSUPP;
+
+ /* We're only interested in geting the address family */
+ err = lwip_getsockname (user->sock->sockno, addr, (socklen_t *) & buflen);
+ if (err)
+ return err;
+
+ if (sin->sin_family != AF_INET)
+ err = EINVAL;
+ else
+ {
+ inquire_device (netif, &addrs[0], &addrs[1], &addrs[2], &addrs[3], 0, 0,
+ 0);
+ sin->sin_addr.s_addr = addrs[type];
+ }
+
+ return err;
+}
+
+#define SIOCSIF(name, type) \
+ kern_return_t \
+ lwip_S_iioctl_siocsif##name (struct sock_user *user, \
+ ifname_t ifnam, \
+ sockaddr_t addr) \
+ { \
+ return siocsifXaddr (user, ifnam, &addr, type); \
+ }
+
+/* Set some sockaddr type of info. */
+static kern_return_t
+siocsifXaddr (struct sock_user *user,
+ ifname_t ifnam, sockaddr_t * addr, enum siocgif_type type)
+{
+ error_t err = 0;
+ struct sockaddr_in sin;
+ size_t buflen = sizeof (struct sockaddr_in);
+ struct netif *netif;
+ uint32_t ipv4_addrs[5];
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (!user->isroot)
+ return EPERM;
+
+ netif = get_if (ifnam);
+
+ if (!netif)
+ return ENODEV;
+
+ if (type == DSTADDR || type == BRDADDR)
+ return EOPNOTSUPP;
+
+ err = lwip_getsockname (user->sock->sockno,
+ (sockaddr_t *) & sin, (socklen_t *) & buflen);
+ if (err)
+ return err;
+
+ if (sin.sin_family != AF_INET)
+ err = EINVAL;
+ else
+ {
+ inquire_device (netif, &ipv4_addrs[0], &ipv4_addrs[1],
+ &ipv4_addrs[2], &ipv4_addrs[3], &ipv4_addrs[4], 0, 0);
+
+ ipv4_addrs[type] = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+
+ err = configure_device (netif, ipv4_addrs[0], ipv4_addrs[1],
+ ipv4_addrs[2], ipv4_addrs[3], ipv4_addrs[4], 0,
+ 0);
+ }
+
+ return err;
+}
+
+/* 12 SIOCSIFADDR -- Set address of a network interface. */
+SIOCSIF (addr, ADDR);
+
+/* 14 SIOCSIFDSTADDR -- Set point-to-point (peer) address of a network interface. */
+SIOCSIF (dstaddr, DSTADDR);
+
+/* 16 SIOCSIFFLAGS -- Set flags of a network interface. */
+kern_return_t
+lwip_S_iioctl_siocsifflags (struct sock_user * user,
+ ifname_t ifnam,
+ short flags)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (ifnam);
+
+ if (!user->isroot)
+ err = EPERM;
+ else if (!netif)
+ err = ENODEV;
+ else
+ err = if_change_flags (netif, flags);
+
+ return err;
+}
+
+/* 17 SIOCGIFFLAGS -- Get flags of a network interface. */
+kern_return_t
+lwip_S_iioctl_siocgifflags (struct sock_user * user, char *name, short *flags)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (name);
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ *flags = netif_get_state (netif)->flags;
+ }
+
+ return err;
+}
+
+/* 19 SIOCSIFBRDADDR -- Set broadcast address of a network interface. */
+SIOCSIF (brdaddr, BRDADDR);
+
+/* 22 SIOCSIFNETMASK -- Set netmask of a network interface. */
+SIOCSIF (netmask, NETMASK);
+
+/* 23 SIOCGIFMETRIC -- Get metric of a network interface. */
+kern_return_t
+lwip_S_iioctl_siocgifmetric (struct sock_user * user,
+ ifname_t ifnam,
+ int *metric)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (ifnam);
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ *metric = 0; /* Not supported. */
+ }
+
+ return err;
+}
+
+/* 24 SIOCSIFMETRIC -- Set metric of a network interface. */
+kern_return_t
+lwip_S_iioctl_siocsifmetric (struct sock_user * user,
+ ifname_t ifnam,
+ int metric)
+{
+ return EOPNOTSUPP;
+}
+
+/* 25 SIOCDIFADDR -- Delete interface address. */
+kern_return_t
+lwip_S_iioctl_siocdifaddr (struct sock_user * user,
+ ifname_t ifnam,
+ sockaddr_t addr)
+{
+ return EOPNOTSUPP;
+}
+
+/* 33 SIOCGIFADDR -- Get address of a network interface. */
+SIOCGIF (addr, ADDR);
+
+/* 34 SIOCGIFDSTADDR -- Get point-to-point address of a network interface. */
+SIOCGIF (dstaddr, DSTADDR);
+
+/* 35 SIOCGIFBRDADDR -- Get broadcast address of a network interface. */
+SIOCGIF (brdaddr, BRDADDR);
+
+/* 37 SIOCGIFNETMASK -- Get netmask of a network interface. */
+SIOCGIF (netmask, NETMASK);
+
+/* 39 SIOCGIFHWADDR -- Get the hardware address of a network interface. */
+error_t
+lwip_S_iioctl_siocgifhwaddr (struct sock_user * user,
+ ifname_t ifname,
+ sockaddr_t * addr)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (ifname);
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ memcpy (addr->sa_data, netif->hwaddr, netif->hwaddr_len);
+ addr->sa_family = netif_get_state (netif)->type;
+ }
+
+ return err;
+}
+
+/* 51 SIOCGIFMTU -- Get mtu of a network interface. */
+error_t
+lwip_S_iioctl_siocgifmtu (struct sock_user * user, ifname_t ifnam, int *mtu)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ netif = get_if (ifnam);
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ *mtu = netif->mtu;
+ }
+
+ return err;
+}
+
+/* 51 SIOCSIFMTU -- Set mtu of a network interface. */
+error_t
+lwip_S_iioctl_siocsifmtu (struct sock_user * user, ifname_t ifnam, int mtu)
+{
+ error_t err = 0;
+ struct netif *netif;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (!user->isroot)
+ return EPERM;
+
+ if (mtu <= 0)
+ return EINVAL;
+
+ netif = get_if (ifnam);
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ err = netif_get_state (netif)->update_mtu (netif, mtu);
+ }
+
+ return err;
+}
+
+/* 100 SIOCGIFINDEX -- Get index number of a network interface. */
+error_t
+lwip_S_iioctl_siocgifindex (struct sock_user * user,
+ ifname_t ifnam,
+ int *index)
+{
+ error_t err = 0;
+ struct netif *netif;
+ int i;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ i = 1; /* The first index must be 1 */
+ for (netif = netif_list; netif != 0; netif = netif->next)
+ {
+ if (strcmp (netif_get_state (netif)->devname, ifnam) == 0)
+ {
+ *index = i;
+ break;
+ }
+
+ i++;
+ }
+
+ if (!netif)
+ err = ENODEV;
+
+ return err;
+}
+
+/* 101 SIOCGIFNAME -- Get name of a network interface from index number. */
+error_t
+lwip_S_iioctl_siocgifname (struct sock_user * user,
+ ifname_t ifnam,
+ int *index)
+{
+ error_t err = 0;
+ struct netif *netif;
+ int i;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (*index < 0)
+ return EINVAL;
+
+ i = 1; /* The first index is 1 */
+ for (netif = netif_list; netif != 0; netif = netif->next)
+ {
+ if (i == *index)
+ break;
+
+ i++;
+ }
+
+ if (!netif)
+ err = ENODEV;
+ else
+ {
+ strncpy (ifnam, netif_get_state (netif)->devname, IFNAMSIZ);
+ ifnam[IFNAMSIZ - 1] = '\0';
+ }
+
+ return err;
+}
diff --git a/lwip/io-ops.c b/lwip/io-ops.c
new file mode 100644
index 00000000..636c26f7
--- /dev/null
+++ b/lwip/io-ops.c
@@ -0,0 +1,554 @@
+/*
+ Copyright (C) 1995,96,97,98,99,2000,02,17 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* General input/output operations */
+
+#include <lwip_io_S.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <lwip/sockets.h>
+
+error_t
+lwip_S_io_write (struct sock_user *user,
+ char *data,
+ size_t datalen,
+ off_t offset, mach_msg_type_number_t * amount)
+{
+ int sent;
+ int sockflags;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ sockflags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+ sent = lwip_send (user->sock->sockno, data, datalen,
+ (sockflags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
+
+ if (sent >= 0)
+ {
+ *amount = sent;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_read (struct sock_user * user,
+ char **data,
+ size_t * datalen, off_t offset, mach_msg_type_number_t amount)
+{
+ error_t err;
+ int alloced = 0;
+ int flags;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Instead of this, we should peek and the socket and only
+ allocate as much as necessary. */
+ if (amount > *datalen)
+ {
+ *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ /* Should check whether errno is indeed ENOMEM --
+ but this can't be done in a straightforward way,
+ because the glue headers #undef errno. */
+ return ENOMEM;
+ alloced = 1;
+ }
+
+ /* Get flags */
+ flags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+
+ err = lwip_recv (user->sock->sockno, *data, amount,
+ (flags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
+
+ if (err < 0)
+ {
+ if (alloced)
+ munmap (*data, amount);
+ }
+ else
+ {
+ *datalen = err;
+ if (alloced && round_page (*datalen) < round_page (amount))
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
+ errno = 0;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_seek (struct sock_user * user,
+ off_t offset, int whence, off_t * newp)
+{
+ return user ? ESPIPE : EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readable (struct sock_user * user, mach_msg_type_number_t * amount)
+{
+ error_t err;
+ if (!user)
+ return EOPNOTSUPP;
+
+ err = lwip_ioctl (user->sock->sockno, FIONREAD, amount);
+
+ if (err < 0)
+ *amount = 0;
+
+ return errno;
+}
+
+error_t
+lwip_S_io_set_all_openmodes (struct sock_user * user, int bits)
+{
+ int opt;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ opt = 1;
+ else
+ opt = 0;
+
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+
+ return errno;
+}
+
+error_t
+lwip_S_io_get_openmodes (struct sock_user * user, int *bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ *bits = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+
+ return errno;
+}
+
+error_t
+lwip_S_io_set_some_openmodes (struct sock_user * user, int bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ {
+ int opt = 1;
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+ }
+
+ return errno;
+}
+
+
+error_t
+lwip_S_io_clear_some_openmodes (struct sock_user * user, int bits)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (bits & O_NONBLOCK)
+ {
+ int opt = 0;
+ lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
+ }
+
+ return errno;
+}
+
+/*
+ * Arrange things to call lwip_poll()
+ */
+static error_t
+lwip_io_select_common (struct sock_user *user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tv, int *select_type)
+{
+ int ret;
+ int timeout;
+ struct pollfd fdp;
+ nfds_t nfds;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Make this thread cancellable */
+ ports_interrupt_self_on_notification (user, reply, MACH_NOTIFY_DEAD_NAME);
+
+ memset (&fdp, 0, sizeof (struct pollfd));
+ fdp.fd = user->sock->sockno;
+
+ if (*select_type & SELECT_READ)
+ {
+ fdp.events |= POLLIN;
+ }
+ if (*select_type & SELECT_WRITE)
+ {
+ fdp.events |= POLLOUT;
+ }
+ if (*select_type & SELECT_URG)
+ {
+ fdp.events |= POLLPRI;
+ }
+
+ *select_type = 0;
+
+ nfds = 1;
+ timeout = tv ? tv->tv_sec * 1000 + tv->tv_nsec / 1000000 : -1;
+ ret = lwip_poll (&fdp, nfds, timeout);
+
+ if (ret > 0)
+ {
+ if (fdp.revents & POLLIN)
+ *select_type |= SELECT_READ;
+
+ if (fdp.revents & POLLOUT)
+ *select_type |= SELECT_WRITE;
+
+ if (fdp.revents & POLLPRI)
+ *select_type |= SELECT_URG;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_io_select (struct sock_user * user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int *select_type)
+{
+ return lwip_io_select_common (user, reply, reply_type, 0, select_type);
+}
+
+error_t
+lwip_S_io_select_timeout (struct sock_user * user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts, int *select_type)
+{
+ struct timespec current_ts;
+ clock_gettime (CLOCK_REALTIME, &current_ts);
+
+ ts.tv_sec -= current_ts.tv_sec;
+ ts.tv_nsec -= current_ts.tv_nsec;
+
+ return lwip_io_select_common (user, reply, reply_type, &ts, select_type);
+}
+
+
+error_t
+lwip_S_io_stat (struct sock_user * user, struct stat * st)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ memset (st, 0, sizeof (struct stat));
+
+ st->st_fstype = FSTYPE_SOCKET;
+ st->st_fsid = getpid ();
+ st->st_ino = user->sock->sockno;
+
+ st->st_mode = S_IFSOCK | ACCESSPERMS;
+ st->st_blksize = 512; /* ???? */
+
+ return 0;
+}
+
+error_t
+lwip_S_io_reauthenticate (struct sock_user * user, mach_port_t rend)
+{
+ struct sock_user *newuser;
+ uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
+ uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
+ size_t genuidlen, gengidlen, auxuidlen, auxgidlen;
+ error_t err;
+ size_t i, j;
+ auth_t auth;
+ mach_port_t newright;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
+ gen_uids = gubuf;
+ gen_gids = ggbuf;
+ aux_uids = aubuf;
+ aux_gids = agbuf;
+
+ newuser = make_sock_user (user->sock, 0, 1, 0);
+
+ auth = getauth ();
+ newright = ports_get_send_right (newuser);
+ assert_backtrace (newright != MACH_PORT_NULL);
+
+ do
+ err = auth_server_authenticate (auth,
+ rend,
+ MACH_MSG_TYPE_COPY_SEND,
+ newright,
+ MACH_MSG_TYPE_COPY_SEND,
+ &gen_uids, &genuidlen,
+ &aux_uids, &auxuidlen,
+ &gen_gids, &gengidlen,
+ &aux_gids, &auxgidlen);
+ while (err == EINTR);
+
+ mach_port_deallocate (mach_task_self (), rend);
+ mach_port_deallocate (mach_task_self (), newright);
+ mach_port_deallocate (mach_task_self (), auth);
+
+ if (err)
+ newuser->isroot = 0;
+ else
+ /* Check permission as fshelp_isowner would do. */
+ for (i = 0; i < genuidlen; i++)
+ {
+ if (gen_uids[i] == 0 || gen_uids[i] == lwip_owner)
+ newuser->isroot = 1;
+ if (gen_uids[i] == lwip_group)
+ for (j = 0; j < gengidlen; j++)
+ if (gen_gids[j] == lwip_group)
+ newuser->isroot = 1;
+ }
+
+ mach_port_move_member (mach_task_self (), newuser->pi.port_right,
+ lwip_bucket->portset);
+
+ ports_port_deref (newuser);
+
+ if (gubuf != gen_uids)
+ munmap (gen_uids, genuidlen * sizeof (uid_t));
+ if (ggbuf != gen_gids)
+ munmap (gen_gids, gengidlen * sizeof (uid_t));
+ if (aubuf != aux_uids)
+ munmap (aux_uids, auxuidlen * sizeof (uid_t));
+ if (agbuf != aux_gids)
+ munmap (aux_gids, auxgidlen * sizeof (uid_t));
+
+ return 0;
+}
+
+error_t
+lwip_S_io_restrict_auth (struct sock_user * user,
+ mach_port_t * newobject,
+ mach_msg_type_name_t * newobject_type,
+ uid_t * uids, size_t uidslen,
+ uid_t * gids, size_t gidslen)
+{
+ struct sock_user *newuser;
+ int i, j;
+ int isroot;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ isroot = 0;
+ if (user->isroot)
+ /* Check permission as fshelp_isowner would do. */
+ for (i = 0; i < uidslen; i++)
+ {
+ if (uids[i] == 0 || uids[i] == lwip_owner)
+ isroot = 1;
+ if (uids[i] == lwip_group)
+ for (j = 0; j < gidslen; j++)
+ if (gids[j] == lwip_group)
+ isroot = 1;
+ }
+
+ newuser = make_sock_user (user->sock, isroot, 0, 0);
+ *newobject = ports_get_right (newuser);
+ *newobject_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+
+ return 0;
+}
+
+error_t
+lwip_S_io_duplicate (struct sock_user * user,
+ mach_port_t * newobject,
+ mach_msg_type_name_t * newobject_type)
+{
+ struct sock_user *newuser;
+ if (!user)
+ return EOPNOTSUPP;
+
+ newuser = make_sock_user (user->sock, user->isroot, 0, 0);
+ *newobject = ports_get_right (newuser);
+ *newobject_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+
+ return 0;
+}
+
+error_t
+lwip_S_io_identity (struct sock_user * user,
+ mach_port_t * id,
+ mach_msg_type_name_t * idtype,
+ mach_port_t * fsys,
+ mach_msg_type_name_t * fsystype, ino_t * fileno)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ if (user->sock->identity == MACH_PORT_NULL)
+ {
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &user->sock->identity);
+ if (err)
+ {
+ return err;
+ }
+ }
+
+ *id = user->sock->identity;
+ *idtype = MACH_MSG_TYPE_MAKE_SEND;
+ *fsys = fsys_identity;
+ *fsystype = MACH_MSG_TYPE_MAKE_SEND;
+ *fileno = user->sock->sockno;
+
+ return 0;
+}
+
+error_t
+lwip_S_io_revoke (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_async (struct sock_user * user,
+ mach_port_t notify,
+ mach_port_t * id, mach_msg_type_name_t * idtype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_mod_owner (struct sock_user * user, pid_t owner)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_owner (struct sock_user * user, pid_t * owner)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_icky_async_id (struct sock_user * user,
+ mach_port_t * id, mach_msg_type_name_t * idtype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_server_version (struct sock_user * user,
+ char *name, int *major, int *minor, int *edit)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_pathconf (struct sock_user * user, int name, int *value)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_map (struct sock_user * user,
+ mach_port_t * rdobj,
+ mach_msg_type_name_t * rdobj_type,
+ mach_port_t * wrobj, mach_msg_type_name_t * wrobj_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_map_cntl (struct sock_user * user,
+ mach_port_t * obj, mach_msg_type_name_t * obj_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_get_conch (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_release_conch (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_eofnotify (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_prenotify (struct sock_user * user,
+ vm_offset_t start, vm_offset_t end)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_postnotify (struct sock_user * user,
+ vm_offset_t start, vm_offset_t end)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readnotify (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_readsleep (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+lwip_S_io_sigio (struct sock_user * user)
+{
+ return EOPNOTSUPP;
+}
diff --git a/lwip/lwip-hurd.h b/lwip/lwip-hurd.h
new file mode 100644
index 00000000..9e05550b
--- /dev/null
+++ b/lwip/lwip-hurd.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 1995, 1996, 1999, 2000, 2002, 2007, 2017
+ Free Software Foundation, Inc.
+
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Translator global declarations */
+
+#ifndef LWIP_HURD_H
+#define LWIP_HURD_H
+
+#include <sys/socket.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <refcount.h>
+
+struct port_bucket *lwip_bucket;
+struct port_class *socketport_class;
+struct port_class *addrport_class;
+struct port_class *shutdown_notify_class;
+
+struct port_class *lwip_protid_portclasses[2];
+struct port_class *lwip_cntl_portclasses[2];
+
+/* Which portclass to install on the bootstrap port, default to IPv4. */
+int lwip_bootstrap_portclass;
+
+mach_port_t fsys_identity;
+
+/* Trivfs control structure for lwip. */
+struct trivfs_control *lwipcntl;
+
+/* Address family port classes. */
+enum
+{
+ PORTCLASS_INET,
+ PORTCLASS_INET6,
+};
+
+struct socket
+{
+ int sockno;
+ mach_port_t identity;
+ refcount_t refcnt;
+};
+
+/* Multiple sock_user's can point to the same socket. */
+struct sock_user
+{
+ struct port_info pi;
+ int isroot;
+ struct socket *sock;
+};
+
+/* Socket address ports. */
+struct sock_addr
+{
+ struct port_info pi;
+ union
+ {
+ struct sockaddr_storage storage;
+ struct sockaddr sa;
+ } address;
+};
+
+/* Owner of the underlying node. */
+uid_t lwip_owner;
+
+/* Group of the underlying node. */
+uid_t lwip_group;
+
+struct socket *sock_alloc (void);
+void sock_release (struct socket *);
+
+void clean_addrport (void *);
+void clean_socketport (void *);
+
+struct sock_user *make_sock_user (struct socket *, int, int, int);
+error_t make_sockaddr_port (int, int, mach_port_t *, mach_msg_type_name_t *);
+
+void init_ifs (void *);
+
+/* Install portclass on node NAME. */
+void translator_bind (int portclass, const char *name);
+
+#endif
diff --git a/lwip/lwip-util.c b/lwip/lwip-util.c
new file mode 100644
index 00000000..c65b093b
--- /dev/null
+++ b/lwip/lwip-util.c
@@ -0,0 +1,343 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Lwip management module */
+
+#include <lwip-util.h>
+
+#include <error.h>
+#include <net/if_arp.h>
+
+#include <lwip/sockets.h>
+#include <lwip/netifapi.h>
+
+#include <lwip-hurd.h>
+#include <options.h>
+#include <netif/hurdethif.h>
+#include <netif/hurdtunif.h>
+#include <netif/hurdloopif.h>
+
+/*
+ * Detect the proper module for the given device name
+ * and returns its init callback
+ */
+static error_t
+create_netif_state (char *name, struct ifcommon *ifc)
+{
+ char *base_name;
+
+ memset (ifc, 0, sizeof (struct ifcommon));
+
+ base_name = strrchr (name, '/');
+ if (base_name)
+ base_name++;
+ else
+ base_name = name;
+
+ if (strncmp (base_name, "tun", 3) == 0)
+ ifc->init = hurdtunif_device_init;
+ else
+ ifc->init = hurdethif_device_init;
+
+ /* Freed in the module terminate callback */
+ ifc->devname = strndup (name, strlen (name));
+
+ return errno;
+}
+
+/* Some checks for IPv4 configurations */
+static int
+ipv4config_is_valid (uint32_t addr, uint32_t netmask,
+ uint32_t gateway, uint32_t broadcast)
+{
+ /* Check whether the user provided a valid netmask */
+ if (netmask != INADDR_NONE && !ip4_addr_netmask_valid (netmask))
+ {
+ error (0, 0, "Error: Invalid network mask.\n");
+ return 0;
+ }
+
+ /* The given gateway, if any, must be in the same network as the address */
+ if (gateway != INADDR_NONE && (gateway & netmask) != (addr & netmask))
+ {
+ error (0, 0,
+ "Error: the gateway is not in the same network as the address.\n");
+ return 0;
+ }
+
+ /*
+ * LwIP doesn't allow setting the broadcast address.
+ * We must ensure the given broadcast address is the default one for this
+ * network.
+ */
+ if (broadcast != INADDR_NONE
+ && netmask != INADDR_NONE && broadcast != (addr | ~netmask))
+ {
+ error (0, 0,
+ "Error: the broadcast address doesn't match the network mask.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Configure the loopback interface */
+static void
+init_loopback ()
+{
+ struct ifcommon ifc;
+
+ memset (&ifc, 0, sizeof (struct ifcommon));
+ ifc.init = hurdloopif_device_init;
+ netif_list->state = &ifc;
+
+ if_init (netif_list);
+}
+
+/* Remove the existing interfaces, but the loopback one */
+void
+remove_ifs ()
+{
+ struct netif *netif;
+
+ netif = netif_list;
+ while (netif != 0)
+ {
+ /* Skip the loopback interface */
+ if (netif_get_state (netif)->type == ARPHRD_LOOPBACK)
+ {
+ netif = netif->next;
+ continue;
+ }
+ if_terminate (netif);
+ netifapi_netif_remove (netif);
+ free (netif);
+
+ netif = netif_list;
+ }
+
+ return;
+}
+
+/* Initialize the interfaces given by the user through command line */
+void
+init_ifs (void *arg)
+{
+ error_t err;
+ struct parse_interface *in;
+ struct parse_hook *ifs;
+ struct netif *netif;
+ struct ifcommon ifc;
+ int8_t ipv6_addr_idx;
+ ip6_addr_t *address6;
+ int i;
+
+ if (netif_list != 0)
+ {
+ if (netif_list->next == 0)
+ init_loopback ();
+ else
+ remove_ifs ();
+ }
+
+ /*
+ * Go through the list backwards. For LwIP
+ * to create its list in the proper order.
+ */
+ ifs = (struct parse_hook *) arg;
+ for (in = ifs->interfaces + ifs->num_interfaces - 1;
+ in >= ifs->interfaces; in--)
+ {
+ /* The interface hasn't been completely configured */
+ if (!in->dev_name[0])
+ continue;
+
+ if (!ipv4config_is_valid (in->address.addr, in->netmask.addr,
+ in->gateway.addr, INADDR_NONE))
+ continue;
+
+ netif = calloc (1, sizeof (struct netif));
+
+ create_netif_state (in->dev_name, &ifc);
+
+ /*
+ * Create a new interface and configre IPv4.
+ *
+ * Fifth parameter (in->name) is a hook.
+ */
+ err = netifapi_netif_add
+ (netif, &in->address, &in->netmask, &in->gateway, &ifc, if_init,
+ tcpip_input);
+ if (err)
+ {
+ /* The interface failed to init */
+ if (netif->state != in->dev_name)
+ /* It failed after setting the control block, must free it */
+ mem_free (netif->state);
+ free (netif);
+ continue;
+ }
+
+ /* Add IPv6 configuration */
+ netif->ip6_autoconfig_enabled = 1;
+ netif_create_ip6_linklocal_address (netif, 1);
+
+ /* Add user given unicast addresses */
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ {
+ address6 = (ip6_addr_t *) & in->addr6[i];
+
+ if (!ip6_addr_isany (address6) && !ip6_addr_ismulticast (address6))
+ {
+ netif_add_ip6_address (netif, address6, &ipv6_addr_idx);
+
+ if (ipv6_addr_idx >= 0)
+ /* First use DAD to make sure nobody else has it */
+ netif_ip6_addr_set_state (netif, ipv6_addr_idx,
+ IP6_ADDR_TENTATIVE);
+ else
+ error (0, 0, "No free slot for IPv6 address: %s\n",
+ ip6addr_ntoa (address6));
+ }
+ }
+
+ /* Up the inerface */
+ netifapi_netif_set_up (netif);
+
+ /* Set the first interface with valid gateway as default */
+ if (in->gateway.addr != INADDR_NONE)
+ {
+ netifapi_netif_set_default (netif);
+ }
+ }
+
+ /* Free the hook */
+ free (ifs->interfaces);
+ free (ifs);
+
+ return;
+}
+
+/*
+ * Change the IP configuration of an interface
+ */
+static error_t
+update_if (struct netif *netif, uint32_t addr, uint32_t netmask,
+ uint32_t peer, uint32_t broadcast, uint32_t gateway,
+ uint32_t * addr6, uint8_t * addr6_prefix_len)
+{
+ error_t err;
+ int i;
+
+ err = 0;
+
+ netifapi_netif_set_addr (netif, (ip4_addr_t *) & addr,
+ (ip4_addr_t *) & netmask,
+ (ip4_addr_t *) & gateway);
+
+ if (addr6)
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ {
+ ip6_addr_t *laddr6 = ((ip6_addr_t *) addr6 + i);
+ if (!ip6_addr_isany (laddr6))
+ {
+ netif_ip6_addr_set (netif, i, laddr6);
+
+ if (!ip6_addr_islinklocal (laddr6))
+ netif_ip6_addr_set_state (netif, i, IP6_ADDR_TENTATIVE);
+ }
+ }
+
+ if (addr6_prefix_len)
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ *(addr6_prefix_len + i) = 64;
+
+ return err;
+}
+
+/* Get the IP configuration of an interface */
+void
+inquire_device (struct netif *netif, uint32_t * addr, uint32_t * netmask,
+ uint32_t * peer, uint32_t * broadcast, uint32_t * gateway,
+ uint32_t * addr6, uint8_t * addr6_prefix_len)
+{
+ int i;
+
+ if (netif)
+ {
+ if (addr)
+ *addr = netif_ip4_addr (netif)->addr;
+
+ if (netmask)
+ *netmask = netif_ip4_netmask (netif)->addr;
+
+ if (peer)
+ *peer = INADDR_NONE;
+
+ if (broadcast)
+ *broadcast =
+ netif_ip4_addr (netif)->addr | ~netif_ip4_netmask (netif)->addr;
+
+ if (gateway)
+ *gateway = netif_ip4_gw (netif)->addr;
+
+ if (addr6)
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ {
+ *(addr6 + i * 4 + 0) = netif_ip6_addr (netif, i)->addr[0];
+ *(addr6 + i * 4 + 1) = netif_ip6_addr (netif, i)->addr[1];
+ *(addr6 + i * 4 + 2) = netif_ip6_addr (netif, i)->addr[2];
+ *(addr6 + i * 4 + 3) = netif_ip6_addr (netif, i)->addr[3];
+ }
+
+ if (addr6_prefix_len)
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ *(addr6_prefix_len + i) = 64;
+ }
+}
+
+/*
+ * Check and change the IP configuration of an interface.
+ * Called from ioctls.
+ */
+error_t
+configure_device (struct netif *netif, uint32_t addr, uint32_t netmask,
+ uint32_t peer, uint32_t broadcast, uint32_t gateway,
+ uint32_t * addr6, uint8_t * addr6_prefix_len)
+{
+ error_t err = 0;
+
+ if (netmask != INADDR_NONE)
+ /*
+ * If broadcasting is enabled and we have a netmask lesser than 31 bits
+ * long, we need to update the broadcast address too.
+ */
+ if ((netif->flags & NETIF_FLAG_BROADCAST)
+ && ip4_addr_netmask_valid (netmask) && netmask <= 0xfffffffc)
+ broadcast = (addr | ~netmask);
+
+ if (!ipv4config_is_valid (addr, netmask, gateway, broadcast))
+ err = EINVAL;
+ else
+ err = update_if (netif, addr, netmask, peer, broadcast,
+ gateway, addr6, addr6_prefix_len);
+
+ return err;
+}
diff --git a/lwip/lwip-util.h b/lwip/lwip-util.h
new file mode 100644
index 00000000..03022331
--- /dev/null
+++ b/lwip/lwip-util.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Lwip management module */
+
+#ifndef LWIP_UTIL_H
+#define LWIP_UTIL_H
+
+#define LOOP_DEV_NAME "lo"
+
+#include <lwip/netif.h>
+
+void init_ifs (void *arg);
+
+void inquire_device (struct netif *netif, uint32_t * addr, uint32_t * netmask,
+ uint32_t * peer, uint32_t * broadcast,
+ uint32_t * gateway, uint32_t * addr6,
+ uint8_t * addr6_prefix_len);
+error_t configure_device (struct netif *netif, uint32_t addr,
+ uint32_t netmask, uint32_t peer, uint32_t broadcast,
+ uint32_t gateway, uint32_t * addr6,
+ uint8_t * addr6_prefix_len);
+
+#endif /* LWIP_UTIL_H */
diff --git a/lwip/main.c b/lwip/main.c
new file mode 100644
index 00000000..9f7eb9b2
--- /dev/null
+++ b/lwip/main.c
@@ -0,0 +1,272 @@
+/*
+ Copyright (C) 1995,96,97,99,2000,02,07,17 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <lwip-hurd.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <sys/mman.h>
+#include <hurd/trivfs.h>
+
+#include <lwip_io_S.h>
+#include <lwip_socket_S.h>
+#include <lwip_pfinet_S.h>
+#include <lwip_iioctl_S.h>
+#include <lwip_startup_notify_S.h>
+
+#include <netif/hurdethif.h>
+#include <netif/hurdtunif.h>
+#include <startup.h>
+
+/* Translator initialization */
+
+extern struct argp lwip_argp;
+
+extern struct netif *netif_list;
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t * st)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ if (flags & FSYS_GOAWAY_FORCE)
+ exit (0);
+ else
+ {
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (lwip_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (lwip_protid_portclasses[0]);
+ ports_inhibit_class_rpcs (lwip_cntl_portclasses[1]);
+ ports_inhibit_class_rpcs (lwip_protid_portclasses[1]);
+ ports_inhibit_class_rpcs (socketport_class);
+ ports_inhibit_class_rpcs (addrport_class);
+
+ if (ports_count_class (socketport_class) != 0
+ || ports_count_class (addrport_class) != 0)
+ {
+ /* We won't go away, so start things going again... */
+ ports_resume_class_rpcs (addrport_class);
+ ports_resume_class_rpcs (socketport_class);
+ ports_resume_class_rpcs (lwip_cntl_portclasses[1]);
+ ports_resume_class_rpcs (lwip_protid_portclasses[1]);
+ ports_resume_class_rpcs (lwip_cntl_portclasses[0]);
+ ports_resume_class_rpcs (lwip_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+
+ /* There are no sockets, so we can die without breaking anybody
+ too badly. We don't let user ports on the /servers/socket/2
+ file keep us alive because those get cached in every process
+ that ever makes a PF_INET socket, libc copes with getting
+ MACH_SEND_INVALID_DEST and looking up the new translator. */
+ exit (0);
+ }
+}
+
+int
+lwip_demuxer (mach_msg_header_t * inp, mach_msg_header_t * outp)
+{
+ struct port_info *pi;
+
+ /* Clear errno to prevent raising previous errors again */
+ errno = 0;
+
+ /* We have several classes in one bucket, which need to be demuxed
+ differently. */
+ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ==
+ MACH_MSG_TYPE_PROTECTED_PAYLOAD)
+ pi = ports_lookup_payload (lwip_bucket,
+ inp->msgh_protected_payload, socketport_class);
+ else
+ pi = ports_lookup_port (lwip_bucket,
+ inp->msgh_local_port, socketport_class);
+
+ if (pi)
+ {
+ ports_port_deref (pi);
+
+ mig_routine_t routine;
+ if ((routine = lwip_io_server_routine (inp)) ||
+ (routine = lwip_socket_server_routine (inp)) ||
+ (routine = lwip_pfinet_server_routine (inp)) ||
+ (routine = lwip_iioctl_server_routine (inp)) ||
+ (routine = NULL, trivfs_demuxer (inp, outp)) ||
+ (routine = lwip_startup_notify_server_routine (inp)))
+ {
+ if (routine)
+ (*routine) (inp, outp);
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+ mig_routine_t routine;
+ if ((routine = lwip_socket_server_routine (inp)) ||
+ (routine = lwip_pfinet_server_routine (inp)) ||
+ (routine = lwip_iioctl_server_routine (inp)) ||
+ (routine = NULL, trivfs_demuxer (inp, outp)) ||
+ (routine = lwip_startup_notify_server_routine (inp)))
+ {
+ if (routine)
+ (*routine) (inp, outp);
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return 0;
+}
+
+void
+translator_bind (int portclass, const char *name)
+{
+ struct trivfs_control *cntl;
+ error_t err = 0;
+ mach_port_t right;
+ file_t file = file_name_lookup (name, O_CREAT | O_NOTRANS, 0666);
+
+ if (file == MACH_PORT_NULL)
+ err = errno;
+
+ if (!err)
+ {
+ if (lwip_protid_portclasses[portclass] != MACH_PORT_NULL)
+ error (1, 0, "Cannot bind one protocol to multiple nodes.\n");
+
+ err =
+ trivfs_add_protid_port_class (&lwip_protid_portclasses[portclass]);
+ if (err)
+ error (1, 0, "error creating control port class");
+
+ err = trivfs_add_control_port_class (&lwip_cntl_portclasses[portclass]);
+ if (err)
+ error (1, 0, "error creating control port class");
+
+ err = trivfs_create_control (file, lwip_cntl_portclasses[portclass],
+ lwip_bucket,
+ lwip_protid_portclasses[portclass],
+ lwip_bucket, &cntl);
+ }
+
+ if (!err)
+ {
+ right = ports_get_send_right (cntl);
+ err = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET,
+ 0, 0, 0, right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
+ }
+
+ if (err)
+ error (1, err, "%s", name);
+
+ ports_port_deref (cntl);
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct stat st;
+ mach_port_t bootstrap;
+
+ lwip_bucket = ports_create_bucket ();
+ addrport_class = ports_create_class (clean_addrport, 0);
+ socketport_class = ports_create_class (clean_socketport, 0);
+ lwip_bootstrap_portclass = PORTCLASS_INET;
+
+ mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE, &fsys_identity);
+
+ /* Init the device modules */
+ hurdethif_module_init ();
+ hurdtunif_module_init ();
+
+ /* Parse options. When successful, this configures the interfaces
+ before returning */
+ argp_parse (&lwip_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (-1, 0, "Must be started as a translator");
+
+ /* Create portclass to install on the bootstrap port. */
+ if (lwip_protid_portclasses[lwip_bootstrap_portclass] != MACH_PORT_NULL)
+ error (1, 0, "No portclass left to assign to bootstrap port");
+
+ err =
+ trivfs_add_protid_port_class (&lwip_protid_portclasses
+ [lwip_bootstrap_portclass]);
+ if (err)
+ error (1, 0, "error creating control port class");
+
+ err =
+ trivfs_add_control_port_class (&lwip_cntl_portclasses
+ [lwip_bootstrap_portclass]);
+ if (err)
+ error (1, 0, "error creating control port class");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0,
+ lwip_cntl_portclasses[lwip_bootstrap_portclass],
+ lwip_bucket,
+ lwip_protid_portclasses[lwip_bootstrap_portclass],
+ lwip_bucket, &lwipcntl);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ {
+ return (-1);
+ }
+
+ /* Initialize status from underlying node. */
+ lwip_owner = lwip_group = 0;
+ err = io_stat (lwipcntl->underlying, &st);
+ if (!err)
+ {
+ lwip_owner = st.st_uid;
+ lwip_group = st.st_gid;
+ }
+
+ /* Ask init to tell us when the system is going down,
+ so we can try to be friendly to our correspondents on the network. */
+ arrange_shutdown_notification ();
+
+ ports_manage_port_operations_multithread (lwip_bucket, lwip_demuxer,
+ 30 * 1000, 2 * 60 * 1000, 0);
+
+ return 0;
+}
diff --git a/lwip/mig-decls.h b/lwip/mig-decls.h
new file mode 100644
index 00000000..907369ee
--- /dev/null
+++ b/lwip/mig-decls.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 1995,96,2000,2017 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LWIP_MIG_DECLS_H__
+#define __LWIP_MIG_DECLS_H__
+
+#include <lwip-hurd.h>
+
+/* MiG bogosity */
+typedef struct sock_user *sock_user_t;
+typedef struct sock_addr *sock_addr_t;
+
+static inline struct sock_user * __attribute__ ((unused))
+begin_using_socket_port (mach_port_t port)
+{
+ return ports_lookup_port (lwip_bucket, port, socketport_class);
+}
+
+static inline struct sock_user * __attribute__ ((unused))
+begin_using_socket_payload (unsigned long payload)
+{
+ return ports_lookup_payload (lwip_bucket, payload, socketport_class);
+}
+
+static inline void __attribute__ ((unused))
+end_using_socket_port (struct sock_user *user)
+{
+ if (user)
+ ports_port_deref (user);
+}
+
+static inline struct sock_addr * __attribute__ ((unused))
+begin_using_sockaddr_port (mach_port_t port)
+{
+ return ports_lookup_port (lwip_bucket, port, addrport_class);
+}
+
+static inline struct sock_addr * __attribute__ ((unused))
+begin_using_sockaddr_payload (unsigned long payload)
+{
+ return ports_lookup_payload (lwip_bucket, payload, addrport_class);
+}
+
+static inline void __attribute__ ((unused))
+end_using_sockaddr_port (struct sock_addr *addr)
+{
+ if (addr)
+ ports_port_deref (addr);
+}
+
+#endif /* __LWIP_MIG_DECLS_H__ */
diff --git a/lwip/mig-mutate.h b/lwip/mig-mutate.h
new file mode 100644
index 00000000..3ed89c55
--- /dev/null
+++ b/lwip/mig-mutate.h
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 1995,2017 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Only CPP macro definitions should go in this file. */
+
+#define IO_SELECT_REPLY_PORT
+
+#define IO_INTRAN sock_user_t begin_using_socket_port (io_t)
+#define IO_INTRAN_PAYLOAD sock_user_t begin_using_socket_payload
+#define IO_DESTRUCTOR end_using_socket_port (sock_user_t)
+#define IO_IMPORTS import "mig-decls.h";
+#define IIOCTL_IMPORTS import "mig-decls.h";
+
+#define SOCKET_INTRAN sock_user_t begin_using_socket_port (socket_t)
+#define SOCKET_INTRAN_PAYLOAD sock_user_t begin_using_socket_payload
+#define SOCKET_DESTRUCTOR end_using_socket_port (sock_user_t)
+#define SOCKET_IMPORTS \
+ import "mig-decls.h"; \
+ import "../libtrivfs/mig-decls.h"; \
+
+#define ADDRPORT_INTRAN sock_addr_t begin_using_sockaddr_port (addr_port_t)
+#define ADDRPORT_INTRAN_PAYLOAD sock_addr_t begin_using_sockaddr_payload
+#define ADDRPORT_DESTRUCTOR end_using_sockaddr_port (sock_addr_t)
+
+#define PF_INTRAN trivfs_protid_t trivfs_begin_using_protid (pf_t)
+#define PF_INTRAN_PAYLOAD trivfs_protid_t trivfs_begin_using_protid_payload
+#define PF_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
diff --git a/lwip/options.c b/lwip/options.c
new file mode 100644
index 00000000..6591ac52
--- /dev/null
+++ b/lwip/options.c
@@ -0,0 +1,342 @@
+/*
+ Copyright (C) 1996, 1997, 2000, 2001, 2006, 2007, 2017
+ Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Fsysopts and command line option parsing */
+
+#include <options.h>
+
+#include <stdlib.h>
+#include <argp.h>
+#include <argz.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if_arp.h>
+#include <error.h>
+
+#include <lwip/netif.h>
+#include <lwip/tcpip.h>
+
+#include <lwip-hurd.h>
+#include <lwip-util.h>
+#include <netif/ifcommon.h>
+
+/* Fsysopts and command line option parsing */
+
+/* Adds an empty interface slot to H, and sets H's current interface to it, or
+ returns an error. */
+static error_t
+parse_hook_add_interface (struct parse_hook *h)
+{
+ int i;
+
+ struct parse_interface *new = realloc (h->interfaces,
+ (h->num_interfaces +
+ 1) *
+ sizeof (struct parse_interface));
+ if (!new)
+ return ENOMEM;
+
+ h->interfaces = new;
+ h->num_interfaces++;
+ h->curint = new + h->num_interfaces - 1;
+ memset (&h->curint->dev_name, 0, DEV_NAME_LEN);
+ h->curint->address.addr = INADDR_NONE;
+ h->curint->netmask.addr = INADDR_NONE;
+ h->curint->peer.addr = INADDR_NONE;
+ h->curint->gateway.addr = INADDR_NONE;
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ ip6_addr_set_zero ((ip6_addr_t *) & h->curint->addr6[i]);
+
+ return 0;
+}
+
+/* Option parser */
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ error_t err = 0;
+ struct parse_hook *h = state->hook;
+ int i;
+
+ /* Return _ERR from this routine */
+#define RETURN(_err) \
+ do { return _err; } while (0)
+
+ /* Print a parsing error message and (if exiting is turned off) return the
+ error code ERR. */
+#define PERR(err, fmt, args...) \
+ do { argp_error (state, fmt , ##args); RETURN (err); } while (0)
+
+ /* Like PERR but for non-parsing errors. */
+#define FAIL(rerr, status, perr, fmt, args...) \
+ do{ argp_failure (state, status, perr, fmt , ##args); RETURN (rerr); } while(0)
+
+ /* Parse STR and return the corresponding internet address. If STR is not
+ a valid internet address, signal an error mentioned TYPE. */
+#undef ADDR
+#define ADDR(str, type) \
+ ({ unsigned long addr = inet_addr (str); \
+ if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \
+ addr; })
+
+ if (!arg && state->next < state->argc && (*state->argv[state->next] != '-'))
+ {
+ arg = state->argv[state->next];
+ state->next++;
+ }
+
+ switch (opt)
+ {
+ struct parse_interface *in;
+ uint8_t addr6_prefix_len;
+ ip6_addr_t *address6;
+ char *ptr;
+
+ case 'i':
+ /* An interface. */
+ err = 0;
+
+ /* First see if a previously specified one is being re-specified. */
+ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
+ if (strcmp (in->dev_name, arg) == 0)
+ /* Re-use an old slot. */
+ {
+ h->curint = in;
+ return 0;
+ }
+
+ if (h->curint->dev_name[0])
+ /* The current interface slot is not available. */
+ {
+ /* Add a new interface entry. */
+ err = parse_hook_add_interface (h);
+ }
+ in = h->curint;
+
+ strncpy (in->dev_name, arg, DEV_NAME_LEN);
+ break;
+
+ case 'a':
+ /* An address */
+ if (arg)
+ {
+ /* Check if it's legal */
+ h->curint->address.addr = ADDR (arg, "address");
+ if (!IN_CLASSA (ntohl (h->curint->address.addr))
+ && !IN_CLASSB (ntohl (h->curint->address.addr))
+ && !IN_CLASSC (ntohl (h->curint->address.addr)))
+ {
+ if (IN_MULTICAST (ntohl (h->curint->address.addr)))
+ FAIL (EINVAL, 1, 0,
+ "%s: Cannot set interface address to multicast address",
+ arg);
+ else
+ FAIL (EINVAL, 1, 0,
+ "%s: Illegal or undefined network address", arg);
+ }
+ }
+ else
+ {
+ /* No address given, set default values */
+ h->curint->address.addr = ADDR ("0.0.0.0", "address");
+ h->curint->netmask.addr = ADDR ("255.0.0.0", "netmask");
+ h->curint->gateway.addr = INADDR_NONE;
+ }
+ break;
+
+ case 'm':
+ /* Netmask */
+ if (arg)
+ h->curint->netmask.addr = ADDR (arg, "netmask");
+ else
+ h->curint->netmask.addr = INADDR_NONE;
+ break;
+
+ case 'p':
+ /* Peer address */
+ if (arg)
+ h->curint->peer.addr = ADDR (arg, "peer");
+ else
+ h->curint->peer.addr = INADDR_NONE;
+ break;
+
+ case 'g':
+ /* Gateway for the current interface */
+ if (arg)
+ {
+ h->curint->gateway.addr = ADDR (arg, "gateway");
+ }
+ else
+ h->curint->gateway.addr = INADDR_NONE;
+ break;
+
+ case '4':
+ translator_bind (PORTCLASS_INET, arg);
+
+ /* Install IPv6 port class on bootstrap port. */
+ lwip_bootstrap_portclass = PORTCLASS_INET6;
+ break;
+
+ case '6':
+ translator_bind (PORTCLASS_INET6, arg);
+ break;
+
+ case 'A':
+ /* IPv6 address */
+ if (arg)
+ {
+ /* Check prefix */
+ if ((ptr = strchr (arg, '/')))
+ {
+ addr6_prefix_len = atoi (ptr + 1);
+ if (addr6_prefix_len > 128)
+ FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg);
+
+ /* Remove the prefix from the address */
+ *ptr = 0;
+
+ if (addr6_prefix_len != 64)
+ {
+ error (0, 0,
+ "The only supported value for the prefix-length"
+ " is /64. Defaulting to %s/64.\n", arg);
+ }
+ }
+ else
+ {
+ error (0, 0, "No prefix-length given, "
+ "defaulting to %s/64.\n", arg);
+ }
+
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ {
+ address6 = (ip6_addr_t *) & h->curint->addr6[i];
+
+ /* Is the slot free? */
+ if (!ip6_addr_isany (address6))
+ continue;
+
+ /* Use the slot */
+ if (ip6addr_aton (arg, address6) <= 0)
+ PERR (EINVAL, "Malformed address");
+
+ break;
+ }
+ }
+
+ break;
+
+ case ARGP_KEY_INIT:
+ /* Initialize our parsing state. */
+ h = malloc (sizeof (struct parse_hook));
+ if (!h)
+ FAIL (ENOMEM, 11, ENOMEM, "option parsing");
+
+ h->interfaces = 0;
+ h->num_interfaces = 0;
+ err = parse_hook_add_interface (h);
+ if (err)
+ FAIL (err, 12, err, "option parsing");
+
+ state->hook = h;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ /* If the interface list is not empty, a previous configuration exists */
+ if (netif_list == 0)
+ /* Inititalize LwIP */
+ tcpip_init (init_ifs, h);
+ else
+ /* No need to initialize the stack again */
+ init_ifs (h);
+ break;
+
+ case ARGP_KEY_ERROR:
+ /* Parsing error occurred, free everything. */
+ free (h->interfaces);
+ free (h);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return err;
+}
+
+/* Create the output for fsysopts */
+error_t
+trivfs_append_args (struct trivfs_control * fsys, char **argz,
+ size_t * argz_len)
+{
+ error_t err = 0;
+ struct netif *netif;
+ int i;
+ uint32_t addr, netmask, gateway;
+ uint32_t addr6[LWIP_IPV6_NUM_ADDRESSES][4];
+ uint8_t addr6_prefix_len[LWIP_IPV6_NUM_ADDRESSES];
+
+#define ADD_OPT(fmt, args...) \
+ do { char buf[100]; \
+ if (! err) { \
+ snprintf (buf, sizeof buf, fmt , ##args); \
+ err = argz_add (argz, argz_len, buf); } } while (0)
+#define ADD_ADDR_OPT(name, addr) \
+ do { struct in_addr i; \
+ i.s_addr = (addr); \
+ ADD_OPT ("--%s=%s", name, inet_ntoa (i)); } while (0)
+
+ for (netif = netif_list; netif != 0; netif = netif->next)
+ {
+ /* Skip the loopback interface */
+ if (netif_get_state (netif)->type == ARPHRD_LOOPBACK)
+ {
+ continue;
+ }
+
+ inquire_device (netif, &addr, &netmask, 0, 0, &gateway,
+ (uint32_t *) addr6, addr6_prefix_len);
+
+ ADD_OPT ("--interface=%s", netif_get_state (netif)->devname);
+ if (addr != INADDR_NONE)
+ ADD_ADDR_OPT ("address", addr);
+ if (netmask != INADDR_NONE)
+ ADD_ADDR_OPT ("netmask", netmask);
+ if (gateway != INADDR_NONE)
+ ADD_ADDR_OPT ("gateway", gateway);
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
+ if (!ip6_addr_isany (((ip6_addr_t *) & addr6[i])))
+ ADD_OPT ("--address6=%s/%d",
+ ip6addr_ntoa (((ip6_addr_t *) & addr6[i])),
+ addr6_prefix_len[i]);
+ }
+
+#undef ADD_ADDR_OPT
+
+#undef ADD_OPT
+ return err;
+}
+
+struct argp lwip_argp = { options, parse_opt, 0, doc };
+
+struct argp *trivfs_runtime_argp = &lwip_argp;
diff --git a/lwip/options.h b/lwip/options.h
new file mode 100644
index 00000000..e370fab0
--- /dev/null
+++ b/lwip/options.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 1996, 1997, 2000, 2001, 2006, 2007, 2017
+ Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Fsysopts and command line option parsing */
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <argp.h>
+
+#include <lwip/ip.h>
+#include <lwip/netif.h>
+
+#define DEV_NAME_LEN 256
+
+/* Used to describe a particular interface during argument parsing. */
+struct parse_interface
+{
+ /* The network interface in question. */
+ char dev_name[DEV_NAME_LEN];
+
+ /* New values to apply to it. (IPv4) */
+ ip4_addr_t address, netmask, peer, gateway;
+
+ /* New IPv6 configuration to apply. */
+ uint32_t addr6[LWIP_IPV6_NUM_ADDRESSES][4];
+};
+
+/* Used to hold data during argument parsing. */
+struct parse_hook
+{
+ /* A list of specified interfaces and their corresponding options. */
+ struct parse_interface *interfaces;
+ size_t num_interfaces;
+
+ /* Interface to which options apply. If the device field isn't filled in
+ then it should be by the next --interface option. */
+ struct parse_interface *curint;
+};
+
+/* Lwip translator options. Used for both startup and runtime. */
+static const struct argp_option options[] = {
+ {"interface", 'i', "DEVICE", 0, "Network interface to use", 1},
+ {0, 0, 0, 0, "These apply to a given interface:", 2},
+ {"address", 'a', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the network address"},
+ {"netmask", 'm', "MASK", OPTION_ARG_OPTIONAL, "Set the netmask"},
+ {"gateway", 'g', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the default gateway"},
+ {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"},
+ {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"},
+ {"address6", 'A', "ADDR/LEN", OPTION_ARG_OPTIONAL,
+ "Set the global IPv6 address"},
+ {0}
+};
+
+static const char doc[] = "Interface-specific options before the first \
+interface specification apply to the first following interface; otherwise \
+they apply to the previously specified interface.";
+
+#endif // OPTIONS_H
diff --git a/lwip/pfinet-ops.c b/lwip/pfinet-ops.c
new file mode 100644
index 00000000..96d2d12b
--- /dev/null
+++ b/lwip/pfinet-ops.c
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2000,02,17 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Operations offered by the stack */
+
+#include <lwip_pfinet_S.h>
+
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <lwip/netif.h>
+#include <sys/mman.h>
+
+#include <lwip-util.h>
+#include <netif/hurdethif.h>
+
+/*
+ * Get all the data requested by SIOCGIFCONF for a particular interface.
+ *
+ * When ifc->ifc_ifreq == NULL, this function is being called for getting
+ * the needed buffer length and not the actual data.
+ */
+static void
+dev_ifconf (struct ifconf *ifc)
+{
+ struct netif *netif;
+ struct ifreq *ifr;
+ struct sockaddr_in *saddr;
+ int len;
+
+ ifr = ifc->ifc_req;
+ len = ifc->ifc_len;
+ saddr = (struct sockaddr_in *) &ifr->ifr_addr;
+ for (netif = netif_list; netif != 0; netif = netif->next)
+ {
+ if (ifc->ifc_req != 0)
+ {
+ /* Get the data */
+ if (len < (int) sizeof (struct ifreq))
+ break;
+
+ memset (ifr, 0, sizeof (struct ifreq));
+
+ strncpy (ifr->ifr_name, netif_get_state (netif)->devname,
+ strlen (netif_get_state (netif)->devname) + 1);
+ saddr->sin_len = sizeof (struct sockaddr_in);
+ saddr->sin_family = AF_INET;
+ saddr->sin_addr.s_addr = netif_ip4_addr (netif)->addr;
+
+ len -= sizeof (struct ifreq);
+ }
+ /* Update the needed buffer length */
+ ifr++;
+ }
+
+ ifc->ifc_len = (uintptr_t) ifr - (uintptr_t) ifc->ifc_req;
+}
+
+/* Return the list of devices in the format provided by SIOCGIFCONF
+ in IFR, but don't return more then AMOUNT bytes. If AMOUNT is
+ negative, there is no limit. */
+error_t
+lwip_S_pfinet_siocgifconf (io_t port,
+ vm_size_t amount,
+ char **ifr, mach_msg_type_number_t * len)
+{
+ struct ifconf ifc;
+
+ if (amount == (vm_size_t) - 1)
+ {
+ /* Get the needed buffer length */
+ ifc.ifc_buf = 0;
+ ifc.ifc_len = 0;
+ dev_ifconf (&ifc);
+ amount = ifc.ifc_len;
+ }
+ else
+ ifc.ifc_len = amount;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer */
+ if (*len < amount)
+ ifc.ifc_buf = (char *) mmap (0, amount, PROT_READ | PROT_WRITE,
+ MAP_ANON, 0, 0);
+ else
+ ifc.ifc_buf = *ifr;
+
+ dev_ifconf (&ifc);
+ }
+
+ *len = ifc.ifc_len;
+ *ifr = ifc.ifc_buf;
+
+ return 0;
+}
diff --git a/lwip/port-objs.c b/lwip/port-objs.c
new file mode 100644
index 00000000..07bcab8f
--- /dev/null
+++ b/lwip/port-objs.c
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 1995,2000,02,17 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Libports objects management */
+
+#include "lwip-hurd.h"
+
+#include <assert.h>
+#include <refcount.h>
+
+#include <lwip/sockets.h>
+
+/* Create a sockaddr port. Fill in *ADDR and *ADDRTYPE accordingly.
+ The address should come from SOCK; PEER is 0 if we want this socket's
+ name and 1 if we want the peer's name. */
+error_t
+make_sockaddr_port (int sock,
+ int peer,
+ mach_port_t * addr, mach_msg_type_name_t * addrtype)
+{
+ struct sockaddr_storage buf;
+ int buflen = sizeof buf;
+ error_t err;
+ struct sock_addr *addrstruct;
+
+ if (peer)
+ err =
+ lwip_getpeername (sock, (struct sockaddr *) &buf,
+ (socklen_t *) & buflen);
+ else
+ err =
+ lwip_getsockname (sock, (struct sockaddr *) &buf,
+ (socklen_t *) & buflen);
+ if (err)
+ return -err;
+
+ err = ports_create_port (addrport_class, lwip_bucket,
+ (offsetof (struct sock_addr, address)
+ +buflen), &addrstruct);
+ if (!err)
+ {
+ addrstruct->address.sa.sa_family = buf.ss_family;
+ addrstruct->address.sa.sa_len = buflen;
+ memcpy (addrstruct->address.sa.sa_data,
+ ((struct sockaddr *) &buf)->sa_data,
+ buflen - offsetof (struct sockaddr, sa_data));
+ *addr = ports_get_right (addrstruct);
+ *addrtype = MACH_MSG_TYPE_MAKE_SEND;
+ }
+
+ ports_port_deref (addrstruct);
+
+ return err;
+}
+
+struct socket *
+sock_alloc (void)
+{
+ struct socket *sock;
+
+ sock = calloc (1, sizeof *sock);
+ if (!sock)
+ return 0;
+ sock->sockno = -1;
+ sock->identity = MACH_PORT_NULL;
+ refcount_init (&sock->refcnt, 1);
+
+ return sock;
+}
+
+/* This is called from the port cleanup function below, and on
+ a newly allocated socket when something went wrong in its creation. */
+void
+sock_release (struct socket *sock)
+{
+ if (refcount_deref (&sock->refcnt) != 0)
+ return;
+
+ if (sock->sockno > -1)
+ lwip_close (sock->sockno);
+
+ if (sock->identity != MACH_PORT_NULL)
+ mach_port_destroy (mach_task_self (), sock->identity);
+
+ free (sock);
+}
+
+/* Create a sock_user structure, initialized from SOCK and ISROOT.
+ If NOINSTALL is set, don't put it in the portset.*/
+struct sock_user *
+make_sock_user (struct socket *sock, int isroot, int noinstall, int consume)
+{
+ error_t err;
+ struct sock_user *user;
+
+ assert_backtrace (sock->refcnt != 0);
+
+ if (noinstall)
+ err = ports_create_port_noinstall (socketport_class, lwip_bucket,
+ sizeof (struct sock_user), &user);
+ else
+ err = ports_create_port (socketport_class, lwip_bucket,
+ sizeof (struct sock_user), &user);
+ if (err)
+ return 0;
+
+ if (!consume)
+ refcount_ref (&sock->refcnt);
+
+ user->isroot = isroot;
+ user->sock = sock;
+ return user;
+}
+
+/* Release the referenced socket. */
+void
+clean_socketport (void *arg)
+{
+ struct sock_user *const user = arg;
+
+ sock_release (user->sock);
+}
+
+/* Nothing need be done here. */
+void
+clean_addrport (void *arg)
+{
+}
diff --git a/lwip/port/include/netif/hurdethif.h b/lwip/port/include/netif/hurdethif.h
new file mode 100644
index 00000000..326b1cf9
--- /dev/null
+++ b/lwip/port/include/netif/hurdethif.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Ethernet devices module */
+
+#ifndef LWIP_HURDETHIF_H
+#define LWIP_HURDETHIF_H
+
+#include <hurd/ports.h>
+
+#include <lwip/netif.h>
+#include <netif/ifcommon.h>
+
+typedef struct ifcommon hurdethif;
+
+/* Device initialization */
+error_t hurdethif_device_init (struct netif *netif);
+
+/* Module initialization */
+error_t hurdethif_module_init ();
+
+#endif /* LWIP_HURDETHIF_H */
diff --git a/lwip/port/include/netif/hurdloopif.h b/lwip/port/include/netif/hurdloopif.h
new file mode 100644
index 00000000..fb5c5b83
--- /dev/null
+++ b/lwip/port/include/netif/hurdloopif.h
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Loopback devices module */
+
+#ifndef LWIP_HURDLOOPIF_H
+#define LWIP_HURDLOOPIF_H
+
+#include <hurd/ports.h>
+
+#include <lwip/netif.h>
+#include <netif/ifcommon.h>
+
+typedef struct ifcommon hurdloopif;
+
+/* Device initialization */
+error_t hurdloopif_device_init (struct netif *netif);
+
+#endif /* LWIP_HURDLOOPIF_H */
diff --git a/lwip/port/include/netif/hurdtunif.h b/lwip/port/include/netif/hurdtunif.h
new file mode 100644
index 00000000..938465bb
--- /dev/null
+++ b/lwip/port/include/netif/hurdtunif.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Tunnel devices module */
+
+#ifndef LWIP_HURDTUNIF_H
+#define LWIP_HURDTUNIF_H
+
+#include <hurd/ports.h>
+
+#include <lwip/netif.h>
+#include <netif/ifcommon.h>
+
+/* Queue of data in the tunnel */
+struct pbufqueue
+{
+ struct pbuf *head;
+ struct pbuf **tail;
+ uint8_t len;
+};
+
+/* Extension of the common device interface to store tunnel metadata */
+struct hurdtunif
+{
+ struct ifcommon comm;
+
+ struct trivfs_control *cntl; /* Identify the tunnel device in use */
+ file_t underlying; /* Underlying node where the tunnel is bound */
+ struct iouser *user; /* Restrict the access to one user at a time */
+ struct pbufqueue queue; /* Output queue */
+
+ /* Concurrent access to the queue */
+ pthread_mutex_t lock;
+ pthread_cond_t read;
+ pthread_cond_t select;
+ uint8_t read_blocked;
+};
+
+struct port_class *tunnel_cntlclass;
+struct port_class *tunnel_class;
+
+/* Device initialization */
+error_t hurdtunif_device_init (struct netif *netif);
+
+/* Module initialization */
+error_t hurdtunif_module_init ();
+
+#endif /* LWIP_HURDTUNIF_H */
diff --git a/lwip/port/include/netif/ifcommon.h b/lwip/port/include/netif/ifcommon.h
new file mode 100644
index 00000000..15493dc9
--- /dev/null
+++ b/lwip/port/include/netif/ifcommon.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Common interface for all kinds of devices */
+
+#ifndef LWIP_IFCOMMON_H
+#define LWIP_IFCOMMON_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <device/device.h>
+
+#include <lwip/netif.h>
+
+/*
+ * Helper struct to hold private data used to operate your interface.
+ */
+struct ifcommon
+{
+ uint16_t type;
+ device_t ether_port;
+ struct port_info *readpt;
+ mach_port_t readptname;
+ char *devname;
+ uint16_t flags;
+
+ /* Callbacks */
+ error_t (*init) (struct netif * netif);
+ error_t (*terminate) (struct netif * netif);
+ error_t (*open) (struct netif * netif);
+ error_t (*close) (struct netif * netif);
+ error_t (*update_mtu) (struct netif * netif, uint32_t mtu);
+ error_t (*change_flags) (struct netif * netif, uint16_t flags);
+};
+
+error_t if_init (struct netif *netif);
+error_t if_terminate (struct netif *netif);
+error_t if_change_flags (struct netif *netif, uint16_t flags);
+
+/* Get the state from a netif */
+#define netif_get_state(netif) ((struct ifcommon *)netif->state)
+
+#endif /* LWIP_IFCOMMON_H */
diff --git a/lwip/port/netif/hurdethif.c b/lwip/port/netif/hurdethif.c
new file mode 100644
index 00000000..bcf2e4dd
--- /dev/null
+++ b/lwip/port/netif/hurdethif.c
@@ -0,0 +1,573 @@
+/*
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007, 2017
+ Free Software Foundation, Inc.
+
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Ethernet devices module */
+
+#include <netif/hurdethif.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <pthread.h>
+#include <error.h>
+#include <device/device.h>
+#include <device/net_status.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include <lwip/opt.h>
+#include <lwip/def.h>
+#include <lwip/mem.h>
+#include <lwip/pbuf.h>
+#include <lwip/stats.h>
+#include <lwip/snmp.h>
+#include <lwip/ethip6.h>
+#include <lwip/etharp.h>
+
+/* Get the MAC address from an array of int */
+#define GET_HWADDR_BYTE(x,n) (((char*)x)[n])
+
+static short ether_filter[] = {
+#ifdef NETF_IN
+ /* We have to tell the packet filtering code that we're interested in
+ incoming packets. */
+ NETF_IN, /* Header. */
+#endif
+ NETF_PUSHLIT | NETF_NOP,
+ 1
+};
+
+static int ether_filter_len = sizeof (ether_filter) / sizeof (short);
+
+static struct bpf_insn bpf_ether_filter[] = {
+ {NETF_IN | NETF_BPF, 0, 0, 0}, /* Header. */
+ {BPF_LD | BPF_H | BPF_ABS, 0, 0, 12}, /* Load Ethernet type */
+ {BPF_JMP | BPF_JEQ | BPF_K, 2, 0, 0x0806}, /* Accept ARP */
+ {BPF_JMP | BPF_JEQ | BPF_K, 1, 0, 0x0800}, /* Accept IPv4 */
+ {BPF_JMP | BPF_JEQ | BPF_K, 0, 1, 0x86DD}, /* Accept IPv6 */
+ /*
+ * And return an amount of bytes equal to:
+ * MSS + IP and transport headers length + Ethernet header length
+ */
+ {BPF_RET | BPF_K, 0, 0, TCP_MSS + 0x28 + PBUF_LINK_HLEN},
+ {BPF_RET | BPF_K, 0, 0, 0}, /* Or discard it all */
+};
+
+static int bpf_ether_filter_len = sizeof (bpf_ether_filter) / sizeof (short);
+
+/* Bucket and class for the incoming data */
+struct port_bucket *etherport_bucket;
+struct port_class *etherread_class;
+
+/* Thread for the incoming data */
+static pthread_t input_thread;
+
+/* Get the device flags */
+static error_t
+hurdethif_device_get_flags (struct netif *netif, uint16_t * flags)
+{
+ error_t err = 0;
+ size_t count;
+ struct net_status status;
+ hurdethif *ethif;
+
+ memset (&status, 0, sizeof (struct net_status));
+
+ ethif = netif_get_state (netif);
+ count = NET_STATUS_COUNT;
+ err = device_get_status (ethif->ether_port,
+ NET_STATUS, (dev_status_t) & status, &count);
+ if (err == D_INVALID_OPERATION)
+ {
+ /*
+ * eth-multiplexer doesn't support setting flags.
+ * We must ignore D_INVALID_OPERATION.
+ */
+ error (0, 0, "%s: hardware doesn't support getting flags.\n",
+ ethif->devname);
+ err = 0;
+ }
+ else if (err)
+ error (0, err, "%s: Cannot get hardware flags", ethif->devname);
+ else
+ *flags = status.flags;
+
+ return err;
+}
+
+/* Set the device flags */
+static error_t
+hurdethif_device_set_flags (struct netif *netif, uint16_t flags)
+{
+ error_t err = 0;
+ hurdethif *ethif;
+ int sflags;
+
+ sflags = flags;
+ ethif = netif_get_state (netif);
+
+ if (ethif->ether_port == MACH_PORT_NULL)
+ /* The device is closed */
+ return 0;
+
+ err = device_set_status (ethif->ether_port, NET_FLAGS, &sflags, 1);
+ if (err == D_INVALID_OPERATION)
+ {
+ /*
+ * eth-multiplexer doesn't support setting flags.
+ * We must ignore D_INVALID_OPERATION.
+ */
+ error (0, 0, "%s: hardware doesn't support setting flags.\n",
+ ethif->devname);
+ err = 0;
+ }
+ else if (err)
+ error (0, err, "%s: Cannot set hardware flags", ethif->devname);
+ else
+ ethif->flags = flags;
+
+ return err;
+}
+
+/* Use the device interface to access the device */
+static error_t
+hurdethif_device_open (struct netif *netif)
+{
+ error_t err = ERR_OK;
+ device_t master_device;
+ hurdethif *ethif = netif_get_state (netif);
+
+ if (ethif->ether_port != MACH_PORT_NULL)
+ {
+ error (0, 0, "Already opened: %s", ethif->devname);
+ return -1;
+ }
+
+ err = ports_create_port (etherread_class, etherport_bucket,
+ sizeof (struct port_info), &ethif->readpt);
+ if (err)
+ {
+ error (0, err, "ports_create_port on %s", ethif->devname);
+ }
+ else
+ {
+ ethif->readptname = ports_get_right (ethif->readpt);
+ mach_port_insert_right (mach_task_self (), ethif->readptname,
+ ethif->readptname, MACH_MSG_TYPE_MAKE_SEND);
+
+ mach_port_set_qlimit (mach_task_self (), ethif->readptname,
+ MACH_PORT_QLIMIT_MAX);
+
+ master_device = file_name_lookup (ethif->devname, O_RDWR, 0);
+ if (master_device != MACH_PORT_NULL)
+ {
+ /* The device name here is the path of a device file. */
+ err = device_open (master_device, D_WRITE | D_READ,
+ "eth", &ethif->ether_port);
+ mach_port_deallocate (mach_task_self (), master_device);
+ if (err)
+ error (0, err, "device_open on %s", ethif->devname);
+ else
+ {
+ err = device_set_filter (ethif->ether_port, ethif->readptname,
+ MACH_MSG_TYPE_MAKE_SEND, 0,
+ (filter_array_t) bpf_ether_filter,
+ bpf_ether_filter_len);
+ if (err)
+ error (0, err, "device_set_filter on %s", ethif->devname);
+ }
+ }
+ else
+ {
+ /* No, perhaps a Mach device? */
+ int file_errno = errno;
+ err = get_privileged_ports (0, &master_device);
+ if (err)
+ {
+ error (0, file_errno, "file_name_lookup %s", ethif->devname);
+ error (0, err, "and cannot get device master port");
+ }
+ else
+ {
+ err = device_open (master_device, D_WRITE | D_READ,
+ ethif->devname, &ethif->ether_port);
+ mach_port_deallocate (mach_task_self (), master_device);
+ if (err)
+ {
+ error (0, file_errno, "file_name_lookup %s",
+ ethif->devname);
+ error (0, err, "device_open(%s)", ethif->devname);
+ }
+ else
+ {
+ err =
+ device_set_filter (ethif->ether_port, ethif->readptname,
+ MACH_MSG_TYPE_MAKE_SEND, 0,
+ (filter_array_t) ether_filter,
+ ether_filter_len);
+ if (err)
+ error (0, err, "device_set_filter on %s", ethif->devname);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+/* Destroy our link to the device */
+static error_t
+hurdethif_device_close (struct netif *netif)
+{
+ hurdethif *ethif = netif_get_state (netif);
+
+ if (ethif->ether_port == MACH_PORT_NULL)
+ {
+ error (0, 0, "Already closed: %s", ethif->devname);
+ return -1;
+ }
+
+ mach_port_deallocate (mach_task_self (), ethif->readptname);
+ ethif->readptname = MACH_PORT_NULL;
+ ports_destroy_right (ethif->readpt);
+ ethif->readpt = NULL;
+ device_close (ethif->ether_port);
+ mach_port_deallocate (mach_task_self (), ethif->ether_port);
+ ethif->ether_port = MACH_PORT_NULL;
+
+ return ERR_OK;
+}
+
+/*
+ * Called from lwip when outgoing data is ready
+ */
+static error_t
+hurdethif_output (struct netif *netif, struct pbuf *p)
+{
+ error_t err;
+ hurdethif *ethif = netif_get_state (netif);
+ int count;
+ uint8_t tried;
+
+ if (p->tot_len != p->len)
+ /* Drop the packet */
+ return ERR_OK;
+
+ tried = 0;
+ /* Send the data from the pbuf to the interface, one pbuf at a
+ time. The size of the data in each pbuf is kept in the ->len
+ variable. */
+ do
+ {
+ tried++;
+ err = device_write (ethif->ether_port, D_NOWAIT, 0,
+ p->payload, p->len, &count);
+ if (err)
+ {
+ if (tried == 2)
+ /* Too many tries, abort */
+ break;
+
+ if (err == EMACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
+ {
+ /* Device probably just died, try to reopen it. */
+ hurdethif_device_close (netif);
+ hurdethif_device_open (netif);
+ }
+ }
+ else if (count != p->len)
+ /* Incomplete package sent, reattempt */
+ err = -1;
+ }
+ while (err);
+
+ return ERR_OK;
+}
+
+/*
+ * Called from the demuxer when incoming data is ready
+ */
+void
+hurdethif_input (struct netif *netif, struct net_rcv_msg *msg)
+{
+ struct pbuf *p, *q;
+ uint16_t len;
+ uint16_t off;
+ uint16_t next_read;
+
+ /* Get the size of the whole packet */
+ len = PBUF_LINK_HLEN
+ + msg->packet_type.msgt_number - sizeof (struct packet_header);
+
+ /* Allocate an empty pbuf chain for the data */
+ p = pbuf_alloc (PBUF_RAW, len, PBUF_POOL);
+
+ if (p)
+ {
+ /*
+ * Iterate to fill the pbuf chain.
+ *
+ * First read the Ethernet header from msg->header. Then read the
+ * payload from msg->packet
+ */
+ q = p;
+ off = 0;
+ do
+ {
+ if (off < PBUF_LINK_HLEN)
+ {
+ /* We still haven't ended copying the header */
+ next_read = (off + q->len) > PBUF_LINK_HLEN ?
+ (PBUF_LINK_HLEN - off) : q->len;
+ memcpy (q->payload, msg->header + off, next_read);
+
+ if ((off + q->len) > PBUF_LINK_HLEN)
+ memcpy (q->payload + PBUF_LINK_HLEN,
+ msg->packet + sizeof (struct packet_header),
+ q->len - next_read);
+ }
+ else
+ /* The header is copyied yet */
+ memcpy (q->payload, msg->packet +
+ sizeof (struct packet_header) + off - PBUF_LINK_HLEN,
+ q->len);
+
+ off += q->len;
+
+ /* q->tot_len == q->len means this was the last pbuf in the chain */
+ if (q->tot_len == q->len)
+ break;
+ else
+ q = q->next;
+ }
+ while (1);
+
+ /* Pass the pbuf chain to he input function */
+ if (netif->input (p, netif) != ERR_OK)
+ {
+ LWIP_DEBUGF (NETIF_DEBUG, ("hurdethif_input: IP input error\n"));
+ pbuf_free (p);
+ p = NULL;
+ }
+ }
+}
+
+/* Demux incoming RPCs from the device */
+int
+hurdethif_demuxer (mach_msg_header_t * inp, mach_msg_header_t * outp)
+{
+ struct net_rcv_msg *msg = (struct net_rcv_msg *) inp;
+ struct netif *netif;
+ mach_port_t local_port;
+
+ if (inp->msgh_id != NET_RCV_MSG_ID)
+ return 0;
+
+ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ==
+ MACH_MSG_TYPE_PROTECTED_PAYLOAD)
+ {
+ struct port_info *pi = ports_lookup_payload (NULL,
+ inp->msgh_protected_payload,
+ NULL);
+ if (pi)
+ {
+ local_port = pi->port_right;
+ ports_port_deref (pi);
+ }
+ else
+ local_port = MACH_PORT_NULL;
+ }
+ else
+ local_port = inp->msgh_local_port;
+
+ for (netif = netif_list; netif; netif = netif->next)
+ if (local_port == netif_get_state (netif)->readptname)
+ break;
+
+ if (!netif)
+ {
+ if (inp->msgh_remote_port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), inp->msgh_remote_port);
+ return 1;
+ }
+
+ hurdethif_input (netif, msg);
+
+ return 1;
+}
+
+/*
+ * Update the interface's MTU and the BPF filter
+ */
+static error_t
+hurdethif_device_update_mtu (struct netif *netif, uint32_t mtu)
+{
+ error_t err = 0;
+
+ netif->mtu = mtu;
+
+ bpf_ether_filter[5].k = mtu + PBUF_LINK_HLEN;
+
+ return err;
+}
+
+/*
+ * Release all resources of this netif.
+ *
+ * Returns 0 on success.
+ */
+static error_t
+hurdethif_device_terminate (struct netif *netif)
+{
+ /* Free the hook */
+ free (netif_get_state (netif)->devname);
+ free (netif_get_state (netif));
+
+ return 0;
+}
+
+/*
+ * Initializes a single device.
+ *
+ * The module must be initialized before calling this function.
+ */
+error_t
+hurdethif_device_init (struct netif * netif)
+{
+ error_t err;
+ size_t count = 2;
+ int net_address[2];
+ device_t ether_port;
+ hurdethif *ethif;
+
+ /*
+ * Replace the hook by a new one with the proper size.
+ * The old one is in the stack and will be removed soon.
+ */
+ ethif = calloc (1, sizeof (hurdethif));
+ if (!ethif)
+ {
+ LWIP_DEBUGF (NETIF_DEBUG, ("hurdethif_init: out of memory\n"));
+ return ERR_MEM;
+ }
+ memcpy (ethif, netif_get_state (netif), sizeof (struct ifcommon));
+ netif->state = ethif;
+
+ /* Interface type */
+ ethif->type = ARPHRD_ETHER;
+
+ /* Set callbacks */
+ netif->output = etharp_output;
+ netif->output_ip6 = ethip6_output;
+ netif->linkoutput = hurdethif_output;
+
+ ethif->open = hurdethif_device_open;
+ ethif->close = hurdethif_device_close;
+ ethif->terminate = hurdethif_device_terminate;
+ ethif->update_mtu = hurdethif_device_update_mtu;
+ ethif->change_flags = hurdethif_device_set_flags;
+
+ /* ---- Hardware initialization ---- */
+
+ /* We need the device to be opened to configure it */
+ err = hurdethif_device_open (netif);
+ if (err)
+ return err;
+
+ /* Get the MAC address */
+ ether_port = netif_get_state (netif)->ether_port;
+ err = device_get_status (ether_port, NET_ADDRESS, net_address, &count);
+ if (err)
+ error (0, err, "%s: Cannot get hardware Ethernet address",
+ netif_get_state (netif)->devname);
+ else if (count * sizeof (int) >= ETHARP_HWADDR_LEN)
+ {
+ net_address[0] = ntohl (net_address[0]);
+ net_address[1] = ntohl (net_address[1]);
+
+ /* Set MAC hardware address length */
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+
+ /* Set MAC hardware address */
+ netif->hwaddr[0] = GET_HWADDR_BYTE (net_address, 0);
+ netif->hwaddr[1] = GET_HWADDR_BYTE (net_address, 1);
+ netif->hwaddr[2] = GET_HWADDR_BYTE (net_address, 2);
+ netif->hwaddr[3] = GET_HWADDR_BYTE (net_address, 3);
+ netif->hwaddr[4] = GET_HWADDR_BYTE (net_address, 4);
+ netif->hwaddr[5] = GET_HWADDR_BYTE (net_address, 5);
+ }
+ else
+ error (0, 0, "%s: Invalid Ethernet address",
+ netif_get_state (netif)->devname);
+
+ /* Maximum transfer unit: MSS + IP header size + TCP header size */
+ netif->mtu = TCP_MSS + 20 + 20;
+
+ /* Enable Ethernet multicasting */
+ hurdethif_device_get_flags (netif, &netif_get_state (netif)->flags);
+ netif_get_state (netif)->flags |=
+ IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_ALLMULTI;
+ hurdethif_device_set_flags (netif, netif_get_state (netif)->flags);
+
+ /*
+ * Up the link, set the interface type to NETIF_FLAG_ETHARP
+ * and enable other features.
+ */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP
+ | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
+
+ return ERR_OK;
+}
+
+static void *
+hurdethif_input_thread (void *arg)
+{
+ ports_manage_port_operations_one_thread (etherport_bucket,
+ hurdethif_demuxer, 0);
+
+ return 0;
+}
+
+/*
+ * Init the thread for the incoming data.
+ *
+ * This function should be called once.
+ */
+error_t
+hurdethif_module_init ()
+{
+ error_t err;
+ etherport_bucket = ports_create_bucket ();
+ etherread_class = ports_create_class (0, 0);
+
+ err = pthread_create (&input_thread, 0, hurdethif_input_thread, 0);
+ if (!err)
+ pthread_detach (input_thread);
+ else
+ {
+ errno = err;
+ perror ("pthread_create");
+ }
+
+ return err;
+}
diff --git a/lwip/port/netif/hurdloopif.c b/lwip/port/netif/hurdloopif.c
new file mode 100644
index 00000000..ef64b8b6
--- /dev/null
+++ b/lwip/port/netif/hurdloopif.c
@@ -0,0 +1,112 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Loopback devices module */
+
+#include <netif/hurdloopif.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <string.h>
+
+#include <lwip-util.h>
+
+/* Set the device flags */
+static error_t
+hurdloopif_device_set_flags (struct netif *netif, uint16_t flags)
+{
+ error_t err = 0;
+ hurdloopif *loopif;
+
+ loopif = netif_get_state (netif);
+ loopif->flags = flags;
+
+ return err;
+}
+
+/*
+ * Update the interface's MTU
+ */
+static error_t
+hurdloopif_device_update_mtu (struct netif *netif, uint32_t mtu)
+{
+ error_t err = 0;
+
+ netif->mtu = mtu;
+
+ return err;
+}
+
+/*
+ * Release all resources of this netif.
+ *
+ * Returns 0 on success.
+ */
+static error_t
+hurdloopif_device_terminate (struct netif *netif)
+{
+ /* Free the hook */
+ free (netif_get_state (netif)->devname);
+ free (netif_get_state (netif));
+
+ return 0;
+}
+
+/*
+ * Set up the LwIP loopback interface
+ */
+error_t
+hurdloopif_device_init (struct netif * netif)
+{
+ error_t err = 0;
+ hurdloopif *loopif;
+
+ /*
+ * Replace the hook by a new one with the proper size.
+ * The old one is in the stack and will be removed soon.
+ */
+ loopif = calloc (1, sizeof (hurdloopif));
+ if (loopif == NULL)
+ {
+ LWIP_DEBUGF (NETIF_DEBUG, ("hurdloopif_init: out of memory\n"));
+ return ERR_MEM;
+ }
+ memcpy (loopif, netif_get_state (netif), sizeof (struct ifcommon));
+ netif->state = loopif;
+
+ /* Device name and type */
+ loopif->devname = LOOP_DEV_NAME;
+ loopif->type = ARPHRD_LOOPBACK;
+
+ /* MTU = MSS + IP header + TCP header */
+ netif->mtu = TCP_MSS + 20 + 20;
+
+ /* Set flags */
+ hurdloopif_device_set_flags (netif, IFF_UP | IFF_RUNNING | IFF_LOOPBACK);
+
+ /* Set callbacks */
+ loopif->open = 0;
+ loopif->close = 0;
+ loopif->terminate = hurdloopif_device_terminate;
+ loopif->update_mtu = hurdloopif_device_update_mtu;
+ loopif->change_flags = hurdloopif_device_set_flags;
+
+ return err;
+}
diff --git a/lwip/port/netif/hurdtunif.c b/lwip/port/netif/hurdtunif.c
new file mode 100644
index 00000000..d7991baa
--- /dev/null
+++ b/lwip/port/netif/hurdtunif.c
@@ -0,0 +1,721 @@
+/*
+ Copyright (C) 1995,96,98,99,2000,02,17 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Tunnel devices module */
+
+#include <netif/hurdtunif.h>
+
+#include <hurd/trivfs.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <error.h>
+#include <sys/mman.h>
+
+#include <lwip-hurd.h>
+
+/* Add to the end of the queue */
+static void
+enqueue (struct pbufqueue *q, struct pbuf *p)
+{
+ *(q->tail) = p;
+ p->next = 0;
+ q->tail = &p->next;
+
+ q->len++;
+}
+
+/* Get from the head of the queue */
+static struct pbuf *
+dequeue (struct pbufqueue *q)
+{
+ struct pbuf *ret;
+
+ if (!q->head)
+ return 0;
+
+ ret = q->head;
+ q->head = q->head->next;
+ ret->next = 0;
+ q->len--;
+
+ if (!q->head)
+ q->tail = &q->head;
+
+ return ret;
+}
+
+/*
+ * Update the interface's MTU
+ */
+static error_t
+hurdtunif_device_update_mtu (struct netif *netif, uint32_t mtu)
+{
+ error_t err = 0;
+
+ netif->mtu = mtu;
+
+ return err;
+}
+
+/* Set the device flags */
+static error_t
+hurdtunif_device_set_flags (struct netif *netif, uint16_t flags)
+{
+ error_t err = 0;
+ struct ifcommon *tunif;
+
+ tunif = netif_get_state (netif);
+ tunif->flags = flags;
+
+ return err;
+}
+
+/*
+ * Release all resources of this netif.
+ *
+ * Returns 0 on success.
+ */
+static error_t
+hurdtunif_device_terminate (struct netif *netif)
+{
+ struct pbuf *p;
+ struct hurdtunif *tunif = (struct hurdtunif *) netif_get_state (netif);
+
+ /* Clear the queue */
+ while ((p = dequeue (&tunif->queue)) != 0)
+ pbuf_free (p);
+ pthread_cond_destroy (&tunif->read);
+ pthread_cond_destroy (&tunif->select);
+ pthread_mutex_destroy (&tunif->lock);
+
+ /* Free the hook */
+ free (netif_get_state (netif)->devname);
+ free (netif_get_state (netif));
+
+ return 0;
+}
+
+/*
+ * Called from lwip.
+ *
+ * Just enqueue the data.
+ */
+static error_t
+hurdtunif_output (struct netif *netif, struct pbuf *p,
+ const ip4_addr_t * ipaddr)
+{
+ error_t err = 0;
+ struct hurdtunif *tunif;
+ struct pbuf *pcopy, *oldest;
+
+ tunif = (struct hurdtunif *) netif_get_state (netif);
+
+ /*
+ * The stack is responsible for allocating and freeing the pbuf p.
+ * Sometimes it keeps the pbuf for the case it needs to be retransmitted,
+ * but at other times it frees the pbuf while it's still in our queue,
+ * that's why we need a copy.
+ */
+ pcopy = pbuf_alloc (PBUF_IP, p->tot_len, PBUF_RAM);
+ if (pcopy != NULL)
+ if (pbuf_copy (pcopy, p) != ERR_OK)
+ {
+ pbuf_free (pcopy);
+ pcopy = NULL;
+ }
+
+ pthread_mutex_lock (&tunif->lock);
+
+ /* Avoid unlimited growth. */
+ if (tunif->queue.len > 128)
+ {
+ oldest = dequeue (&tunif->queue);
+ pbuf_free (oldest);
+ }
+
+ enqueue (&tunif->queue, pcopy);
+
+ if (tunif->read_blocked)
+ {
+ tunif->read_blocked = 0;
+ pthread_cond_broadcast (&tunif->read);
+ pthread_cond_broadcast (&tunif->select);
+ }
+
+ pthread_mutex_unlock (&tunif->lock);
+
+ return err;
+}
+
+/*
+ * Set up the tunnel a new tunnel device
+ */
+error_t
+hurdtunif_device_init (struct netif * netif)
+{
+ error_t err = 0;
+ struct hurdtunif *tunif;
+ char *base_name, *name = netif_get_state (netif)->devname;
+
+ /*
+ * Replace the hook by a new one with the proper size.
+ * The old one is in the stack and will be removed soon.
+ */
+ tunif = calloc (1, sizeof (struct hurdtunif));
+ if (tunif == NULL)
+ {
+ LWIP_DEBUGF (NETIF_DEBUG, ("hurdtunif_init: out of memory\n"));
+ return ERR_MEM;
+ }
+ memcpy (tunif, netif_get_state (netif), sizeof (struct ifcommon));
+ netif->state = tunif;
+
+ base_name = strrchr (name, '/');
+ if (base_name)
+ /* The user provided a path */
+ base_name++;
+ else
+ /* The user provided a name for the tunnel. We'll create it at /dev */
+ base_name = name;
+
+ if (base_name != name)
+ tunif->comm.devname = strdup (name);
+ else
+ /* Setting up the translator at /dev/tunX. */
+ asprintf (&tunif->comm.devname, "/dev/%s", base_name);
+
+ /* Set the device type */
+ tunif->comm.type = ARPHRD_TUNNEL;
+
+ /* MTU = MSS + IP header + TCP header */
+ netif->mtu = TCP_MSS + 20 + 20;
+
+ /* Set flags */
+ hurdtunif_device_set_flags (netif,
+ IFF_UP | IFF_RUNNING | IFF_POINTOPOINT |
+ IFF_NOARP);
+
+ netif->flags = NETIF_FLAG_LINK_UP;
+
+ /* Set the callbacks */
+ netif->output = hurdtunif_output;
+ tunif->comm.open = 0;
+ tunif->comm.close = 0;
+ tunif->comm.terminate = hurdtunif_device_terminate;
+ tunif->comm.update_mtu = hurdtunif_device_update_mtu;
+ tunif->comm.change_flags = hurdtunif_device_set_flags;
+
+ /* Bind the translator to tunif->comm.devname */
+ tunif->underlying = file_name_lookup (tunif->comm.devname,
+ O_CREAT | O_NOTRANS, 0664);
+
+ if (tunif->underlying == MACH_PORT_NULL)
+ {
+ error (0, 0, "%s", tunif->comm.devname);
+ return -1;
+ }
+
+ err = trivfs_create_control (tunif->underlying, tunnel_cntlclass,
+ lwip_bucket, tunnel_class, lwip_bucket,
+ &tunif->cntl);
+
+ if (!err)
+ {
+ mach_port_t right = ports_get_send_right (tunif->cntl);
+ err = file_set_translator (tunif->underlying, 0,
+ FS_TRANS_SET | FS_TRANS_ORPHAN, 0, 0, 0,
+ right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
+ }
+
+ if (err)
+ error (0, err, "%s", tunif->comm.devname);
+
+ /* We'll need to get the netif from trivfs operations */
+ tunif->cntl->hook = netif;
+
+ /* Output queue initialization */
+ tunif->queue.head = 0;
+ tunif->queue.tail = &tunif->queue.head;
+ tunif->queue.len = 0;
+ pthread_mutex_init (&tunif->lock, NULL);
+ pthread_cond_init (&tunif->read, NULL);
+ pthread_cond_init (&tunif->select, NULL);
+ tunif->read_blocked = 0;
+
+ return err;
+}
+
+/*
+ * Set libports classes
+ *
+ * This function should be called once.
+ */
+error_t
+hurdtunif_module_init ()
+{
+ error_t err = 0;
+
+ trivfs_add_control_port_class (&tunnel_cntlclass);
+ trivfs_add_protid_port_class (&tunnel_class);
+
+ return err;
+}
+
+/* If a new open with read and/or write permissions is requested,
+ restrict to exclusive usage. */
+static error_t
+check_open_hook (struct trivfs_control *cntl, struct iouser *user, int flags)
+{
+ struct netif *netif;
+ struct hurdtunif *tunif;
+
+ for (netif = netif_list; netif; netif = netif->next)
+ {
+ tunif = (struct hurdtunif *) netif_get_state (netif);
+ if (tunif->cntl == cntl)
+ break;
+ }
+
+ if (netif && flags != O_NORW)
+ {
+ if (tunif->user)
+ return EBUSY;
+ else
+ tunif->user = user;
+ }
+
+ return 0;
+}
+
+/* When a protid is destroyed, check if it is the current user.
+ If yes, release the interface for other users. */
+static void
+pi_destroy_hook (struct trivfs_protid *cred)
+{
+ struct netif *netif;
+ struct hurdtunif *tunif;
+
+ if (cred->pi.class != tunnel_class)
+ return;
+
+ netif = (struct netif *) cred->po->cntl->hook;
+ tunif = (struct hurdtunif *) netif_get_state (netif);
+
+ if (tunif->user == cred->user)
+ tunif->user = 0;
+}
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_check_open_hook) (struct trivfs_control *,
+ struct iouser *, int) = check_open_hook;
+
+/* If this variable is set, it is called every time a protid structure
+ is about to be destroyed. */
+void (*trivfs_protid_destroy_hook) (struct trivfs_protid *) = pi_destroy_hook;
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t * data_len,
+ loff_t offs, size_t amount)
+{
+ struct hurdtunif *tunif;
+ struct pbuf *p;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tunif =
+ (struct hurdtunif *)
+ netif_get_state (((struct netif *) cred->po->cntl->hook));
+
+ pthread_mutex_lock (&tunif->lock);
+
+ while (tunif->queue.len == 0)
+ {
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ pthread_mutex_unlock (&tunif->lock);
+ return EWOULDBLOCK;
+ }
+
+ tunif->read_blocked = 1;
+ if (pthread_hurd_cond_wait_np (&tunif->read, &tunif->lock))
+ {
+ pthread_mutex_unlock (&tunif->lock);
+ return EINTR;
+ }
+ }
+
+ p = dequeue (&tunif->queue);
+
+ if (p->tot_len < amount)
+ amount = p->tot_len;
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ {
+ *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ {
+ pbuf_free (p);
+ pthread_mutex_unlock (&tunif->lock);
+ return ENOMEM;
+ }
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, p->payload, amount);
+ }
+ *data_len = amount;
+ pbuf_free (p);
+
+ pthread_mutex_unlock (&tunif->lock);
+
+ return 0;
+}
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they receive more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ char *data,
+ mach_msg_type_number_t datalen,
+ off_t offset, mach_msg_type_number_t * amount)
+{
+ struct netif *netif;
+ struct pbuf *p, *q;
+ uint16_t off;
+
+ /* Deny access if they have bad credentials. */
+ if (!cred)
+ return EOPNOTSUPP;
+
+ else if (!(cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ netif = (struct netif *) cred->po->cntl->hook;
+
+ /* Allocate an empty pbuf chain for the data */
+ p = pbuf_alloc (PBUF_RAW, datalen, PBUF_POOL);
+
+ if (p)
+ {
+ /* Iterate to fill the pbuf chain. */
+ q = p;
+ off = 0;
+ do
+ {
+ memcpy (q->payload, data, q->len);
+
+ off += q->len;
+
+ if (q->tot_len == q->len)
+ break;
+ else
+ q = q->next;
+ }
+ while (1);
+
+ /* pass it to the stack */
+ if (netif->input (p, netif) != ERR_OK)
+ {
+ LWIP_DEBUGF (NETIF_DEBUG, ("trivfs_S_io_write: IP input error\n"));
+ pbuf_free (p);
+ p = NULL;
+ }
+
+ *amount = datalen;
+ }
+
+ return 0;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid * cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t * amount)
+{
+ struct hurdtunif *tunif;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tunif =
+ (struct hurdtunif *)
+ netif_get_state (((struct netif *) cred->po->cntl->hook));
+
+ pthread_mutex_lock (&tunif->lock);
+
+ if (tunif->queue.head)
+ *amount = tunif->queue.head->tot_len;
+ else
+ *amount = 0;
+
+ pthread_mutex_unlock (&tunif->lock);
+
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *type)
+{
+ error_t err;
+ struct hurdtunif *tunif;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ /* Make this thread cancellable */
+ ports_interrupt_self_on_port_death (cred, reply);
+
+ /* We only deal with SELECT_READ and SELECT_WRITE here. */
+ *type &= SELECT_READ | SELECT_WRITE;
+
+ if (*type == 0)
+ return 0;
+
+ tunif =
+ (struct hurdtunif *)
+ netif_get_state (((struct netif *) cred->po->cntl->hook));
+
+ pthread_mutex_lock (&tunif->lock);
+
+ if (*type & SELECT_WRITE)
+ {
+ /* We are always writable. */
+ if (tunif->queue.len == 0)
+ *type &= ~SELECT_READ;
+ pthread_mutex_unlock (&tunif->lock);
+ return 0;
+ }
+
+ while (1)
+ {
+ /* There's data on the queue */
+ if (tunif->queue.len != 0)
+ {
+ *type = SELECT_READ;
+ pthread_mutex_unlock (&tunif->lock);
+ return 0;
+ }
+
+ /* The queue is empty, we must wait */
+ tunif->read_blocked = 1;
+ err =
+ pthread_hurd_cond_timedwait_np (&tunif->select, &tunif->lock, tsp);
+ if (err)
+ {
+ *type = 0;
+ pthread_mutex_unlock (&tunif->lock);
+
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
+ }
+ }
+}
+
+error_t
+trivfs_S_io_select (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int *type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts, int *type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, type);
+}
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid * cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t * new_offs)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return ESPIPE;
+}
+
+/* Change the size of the file. If the size increases, new blocks are
+ zero-filled. After successful return, it is safe to reference mapped
+ areas of the file up to NEW_SIZE. */
+error_t
+trivfs_S_file_set_size (struct trivfs_protid * cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+error_t
+trivfs_S_io_set_all_openmodes (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type, pid_t * owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid * cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map (struct trivfs_protid * cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ memory_object_t * rdobj,
+ mach_msg_type_name_t * rdtype,
+ memory_object_t * wrobj, mach_msg_type_name_t * wrtype)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
diff --git a/lwip/port/netif/ifcommon.c b/lwip/port/netif/ifcommon.c
new file mode 100644
index 00000000..11ede76d
--- /dev/null
+++ b/lwip/port/netif/ifcommon.c
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Joan Lledó.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Common interface for all kinds of devices */
+
+#include <netif/ifcommon.h>
+
+#include <net/if.h>
+
+#include <lwip/netifapi.h>
+
+/* Open the device and set the interface up */
+static error_t
+if_open (struct netif *netif)
+{
+ error_t err = 0;
+ struct ifcommon *ifc = netif_get_state (netif);
+
+ if (ifc->open)
+ err = ifc->open (netif);
+ if (!err)
+ {
+ /* Up the inerface */
+ ifc->flags |= IFF_UP | IFF_RUNNING;
+ netifapi_netif_set_up (netif);
+ }
+
+ return err;
+}
+
+/* Close the device and set the interface down */
+static error_t
+if_close (struct netif *netif)
+{
+ error_t err = 0;
+ struct ifcommon *ifc = netif_get_state (netif);
+
+ if (ifc->close)
+ err = ifc->close (netif);
+ if (!err)
+ {
+ /* Down the inerface */
+ ifc->flags &= ~(IFF_UP | IFF_RUNNING);
+ netifapi_netif_set_down (netif);
+ }
+
+ return err;
+}
+
+/*
+ * Common initialization callback for all kinds of devices.
+ *
+ * This function doesn't assume there's a device nor tries to open it.
+ * If a device is present, it must be opened from the ifc->init() callback.
+ */
+error_t
+if_init (struct netif * netif)
+{
+ struct ifcommon *ifc = netif_get_state (netif);
+
+ if (netif == NULL)
+ /* The user provided no interface */
+ return -1;
+
+ return ifc->init (netif);
+}
+
+/* Tries to close the device and frees allocated resources */
+error_t
+if_terminate (struct netif * netif)
+{
+ error_t err;
+ struct ifcommon *ifc = netif_get_state (netif);
+
+ if (netif == NULL)
+ /* The user provided no interface */
+ return -1;
+
+ err = if_close (netif);
+ if (err)
+ return err;
+
+ return ifc->terminate (netif);
+}
+
+/*
+ * Change device flags.
+ *
+ * If IFF_UP changes, it opens/closes the device accordingly.
+ */
+error_t
+if_change_flags (struct netif * netif, uint16_t flags)
+{
+ error_t err;
+ struct ifcommon *ifc = netif_get_state (netif);
+ uint16_t oldflags = ifc->flags;
+
+ err = ifc->change_flags (netif, flags);
+
+ if ((oldflags ^ flags) & IFF_UP) /* Bit is different ? */
+ ((oldflags & IFF_UP) ? if_close : if_open) (netif);
+
+ return err;
+}
diff --git a/lwip/socket-ops.c b/lwip/socket-ops.c
new file mode 100644
index 00000000..62b36e08
--- /dev/null
+++ b/lwip/socket-ops.c
@@ -0,0 +1,451 @@
+/*
+ Copyright (C) 1995,96,97,99,2000,02,07,17 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Socket operations */
+
+#include <lwip_socket_S.h>
+
+#include <sys/mman.h>
+#include <hurd/fshelp.h>
+
+#include <lwip/sockets.h>
+#include <lwip-hurd.h>
+
+error_t
+lwip_S_socket_create (struct trivfs_protid *master,
+ int sock_type,
+ int protocol,
+ mach_port_t * port, mach_msg_type_name_t * porttype)
+{
+ error_t err;
+ struct sock_user *user;
+ struct socket *sock;
+ int isroot;
+ int domain;
+
+ if (!master)
+ return EOPNOTSUPP;
+
+ if (sock_type != SOCK_STREAM
+ && sock_type != SOCK_DGRAM && sock_type != SOCK_RAW)
+ return EPROTOTYPE;
+
+ /* The class tell us which domain must we use */
+ if (master->pi.class == lwip_protid_portclasses[PORTCLASS_INET])
+ domain = PF_INET;
+ else
+ domain = PF_INET6;
+
+ sock = sock_alloc ();
+ if (!sock)
+ return ENOMEM;
+
+ sock->sockno = lwip_socket (domain, sock_type, protocol);
+ if (sock->sockno < 0)
+ {
+ sock_release (sock);
+ return errno;
+ }
+
+ isroot = master->isroot;
+ if (!isroot)
+ {
+ struct stat st;
+
+ st.st_uid = lwip_owner;
+ st.st_gid = lwip_group;
+
+ err = fshelp_isowner (&st, master->user);
+ if (!err)
+ isroot = 1;
+ }
+
+ user = make_sock_user (sock, isroot, 0, 1);
+ *port = ports_get_right (user);
+ *porttype = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (user);
+
+ return errno;
+}
+
+
+/* Listen on a socket. */
+error_t
+lwip_S_socket_listen (struct sock_user * user, int queue_limit)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ lwip_listen (user->sock->sockno, queue_limit);
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_accept (struct sock_user * user,
+ mach_port_t * new_port,
+ mach_msg_type_name_t * new_port_type,
+ mach_port_t * addr_port,
+ mach_msg_type_name_t * addr_port_type)
+{
+ struct sock_user *newuser;
+ struct sockaddr_storage addr;
+ socklen_t addr_len;
+ error_t err;
+ struct socket *sock, *newsock;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ sock = user->sock;
+
+ newsock = sock_alloc ();
+ if (!newsock)
+ return ENOMEM;
+
+ addr_len = sizeof (addr);
+ newsock->sockno =
+ lwip_accept (sock->sockno, (struct sockaddr *) &addr, &addr_len);
+
+ if (newsock->sockno == -1)
+ {
+ sock_release (newsock);
+ }
+ else
+ {
+ /* Set the peer's address for the caller */
+ err =
+ lwip_S_socket_create_address (0, addr.ss_family, (void *) &addr,
+ addr_len, addr_port, addr_port_type);
+ if (err)
+ return err;
+
+ newuser = make_sock_user (newsock, user->isroot, 0, 1);
+ *new_port = ports_get_right (newuser);
+ *new_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_connect (struct sock_user * user, struct sock_addr * addr)
+{
+ error_t err;
+
+ if (!user || !addr)
+ return EOPNOTSUPP;
+
+ err = lwip_connect (user->sock->sockno,
+ &addr->address.sa, addr->address.sa.sa_len);
+
+ /* MiG should do this for us, but it doesn't. */
+ if (!err)
+ mach_port_deallocate (mach_task_self (), addr->pi.port_right);
+
+ /* When a connection fails, e.g. there's nobody there, LwIP returns ECONNRESET
+ * but Glibc doesn't expect that, we must return ECONNREFUSED instead. */
+ if (errno == ECONNRESET)
+ errno = ECONNREFUSED;
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_bind (struct sock_user * user, struct sock_addr * addr)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+ if (!addr)
+ return EADDRNOTAVAIL;
+
+ err = lwip_bind (user->sock->sockno,
+ &addr->address.sa, addr->address.sa.sa_len);
+
+ /* MiG should do this for us, but it doesn't. */
+ if (!err)
+ mach_port_deallocate (mach_task_self (), addr->pi.port_right);
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_name (struct sock_user * user,
+ mach_port_t * addr_port,
+ mach_msg_type_name_t * addr_port_name)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ err = make_sockaddr_port (user->sock->sockno, 0, addr_port, addr_port_name);
+
+ return err;
+}
+
+error_t
+lwip_S_socket_peername (struct sock_user * user,
+ mach_port_t * addr_port,
+ mach_msg_type_name_t * addr_port_name)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ err = make_sockaddr_port (user->sock->sockno, 1, addr_port, addr_port_name);
+
+ return err;
+}
+
+error_t
+lwip_S_socket_connect2 (struct sock_user * user, struct sock_user * sock2)
+{
+ /* We don't answer AF_UNIX requests */
+ return EOPNOTSUPP;
+}
+
+/*
+ * Receive address data, create a libports object and return its port
+ */
+error_t
+lwip_S_socket_create_address (mach_port_t server,
+ int sockaddr_type,
+ char *data,
+ mach_msg_type_number_t data_len,
+ mach_port_t * addr_port,
+ mach_msg_type_name_t * addr_port_type)
+{
+ error_t err;
+ struct sock_addr *addrstruct;
+ const struct sockaddr *const sa = (void *) data;
+
+ if (sockaddr_type != AF_INET && sockaddr_type != AF_INET6
+ && sockaddr_type != AF_UNSPEC)
+ return EAFNOSUPPORT;
+ if (sa->sa_family != sockaddr_type
+ || data_len < offsetof (struct sockaddr, sa_data))
+ return EINVAL;
+
+ err = ports_create_port (addrport_class, lwip_bucket,
+ (offsetof (struct sock_addr, address)
+ +data_len), &addrstruct);
+ if (err)
+ return err;
+
+ memcpy (&addrstruct->address.sa, data, data_len);
+
+ /* BSD does not require incoming sa_len to be set, so we don't either. */
+ addrstruct->address.sa.sa_len = data_len;
+
+ *addr_port = ports_get_right (addrstruct);
+ *addr_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (addrstruct);
+ return 0;
+}
+
+error_t
+lwip_S_socket_fabricate_address (mach_port_t server,
+ int sockaddr_type,
+ mach_port_t * addr_port,
+ mach_msg_type_name_t * addr_port_type)
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * Receive a libports object and return its data
+ */
+error_t
+lwip_S_socket_whatis_address (struct sock_addr * addr,
+ int *type,
+ char **data, mach_msg_type_number_t * datalen)
+{
+ if (!addr)
+ return EOPNOTSUPP;
+
+ *type = addr->address.sa.sa_family;
+ if (*datalen < addr->address.sa.sa_len)
+ *data = mmap (0, addr->address.sa.sa_len,
+ PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ *datalen = addr->address.sa.sa_len;
+ memcpy (*data, &addr->address.sa, addr->address.sa.sa_len);
+
+ return 0;
+}
+
+error_t
+lwip_S_socket_shutdown (struct sock_user * user, int direction)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ lwip_shutdown (user->sock->sockno, direction);
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_getopt (struct sock_user * user,
+ int level, int option, char **data, size_t * datalen)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ int len = *datalen;
+ lwip_getsockopt (user->sock->sockno, level, option, *data,
+ (socklen_t *) & len);
+ *datalen = len;
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_setopt (struct sock_user * user,
+ int level, int option, char *data, size_t datalen)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ lwip_setsockopt (user->sock->sockno, level, option, data, datalen);
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_send (struct sock_user * user,
+ struct sock_addr * addr,
+ int flags,
+ char *data,
+ size_t datalen,
+ mach_port_t * ports,
+ size_t nports,
+ char *control,
+ size_t controllen, mach_msg_type_number_t * amount)
+{
+ int sent;
+ int sockflags;
+ struct iovec iov = { data, datalen };
+struct msghdr m = { msg_name:addr ? &addr->address : 0,
+ msg_namelen:addr ? addr->address.sa.sa_len : 0,
+ msg_flags:flags,
+ msg_controllen: 0, msg_iov: &iov, msg_iovlen:1
+ };
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Don't do this yet, it's too bizarre to think about right now. */
+ if (nports != 0 || controllen != 0)
+ return EINVAL;
+
+ sockflags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+ if (sockflags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+ sent = lwip_sendmsg (user->sock->sockno, &m, flags);
+
+ /* MiG should do this for us, but it doesn't. */
+ if (addr && sent >= 0)
+ mach_port_deallocate (mach_task_self (), addr->pi.port_right);
+
+ if (sent >= 0)
+ {
+ *amount = sent;
+ }
+
+ return errno;
+}
+
+error_t
+lwip_S_socket_recv (struct sock_user * user,
+ mach_port_t * addrport,
+ mach_msg_type_name_t * addrporttype,
+ int flags,
+ char **data,
+ size_t * datalen,
+ mach_port_t ** ports,
+ mach_msg_type_name_t * portstype,
+ size_t * nports,
+ char **control,
+ size_t * controllen,
+ int *outflags, mach_msg_type_number_t amount)
+{
+ error_t err;
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof (addr);
+ int alloced = 0;
+ int sockflags;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Instead of this, we should peek and the socket and only
+ allocate as much as necessary. */
+ if (amount > *datalen)
+ {
+ *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ /* Should check whether errno is indeed ENOMEM --
+ but this can't be done in a straightforward way,
+ because the glue headers #undef errno. */
+ return ENOMEM;
+ alloced = 1;
+ }
+
+ sockflags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
+ if (sockflags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+
+ /* TODO: use recvmsg instead */
+ err = lwip_recvfrom (user->sock->sockno, *data, amount,
+ flags, (struct sockaddr *) &addr, &addrlen);
+
+ if (err < 0)
+ {
+ if (alloced)
+ munmap (*data, amount);
+ }
+ else
+ {
+ *datalen = err;
+ if (alloced && round_page (*datalen) < round_page (amount))
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
+
+ /* Set the peer's address for the caller */
+ err =
+ lwip_S_socket_create_address (0, addr.ss_family, (void *) &addr,
+ addrlen, addrport, addrporttype);
+
+ if (err && alloced)
+ munmap (*data, *datalen);
+
+ *outflags = 0; /* FIXME */
+ *nports = 0;
+ *portstype = MACH_MSG_TYPE_COPY_SEND;
+ *controllen = 0;
+ }
+
+ return errno;
+}
diff --git a/lwip/startup-ops.c b/lwip/startup-ops.c
new file mode 100644
index 00000000..ac1fe547
--- /dev/null
+++ b/lwip/startup-ops.c
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <lwip_startup_notify_S.h>
+
+#include <lwip-hurd.h>
+
+/* The system is going down; destroy all the extant port rights. That
+ will cause net channels and such to close promptly. */
+error_t
+lwip_S_startup_dosync (mach_port_t handle)
+{
+ struct port_info *inpi = ports_lookup_port (lwip_bucket, handle,
+ shutdown_notify_class);
+
+ if (!inpi)
+ return EOPNOTSUPP;
+
+ ports_class_iterate (socketport_class, ports_destroy_right);
+ ports_class_iterate (addrport_class, ports_destroy_right);
+ return 0;
+}
diff --git a/lwip/startup.c b/lwip/startup.c
new file mode 100644
index 00000000..a21dfe33
--- /dev/null
+++ b/lwip/startup.c
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <startup.h>
+
+#include <unistd.h>
+#include <hurd/paths.h>
+#include <hurd/startup.h>
+
+#include <lwip-hurd.h>
+
+static void
+sigterm_handler (int signo)
+{
+ ports_class_iterate (socketport_class, ports_destroy_right);
+ ports_class_iterate (addrport_class, ports_destroy_right);
+ sleep (10);
+ signal (SIGTERM, SIG_DFL);
+ raise (SIGTERM);
+}
+
+void
+arrange_shutdown_notification ()
+{
+ error_t err;
+ mach_port_t initport, notify;
+ struct port_info *pi;
+
+ shutdown_notify_class = ports_create_class (0, 0);
+
+ signal (SIGTERM, sigterm_handler);
+
+ /* Arrange to get notified when the system goes down,
+ but if we fail for some reason, just silently give up. No big deal. */
+
+ err = ports_create_port (shutdown_notify_class, lwip_bucket,
+ sizeof (struct port_info), &pi);
+ if (err)
+ return;
+
+ initport = file_name_lookup (_SERVERS_STARTUP, 0, 0);
+ if (initport == MACH_PORT_NULL)
+ return;
+
+ notify = ports_get_send_right (pi);
+ ports_port_deref (pi);
+ startup_request_notification (initport, notify,
+ MACH_MSG_TYPE_MAKE_SEND,
+ program_invocation_short_name);
+ mach_port_deallocate (mach_task_self (), notify);
+ mach_port_deallocate (mach_task_self (), initport);
+}
diff --git a/lwip/startup.h b/lwip/startup.h
new file mode 100644
index 00000000..0c197bf0
--- /dev/null
+++ b/lwip/startup.h
@@ -0,0 +1,26 @@
+/*
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef LWIP_STARTUP_H
+#define LWIP_STARTUP_H
+
+void arrange_shutdown_notification ();
+
+#endif /* LWIP_STARTUP_H */