commit-hurd
[Top][All Lists]
Advanced

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

[hurd] 21/28: eth-multiplexer: Merge the eth-multiplexer.


From: Samuel Thibault
Subject: [hurd] 21/28: eth-multiplexer: Merge the eth-multiplexer.
Date: Wed, 16 Nov 2016 08:30:27 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch upstream
in repository hurd.

commit 25d614aa11e52370c200e677099746a619ea76db
Author: Zheng Da <address@hidden>
Date:   Wed Nov 2 18:06:53 2016 +0100

    eth-multiplexer: Merge the eth-multiplexer.
    
    * Makefile (prog-subdirs): Add the new program.
    * NEWS: Update.
    * eth-multiplexer/ChangeLog: New file.
    * eth-multiplexer/Makefile: Likewise.
    * eth-multiplexer/README: Likewise.
    * eth-multiplexer/demuxer.c: Likewise.
    * eth-multiplexer/dev_stat.c: Likewise.
    * eth-multiplexer/device_impl.c: Likewise.
    * eth-multiplexer/ethernet.c: Likewise.
    * eth-multiplexer/ethernet.h: Likewise.
    * eth-multiplexer/mig-decls.h: Likewise.
    * eth-multiplexer/mig-mutate.h: Likewise.
    * eth-multiplexer/multiplexer.c: Likewise.
    * eth-multiplexer/netfs_impl.c: Likewise.
    * eth-multiplexer/netfs_impl.h: Likewise.
    * eth-multiplexer/notify_impl.c: Likewise.
    * eth-multiplexer/test.c: Likewise.
    * eth-multiplexer/util.h: Likewise.
    * eth-multiplexer/vdev.c: Likewise.
    * eth-multiplexer/vdev.h: Likewise.
    
    The eth-multiplexer has been written by Zheng Da.  This merges his
    work into the main repository.
---
 Makefile                      |   1 +
 NEWS                          |   4 +-
 eth-multiplexer/ChangeLog     | 341 ++++++++++++++++++++++++++++
 eth-multiplexer/Makefile      |  34 +++
 eth-multiplexer/README        |  27 +++
 eth-multiplexer/demuxer.c     |  50 +++++
 eth-multiplexer/dev_stat.c    | 101 +++++++++
 eth-multiplexer/device_impl.c | 213 ++++++++++++++++++
 eth-multiplexer/ethernet.c    | 143 ++++++++++++
 eth-multiplexer/ethernet.h    |  39 ++++
 eth-multiplexer/mig-decls.h   |  51 +++++
 eth-multiplexer/mig-mutate.h  |  36 +++
 eth-multiplexer/multiplexer.c | 214 ++++++++++++++++++
 eth-multiplexer/netfs_impl.c  | 508 ++++++++++++++++++++++++++++++++++++++++++
 eth-multiplexer/netfs_impl.h  |  47 ++++
 eth-multiplexer/notify_impl.c |  69 ++++++
 eth-multiplexer/test.c        |  53 +++++
 eth-multiplexer/util.h        |  91 ++++++++
 eth-multiplexer/vdev.c        | 309 +++++++++++++++++++++++++
 eth-multiplexer/vdev.h        |  79 +++++++
 20 files changed, 2408 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index f5940a1..a9ad3f6 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ prog-subdirs = auth proc exec term \
               startup \
               init \
               devnode \
+              eth-multiplexer \
 
 ifeq ($(HAVE_SUN_RPC),yes)
 prog-subdirs += nfs nfsd
diff --git a/NEWS b/NEWS
index cfb76d2..d84ae33 100644
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,8 @@ Version 0.9 (2016-11-XX)
 The 'boot' program can now be run as unprivileged user, allowing any
 user to create unprivileged Subhurds.
 
-The Berkeley Packet Filter library has been merged into this
-repository.
+The Berkeley Packet Filter library and the ethernet multiplexer have
+been merged into this repository.
 
 Version 0.8 (2016-05-18)
 
diff --git a/eth-multiplexer/ChangeLog b/eth-multiplexer/ChangeLog
new file mode 100644
index 0000000..88eebaa
--- /dev/null
+++ b/eth-multiplexer/ChangeLog
@@ -0,0 +1,341 @@
+2009-04-18  Zheng Da  <address@hidden>
+
+       * device_impl.c (ds_device_open): Create a virtual device if it
+                                         doesn't exist.
+
+       * netfs_impl.c (new_node): Test if the lnode structure exists
+                                  before setting its field.
+       (lookup): Copy the device name and don't create the virtual device.
+       (netfs_validate_stat): Set the status with the one of the underlying
+                              node if the node has no lnode structure.
+       (netfs_attempt_chmod): chmod isn't supported if the node has no lnode
+                              structure.
+       (netfs_node_norefs): Free the name in netnode.
+
+       * netfs_impl.h (net_node): Add a new field 'name'.
+
+2009-04-18  Zheng Da  <address@hidden>
+
+       * device_impl.c (ds_device_open): Check the mode for opening the file.
+
+       * multiplexer.c
+       (underlying_node_stat): New variable.
+       (main): Get the mapped time from Mach and set the time of the underlying
+               node of the translator.
+
+       * netfs_impl.c (lookup): Set the new created node with the same 
permission
+                                as the underlying node of the translator and 
its time.
+       (netfs_check_open_permissions): Check the open permission of a node
+                                       in the same way.
+       (netfs_attempt_unlink): Change the return value.
+       (netfs_attempt_rename): Likewise.
+       (netfs_attempt_mkdir): Likewise.
+       (netfs_attempt_rmdir): Likewise.
+       (netfs_attempt_chown): Likewise.
+       (netfs_attempt_chauthor): Likewise.
+       (netfs_attempt_mksymlink): Likewise.
+       (netfs_attempt_mkdev): Likewise.
+       (netfs_set_translator): Likewise.
+       (netfs_attempt_chflags): Likewise.
+       (netfs_attempt_set_size): Likewise.
+       (netfs_attempt_link): Likewise.
+       (netfs_attempt_mkfile): Likewise.
+       (netfs_attempt_write): Likewise.
+       (netfs_attempt_chmod): Write the code to support the change of the mode.
+
+       * netfs_impl.h (multiplexer_maptime): Add the declaration.
+
+2009-01-03  Zheng Da  <address@hidden>
+
+       * device_impl.c (ds_device_write): Deallocate the out-of-line data.
+
+2008-12-12  Zheng Da  <address@hidden>
+
+       * multiplexer.c (main): Initialize the file status of the root node.
+
+       * netfs_impl.c (netfs_validate_stat): Set the file status of the node
+                                             with the one in the light node.
+
+       * vdev.h (dev_act_func): Define a new type.
+       (foreach_dev_do): Declare the function.
+
+2008-11-18  Zheng Da  <address@hidden>
+
+       * netfs_impl.c (netfs_get_dirents): Use foreach_dev_do.
+
+       * vdev.c (dev_head, dev_num): Hide in the file.
+       (dev_list_lock): New variable.
+       (get_dev_num): New function.
+       (lookup_dev_by_name): Use lock.
+       (foreach_dev_do): New function.
+       (remove_dead_port_from_dev): Use lock.
+       (broadcast_pack, broadcast_msg): Use foreach_dev_do.
+
+       * vdev.h (dev_num): Remove declaration.
+       (get_dev_num): Add declaration.
+
+2008-11-13  Zheng Da  <address@hidden>
+
+       * device_impl.c (ds_device_open): Use dev_port, dereference pi.
+
+       * util.h (print_backtrace): New macro.
+
+       * vdev.c (add_vdev): Set dev_port.
+
+       * vdev.h (vether_device): Add dev_port.
+
+2008-11-12  Zheng Da  <address@hidden>
+
+       * Makefile (SRCS): Updated.
+
+       * demuxer.c: New file.
+
+       * device_impl.c (ds_device_open): Use netfs_port_bucket.
+
+       * make-protid.c: Deleted.
+
+2008-11-02  Zheng Da  <address@hidden>
+
+       * Makefile (CFLAGS): Add a macro.
+       (SRCS): Add new C files.
+       (LCLHDRS): Add new H files.
+       (HURDLIBS): Change libraries.
+
+       * demuxer.c: New file.
+
+       * device_impl.c: New file.
+
+       * make-protid.c: New file.
+
+       * netfs_impl.c: New file.
+
+       * netfs_impl.h: New file.
+
+       * notify_impl.c: New file.
+
+       * multiplexer.c: Remove the trivfs variables. Move the implementation of
+       notify interface. Move the implementation of device interface.
+       (multiplexer_thread): New functions.
+       (main): Run the libnetfs translator.
+
+       * util.h (debug): Update.
+
+       * vdev.c (lookup_dev_by_name): Use strncmp.
+       (add_vdev): Change its interface.
+
+2008-10-27  Zheng Da  <address@hidden>
+
+       * README: Update.
+
+       * bpf_impl.c (destroy_filters): New function.
+
+       * multiplexer.c (nb_dev): Deleted.
+       (options): Remove the option '-v'.
+       (do_mach_notify_no_senders): Remove all port_info in the same way.
+       (ds_device_open): Create new devices if they don't exist, and decrease
+                         their reference counts.
+       (ds_device_set_filter): Fix a bug.
+       (trivfs_goaway): Use has_vdev() to test.
+       (parse_opt): Remove the code of handling '-v'.
+       (main): Remove the code of creating virtual devices.
+
+       * util.h (ETH_P_IP): New macro.
+
+       * vdev.c (all_dev_close): Deleted.
+       (add_vdev): Link virtual device.
+       (destroy_vdev): New function.
+
+       * vdev.h (vether_device): Changed.
+
+
+2008-10-03  Zheng Da  <address@hidden>
+
+       * Makefile (CFLAGS): Remove the include paths from pfinet.
+
+       * util.h: Remove the line of including linux/if_ether.h.
+       (ETH_ALEN): New macro.
+       (ethhdr): New structure.
+
+       * vdev.c (ETH_HLEN): New macro.
+
+       * vdev.h: Remove the line of including linux/etherdevice.h and include 
util.h
+
+2008-10-03  Zheng Da  <address@hidden>
+
+       * multiplexer.c (parse_opt): Don't create the virtual devices in case 
'v'.
+       (main): Create the virtual devices.
+
+       * README: Update.
+
+2008-10-03  Zheng Da  <address@hidden>
+
+       * multiplexer.c (ds_device_write): Don't call device_write when 
ether_port is NULL.
+       (ds_device_get_status): Call dev_getstat when ether_port is NULL.
+       (main): If device_file isn't specified, don't open the underlying 
device.
+
+2008-09-26  Zheng Da  <address@hidden>
+
+       * vdev.c (deliver_msg): Use non-block send.
+
+2008-09-21  Zheng Da  <address@hidden>
+
+       * README: Update.
+
+2008-09-02  Zheng Da  <address@hidden>
+
+       * ethernet.c (ether_filter): Use the original NPF filter.
+
+2008-9-01  Zheng Da  <address@hidden>
+
+       * multiplexer.c (ds_device_write): Reverse the calling of functions.
+       (ds_device_get_status): Call device_get_status.
+
+       * vdev.c (broadcast_pack): Change its function prototype. Broadcast to
+       all other interface.
+       (deliver_pack): Don't set the message header.
+       (broadcast_msg): Save the original message header and restore it.
+       (deliver_msg): Deallocate the port if mach_msg fails.
+
+       * vdev.h (broadcast_pack): Change its function prototype.
+
+2008-8-29  Zheng Da <address@hidden>
+
+       * ethernet.c (ethernet_open): Use error instead of assert_perror.
+
+       * multiplexer.c (ds_device_set_filter): Return the error.
+
+2008-8-28 Zheng Da <address@hidden>
+
+       * ethernet.c (NET_FLAGS): New macro.
+
+2008-8-22 Zheng Da <address@hidden>
+
+       * README: Update.
+
+       * Makefile: Remove list.h.
+
+       * multiplexer.c (do_mach_notify_no_senders): Get vether_device object
+       with ports_lookup_port().
+       (ds_xxx_device_set_status): Likewise.
+       (ds_xxx_device_get_status): Likewise.
+       (ds_xxx_device_set_filter): Likewise.
+       (ds_device_write): Likewise.
+       (ds_device_write_inband): Likewise.
+       (ds_device_read): Likewise.
+       (ds_device_read_inband): Likewise.
+       (ds_device_map): Likewise.
+       (ds_device_set_status): Likewise.
+       (ds_device_get_status): Likewise.
+       (ds_device_set_filter): Likewise.
+       (do_mach_notify_dead_name): Deallocate the port.
+       (ds_device_open): Get the name directly from the vether_device object.
+       (ds_device_close): Return 0 immediately.
+
+       * vdev.c (dev_head): Point to the head of the device list.
+       (print_eth_addr): Removed.
+       (lookup_dev_by_devport): Likewise.
+       (lookup_dev_by_name): Use the for loop to replace list_for_each_entry.
+       (remove_dead_port_from_dev): Likewise.
+       (all_dev_close): Likewise.
+       (broadcast_pack): Likewise.
+       (broadcast_msg): Likewise.
+       (add_vdev): Create the vether_device object with ports_create_port.
+       (has_vdev): Test if the device list is empty.
+
+       * vdev.h: Don't include list.h.
+       (vether_device): Include the port_info object instead of its pointer.
+       (next): Replace dev_list.
+
+       * list.h: Removed.
+
+2008-8-20 Zheng Da <address@hidden>
+
+       * README: Update.
+
+       * multiplexer.c (options): Update.
+
+2008-8-20 Zheng Da <address@hidden>
+
+       * multiplexer.c (main): Test device_file before using it.
+
+2008-8-20 Zheng Da <address@hidden>
+
+       * multiplexer.c (device_file): Rename a variable.
+       (main): Use device_file directly.
+
+2008-8-19 Zheng Da <address@hidden>
+
+       * multiplexer.c (main): Generate the device file name, and use it
+       to open the device.
+
+2008-8-18 Zheng Da <address@hidden>
+
+       * README: New file.
+
+       * multiplexer.c (options): Change the meaning of '-v' option.
+       (parse_opt): Change the way of handling '-v' option.
+
+       * vdev.c (has_vdev): New function.
+
+       * vdev.h (has_vdev): New declaration.
+
+2008-8-17 Zheng Da <address@hidden>
+
+       * ethernet.c (ethernet_open): Use a hard coded string for the device 
name.
+
+       * multiplexer.c: Remove the option '-M'.
+       (parse_opt): Remove the code of handling '-M' option.
+       (main): Get the master device port from the device file.
+
+2008-8-14 Zheng Da <address@hidden>
+
+       * ChangeLog: New file.
+
+       * multiplexer.c (vdev_portclass, other_portclass):
+       New variables.
+       (do_mach_notify_no_senders): Mark the device unused when there are no
+       senders for the device.
+       (do_mach_notify_dead_name): Return 0.
+       (ds_device_open): Mark the device used.
+       (ds_device_close): Remove the code of decreasing the count of the 
device.
+       (trivfs_goaway): Only test if all devices aren't used, and delete the 
code
+       of closing the device.
+       (parse_opt): Use vdev_portclass to create the virtual device.
+       (main): Create vdev_portclass and other_portclass, open the ethernet
+       device with other_portclass and create notify_pi with other_portclass.
+
+       * vdev.c (all_dev_close): Change the way of testing if all devices are
+       closed.
+
+       * vdev.h (vether_device): Replace count field with used.
+
+2008-8-13 Zheng Da <address@hidden>
+
+       * bpf_impl.c: New file.
+
+       * bpf_impl.h: New file.
+
+       * dev_stat.c: New file.
+
+       * ethernet.c: New file.
+
+       * ethernet.h: New file.
+
+       * list.h: New file.
+
+       * Makefile: New file.
+
+       * multiplexer.c: New file.
+
+       * queue.c: New file.
+
+       * queue.h: New file.
+
+       * test.c: New file.
+
+       * util.h: New file.
+
+       * vdev.c: New file.
+
+       * vdev.h: New file.
+
diff --git a/eth-multiplexer/Makefile b/eth-multiplexer/Makefile
new file mode 100644
index 0000000..35110a8
--- /dev/null
+++ b/eth-multiplexer/Makefile
@@ -0,0 +1,34 @@
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 2008 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; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := eth-multiplexer
+makemode := server
+target = eth-multiplexer
+
+#CFLAGS += -DDEBUG
+SRCS = ethernet.c vdev.c multiplexer.c dev_stat.c netfs_impl.c notify_impl.c 
device_impl.c demuxer.c
+MIGSTUBS = deviceServer.o notifyServer.o
+MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+device-MIGSFLAGS="-DMACH_PAYLOAD_TO_PORT=ports_payload_get_name"
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+LCLHDRS = ethernet.h util.h vdev.h netfs_impl.h
+HURDLIBS=ports fshelp shouldbeinlibc netfs bpf
+LDLIBS = -lpthread
+
+CFLAGS += -I$(top_srcdir)/libbpf
+
+include ../Makeconf
diff --git a/eth-multiplexer/README b/eth-multiplexer/README
new file mode 100644
index 0000000..940c7e4
--- /dev/null
+++ b/eth-multiplexer/README
@@ -0,0 +1,27 @@
+[Introduction]
+
+eth-multiplexer is a network multiplexer. It creates virtual ethernet 
interface and dispatches the packet to the right user program that opens its 
virtual interface. It also works as a bridge to connect the real ethernet 
interface and the virtual ones.
+
+
+[Usage]
+
+Usage: eth-multiplexer [OPTION...]
+Hurd multiplexer server.
+
+  -i, --interface=DEVICE     Network interface to use
+  -?, --help                 Give this help list
+      --usage                Give a short usage message
+  -V, --version              Print program version
+
+Mandatory or optional arguments to long options are also mandatory or optional
+for any corresponding short options.
+
+
+The '-i' option specifies the network interface the translator sits on. 
eth-multiplexer can only connect to one network interface and the '-i' option 
should be only used once. DEVICE is a device file that is created by the 
devnode translator.
+
+
+[Internal]
+
+eth-multiplexer implements the server side functions in device.defs, so other 
programs can access the virtual device as other devices. All information about 
the virtual interface is kept in the vether_device structure.
+When eth-multiplexer gets a packet from a virtual interface (which happens in 
ds_device_write) or from the real interface (which happens in 
ethernet_demuxer), it sends the packet to all other interfaces. eth-multipexer 
has BPF filters for each client. The BPF filter decides whether to deliver the 
packet. The packet delivery is done by deliver_pack(). There is no filter for 
the real network interface in eth-multiplexer, so every packet from the virtual 
interface will be sent to the real i [...]
+eth-multiplexer sets the real interface into the promiscuous mode, so 
eth-multiplexer can receive the packet with the virtual interface's hardware 
address from the real interface.
diff --git a/eth-multiplexer/demuxer.c b/eth-multiplexer/demuxer.c
new file mode 100644
index 0000000..1efbc6d
--- /dev/null
+++ b/eth-multiplexer/demuxer.c
@@ -0,0 +1,50 @@
+/*
+   Copyright (C) 1996, 2013 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#include <hurd/netfs.h>
+
+#include "libnetfs/io_S.h"
+#include "libnetfs/fs_S.h"
+#include "libports/notify_S.h"
+#include "libnetfs/fsys_S.h"
+#include "libports/interrupt_S.h"
+#include "libnetfs/ifsock_S.h"
+#include "device_S.h"
+
+int
+netfs_demuxer (mach_msg_header_t *inp,
+              mach_msg_header_t *outp)
+{
+  mig_routine_t routine;
+  if ((routine = netfs_io_server_routine (inp)) ||
+      (routine = netfs_fs_server_routine (inp)) ||
+      (routine = ports_notify_server_routine (inp)) ||
+      (routine = netfs_fsys_server_routine (inp)) ||
+      (routine = ports_interrupt_server_routine (inp)) ||
+      (routine = netfs_ifsock_server_routine (inp)) ||
+      (routine = device_server_routine (inp)))
+    {
+      (*routine) (inp, outp);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
diff --git a/eth-multiplexer/dev_stat.c b/eth-multiplexer/dev_stat.c
new file mode 100644
index 0000000..bfbb433
--- /dev/null
+++ b/eth-multiplexer/dev_stat.c
@@ -0,0 +1,101 @@
+ /*
+  * Mach Operating System
+  * Copyright (c) 1993-1989 Carnegie Mellon University
+  * All Rights Reserved.
+  *
+  * Permission to use, copy, modify and distribute this software and its
+  * documentation is hereby granted, provided that both the copyright
+  * notice and this permission notice appear in all copies of the
+  * software, derivative works or modified versions, and any portions
+  * thereof, and that both notices appear in supporting documentation.
+  *
+  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+  *
+  * Carnegie Mellon requests users of this software to return to
+  *
+  *  Software Distribution Coordinator  or  address@hidden
+  *  School of Computer Science
+  *  Carnegie Mellon University
+  *  Pittsburgh PA 15213-3890
+  *
+  * any improvements or extensions that they make and grant Carnegie Mellon
+  * the rights to redistribute these changes.
+  */
+/*
+ *     Author: David B. Golub, Carnegie Mellon University
+ *     Date:   3/98
+ *
+ *     Network IO.
+ *
+ *     Packet filter code taken from vaxif/enet.c written
+ *             CMU and Stanford.
+ */
+
+/* the code copied from device/net_io.c in Mach */
+
+#include <string.h>
+#include <arpa/inet.h>
+
+#include <mach.h>
+
+#include "vdev.h"
+
+io_return_t
+dev_getstat(struct vether_device *ifp, dev_flavor_t flavor,
+               dev_status_t status, natural_t *count)
+{
+       switch (flavor) {
+               case NET_STATUS:
+                       {
+                               register struct net_status *ns = (struct 
net_status *)status;
+
+                               if (*count < NET_STATUS_COUNT)
+                                       return (D_INVALID_OPERATION);
+
+                               ns->min_packet_size = ifp->if_header_size;
+                               ns->max_packet_size = ifp->if_header_size + 
ifp->if_mtu;
+                               ns->header_format = ifp->if_header_format;
+                               ns->header_size = ifp->if_header_size;
+                               ns->address_size = ifp->if_address_size;
+                               ns->flags = ifp->if_flags;
+                               ns->mapped_size = 0;
+
+                               *count = NET_STATUS_COUNT;
+                               break;
+                       }
+               case NET_ADDRESS:
+                       {
+                               register int    addr_byte_count;
+                               register int    addr_int_count;
+                               register int    i;
+
+                               addr_byte_count = ifp->if_address_size;
+                               addr_int_count = (addr_byte_count + 
(sizeof(int)-1))
+                                       / sizeof(int);
+
+                               if (*count < addr_int_count) {
+                                       return (D_INVALID_OPERATION);
+                               }
+
+                               memcpy(status, ifp->if_address, 
addr_byte_count);
+                               if (addr_byte_count < addr_int_count * 
sizeof(int))
+                                       memset((char *)status + 
addr_byte_count, 0,
+                                                       (addr_int_count * 
sizeof(int)
+                                                        - addr_byte_count));
+
+                               for (i = 0; i < addr_int_count; i++) {
+                                       register int word;
+
+                                       word = status[i];
+                                       status[i] = htonl(word);
+                               }
+                               *count = addr_int_count;
+                               break;
+                       }
+               default:
+                       return (D_INVALID_OPERATION);
+       }
+       return (D_SUCCESS);
+}
diff --git a/eth-multiplexer/device_impl.c b/eth-multiplexer/device_impl.c
new file mode 100644
index 0000000..d96fc0f
--- /dev/null
+++ b/eth-multiplexer/device_impl.c
@@ -0,0 +1,213 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <fcntl.h>
+#include <mach.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/netfs.h>
+#include <device/device.h>
+
+#include "ethernet.h"
+#include "vdev.h"
+#include "device_S.h"
+#include "notify_S.h"
+#include "bpf_impl.h"
+#include "netfs_impl.h"
+#include "util.h"
+
+extern struct port_bucket *port_bucket;
+extern struct port_class *vdev_portclass;
+extern struct port_class *other_portclass;
+extern struct port_info *notify_pi;
+
+/* Implementation of device interface */
+
+/*
+ * This function is currently running in the multithread environment,
+ * it should be protected by locks.
+ */
+kern_return_t
+ds_device_open (mach_port_t master_port, mach_port_t reply_port,
+               mach_msg_type_name_t reply_portPoly,
+               dev_mode_t mode, dev_name_t name, mach_port_t *device,
+               mach_msg_type_name_t *devicetype)
+{
+  struct vether_device *dev;
+  struct protid *pi = ports_lookup_port (netfs_port_bucket, master_port, 0);
+  if (pi == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  /* If the virtual device hasn't been created yet,
+   * create it now. */
+  if (pi->po->np->nn->ln == NULL)
+    {
+      extern struct port_bucket *port_bucket;
+      extern struct port_class *vdev_portclass;
+      extern struct stat underlying_node_stat;
+      static int ino_count = 0;
+      /* Create a new light node (virtual device). */
+      struct lnode *ln = (struct lnode *) add_vdev (pi->po->np->nn->name,
+                                                   sizeof (*ln),
+                                                   vdev_portclass,
+                                                   port_bucket);
+      if (ln == NULL)
+       {
+         ports_port_deref (pi);
+         return D_NO_MEMORY;
+       }
+      memset (&ln->st, 0, sizeof (ln->st));
+      ln->st.st_ino = ++ino_count;
+      ln->st.st_mode = S_IFCHR | (underlying_node_stat.st_mode & ~S_IFMT);
+      ln->st.st_ctime = ln->st.st_mtime = ln->st.st_atime = time (NULL);
+      fshelp_touch (&ln->st, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+                   multiplexer_maptime);
+      pi->po->np->nn->ln = ln;
+    }
+
+  dev = (struct vether_device *) pi->po->np->nn->ln;
+  if (dev)
+    {
+      *device = dev->dev_port;
+      *devicetype = MACH_MSG_TYPE_MAKE_SEND;
+      return 0;
+    }
+  return D_NO_SUCH_DEVICE;
+}
+
+kern_return_t
+ds_device_close (struct vether_device *device)
+{
+  return 0;
+}
+
+kern_return_t
+ds_device_write (struct vether_device *vdev, mach_port_t reply_port,
+                mach_msg_type_name_t reply_type, dev_mode_t mode,
+                recnum_t recnum, io_buf_ptr_t data, size_t datalen,
+                int *bytes_written)
+{
+  kern_return_t ret = 0;
+  if (vdev == NULL)
+    {
+      vm_deallocate (mach_task_self (), (vm_address_t) data, datalen);
+      return D_NO_SUCH_DEVICE;
+    }
+  /* The packet is forwarded to all virtual interfaces and
+   * the interface which the multiplexer connects to. */
+  broadcast_pack (data, datalen, vdev);
+  *bytes_written = datalen;
+  if(ether_port != MACH_PORT_NULL)
+    ret = device_write (ether_port, mode , recnum ,
+                       data, datalen, bytes_written);
+  /* The data in device_write() is transmifered out of line,
+   * so the server-side function has to deallocate it. */
+  vm_deallocate (mach_task_self (), (vm_address_t) data, datalen);
+  return ret;
+}
+
+kern_return_t
+ds_device_write_inband (struct vether_device *vdev, mach_port_t reply_port,
+                       mach_msg_type_name_t reply_type, dev_mode_t mode,
+                       recnum_t recnum, io_buf_ptr_inband_t data,
+                       size_t datalen, int *bytes_written)
+{
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read (struct vether_device *vdev, mach_port_t reply_port,
+               mach_msg_type_name_t reply_type, dev_mode_t mode,
+               recnum_t recnum, int bytes_wanted,
+               io_buf_ptr_t *data, size_t *datalen)
+{
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read_inband (struct vether_device *vdev, mach_port_t reply_port,
+                      mach_msg_type_name_t reply_type, dev_mode_t mode,
+                      recnum_t recnum, int bytes_wanted,
+                      io_buf_ptr_inband_t data, size_t *datalen)
+{
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_map (struct vether_device *vdev, vm_prot_t prot, vm_offset_t offset,
+              vm_size_t size, memory_object_t *pager, int unmap)
+{
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_set_status (struct vether_device *vdev, dev_flavor_t flavor,
+                     dev_status_t status, size_t statuslen)
+{
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_get_status (struct vether_device *vdev, dev_flavor_t flavor,
+                     dev_status_t status, size_t *statuslen)
+{
+  extern io_return_t dev_getstat (struct vether_device *, dev_flavor_t,
+                                 dev_status_t, natural_t *);
+  kern_return_t ret = 0;
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  if(ether_port != MACH_PORT_NULL)
+    ret = device_get_status (ether_port, flavor, status, statuslen);
+  else
+    ret = dev_getstat (vdev, flavor, status, statuslen);
+  return ret;
+}
+
+kern_return_t
+ds_device_set_filter (struct vether_device *vdev, mach_port_t receive_port,
+                     int priority, filter_array_t filter, size_t filterlen)
+{
+  mach_port_t tmp;
+  kern_return_t err;
+  if (vdev == NULL)
+    return D_NO_SUCH_DEVICE;
+  err = mach_port_request_notification (mach_task_self (), receive_port,
+                                       MACH_NOTIFY_DEAD_NAME, 0,
+                                       ports_get_right (notify_pi),
+                                       MACH_MSG_TYPE_MAKE_SEND_ONCE, &tmp);
+  if (err != KERN_SUCCESS)
+    goto out;
+  if (tmp != MACH_PORT_NULL)
+    mach_port_deallocate (mach_task_self (), tmp);
+  err = net_set_filter (&vdev->port_list, receive_port,
+                       priority, filter, filterlen);
+out:
+  return err;
+}
diff --git a/eth-multiplexer/ethernet.c b/eth-multiplexer/ethernet.c
new file mode 100644
index 0000000..002f30c
--- /dev/null
+++ b/eth-multiplexer/ethernet.c
@@ -0,0 +1,143 @@
+/*
+   Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007, 2008
+   Free Software Foundation, Inc.
+
+   Written by Zheng Da
+
+   Based on pfinet/ethernet.c, 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#include <string.h>
+#include <error.h>
+#include <assert.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include <hurd/ports.h>
+#include <device/device.h>
+#include <device/net_status.h>
+
+#include "ethernet.h"
+#include "vdev.h"
+#include "util.h"
+
+#define ETH_HLEN 14
+
+static struct port_info *readpt;
+
+/* Port for writing message to the real network interface. */
+mach_port_t ether_port;
+/* Port for receiving messages from the interface. */
+static mach_port_t readptname;
+
+/* The BPF instruction allows IP and ARP packets */
+static struct bpf_insn ether_filter[] =
+{
+    {NETF_IN|NETF_BPF, /* Header. */ 0, 0, 0},
+    {40, 0, 0, 12},
+    {21, 1, 0, 2054},
+    {21, 0, 1, 2048},
+    {6, 0, 0, 1500},
+    {6, 0, 0, 0}
+};
+static int ether_filter_len = sizeof (ether_filter) / sizeof (short);
+
+int ethernet_demuxer (mach_msg_header_t *inp,
+                     mach_msg_header_t *outp)
+{
+  struct net_rcv_msg *msg = (struct net_rcv_msg *) inp;
+
+  if (inp->msgh_id != NET_RCV_MSG_ID)
+    return 0;
+
+  broadcast_msg (msg);
+  /* The data from the underlying network is inside the message,
+   * so we don't need to deallocate the data. */
+  return 1;
+}
+
+int set_promisc (char *dev_name, mach_port_t ether_port, int is_promisc)
+{
+#ifndef NET_FLAGS
+#define NET_FLAGS (('n'<<16) + 4)
+#endif
+  int flags;
+  int ret;
+  size_t count;
+
+  debug ("set_promisc is called, is_promisc: %d\n", is_promisc);
+  count = 1;
+  ret = device_get_status (ether_port, NET_FLAGS, (dev_status_t) &flags,
+                           &count);
+  if (ret)
+    {
+      error (0, ret, "device_get_status");
+      return -1;
+    }
+  if (is_promisc)
+    flags |= IFF_PROMISC;
+  else
+    flags &= ~IFF_PROMISC;
+  ret = device_set_status(ether_port, NET_FLAGS, (dev_status_t) &flags, 1);
+  if (ret)
+    {
+      error (0, ret, "device_set_status");
+      return -1;
+    }
+  return 0;
+}
+
+int ethernet_open (char *dev_name, device_t master_device,
+                  struct port_bucket *etherport_bucket,
+                  struct port_class *etherreadclass)
+{
+  error_t err;
+
+  assert (ether_port == MACH_PORT_NULL);
+
+  err = ports_create_port (etherreadclass, etherport_bucket,
+                          sizeof (struct port_info), &readpt);
+  if (err)
+    error (2, err, "ports_create_port");
+  readptname = ports_get_right (readpt);
+  mach_port_insert_right (mach_task_self (), readptname, readptname,
+                         MACH_MSG_TYPE_MAKE_SEND);
+
+  mach_port_set_qlimit (mach_task_self (), readptname, MACH_PORT_QLIMIT_MAX);
+
+  err = device_open (master_device, D_WRITE | D_READ, "eth", &ether_port);
+  mach_port_deallocate (mach_task_self (), master_device);
+  if (err)
+    error (2, err, "device_open: %s", dev_name);
+
+  err = device_set_filter (ether_port, ports_get_right (readpt),
+                          MACH_MSG_TYPE_MAKE_SEND, 0,
+                          (unsigned short *)ether_filter, ether_filter_len);
+  if (err)
+    error (2, err, "device_set_filter: %s", dev_name);
+
+  set_promisc (dev_name, ether_port, 1);
+  return 0;
+}
+
+int ethernet_close (char *dev_name)
+{
+  set_promisc (dev_name, ether_port, 0);
+  return 0;
+}
+
diff --git a/eth-multiplexer/ethernet.h b/eth-multiplexer/ethernet.h
new file mode 100644
index 0000000..8efab9b
--- /dev/null
+++ b/eth-multiplexer/ethernet.h
@@ -0,0 +1,39 @@
+/*
+   Copyright (C) 2008
+   Free Software Foundation, Inc.
+
+   Written by Zheng Da.
+
+   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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#ifndef ETHERNET_H
+#define ETHERNET_H
+
+#include <netinet/in.h>
+#include <stdlib.h>
+
+extern mach_port_t ether_port;
+
+int ethernet_open (char *dev_name, device_t master_device,
+                  struct port_bucket *etherport_bucket,
+                  struct port_class *etherreadclass);
+int ethernet_close (char *dev_name);
+int ethernet_demuxer (mach_msg_header_t *inp,
+                     mach_msg_header_t *outp);
+
+#endif
+
diff --git a/eth-multiplexer/mig-decls.h b/eth-multiplexer/mig-decls.h
new file mode 100644
index 0000000..6ad9ebf
--- /dev/null
+++ b/eth-multiplexer/mig-decls.h
@@ -0,0 +1,51 @@
+/*
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Written by Justus Winter.
+
+   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 __ETH_MULTIPLEXER_MIG_DECLS_H__
+#define __ETH_MULTIPLEXER_MIG_DECLS_H__
+
+#include <hurd/ports.h>
+
+typedef struct vether_device *vether_device_t;
+
+extern struct port_bucket *port_bucket;
+extern struct port_class *vdev_portclass;
+
+/* Called by server stub functions.  */
+
+static inline struct vether_device * __attribute__ ((unused))
+begin_using_device_port (mach_port_t port)
+{
+  return ports_lookup_port (port_bucket, port, vdev_portclass);
+}
+
+static inline struct vether_device * __attribute__ ((unused))
+begin_using_device_payload (unsigned long payload)
+{
+  return ports_lookup_payload (port_bucket, payload, vdev_portclass);
+}
+
+static inline void __attribute__ ((unused))
+end_using_device (struct vether_device *p)
+{
+  if (p)
+    ports_port_deref (p);
+}
+
+#endif /* __ETH_MULTIPLEXER_MIG_DECLS_H__ */
diff --git a/eth-multiplexer/mig-mutate.h b/eth-multiplexer/mig-mutate.h
new file mode 100644
index 0000000..55eca31
--- /dev/null
+++ b/eth-multiplexer/mig-mutate.h
@@ -0,0 +1,36 @@
+/*
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Written by Justus Winter.
+
+   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/>.  */
+
+#define NOTIFY_INTRAN                                          \
+  port_info_t begin_using_port_info_port (mach_port_t)
+#define NOTIFY_INTRAN_PAYLOAD                                  \
+  port_info_t begin_using_port_info_payload
+#define NOTIFY_DESTRUCTOR                                      \
+  end_using_port_info (port_info_t)
+#define NOTIFY_IMPORTS                                         \
+  import "libports/mig-decls.h";
+
+#define DEVICE_INTRAN                                          \
+  vether_device_t begin_using_device_port (mach_port_t)
+#define DEVICE_INTRAN_PAYLOAD                                  \
+  vether_device_t begin_using_device_payload
+#define DEVICE_DESTRUCTOR                                      \
+  end_using_device (vether_device_t)
+#define DEVICE_IMPORTS                                         \
+  import "eth-multiplexer/mig-decls.h";
diff --git a/eth-multiplexer/multiplexer.c b/eth-multiplexer/multiplexer.c
new file mode 100644
index 0000000..9b661cd
--- /dev/null
+++ b/eth-multiplexer/multiplexer.c
@@ -0,0 +1,214 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+ * The multiplexer server provides the virtual network interface.
+ * When it gets a packet, it forwards it to every other network interface,
+ * the ones that are created by itself or that it connects to.
+ * BPF is ported to the multiplexer to help deliver packets
+ * to the right pfinet.
+ */
+
+#include <argz.h>
+#include <argp.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <hurd.h>
+#include <mach.h>
+#include <version.h>
+#include <device/device.h>
+#include <hurd/ports.h>
+#include <hurd/netfs.h>
+#include <version.h>
+
+#include "ethernet.h"
+#include "vdev.h"
+#include "device_S.h"
+#include "notify_S.h"
+#include "bpf_impl.h"
+#include "netfs_impl.h"
+#include "util.h"
+
+/* The device which the multiplexer connects to */
+static char *device_file;
+
+const char *argp_program_version = STANDARD_HURD_VERSION (eth-multiplexer);
+
+static const char doc[] = "Hurd multiplexer server.";
+static const struct argp_option options[] =
+{
+    {"interface", 'i', "DEVICE", 0,
+      "Network interface to use", 2},
+    {0}
+};
+
+/* Port bucket we service requests on.  */
+struct port_bucket *port_bucket;
+struct port_class *other_portclass;
+struct port_class *vdev_portclass;
+struct port_info *notify_pi;
+
+int netfs_maxsymlinks = 12;
+char *netfs_server_name = "multiplexer";
+char *netfs_server_version = HURD_VERSION;
+file_t root_file;
+struct lnode root;
+struct stat underlying_node_stat;
+
+static int
+multiplexer_demuxer (mach_msg_header_t *inp,
+                 mach_msg_header_t *outp)
+{
+  mig_routine_t routine;
+  if ((routine = NULL, ethernet_demuxer (inp, outp)) ||
+      (routine = device_server_routine (inp)) ||
+      (routine = notify_server_routine (inp)))
+    {
+      if (routine)
+        (*routine) (inp, outp);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void *
+multiplexer_thread (void *arg)
+{
+  ports_manage_port_operations_one_thread (port_bucket,
+                                          multiplexer_demuxer,
+                                          0);
+  return 0;
+}
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+  switch (opt)
+    {
+    case 'i':
+      device_file = arg;
+      break;
+    case ARGP_KEY_ERROR:
+    case ARGP_KEY_SUCCESS:
+    case ARGP_KEY_INIT:
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  error_t err;
+  mach_port_t bootstrap;
+  mach_port_t master_device;
+  const struct argp argp = { options, parse_opt, 0, doc };
+  pthread_t t;
+
+  port_bucket = ports_create_bucket ();
+  other_portclass = ports_create_class (0, 0);
+  vdev_portclass = ports_create_class (destroy_vdev, 0);
+
+  argp_parse (&argp, argc, argv, 0, 0, 0);
+
+  /* Open the network interface. */
+  if (device_file)
+    {
+      master_device = file_name_lookup (device_file, 0, 0);
+      if (master_device == MACH_PORT_NULL)
+       error (1, errno, "file_name_lookup");
+
+      ethernet_open (device_file, master_device, port_bucket,
+                    other_portclass);
+    }
+
+  /* Prepare for the notification. */
+  err = ports_create_port (other_portclass, port_bucket,
+                          sizeof (struct port_info), &notify_pi);
+  if (err)
+    error (1, err, "ports_create_port for notification");
+
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
+  if (bootstrap == MACH_PORT_NULL)
+    error (1, 0, "must be started as a translator");
+
+  /* Run the multiplexer server in another thread. */
+  pthread_create (&t, NULL, multiplexer_thread, NULL);
+  pthread_detach (t);
+
+  err = maptime_map (0, 0, &multiplexer_maptime);
+  if (err)
+    error (4, err, "Cannot map time");
+
+  /* Initialize netfs and start the translator. */
+  netfs_init ();
+
+  root_file = netfs_startup (bootstrap, O_READ);
+  err = new_node (&root, &netfs_root_node);
+  if (err)
+    error (5, err, "Cannot create root node");
+
+  err = io_stat (root_file, &underlying_node_stat);
+  if (err)
+    error (6, err, "Cannot stat underlying node");
+
+  struct stat stat = underlying_node_stat;
+  /* If the underlying node is not a directory, increase its permissions */
+  if(!S_ISDIR(stat.st_mode))
+    {
+      if(stat.st_mode & S_IRUSR)
+       stat.st_mode |= S_IXUSR;
+      if(stat.st_mode & S_IRGRP)
+       stat.st_mode |= S_IXGRP;
+      if(stat.st_mode & S_IROTH)
+       stat.st_mode |= S_IXOTH;
+    }
+
+  stat.st_mode &= ~(S_ITRANS | S_IFMT);
+  stat.st_mode |= S_IFDIR;
+  netfs_root_node->nn->ln->st = stat;
+  fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+               multiplexer_maptime);
+
+  netfs_server_loop ();         /* Never returns.  */
+  return 0;
+}
+
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+  error_t err = 0;
+
+#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)
+  if (device_file)
+    ADD_OPT ("--interface=%s", device_file);
+#undef ADD_OPT
+  return err;
+}
diff --git a/eth-multiplexer/netfs_impl.c b/eth-multiplexer/netfs_impl.c
new file mode 100644
index 0000000..040512a
--- /dev/null
+++ b/eth-multiplexer/netfs_impl.c
@@ -0,0 +1,508 @@
+/*
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <hurd/netfs.h>
+
+#include "netfs_impl.h"
+#include "vdev.h"
+#include "util.h"
+
+#define DIRENTS_CHUNK_SIZE      (8*1024)
+/* Returned directory entries are aligned to blocks this many bytes long.
+ * Must be a power of two.  */
+#define DIRENT_ALIGN 4
+#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name)
+
+/* Length is structure before the name + the name + '\0', all
+ *    padded to a four-byte alignment.  */
+#define DIRENT_LEN(name_len)                                                  \
+  ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1))                   \
+   & ~(DIRENT_ALIGN - 1))
+
+extern struct stat underlying_node_stat;
+
+int
+is_num (char *str)
+{
+  for (; *str; str++)
+    {
+      if (!isdigit (*str))
+       return 0;
+    }
+  return 1;
+}
+
+/* Make a new virtual node.  Always consumes the ports.  */
+error_t
+new_node (struct lnode *ln, struct node **np)
+{
+  error_t err = 0;
+  struct netnode *nn = calloc (1, sizeof *nn);
+  struct node *node;
+
+  if (nn == 0)
+    return ENOMEM;
+  node = netfs_make_node (nn);
+  if (node == 0)
+    {
+      free (nn);
+      *np = NULL;
+      return ENOMEM;
+    }
+  if (ln)
+    ln->n = node;
+  nn->ln = ln;
+  *np = node;
+  return err;
+}
+
+struct node *
+lookup (char *name)
+{
+  struct lnode *ln = (struct lnode *) lookup_dev_by_name (name);
+
+  char *copied_name = malloc (strlen (name) + 1);
+  strcpy (copied_name, name);
+  if (ln)
+    {
+      new_node (ln, &ln->n);
+      ln->n->nn->name = copied_name;
+      return ln->n;
+    }
+  else
+    {
+      struct node *n;
+      new_node (ln, &n);
+      n->nn->name = copied_name;
+      return n;
+    }
+}
+
+/* Attempt to create a file named NAME in DIR for USER with MODE.  Set *NODE
+   to the new node upon return.  On any error, clear *NODE.  *NODE should be
+   locked on success; no matter what, unlock DIR before returning.  */
+error_t
+netfs_attempt_create_file (struct iouser *user, struct node *dir,
+                          char *name, mode_t mode, struct node **node)
+{
+  debug("");
+  *node = 0;
+  pthread_mutex_unlock (&dir->lock);
+  return EOPNOTSUPP;
+}
+
+/* Node NODE is being opened by USER, with FLAGS.  NEWNODE is nonzero if we
+   just created this node.  Return an error if we should not permit the open
+   to complete because of a permission restriction. */
+error_t
+netfs_check_open_permissions (struct iouser *user, struct node *node,
+                             int flags, int newnode)
+{
+  error_t err = 0;
+
+  /*Cheks user's permissions*/
+  if(flags & O_READ)
+    err = fshelp_access(&node->nn_stat, S_IREAD, user);
+  if(!err && (flags & O_WRITE))
+    err = fshelp_access(&node->nn_stat, S_IWRITE, user);
+  if(!err && (flags & O_EXEC))
+    err = fshelp_access(&node->nn_stat, S_IEXEC, user);
+
+  debug("the mode of node: %o, return result: %d",
+       (node->nn_stat.st_mode & ~S_IFMT), err);
+  /*Return the result of the check*/
+  return err;
+}
+
+/* This should attempt a utimes call for the user specified by CRED on node
+   NODE, to change the atime to ATIME and the mtime to MTIME. */
+error_t
+netfs_attempt_utimes (struct iouser *cred, struct node *node,
+                     struct timespec *atime, struct timespec *mtime)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and O_EXEC)
+   in *TYPES for file NODE and user CRED.  */
+error_t
+netfs_report_access (struct iouser *cred, struct node *node, int *types)
+{
+  debug("");
+  *types = 0;
+  return 0;
+}
+
+/* Make sure that NP->nn_stat is filled with current information.  CRED
+   identifies the user responsible for the operation.  */
+error_t
+netfs_validate_stat (struct node *node, struct iouser *cred)
+{
+  struct stat st;
+
+  if (node->nn->ln)
+    st = node->nn->ln->st;
+  else
+    st = underlying_node_stat;
+
+  debug("node: %p", node);
+  node->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0;
+  node->nn_stat = st;
+  return 0;
+}
+
+/* This should sync the file NODE completely to disk, for the user CRED.  If
+   WAIT is set, return only after sync is completely finished.  */
+error_t
+netfs_attempt_sync (struct iouser *cred, struct node *node, int wait)
+{
+  debug("");
+  return 0;
+}
+
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+                  int first_entry, int max_entries, char **data,
+                  mach_msg_type_number_t *data_len,
+                  vm_size_t max_data_len, int *data_entries)
+{
+  error_t err;
+  int count = 0;
+  char *data_p;
+  size_t size = (max_data_len == 0 || max_data_len > DIRENTS_CHUNK_SIZE
+     ? DIRENTS_CHUNK_SIZE : max_data_len);
+  debug ("");
+  int
+    add_dirent (const char * name, ino_t ino, int type)
+      {
+       /*If the required number of dirents has not been listed yet*/
+       if((max_entries == -1) || (count < max_entries))
+         {
+           struct dirent hdr;
+           size_t name_len = strlen(name);
+           size_t sz = DIRENT_LEN(name_len);
+
+           /*If there is no room for this dirent*/
+           if ((data_p - *data) + sz > size)
+             {
+               if (max_data_len > 0)
+                 return 1;
+               else
+                 /* Try to grow our return buffer.  */
+                 {
+                   error_t err;
+                   vm_address_t extension = (vm_address_t)(*data + size);
+                   err = vm_allocate (mach_task_self (), &extension,
+                                      DIRENTS_CHUNK_SIZE, 0);
+                   if (err)
+                     {
+                       munmap (*data, size);
+                       return 1;
+                     }
+                   size += DIRENTS_CHUNK_SIZE;
+                 }
+             }
+
+           /*setup the dirent*/
+           hdr.d_ino = ino;
+           hdr.d_reclen = sz;
+           hdr.d_type = type;
+           hdr.d_namlen = name_len;
+           memcpy(data_p, &hdr, DIRENT_NAME_OFFS);
+           strcpy(data_p + DIRENT_NAME_OFFS, name);
+           data_p += sz;
+
+           /*count the new dirent*/
+           ++count;
+         }
+       return 0;
+      }
+  int add_each_dev (struct vether_device *dev)
+    {
+      struct lnode *ln = (struct lnode *) dev;
+      add_dirent (ln->vdev.name, ln->st.st_ino, DT_CHR);
+      return 0;
+    }
+  if (dir != netfs_root_node)
+    return ENOTDIR;
+
+  *data = mmap (0, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+  err = ((void *) *data == (void *) -1) ? errno : 0;
+  if (!err)
+    {
+      data_p = *data;
+      if (first_entry < 2 + get_dev_num ())
+       {
+         add_dirent (".", 2, DT_DIR);
+         add_dirent ("..", 2, DT_DIR);
+         foreach_dev_do (add_each_dev);
+       }
+
+      vm_address_t alloc_end = (vm_address_t)(*data + size);
+      vm_address_t real_end = round_page (data_p);
+      if (alloc_end > real_end)
+       munmap ((caddr_t) real_end, alloc_end - real_end);
+      *data_entries = count;
+      debug ("first_entry is %d, count is %d", first_entry, count);
+      *data_len = data_p - *data;
+    }
+  return err;
+}
+
+/* Lookup NAME in DIR for USER; set *NODE to the found name upon return.  If
+   the name was not found, then return ENOENT.  On any error, clear *NODE.
+   (*NODE, if found, should be locked, this call should unlock DIR no matter
+   what.) */
+error_t netfs_attempt_lookup (struct iouser *user, struct node *dir,
+                             char *name, struct node **node)
+{
+  error_t err = 0;
+
+  debug ("dir: %p, file name: %s", dir, name);
+
+  if (strcmp(name, ".") == 0)
+    {
+      netfs_nref(dir);
+      *node = dir;
+      return 0;
+    }
+  else if (strcmp(name, "..") == 0)
+    {
+      /*The supplied node is always root*/
+      err = ENOENT;
+      *node = NULL;
+
+      /*unlock the directory*/
+      pthread_mutex_unlock (&dir->lock);
+
+      /*stop here*/
+      return err;
+    }
+
+  *node = lookup (name);
+  pthread_mutex_lock (&(*node)->lock);
+  pthread_mutex_unlock (&dir->lock);
+  return 0;
+}
+
+/* Delete NAME in DIR for USER. */
+error_t netfs_attempt_unlink (struct iouser *user, struct node *dir,
+                             char *name)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Note that in this one call, neither of the specific nodes are locked. */
+error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+                             char *fromname, struct node *todir,
+                             char *toname, int excl)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Attempt to create a new directory named NAME in DIR for USER with mode
+   MODE.  */
+error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+                            char *name, mode_t mode)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Attempt to remove directory named NAME in DIR for USER. */
+error_t netfs_attempt_rmdir (struct iouser *user,
+                            struct node *dir, char *name)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should attempt a chmod call for the user specified by CRED on node
+   NODE, to change the owner to UID and the group to GID. */
+error_t netfs_attempt_chown (struct iouser *cred, struct node *node,
+                            uid_t uid, uid_t gid)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should attempt a chauthor call for the user specified by CRED on node
+   NODE, to change the author to AUTHOR. */
+error_t netfs_attempt_chauthor (struct iouser *cred, struct node *node,
+                               uid_t author)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should attempt a chmod call for the user specified by CRED on node
+   NODE, to change the mode to MODE.  Unlike the normal Unix and Hurd meaning
+   of chmod, this function is also used to attempt to change files into other
+   types.  If such a transition is attempted which is impossible, then return
+   EOPNOTSUPP.  */
+error_t netfs_attempt_chmod (struct iouser *cred, struct node *node,
+                            mode_t mode)
+{
+  error_t err = 0;
+  debug("");
+  if (node->nn->ln == NULL)
+    return EOPNOTSUPP;
+
+  mode &= ~S_ITRANS;
+  err = fshelp_isowner (&node->nn->ln->st, cred);
+  if (err)
+    return err;
+  mode |= node->nn->ln->st.st_mode & S_IFMT;
+  node->nn->ln->st.st_mode = mode;
+  fshelp_touch (&node->nn_stat, TOUCH_CTIME, multiplexer_maptime);
+  return err;
+}
+
+/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */
+error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *node,
+                                char *name)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Attempt to turn NODE (user CRED) into a device.  TYPE is either S_IFBLK or
+   S_IFCHR. */
+error_t netfs_attempt_mkdev (struct iouser *cred, struct node *node,
+                            mode_t type, dev_t indexes)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Attempt to set the passive translator record for FILE to ARGZ (of length
+   ARGZLEN) for user CRED. */
+error_t netfs_set_translator (struct iouser *cred, struct node *node,
+                             char *argz, size_t argzlen)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should attempt a chflags call for the user specified by CRED on node
+   NODE, to change the flags to FLAGS. */
+error_t netfs_attempt_chflags (struct iouser *cred, struct node *node,
+                              int flags)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should attempt to set the size of the file NODE (for user CRED) to
+   SIZE bytes long. */
+error_t netfs_attempt_set_size (struct iouser *cred, struct node *node,
+                               off_t size)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/*Fetches the filesystem status information*/
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *node,
+                     struct statfs *st)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* This should sync the entire remote filesystem.  If WAIT is set, return
+   only after sync is completely finished.  */
+error_t netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+  debug("");
+  return 0;
+}
+
+/* Create a link in DIR with name NAME to FILE for USER.  Note that neither
+   DIR nor FILE are locked.  If EXCL is set, do not delete the target, but
+   return EEXIST if NAME is already found in DIR.  */
+error_t netfs_attempt_link (struct iouser *user, struct node *dir,
+                           struct node *file, char *name, int excl)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Attempt to create an anonymous file related to DIR for USER with MODE.
+   Set *NODE to the returned file upon success.  No matter what, unlock DIR. */
+error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir,
+                             mode_t mode, struct node **node)
+{
+  debug("");
+  *node = 0;
+  pthread_mutex_unlock (&dir->lock);
+  return EOPNOTSUPP;
+}
+
+/* Read the contents of NODE (a symlink), for USER, into BUF. */
+error_t netfs_attempt_readlink (struct iouser *user, struct node *node, char 
*buf)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Read from the file NODE for user CRED starting at OFFSET and continuing for
+   up to *LEN bytes.  Put the data at DATA.  Set *LEN to the amount
+   successfully read upon return.  */
+error_t netfs_attempt_read (struct iouser *cred, struct node *node,
+                           off_t offset, size_t *len, void *data)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Write to the file NODE for user CRED starting at OFSET and continuing for up
+   to *LEN bytes from DATA.  Set *LEN to the amount seccessfully written upon
+   return. */
+error_t netfs_attempt_write (struct iouser *cred, struct node *node,
+                            off_t offset, size_t *len, void *data)
+{
+  debug("");
+  return EOPNOTSUPP;
+}
+
+/* Node NP is all done; free all its associated storage. */
+void
+netfs_node_norefs (struct node *node)
+{
+  debug("node: %p", node);
+  if (node->nn->ln)
+    node->nn->ln->n = NULL;
+  free (node->nn->name);
+  free (node->nn);
+  free (node);
+}
+
diff --git a/eth-multiplexer/netfs_impl.h b/eth-multiplexer/netfs_impl.h
new file mode 100644
index 0000000..a3b4c7d
--- /dev/null
+++ b/eth-multiplexer/netfs_impl.h
@@ -0,0 +1,47 @@
+/*
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef NETFS_IMPL
+#define NETFS_IMPL
+
+#include <hurd.h>
+#include <mach.h>
+
+#include "vdev.h"
+
+struct netnode
+{
+  struct lnode *ln;
+  char *name;
+};
+
+struct lnode
+{
+  struct vether_device vdev;
+  struct stat st;
+  struct node *n;
+};
+
+extern file_t root_file;
+volatile struct mapped_time_value *multiplexer_maptime;
+
+error_t new_node (struct lnode *ln, struct node **np);
+
+#endif
diff --git a/eth-multiplexer/notify_impl.c b/eth-multiplexer/notify_impl.c
new file mode 100644
index 0000000..eef5544
--- /dev/null
+++ b/eth-multiplexer/notify_impl.c
@@ -0,0 +1,69 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <mach.h>
+
+#include "vdev.h"
+
+/* Implementation of notify interface */
+kern_return_t
+do_mach_notify_port_deleted (struct port_info *pi,
+                            mach_port_t name)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (struct port_info *pi,
+                            mach_port_t name)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (struct port_info *pi,
+                              mach_port_t port)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (struct port_info *pi,
+                          mach_port_mscount_t mscount)
+{
+  return ports_do_mach_notify_no_senders (pi, mscount);
+}
+
+kern_return_t
+do_mach_notify_send_once (struct port_info *pi)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_dead_name (struct port_info *pi,
+                         mach_port_t name)
+{
+  debug ("do_mach_notify_dead_name is called\n");
+  mach_port_deallocate (mach_task_self (), name);
+  remove_dead_port_from_dev (name);
+  return 0;
+}
diff --git a/eth-multiplexer/test.c b/eth-multiplexer/test.c
new file mode 100644
index 0000000..7a4d63e
--- /dev/null
+++ b/eth-multiplexer/test.c
@@ -0,0 +1,53 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+
+#include <hurd.h>
+#include <mach.h>
+#include <device/device.h>
+
+int
+main(int argc , char *argv[])
+{
+  mach_port_t device;
+  mach_port_t master_device;
+  error_t err;
+
+  err = get_privileged_ports (0, &master_device);
+  if (err)
+    error (2, err, "cannot get device master port");
+
+  err = device_open (master_device, D_READ | D_WRITE, "eth0", &device);
+  if (err)
+    error (1, err, "device_open");
+  printf ("the device port is %d\n", device);
+
+  err = device_open (master_device, D_READ | D_WRITE, "eth0", &device);
+  if (err)
+    error (1, err, "device_open");
+  printf ("the device port is %d\n", device);
+
+  return 0;
+}
diff --git a/eth-multiplexer/util.h b/eth-multiplexer/util.h
new file mode 100644
index 0000000..b062638
--- /dev/null
+++ b/eth-multiplexer/util.h
@@ -0,0 +1,91 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdio.h>
+#include <execinfo.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+
+#include <mach.h>
+
+#ifdef DEBUG
+
+#define debug(format, ...) do                          \
+{                                                      \
+  char buf[1024];                                       \
+  snprintf (buf, 1024, "multiplexer: %s: %s\n", __func__, format);       \
+  fprintf (stderr , buf, ## __VA_ARGS__);              \
+  fflush (stderr);                                     \
+} while (0)
+
+#else
+
+#define debug(format, ...) do {} while (0)
+
+#endif
+
+#define print_backtrace() do                           \
+{                                                      \
+  size_t size;                                         \
+  void *array[30];                                     \
+  size = backtrace (array, sizeof (array));            \
+  debug ("the depth of the stack: %d", size);          \
+  backtrace_symbols_fd(array, size, fileno (stderr));  \
+} while (0)
+
+#define ETH_ALEN 6             /* Octets in one ethernet addr   */
+
+struct ethhdr
+{
+  unsigned char        h_dest[ETH_ALEN];       /* destination eth addr */
+  unsigned char        h_source[ETH_ALEN];     /* source ether addr    */
+  unsigned short h_proto;              /* packet type ID field */
+};
+
+static inline void
+print_pack (char *packet, int len)
+{
+#ifdef DEBUG
+#define ETH_P_IP 0x0800
+  struct ethhdr *ethh = (struct ethhdr *) packet;
+  struct iphdr *iph = (struct iphdr *)(ethh + 1);
+  char src_str[INET_ADDRSTRLEN];
+  char dst_str[INET_ADDRSTRLEN];
+  if (ntohs (ethh->h_proto) == ETH_P_IP
+      && len >= sizeof (struct ethhdr) + sizeof (struct iphdr))
+    {
+      debug ("multiplexer: get a IP packet from %s to %s\n",
+            inet_ntop (AF_INET, &iph->saddr, src_str, INET_ADDRSTRLEN),
+            inet_ntop (AF_INET, &iph->daddr, dst_str, INET_ADDRSTRLEN));
+    }
+  else
+    {
+      debug ("multiplexer: get a non-IP packet\n");
+    }
+#endif
+}
+
+#endif
diff --git a/eth-multiplexer/vdev.c b/eth-multiplexer/vdev.c
new file mode 100644
index 0000000..7620cd0
--- /dev/null
+++ b/eth-multiplexer/vdev.c
@@ -0,0 +1,309 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+/* This file implement the virtual network interface */
+
+#include <string.h>
+#include <stdio.h>
+#include <netinet/ip.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <error.h>
+
+#include <pthread.h>
+
+#include "vdev.h"
+#include "queue.h"
+#include "bpf_impl.h"
+#include "util.h"
+
+#define ETH_HLEN sizeof (struct ethhdr)
+
+static struct vether_device *dev_head;
+static int dev_num;
+
+/* This lock is only used to protected the virtual device list.
+ * TODO every device structure should has its own lock to protect itself. */
+static pthread_mutex_t dev_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+mach_msg_type_t header_type =
+{
+  MACH_MSG_TYPE_BYTE,
+  8,
+  NET_HDW_HDR_MAX,
+  TRUE,
+  FALSE,
+  FALSE,
+  0
+};
+
+mach_msg_type_t packet_type =
+{
+  MACH_MSG_TYPE_BYTE,  /* name */
+  8,                   /* size */
+  0,                   /* number */
+  TRUE,                        /* inline */
+  FALSE,                       /* longform */
+  FALSE                        /* deallocate */
+};
+
+int
+get_dev_num ()
+{
+  return dev_num;
+}
+
+struct vether_device *
+lookup_dev_by_name (char *name)
+{
+  struct vether_device *vdev;
+  pthread_mutex_lock (&dev_list_lock);
+  for (vdev = dev_head; vdev; vdev = vdev->next)
+    {
+      if (strncmp (vdev->name, name, IFNAMSIZ) == 0)
+       break;
+    }
+  pthread_mutex_unlock (&dev_list_lock);
+  return vdev;
+}
+
+int
+foreach_dev_do (int (func) (struct vether_device *))
+{
+  struct vether_device *vdev;
+  int rval = 0;
+  pthread_mutex_lock (&dev_list_lock);
+  for (vdev = dev_head; vdev; vdev = vdev->next)
+    {
+      pthread_mutex_unlock (&dev_list_lock);
+      /* func() can stop the loop by returning <> 0 */
+      rval = func (vdev);
+      pthread_mutex_lock (&dev_list_lock);
+      if (rval)
+       break;
+    }
+  pthread_mutex_unlock (&dev_list_lock);
+  return rval;
+}
+
+/* Remove all filters with the dead name. */
+int
+remove_dead_port_from_dev (mach_port_t dead_port)
+{
+  struct vether_device *vdev;
+  pthread_mutex_lock (&dev_list_lock);
+  for (vdev = dev_head; vdev; vdev = vdev->next)
+    {
+      remove_dead_filter (&vdev->port_list,
+                         &vdev->port_list.if_rcv_port_list, dead_port);
+      remove_dead_filter (&vdev->port_list,
+                         &vdev->port_list.if_snd_port_list, dead_port);
+    }
+  pthread_mutex_unlock (&dev_list_lock);
+  return 0;
+}
+
+/* Add a new virtual interface to the multiplexer. */
+struct vether_device *
+add_vdev (char *name, int size,
+         struct port_class *class, struct port_bucket *bucket)
+{
+  error_t err;
+  struct vether_device *vdev;
+
+  if (size < sizeof (*vdev))
+    size = sizeof (*vdev);
+  err = ports_create_port (class, bucket, size, &vdev);
+  if (err)
+    return NULL;
+
+  vdev->dev_port = ports_get_right (vdev);
+  ports_port_deref (vdev);
+  strncpy (vdev->name, name, IFNAMSIZ);
+  vdev->if_header_size = ETH_HLEN;
+  vdev->if_mtu = ETH_MTU;
+  vdev->if_header_format = HDR_ETHERNET;
+  vdev->if_address_size = ETH_ALEN;
+  vdev->if_flags = 0;
+  vdev->if_address[0] = 0x52;
+  vdev->if_address[1] = 0x54;
+  *(int *)(vdev->if_address + 2) = random ();
+
+  queue_init (&vdev->port_list.if_rcv_port_list);
+  queue_init (&vdev->port_list.if_snd_port_list);
+
+  pthread_mutex_lock (&dev_list_lock);
+  vdev->next = dev_head;
+  dev_head = vdev;
+  vdev->pprev = &dev_head;
+  if (vdev->next)
+    vdev->next->pprev = &vdev->next;
+  dev_num++;
+  pthread_mutex_unlock (&dev_list_lock);
+
+  debug ("initialize the virtual device\n");
+  return vdev;
+}
+
+void
+destroy_vdev (void *port)
+{
+  struct vether_device *vdev = (struct vether_device *)port;
+
+  debug ("device %s is going to be destroyed\n", vdev->name);
+  /* Delete it from the virtual device list */
+  pthread_mutex_lock (&dev_list_lock);
+  *vdev->pprev = vdev->next;
+  if (vdev->next)
+    vdev->next->pprev = vdev->pprev;
+  dev_num--;
+  pthread_mutex_unlock (&dev_list_lock);
+
+  /* TODO Delete all filters in the interface,
+   * there shouldn't be any filters left */
+  destroy_filters (&vdev->port_list);
+}
+
+/* Test if there are devices existing in the list */
+int
+has_vdev ()
+{
+  return dev_head != NULL;
+}
+
+/* Broadcast the packet to all virtual interfaces
+ * except the one the packet is from */
+int
+broadcast_pack (char *data, int datalen, struct vether_device *from_vdev)
+{
+  int internal_deliver_pack (struct vether_device *vdev)
+    {
+      if (from_vdev == vdev)
+       return 0;
+      return deliver_pack (data, datalen, vdev);
+    }
+
+  return foreach_dev_do (internal_deliver_pack);
+}
+
+/* Create a message, and deliver it. */
+int
+deliver_pack (char *data, int datalen, struct vether_device *vdev)
+{
+  struct net_rcv_msg msg;
+  int pack_size;
+  struct ethhdr *header;
+  struct packet_header *packet;
+
+  pack_size = datalen - sizeof (struct ethhdr);
+  /* remember message sizes must be rounded up */
+  msg.msg_hdr.msgh_size = (((mach_msg_size_t) (sizeof(struct net_rcv_msg)
+                                              - NET_RCV_MAX + pack_size)) + 3) 
& ~3;
+
+  header = (struct ethhdr *) msg.header;
+  packet = (struct packet_header *) msg.packet;
+  msg.header_type = header_type;
+  memcpy (header, data, sizeof (struct ethhdr));
+  msg.packet_type = packet_type;
+  memcpy (packet + 1, data + sizeof (struct ethhdr), pack_size);
+  packet->type = header->h_proto;
+  packet->length = pack_size + sizeof (struct packet_header);
+  msg.packet_type.msgt_number = packet->length;
+
+  return deliver_msg (&msg, vdev);
+}
+
+/* Broadcast the message to all virtual interfaces. */
+int
+broadcast_msg (struct net_rcv_msg *msg)
+{
+  int rval = 0;
+  mach_msg_header_t header;
+
+  int internal_deliver_msg (struct vether_device *vdev)
+    {
+      return deliver_msg (msg, vdev);
+    }
+
+  /* Save the message header because deliver_msg will change it. */
+  header = msg->msg_hdr;
+  rval = foreach_dev_do (internal_deliver_msg);
+  msg->msg_hdr = header;
+  return rval;
+}
+
+/*
+ * Deliver the message to all right pfinet servers that
+ * connects to the virtual network interface.
+ */
+int
+deliver_msg(struct net_rcv_msg *msg, struct vether_device *vdev)
+{
+  mach_msg_return_t err;
+  queue_head_t *if_port_list;
+  net_rcv_port_t infp, nextfp;
+
+  msg->msg_hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+  /* remember message sizes must be rounded up */
+  msg->msg_hdr.msgh_local_port = MACH_PORT_NULL;
+  msg->msg_hdr.msgh_kind = MACH_MSGH_KIND_NORMAL;
+  msg->msg_hdr.msgh_id = NET_RCV_MSG_ID;
+
+  if_port_list = &vdev->port_list.if_rcv_port_list;
+  FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input)
+    {
+      mach_port_t dest;
+      net_hash_entry_t entp, *hash_headp;
+      int ret_count;
+
+      entp = (net_hash_entry_t) 0;
+      ret_count = bpf_do_filter (infp,
+                                msg->packet + sizeof (struct packet_header),
+                                msg->net_rcv_msg_packet_count, msg->header,
+                                sizeof (struct ethhdr), &hash_headp, &entp);
+      if (entp == (net_hash_entry_t) 0)
+       dest = infp->rcv_port;
+      else
+       dest = entp->rcv_port;
+
+      if (ret_count)
+       {
+         debug ("before delivering the packet\n");
+         msg->msg_hdr.msgh_remote_port = dest;
+         err = mach_msg ((mach_msg_header_t *)msg,
+                         MACH_SEND_MSG|MACH_SEND_TIMEOUT,
+                         msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL,
+                         0, MACH_PORT_NULL);
+         if (err != MACH_MSG_SUCCESS)
+           {
+             mach_port_deallocate(mach_task_self (),
+                                  ((mach_msg_header_t 
*)msg)->msgh_remote_port);
+             error (0, err, "mach_msg");
+             return -1;
+           }
+         debug ("after delivering the packet\n");
+       }
+    }
+  FILTER_ITERATE_END
+
+    return 0;
+}
+
diff --git a/eth-multiplexer/vdev.h b/eth-multiplexer/vdev.h
new file mode 100644
index 0000000..c869678
--- /dev/null
+++ b/eth-multiplexer/vdev.h
@@ -0,0 +1,79 @@
+/*
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#ifndef VDEV_H
+#define VDEV_H
+
+#include <net/if.h>
+
+#include <hurd.h>
+#include <mach.h>
+#include <hurd/ports.h>
+#include <device/net_status.h>
+
+#include <bpf_impl.h>
+
+#include "queue.h"
+#include "util.h"
+
+#define MAX_SERVERS 10
+#define ETH_MTU 1500
+
+struct vether_device
+{
+  /* The ports used by the socket server to send packets to the interface. */
+  struct port_info dev_pi;
+  mach_port_t dev_port;
+
+  char name[IFNAMSIZ];
+
+  short if_header_size;
+  short if_mtu;
+  short if_header_format;
+  short if_address_size;
+  short if_flags;
+  char if_address[ETH_ALEN];
+
+  struct vether_device *next;
+  struct vether_device **pprev;
+
+  if_filter_list_t port_list;
+};
+
+typedef int (*dev_act_func) (struct vether_device *);
+
+int serv_connect (mach_port_t port);
+int serv_disconnect ();
+struct vether_device *lookup_dev_by_name (char *name);
+int remove_dead_port_from_dev (mach_port_t dead_port);
+struct vether_device *add_vdev (char *name, int size,
+                               struct port_class *class,
+                               struct port_bucket *bucket);
+void destroy_vdev (void *port);
+int has_vdev ();
+int deliver_msg (struct net_rcv_msg *msg, struct vether_device *vdev);
+int deliver_pack (char *data, int datalen, struct vether_device *vdev);
+boolean_t all_dev_close ();
+int broadcast_pack (char *data, int datalen, struct vether_device *from_vdev);
+int broadcast_msg (struct net_rcv_msg *msg);
+int get_dev_num ();
+int foreach_dev_do (dev_act_func func);
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

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