bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] LwIP translator


From: Joan Lledó
Subject: [PATCH] LwIP translator
Date: Mon, 13 Nov 2017 08:31:46 +0100

---
 Makefile                             |   4 +
 config.make.in                       |   7 +
 configure.ac                         |   5 +
 lwip/Makefile                        |  52 +++
 lwip/config.h                        |   5 +
 lwip/iioctl-ops.c                    | 412 ++++++++++++++++++++
 lwip/io-ops.c                        | 554 +++++++++++++++++++++++++++
 lwip/lwip-hurd.h                     | 102 +++++
 lwip/lwip-util.c                     | 343 +++++++++++++++++
 lwip/lwip-util.h                     |  41 ++
 lwip/main.c                          | 272 +++++++++++++
 lwip/mig-decls.h                     |  68 ++++
 lwip/mig-mutate.h                    |  44 +++
 lwip/options.c                       | 342 +++++++++++++++++
 lwip/options.h                       |  81 ++++
 lwip/pfinet-ops.c                    | 113 ++++++
 lwip/port-objs.c                     | 144 +++++++
 lwip/port/include/netif/hurdethif.h  |  39 ++
 lwip/port/include/netif/hurdloopif.h |  36 ++
 lwip/port/include/netif/hurdtunif.h  |  65 ++++
 lwip/port/include/netif/ifcommon.h   |  60 +++
 lwip/port/netif/hurdethif.c          | 573 ++++++++++++++++++++++++++++
 lwip/port/netif/hurdloopif.c         | 112 ++++++
 lwip/port/netif/hurdtunif.c          | 721 +++++++++++++++++++++++++++++++++++
 lwip/port/netif/ifcommon.c           | 121 ++++++
 lwip/socket-ops.c                    | 450 ++++++++++++++++++++++
 lwip/startup-ops.c                   |  39 ++
 lwip/startup.c                       |  69 ++++
 lwip/startup.h                       |  26 ++
 29 files changed, 4900 insertions(+)
 create mode 100644 lwip/Makefile
 create mode 100644 lwip/config.h
 create mode 100644 lwip/iioctl-ops.c
 create mode 100644 lwip/io-ops.c
 create mode 100644 lwip/lwip-hurd.h
 create mode 100644 lwip/lwip-util.c
 create mode 100644 lwip/lwip-util.h
 create mode 100644 lwip/main.c
 create mode 100644 lwip/mig-decls.h
 create mode 100644 lwip/mig-mutate.h
 create mode 100644 lwip/options.c
 create mode 100644 lwip/options.h
 create mode 100644 lwip/pfinet-ops.c
 create mode 100644 lwip/port-objs.c
 create mode 100644 lwip/port/include/netif/hurdethif.h
 create mode 100644 lwip/port/include/netif/hurdloopif.h
 create mode 100644 lwip/port/include/netif/hurdtunif.h
 create mode 100644 lwip/port/include/netif/ifcommon.h
 create mode 100644 lwip/port/netif/hurdethif.c
 create mode 100644 lwip/port/netif/hurdloopif.c
 create mode 100644 lwip/port/netif/hurdtunif.c
 create mode 100644 lwip/port/netif/ifcommon.c
 create mode 100644 lwip/socket-ops.c
 create mode 100644 lwip/startup-ops.c
 create mode 100644 lwip/startup.c
 create mode 100644 lwip/startup.h

diff --git a/Makefile b/Makefile
index 119f130b..2d9d3f80 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,10 @@ ifeq ($(HAVE_SUN_RPC),yes)
 prog-subdirs += nfs nfsd
 endif
 
+ifeq ($(HAVE_LIBLWIP),yes)
+prog-subdirs += lwip
+endif
+
 # Other directories
 other-subdirs = hurd doc config release include
 
diff --git a/config.make.in b/config.make.in
index dfbf0c10..7b62e851 100644
--- a/config.make.in
+++ b/config.make.in
@@ -99,6 +99,13 @@ HAVE_SUN_RPC = @HAVE_SUN_RPC@
 # Whether we found libgcrypt.
 HAVE_LIBGCRYPT = @HAVE_LIBGCRYPT@
 
+# Whether we found liblwip.
+HAVE_LIBLWIP = @HAVE_LIBLWIP@
+
+# How to compile and link against liblwip.
+liblwip_CFLAGS = @liblwip_CFLAGS@
+liblwip_LIBS = @liblwip_LIBS@
+
 # Installation tools.
 INSTALL = @INSTALL@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/configure.ac b/configure.ac
index 54aa72b0..5abedf46 100644
--- a/configure.ac
+++ b/configure.ac
@@ -344,6 +344,11 @@ AC_SUBST([libblkid_CFLAGS])
 AM_PATH_LIBGCRYPT("1:1.6.0",[HAVE_LIBGCRYPT=yes], [HAVE_LIBGCRYPT=no])
 AC_SUBST([HAVE_LIBGCRYPT])
 
+PKG_CHECK_MODULES([liblwip], [lwip], [HAVE_LIBLWIP=yes], [HAVE_LIBLWIP=no])
+AC_SUBST([HAVE_LIBLWIP])
+AC_SUBST([liblwip_CFLAGS])
+AC_SUBST([liblwip_LIBS])
+
 AC_CONFIG_FILES([config.make ${makefiles}])
 AC_OUTPUT
 
diff --git a/lwip/Makefile b/lwip/Makefile
new file mode 100644
index 00000000..c9c4d888
--- /dev/null
+++ b/lwip/Makefile
@@ -0,0 +1,52 @@
+#   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)
+
+CPPFLAGS += -imacros $(srcdir)/config.h
+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/config.h b/lwip/config.h
new file mode 100644
index 00000000..b0d5196d
--- /dev/null
+++ b/lwip/config.h
@@ -0,0 +1,5 @@
+#define __KERNEL__     1
+#undef __SMP__
+
+#define _HURD_         1
+
diff --git a/lwip/iioctl-ops.c b/lwip/iioctl-ops.c
new file mode 100644
index 00000000..ea9d3a8b
--- /dev/null
+++ b/lwip/iioctl-ops.c
@@ -0,0 +1,412 @@
+/*
+   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)
+    err = EPERM;
+
+  if (mtu <= 0)
+    err = 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 <address@hidden>
+
+   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 <address@hidden>
+
+   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..98f713a7
--- /dev/null
+++ b/lwip/socket-ops.c
@@ -0,0 +1,450 @@
+/*
+   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;
+
+  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 */
-- 
2.14.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]