summaryrefslogtreecommitdiff
path: root/eth-multiplexer
diff options
context:
space:
mode:
Diffstat (limited to 'eth-multiplexer')
-rw-r--r--eth-multiplexer/.DS_Storebin0 -> 12292 bytes
-rw-r--r--eth-multiplexer/CVS/Entries21
-rw-r--r--eth-multiplexer/CVS/Repository1
-rw-r--r--eth-multiplexer/CVS/Root1
-rw-r--r--eth-multiplexer/CVS/Tag1
-rw-r--r--eth-multiplexer/ChangeLog341
-rw-r--r--eth-multiplexer/ChangeLog~341
-rw-r--r--eth-multiplexer/Makefile34
-rw-r--r--eth-multiplexer/Makefile~34
-rw-r--r--eth-multiplexer/README27
-rw-r--r--eth-multiplexer/bpf_impl.c866
-rw-r--r--eth-multiplexer/bpf_impl.h156
-rw-r--r--eth-multiplexer/corebin0 -> 614400 bytes
-rw-r--r--eth-multiplexer/demuxer.c41
-rw-r--r--eth-multiplexer/dev_stat.c101
-rw-r--r--eth-multiplexer/device.defs1
-rw-r--r--eth-multiplexer/device.h336
-rw-r--r--eth-multiplexer/device_impl.c283
-rw-r--r--eth-multiplexer/device_impl.c~282
-rw-r--r--eth-multiplexer/eth-multiplexer.prof_d1
-rw-r--r--eth-multiplexer/ethernet.c145
-rw-r--r--eth-multiplexer/ethernet.c~143
-rw-r--r--eth-multiplexer/ethernet.h39
-rw-r--r--eth-multiplexer/multiplexer.c189
-rw-r--r--eth-multiplexer/multiplexer.c~190
-rw-r--r--eth-multiplexer/netfs_impl.c508
-rw-r--r--eth-multiplexer/netfs_impl.c~510
-rw-r--r--eth-multiplexer/netfs_impl.h47
-rw-r--r--eth-multiplexer/netfs_impl.h~46
-rw-r--r--eth-multiplexer/notify.defs1
-rw-r--r--eth-multiplexer/notify_impl.c69
-rw-r--r--eth-multiplexer/notify_impl.c~70
-rw-r--r--eth-multiplexer/ourdevice.defs383
-rw-r--r--eth-multiplexer/queue.c131
-rw-r--r--eth-multiplexer/queue.h329
-rw-r--r--eth-multiplexer/test.c53
-rw-r--r--eth-multiplexer/util.h91
-rw-r--r--eth-multiplexer/vdev.c307
-rw-r--r--eth-multiplexer/vdev.h78
39 files changed, 6197 insertions, 0 deletions
diff --git a/eth-multiplexer/.DS_Store b/eth-multiplexer/.DS_Store
new file mode 100644
index 00000000..4e8d087c
--- /dev/null
+++ b/eth-multiplexer/.DS_Store
Binary files differ
diff --git a/eth-multiplexer/CVS/Entries b/eth-multiplexer/CVS/Entries
new file mode 100644
index 00000000..b63c1ba0
--- /dev/null
+++ b/eth-multiplexer/CVS/Entries
@@ -0,0 +1,21 @@
+/ethernet.h/1.1.2.1/Wed Aug 13 13:33:59 2008//Tzhengda-soc2008-virt-branch
+/queue.h/1.1.2.1/Wed Aug 13 13:33:59 2008//Tzhengda-soc2008-virt-branch
+/README/1.1.2.6/Sun Oct 26 23:26:40 2008//Tzhengda-soc2008-virt-branch
+/bpf_impl.c/1.1.2.2/Sun Oct 26 20:34:05 2008//Tzhengda-soc2008-virt-branch
+/bpf_impl.h/1.1.2.2/Sun Oct 26 23:31:10 2008//Tzhengda-soc2008-virt-branch
+/dev_stat.c/1.1.2.1/Sun Aug 31 02:06:58 2008//Tzhengda-soc2008-virt-branch
+/queue.c/1.1.2.1/Sun Aug 31 02:06:58 2008//Tzhengda-soc2008-virt-branch
+/test.c/1.1.2.1/Sun Aug 31 02:06:58 2008//Tzhengda-soc2008-virt-branch
+/notify_impl.c/1.1.2.1/Mon Oct 27 18:50:39 2008//Tzhengda-soc2008-virt-branch
+/demuxer.c/1.1.2.2/Sun Nov 9 02:56:06 2008//Tzhengda-soc2008-virt-branch
+/util.h/1.1.2.5/Sun Nov 9 09:02:06 2008//Tzhengda-soc2008-virt-branch
+/Makefile/1.1.2.7/Sun Nov 9 13:43:15 2008//Tzhengda-soc2008-virt-branch
+/vdev.c/1.1.2.13/Sun Nov 9 13:08:25 2008//Tzhengda-soc2008-virt-branch
+/vdev.h/1.1.2.11/Mon Dec 8 11:29:32 2008//Tzhengda-soc2008-virt-branch
+/ethernet.c/1.1.2.6/Sat Jan 3 00:57:06 2009//Tzhengda-soc2008-virt-branch
+/multiplexer.c/1.1.2.19/Fri Mar 13 21:14:05 2009//Tzhengda-soc2008-virt-branch
+/ChangeLog/1.1.2.26/Sat Apr 18 10:05:51 2009//Tzhengda-soc2008-virt-branch
+/device_impl.c/1.1.2.6/Sat Apr 18 09:46:21 2009//Tzhengda-soc2008-virt-branch
+/netfs_impl.c/1.1.2.5/Sat Apr 18 09:59:45 2009//Tzhengda-soc2008-virt-branch
+/netfs_impl.h/1.1.2.3/Sat Apr 18 08:28:01 2009//Tzhengda-soc2008-virt-branch
+D
diff --git a/eth-multiplexer/CVS/Repository b/eth-multiplexer/CVS/Repository
new file mode 100644
index 00000000..75b1a8ef
--- /dev/null
+++ b/eth-multiplexer/CVS/Repository
@@ -0,0 +1 @@
+hurd/eth-multiplexer
diff --git a/eth-multiplexer/CVS/Root b/eth-multiplexer/CVS/Root
new file mode 100644
index 00000000..a10aa66d
--- /dev/null
+++ b/eth-multiplexer/CVS/Root
@@ -0,0 +1 @@
+:ext:zhengda@cvs.savannah.gnu.org:/sources/hurd
diff --git a/eth-multiplexer/CVS/Tag b/eth-multiplexer/CVS/Tag
new file mode 100644
index 00000000..7e454c6d
--- /dev/null
+++ b/eth-multiplexer/CVS/Tag
@@ -0,0 +1 @@
+Tzhengda-soc2008-virt-branch
diff --git a/eth-multiplexer/ChangeLog b/eth-multiplexer/ChangeLog
new file mode 100644
index 00000000..37371185
--- /dev/null
+++ b/eth-multiplexer/ChangeLog
@@ -0,0 +1,341 @@
+2009-04-18 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * device_impl.c (ds_device_write): Deallocate the out-of-line data.
+
+2008-12-12 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * vdev.c (deliver_msg): Use non-block send.
+
+2008-09-21 Zheng Da <zhengda1936@gmail.com>
+
+ * README: Update.
+
+2008-09-02 Zheng Da <zhengda1936@gmail.com>
+
+ * ethernet.c (ether_filter): Use the original NPF filter.
+
+2008-9-01 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * ethernet.c (ethernet_open): Use error instead of assert_perror.
+
+ * multiplexer.c (ds_device_set_filter): Return the error.
+
+2008-8-28 Zheng Da <zhengda1936@gmail.com>
+
+ * ethernet.c (NET_FLAGS): New macro.
+
+2008-8-22 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * README: Update.
+
+ * multiplexer.c (options): Update.
+
+2008-8-20 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (main): Test device_file before using it.
+
+2008-8-20 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (device_file): Rename a variable.
+ (main): Use device_file directly.
+
+2008-8-19 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (main): Generate the device file name, and use it
+ to open the device.
+
+2008-8-18 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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/ChangeLog~ b/eth-multiplexer/ChangeLog~
new file mode 100644
index 00000000..dded432e
--- /dev/null
+++ b/eth-multiplexer/ChangeLog~
@@ -0,0 +1,341 @@
+2009-04-18 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 new field 'name'.
+
+2009-04-18 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * device_impl.c (ds_device_write): Deallocate the out-of-line data.
+
+2008-12-12 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * vdev.c (deliver_msg): Use non-block send.
+
+2008-09-21 Zheng Da <zhengda1936@gmail.com>
+
+ * README: Update.
+
+2008-09-02 Zheng Da <zhengda1936@gmail.com>
+
+ * ethernet.c (ether_filter): Use the original NPF filter.
+
+2008-9-01 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * ethernet.c (ethernet_open): Use error instead of assert_perror.
+
+ * multiplexer.c (ds_device_set_filter): Return the error.
+
+2008-8-28 Zheng Da <zhengda1936@gmail.com>
+
+ * ethernet.c (NET_FLAGS): New macro.
+
+2008-8-22 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * README: Update.
+
+ * multiplexer.c (options): Update.
+
+2008-8-20 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (main): Test device_file before using it.
+
+2008-8-20 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (device_file): Rename a variable.
+ (main): Use device_file directly.
+
+2008-8-19 Zheng Da <zhengda1936@gmail.com>
+
+ * multiplexer.c (main): Generate the device file name, and use it
+ to open the device.
+
+2008-8-18 Zheng Da <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 <zhengda1936@gmail.com>
+
+ * 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 00000000..72027ea8
--- /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 bpf_impl.c queue.c dev_stat.c netfs_impl.c notify_impl.c device_impl.c demuxer.c
+MIGSTUBS = ourdeviceServer.o notifyServer.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+LCLHDRS = bpf_impl.h ethernet.h queue.h util.h vdev.h netfs_impl.h
+DIST_FILES = ourdevice.defs notify.defs
+HURDLIBS=ports fshelp shouldbeinlibc netfs
+
+include ../Makeconf
+
+ourdevice.defs: device.defs
+ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@
+
diff --git a/eth-multiplexer/Makefile~ b/eth-multiplexer/Makefile~
new file mode 100644
index 00000000..237bf3a3
--- /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 bpf_impl.c queue.c dev_stat.c netfs_impl.c notify_impl.c device_impl.c demuxer.c
+MIGSTUBS = ourdeviceServer.o notifyServer.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+LCLHDRS = bpf_impl.h ethernet.h queue.h util.h vdev.h netfs_impl.h
+DIST_FILES = ourdevice.defs notify.defs
+HURDLIBS=ports fshelp shouldbeinlibc netfs
+
+include ../Makeconf
+
+ourdevice.defs: device.defs
+ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@
+
diff --git a/eth-multiplexer/README b/eth-multiplexer/README
new file mode 100644
index 00000000..0024a937
--- /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 interface whose filter will decide the destination of the packet.
+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/bpf_impl.c b/eth-multiplexer/bpf_impl.c
new file mode 100644
index 00000000..55c2a87e
--- /dev/null
+++ b/eth-multiplexer/bpf_impl.c
@@ -0,0 +1,866 @@
+ /*
+ * 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 Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * 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 <arpa/inet.h>
+#include <string.h>
+
+#include <mach.h>
+#include <hurd.h>
+
+#include "bpf_impl.h"
+#include "queue.h"
+#include "util.h"
+
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ *
+ * @p: packet data.
+ * @wirelen: data_count (in bytes)
+ * @hlen: header len (in bytes)
+ */
+
+int
+bpf_do_filter(net_rcv_port_t infp, char *p, unsigned int wirelen,
+ char *header, unsigned int hlen, net_hash_entry_t **hash_headpp,
+ net_hash_entry_t *entpp)
+{
+ register bpf_insn_t pc, pc_end;
+ register unsigned int buflen;
+
+ register unsigned long A, X;
+ register int k;
+ unsigned int mem[BPF_MEMWORDS];
+
+ /* Generic pointer to either HEADER or P according to the specified offset. */
+ char *data = NULL;
+
+ pc = ((bpf_insn_t) infp->filter) + 1;
+ /* filter[0].code is (NETF_BPF | flags) */
+ pc_end = (bpf_insn_t)infp->filter_end;
+ buflen = NET_RCV_MAX;
+ *entpp = 0; /* default */
+
+ A = 0;
+ X = 0;
+ for (; pc < pc_end; ++pc) {
+ switch (pc->code) {
+
+ default:
+ abort();
+ case BPF_RET|BPF_K:
+ if (infp->rcv_port == MACH_PORT_NULL &&
+ *entpp == 0) {
+ return 0;
+ }
+ return ((u_int)pc->k <= wirelen) ?
+ pc->k : wirelen;
+
+ case BPF_RET|BPF_A:
+ if (infp->rcv_port == MACH_PORT_NULL &&
+ *entpp == 0) {
+ return 0;
+ }
+ return ((u_int)A <= wirelen) ?
+ A : wirelen;
+
+ case BPF_RET|BPF_MATCH_IMM:
+ if (bpf_match ((net_hash_header_t)infp, pc->jt, mem,
+ hash_headpp, entpp)) {
+ return ((u_int)pc->k <= wirelen) ?
+ pc->k : wirelen;
+ }
+ return 0;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = pc->k;
+
+load_word:
+ if ((u_int)k + sizeof(long) <= hlen)
+ data = header;
+ else if ((u_int)k + sizeof(long) <= buflen) {
+ k -= hlen;
+ data = p;
+ } else
+ return 0;
+
+#ifdef BPF_ALIGN
+ if (((int)(data + k) & 3) != 0)
+ A = EXTRACT_LONG(&data[k]);
+ else
+#endif
+ A = ntohl(*(long *)(data + k));
+ continue;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = pc->k;
+
+load_half:
+ if ((u_int)k + sizeof(short) <= hlen)
+ data = header;
+ else if ((u_int)k + sizeof(short) <= buflen) {
+ k -= hlen;
+ data = p;
+ } else
+ return 0;
+
+ A = EXTRACT_SHORT(&data[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ k = pc->k;
+
+load_byte:
+ if ((u_int)k < hlen)
+ data = header;
+ else if ((u_int)k < buflen) {
+ data = p;
+ k -= hlen;
+ } else
+ return 0;
+
+ A = data[k];
+ continue;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = wirelen;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = wirelen;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + pc->k;
+ goto load_word;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + pc->k;
+ goto load_half;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + pc->k;
+ goto load_byte;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ k = pc->k;
+ if (k < hlen)
+ data = header;
+ else if (k < buflen) {
+ data = p;
+ k -= hlen;
+ } else
+ return 0;
+
+ X = (data[k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = pc->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = pc->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[pc->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[pc->k];
+ continue;
+
+ case BPF_ST:
+ mem[pc->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[pc->k] = X;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ pc += pc->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if (X == 0)
+ return 0;
+ A /= X;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ A &= X;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ A <<= X;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ A >>= X;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += pc->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ A /= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ A &= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ A |= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ A <<= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ A = -A;
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Return 1 if the 'f' is a valid filter program without a MATCH
+ * instruction. Return 2 if it is a valid filter program with a MATCH
+ * instruction. Otherwise, return 0.
+ * The constraints are that each jump be forward and to a valid
+ * code. The code must terminate with either an accept or reject.
+ * 'valid' is an array for use by the routine (it must be at least
+ * 'len' bytes long).
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match)
+{
+ register int i, j, len;
+ register bpf_insn_t p;
+
+ len = BPF_BYTES2LEN(bytes);
+
+ /*
+ * f[0].code is already checked to be (NETF_BPF | flags).
+ * So skip f[0].
+ */
+
+ for (i = 1; i < len; ++i) {
+ /*
+ * Check that that jumps are forward, and within
+ * the code block.
+ */
+ p = &f[i];
+ if (BPF_CLASS(p->code) == BPF_JMP) {
+ register int from = i + 1;
+
+ if (BPF_OP(p->code) == BPF_JA) {
+ if (from + p->k >= len)
+ return 0;
+ }
+ else if (from + p->jt >= len || from + p->jf >= len)
+ return 0;
+ }
+ /*
+ * Check that memory operations use valid addresses.
+ */
+ if ((BPF_CLASS(p->code) == BPF_ST ||
+ (BPF_CLASS(p->code) == BPF_LD &&
+ (p->code & 0xe0) == BPF_MEM)) &&
+ (p->k >= BPF_MEMWORDS || p->k < 0)) {
+ return 0;
+ }
+ /*
+ * Check for constant division by 0.
+ */
+ if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) {
+ return 0;
+ }
+ /*
+ * Check for match instruction.
+ * Only one match instruction per filter is allowed.
+ */
+ if (p->code == (BPF_RET|BPF_MATCH_IMM)) {
+ if (*match != 0 ||
+ p->jt == 0 ||
+ p->jt > N_NET_HASH_KEYS)
+ return 0;
+ i += p->jt; /* skip keys */
+ if (i + 1 > len)
+ return 0;
+
+ for (j = 1; j <= p->jt; j++) {
+ if (p[j].code != (BPF_MISC|BPF_KEY))
+ return 0;
+ }
+
+ *match = p;
+ }
+ }
+ if (BPF_CLASS(f[len - 1].code) == BPF_RET)
+ return ((*match == 0) ? 1 : 2);
+ else
+ return 0;
+}
+
+int
+bpf_eq (bpf_insn_t f1, bpf_insn_t f2, int bytes)
+{
+ register int count;
+
+ count = BPF_BYTES2LEN(bytes);
+ for (; count--; f1++, f2++) {
+ if (!BPF_INSN_EQ(f1, f2)) {
+ if ( f1->code == (BPF_MISC|BPF_KEY) &&
+ f2->code == (BPF_MISC|BPF_KEY) )
+ continue;
+ return FALSE;
+ }
+ };
+ return TRUE;
+}
+
+unsigned int
+bpf_hash (int n, unsigned int *keys)
+{
+ register unsigned int hval = 0;
+
+ while (n--) {
+ hval += *keys++;
+ }
+ return (hval % NET_HASH_SIZE);
+}
+
+
+int
+bpf_match (net_hash_header_t hash, int n_keys, unsigned int *keys,
+ net_hash_entry_t **hash_headpp, net_hash_entry_t *entpp)
+{
+ register net_hash_entry_t head, entp;
+ register int i;
+
+ if (n_keys != hash->n_keys)
+ return FALSE;
+
+ *hash_headpp = &hash->table[bpf_hash(n_keys, keys)];
+ head = **hash_headpp;
+
+ if (head == 0)
+ return FALSE;
+
+ HASH_ITERATE (head, entp)
+ {
+ for (i = 0; i < n_keys; i++) {
+ if (keys[i] != entp->keys[i])
+ break;
+ }
+ if (i == n_keys) {
+ *entpp = entp;
+ return TRUE;
+ }
+ }
+ HASH_ITERATE_END (head, entp)
+ return FALSE;
+}
+
+/*
+ * Removes a hash entry (ENTP) from its queue (HEAD).
+ * If the reference count of filter (HP) becomes zero and not USED,
+ * HP is removed from the corresponding port lists and is freed.
+ */
+
+int
+hash_ent_remove (struct vether_device *ifp, net_hash_header_t hp, int used,
+ net_hash_entry_t *head, net_hash_entry_t entp, queue_entry_t *dead_p)
+{
+ hp->ref_count--;
+
+ if (*head == entp) {
+ if (queue_empty((queue_t) entp)) {
+ *head = 0;
+ ENQUEUE_DEAD(*dead_p, entp, chain);
+ if (hp->ref_count == 0 && !used) {
+ if (((net_rcv_port_t)hp)->filter[0] & NETF_IN)
+ queue_remove(&ifp->if_rcv_port_list,
+ (net_rcv_port_t)hp,
+ net_rcv_port_t, input);
+ if (((net_rcv_port_t)hp)->filter[0] & NETF_OUT)
+ queue_remove(&ifp->if_snd_port_list,
+ (net_rcv_port_t)hp,
+ net_rcv_port_t, output);
+ hp->n_keys = 0;
+ return TRUE;
+ }
+ return FALSE;
+ } else {
+ *head = (net_hash_entry_t)queue_next((queue_t) entp);
+ }
+ }
+
+ remqueue((queue_t)*head, (queue_entry_t)entp);
+ ENQUEUE_DEAD(*dead_p, entp, chain);
+ return FALSE;
+}
+
+/*
+ * net_free_dead_infp (dead_infp)
+ * queue_entry_t dead_infp; list of dead net_rcv_port_t.
+ *
+ * Deallocates dead net_rcv_port_t.
+ * No locks should be held when called.
+ */
+void
+net_free_dead_infp (queue_entry_t dead_infp)
+{
+ register net_rcv_port_t infp, nextfp;
+
+ for (infp = (net_rcv_port_t) dead_infp; infp != 0; infp = nextfp) {
+ nextfp = (net_rcv_port_t) queue_next(&infp->input);
+ mach_port_deallocate(mach_task_self(), infp->rcv_port);
+ free(infp);
+ debug ("a dead infp is freed\n");
+ }
+}
+
+/*
+ * net_free_dead_entp (dead_entp)
+ * queue_entry_t dead_entp; list of dead net_hash_entry_t.
+ *
+ * Deallocates dead net_hash_entry_t.
+ * No locks should be held when called.
+ */
+void
+net_free_dead_entp (queue_entry_t dead_entp)
+{
+ register net_hash_entry_t entp, nextentp;
+
+ for (entp = (net_hash_entry_t)dead_entp; entp != 0; entp = nextentp) {
+ nextentp = (net_hash_entry_t) queue_next(&entp->chain);
+
+ mach_port_deallocate(mach_task_self(), entp->rcv_port);
+ free(entp);
+ debug ("a dead entp is freed\n");
+ }
+}
+
+/*
+ * Set a filter for a network interface.
+ *
+ * We are given a naked send right for the rcv_port.
+ * If we are successful, we must consume that right.
+ */
+io_return_t
+net_set_filter(struct vether_device *ifp, mach_port_t rcv_port, int priority,
+ filter_t *filter, unsigned int filter_count)
+{
+ int filter_bytes;
+ bpf_insn_t match;
+ register net_rcv_port_t infp, my_infp;
+ net_rcv_port_t nextfp;
+ net_hash_header_t hhp;
+ register net_hash_entry_t entp, hash_entp=NULL;
+ net_hash_entry_t *head, nextentp;
+ queue_entry_t dead_infp, dead_entp;
+ int i;
+ int ret, is_new_infp;
+ io_return_t rval;
+ boolean_t in, out;
+
+ /* Check the filter syntax. */
+
+ debug ("filter_count: %d, filter[0]: %d\n", filter_count, filter[0]);
+
+ filter_bytes = CSPF_BYTES (filter_count);
+ match = (bpf_insn_t) 0;
+
+ if (filter_count == 0) {
+ return (D_INVALID_OPERATION);
+ } else if (!((filter[0] & NETF_IN) || (filter[0] & NETF_OUT))) {
+ return (D_INVALID_OPERATION); /* NETF_IN or NETF_OUT required */
+ } else if ((filter[0] & NETF_TYPE_MASK) == NETF_BPF) {
+ ret = bpf_validate((bpf_insn_t)filter, filter_bytes, &match);
+ if (!ret)
+ return (D_INVALID_OPERATION);
+ } else {
+ return (D_INVALID_OPERATION);
+ }
+ debug ("net_set_filter: check over\n");
+
+ rval = D_SUCCESS; /* default return value */
+ dead_infp = dead_entp = 0;
+
+ if (match == (bpf_insn_t) 0) {
+ /*
+ * If there is no match instruction, we allocate
+ * a normal packet filter structure.
+ */
+ my_infp = (net_rcv_port_t) calloc(1, sizeof(struct net_rcv_port));
+ my_infp->rcv_port = rcv_port;
+ is_new_infp = TRUE;
+ } else {
+ /*
+ * If there is a match instruction, we assume there will be
+ * multiple sessions with a common substructure and allocate
+ * a hash table to deal with them.
+ */
+ my_infp = 0;
+ hash_entp = (net_hash_entry_t) calloc(1, sizeof(struct net_hash_entry));
+ is_new_infp = FALSE;
+ }
+
+ /*
+ * Look for an existing filter on the same reply port.
+ * Look for filters with dead ports (for GC).
+ * Look for a filter with the same code except KEY insns.
+ */
+ void check_filter_list(queue_head_t *if_port_list)
+ {
+ FILTER_ITERATE(if_port_list, infp, nextfp,
+ (if_port_list == &ifp->if_rcv_port_list)
+ ? &infp->input : &infp->output)
+ {
+ if (infp->rcv_port == MACH_PORT_NULL) {
+ if (match != 0
+ && infp->priority == priority
+ && my_infp == 0
+ && (infp->filter_end - infp->filter) == filter_count
+ && bpf_eq((bpf_insn_t)infp->filter,
+ (bpf_insn_t)filter, filter_bytes))
+ my_infp = infp;
+
+ for (i = 0; i < NET_HASH_SIZE; i++) {
+ head = &((net_hash_header_t) infp)->table[i];
+ if (*head == 0)
+ continue;
+
+ /*
+ * Check each hash entry to make sure the
+ * destination port is still valid. Remove
+ * any invalid entries.
+ */
+ entp = *head;
+ do {
+ nextentp = (net_hash_entry_t) entp->he_next;
+
+ /* checked without
+ ip_lock(entp->rcv_port) */
+ if (entp->rcv_port == rcv_port) {
+ ret = hash_ent_remove (ifp,
+ (net_hash_header_t)infp,
+ (my_infp == infp),
+ head,
+ entp,
+ &dead_entp);
+ if (ret)
+ goto hash_loop_end;
+ }
+
+ entp = nextentp;
+ /* While test checks head since hash_ent_remove
+ * might modify it.
+ */
+ } while (*head != 0 && entp != *head);
+ }
+
+hash_loop_end:
+ ;
+ } else if (infp->rcv_port == rcv_port) {
+
+ /* Remove the old filter from lists */
+ if (infp->filter[0] & NETF_IN)
+ queue_remove(&ifp->if_rcv_port_list, infp,
+ net_rcv_port_t, input);
+ if (infp->filter[0] & NETF_OUT)
+ queue_remove(&ifp->if_snd_port_list, infp,
+ net_rcv_port_t, output);
+
+ ENQUEUE_DEAD(dead_infp, infp, input);
+ }
+ }
+ FILTER_ITERATE_END
+ }
+
+ in = (filter[0] & NETF_IN) != 0;
+ out = (filter[0] & NETF_OUT) != 0;
+
+ if (in)
+ check_filter_list(&ifp->if_rcv_port_list);
+ if (out)
+ check_filter_list(&ifp->if_snd_port_list);
+
+ if (my_infp == 0) {
+ /* Allocate a dummy infp */
+ for (i = 0; i < N_NET_HASH; i++) {
+ if (filter_hash_header[i].n_keys == 0)
+ break;
+ }
+ if (i == N_NET_HASH) {
+ mach_port_deallocate(mach_task_self() , rcv_port);
+ if (match != 0)
+ free(hash_entp);
+
+ rval = D_NO_MEMORY;
+ goto clean_and_return;
+ }
+
+ hhp = &filter_hash_header[i];
+ hhp->n_keys = match->jt;
+
+ hhp->ref_count = 0;
+ for (i = 0; i < NET_HASH_SIZE; i++)
+ hhp->table[i] = 0;
+
+ my_infp = (net_rcv_port_t)hhp;
+ my_infp->rcv_port = MACH_PORT_NULL; /* indication of dummy */
+ is_new_infp = TRUE;
+ }
+
+ if (is_new_infp) {
+ my_infp->priority = priority;
+ my_infp->rcv_count = 0;
+
+ /* Copy filter program. */
+ memcpy (my_infp->filter, filter, filter_bytes);
+ my_infp->filter_end =
+ (filter_t *)((char *)my_infp->filter + filter_bytes);
+
+ /* Insert my_infp according to priority */
+ if (in) {
+ queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, input)
+ if (priority > infp->priority)
+ break;
+
+ queue_enter(&ifp->if_rcv_port_list, my_infp, net_rcv_port_t, input);
+ }
+
+ if (out) {
+ queue_iterate(&ifp->if_snd_port_list, infp, net_rcv_port_t, output)
+ if (priority > infp->priority)
+ break;
+
+ queue_enter(&ifp->if_snd_port_list, my_infp, net_rcv_port_t, output);
+ }
+ }
+
+ if (match != 0)
+ {
+ /* Insert to hash list */
+ net_hash_entry_t *p;
+
+ hash_entp->rcv_port = rcv_port;
+ for (i = 0; i < match->jt; i++) /* match->jt is n_keys */
+ hash_entp->keys[i] = match[i+1].k;
+ p = &((net_hash_header_t)my_infp)->
+ table[bpf_hash(match->jt, hash_entp->keys)];
+
+ /* Not checking for the same key values */
+ if (*p == 0) {
+ queue_init ((queue_t) hash_entp);
+ *p = hash_entp;
+ } else {
+ enqueue_tail((queue_t)*p, (queue_entry_t)hash_entp);
+ }
+
+ ((net_hash_header_t)my_infp)->ref_count++;
+ }
+
+clean_and_return:
+ /* No locks are held at this point. */
+
+ if (dead_infp != 0)
+ net_free_dead_infp(dead_infp);
+ if (dead_entp != 0)
+ net_free_dead_entp(dead_entp);
+
+ return (rval);
+}
+
+void
+destroy_filters (struct vether_device *ifp)
+{
+}
+
+void
+remove_dead_filter (struct vether_device *ifp, queue_head_t *if_port_list,
+ mach_port_t dead_port)
+{
+ net_rcv_port_t infp;
+ net_rcv_port_t nextfp;
+ net_hash_entry_t *head, nextentp;
+ queue_entry_t dead_infp, dead_entp;
+ net_hash_entry_t entp = NULL;
+ int i, ret;
+
+ dead_infp = dead_entp = 0;
+ FILTER_ITERATE (if_port_list, infp, nextfp,
+ (if_port_list == &ifp->if_rcv_port_list)
+ ? &infp->input : &infp->output) {
+ if (infp->rcv_port == MACH_PORT_NULL) {
+ for (i = 0; i < NET_HASH_SIZE; i++) {
+ head = &((net_hash_header_t) infp)->table[i];
+ if (*head == 0)
+ continue;
+
+ /*
+ * Check each hash entry to make sure the
+ * destination port is still valid. Remove
+ * any invalid entries.
+ */
+ entp = *head;
+ do {
+ nextentp = (net_hash_entry_t) entp->he_next;
+
+ /* checked without
+ ip_lock(entp->rcv_port) */
+ if (entp->rcv_port == dead_port) {
+ ret = hash_ent_remove (ifp,
+ (net_hash_header_t) infp,
+ 0,
+ head,
+ entp,
+ &dead_entp);
+ if (ret)
+ goto hash_loop_end;
+ }
+
+ entp = nextentp;
+ /* While test checks head since hash_ent_remove
+ * might modify it.
+ */
+ } while (*head != 0 && entp != *head);
+ }
+
+hash_loop_end:
+ ;
+ } else if (infp->rcv_port == dead_port) {
+ /* Remove the old filter from lists */
+ if (infp->filter[0] & NETF_IN)
+ queue_remove(&ifp->if_rcv_port_list, infp,
+ net_rcv_port_t, input);
+ if (infp->filter[0] & NETF_OUT)
+ queue_remove(&ifp->if_snd_port_list, infp,
+ net_rcv_port_t, output);
+
+ ENQUEUE_DEAD(dead_infp, infp, input);
+ }
+ }
+ FILTER_ITERATE_END
+
+ if (dead_infp != 0)
+ net_free_dead_infp(dead_infp);
+ if (dead_entp != 0)
+ net_free_dead_entp(dead_entp);
+}
diff --git a/eth-multiplexer/bpf_impl.h b/eth-multiplexer/bpf_impl.h
new file mode 100644
index 00000000..82db1b8d
--- /dev/null
+++ b/eth-multiplexer/bpf_impl.h
@@ -0,0 +1,156 @@
+ /*
+ * 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 Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * 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 */
+
+#ifndef BPF_IMPL_H
+#define BPF_IMPL_H
+
+#include <device/bpf.h>
+
+#include "queue.h"
+#include "vdev.h"
+
+typedef unsigned short filter_t;
+typedef filter_t *filter_array_t;
+
+#define NET_MAX_FILTER 128 /* was 64, bpf programs are big */
+
+#define NET_HASH_SIZE 256
+#define N_NET_HASH 4
+#define N_NET_HASH_KEYS 4
+
+#ifndef BPF_ALIGN
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
+#else
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+0)<<8|\
+ (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_long)*((u_char *)p+0)<<24|\
+ (u_long)*((u_char *)p+1)<<16|\
+ (u_long)*((u_char *)p+2)<<8|\
+ (u_long)*((u_char *)p+3)<<0)
+#endif
+
+#define HASH_ITERATE(head, elt) (elt) = (net_hash_entry_t) (head); do {
+#define HASH_ITERATE_END(head, elt) \
+ (elt) = (net_hash_entry_t) queue_next((queue_entry_t) (elt)); \
+} while ((elt) != (head));
+
+#define FILTER_ITERATE(if_port_list, fp, nextfp, chain) \
+ for ((fp) = (net_rcv_port_t) queue_first(if_port_list); \
+ !queue_end(if_port_list, (queue_entry_t)(fp)); \
+ (fp) = (nextfp)) { \
+ (nextfp) = (net_rcv_port_t) queue_next(chain);
+#define FILTER_ITERATE_END }
+
+/* entry_p must be net_rcv_port_t or net_hash_entry_t */
+#define ENQUEUE_DEAD(dead, entry_p, chain) { \
+ queue_next(&(entry_p)->chain) = (queue_entry_t) (dead); \
+ (dead) = (queue_entry_t)(entry_p); \
+}
+
+#define CSPF_BYTES(n) ((n) * sizeof (filter_t))
+
+/*
+ * Receive port for net, with packet filter.
+ * This data structure by itself represents a packet
+ * filter for a single session.
+ */
+struct net_rcv_port {
+ queue_chain_t input; /* list of input open_descriptors */
+ queue_chain_t output; /* list of output open_descriptors */
+ mach_port_t rcv_port; /* port to send packet to */
+ int rcv_count; /* number of packets received */
+ int priority; /* priority for filter */
+ filter_t *filter_end; /* pointer to end of filter */
+ filter_t filter[NET_MAX_FILTER];
+ /* filter operations */
+};
+typedef struct net_rcv_port *net_rcv_port_t;
+
+/*
+ * A single hash entry.
+ */
+struct net_hash_entry {
+ queue_chain_t chain; /* list of entries with same hval */
+#define he_next chain.next
+#define he_prev chain.prev
+ mach_port_t rcv_port; /* destination port */
+ unsigned int keys[N_NET_HASH_KEYS];
+};
+typedef struct net_hash_entry *net_hash_entry_t;
+
+/*
+ * This structure represents a packet filter with multiple sessions.
+ *
+ * For example, all application level TCP sessions might be
+ * represented by one of these structures. It looks like a
+ * net_rcv_port struct so that both types can live on the
+ * same packet filter queues.
+ */
+struct net_hash_header {
+ struct net_rcv_port rcv;
+ int n_keys; /* zero if not used */
+ int ref_count; /* reference count */
+ net_hash_entry_t table[NET_HASH_SIZE];
+} filter_hash_header[N_NET_HASH];
+
+typedef struct net_hash_header *net_hash_header_t;
+
+int bpf_do_filter(net_rcv_port_t infp, char *p, unsigned int wirelen,
+ char *header, unsigned int hlen, net_hash_entry_t **hash_headpp,
+ net_hash_entry_t *entpp);
+io_return_t net_set_filter(struct vether_device *ifp, mach_port_t rcv_port,
+ int priority, filter_t *filter, unsigned int filter_count);
+
+int bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match);
+int bpf_eq (bpf_insn_t f1, bpf_insn_t f2, int bytes);
+unsigned int bpf_hash (int n, unsigned int *keys);
+int bpf_match (net_hash_header_t hash, int n_keys, unsigned int *keys,
+ net_hash_entry_t **hash_headpp, net_hash_entry_t *entpp);
+
+int hash_ent_remove (struct vether_device *ifp, net_hash_header_t hp, int used,
+ net_hash_entry_t *head, net_hash_entry_t entp, queue_entry_t *dead_p);
+void net_free_dead_infp (queue_entry_t dead_infp);
+void net_free_dead_entp (queue_entry_t dead_entp);
+void remove_dead_filter (struct vether_device *ifp,
+ queue_head_t *if_port_list, mach_port_t dead_port);
+void destroy_filters (struct vether_device *ifp);
+
+#endif /* _DEVICE_BPF_H_ */
diff --git a/eth-multiplexer/core b/eth-multiplexer/core
new file mode 100644
index 00000000..f4475c71
--- /dev/null
+++ b/eth-multiplexer/core
Binary files differ
diff --git a/eth-multiplexer/demuxer.c b/eth-multiplexer/demuxer.c
new file mode 100644
index 00000000..1f671b20
--- /dev/null
+++ b/eth-multiplexer/demuxer.c
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 1996 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>
+
+int
+netfs_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ int netfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_ifsock_server (mach_msg_header_t *, mach_msg_header_t *);
+ int device_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (netfs_io_server (inp, outp)
+ || netfs_fs_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || netfs_fsys_server (inp, outp)
+ || ports_interrupt_server (inp, outp)
+ || netfs_ifsock_server (inp, outp)
+ || device_server (inp, outp));
+}
+
diff --git a/eth-multiplexer/dev_stat.c b/eth-multiplexer/dev_stat.c
new file mode 100644
index 00000000..43c68d6a
--- /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 Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * 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.defs b/eth-multiplexer/device.defs
new file mode 100644
index 00000000..70472689
--- /dev/null
+++ b/eth-multiplexer/device.defs
@@ -0,0 +1 @@
+#include <device/device.defs>
diff --git a/eth-multiplexer/device.h b/eth-multiplexer/device.h
new file mode 100644
index 00000000..db0798d6
--- /dev/null
+++ b/eth-multiplexer/device.h
@@ -0,0 +1,336 @@
+#ifndef _device_user_
+#define _device_user_
+
+/* Module device */
+
+#include <mach/kern_return.h>
+#include <mach/port.h>
+#include <mach/message.h>
+
+#include <mach/std_types.h>
+#include <mach/mach_types.h>
+#include <device/device_types.h>
+#include <device/net_status.h>
+
+/* Routine device_open */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_open
+#if defined(LINTLIBRARY)
+ (master_port, mode, name, device)
+ mach_port_t master_port;
+ dev_mode_t mode;
+ dev_name_t name;
+ mach_port_t *device;
+{ return device_open(master_port, mode, name, device); }
+#else
+(
+ mach_port_t master_port,
+ dev_mode_t mode,
+ dev_name_t name,
+ mach_port_t *device
+);
+#endif
+
+/* Routine device_close */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_close
+#if defined(LINTLIBRARY)
+ (device)
+ mach_port_t device;
+{ return device_close(device); }
+#else
+(
+ mach_port_t device
+);
+#endif
+
+/* Routine device_write */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_write
+#if defined(LINTLIBRARY)
+ (device, mode, recnum, data, dataCnt, bytes_written)
+ mach_port_t device;
+ dev_mode_t mode;
+ recnum_t recnum;
+ io_buf_ptr_t data;
+ mach_msg_type_number_t dataCnt;
+ int *bytes_written;
+{ return device_write(device, mode, recnum, data, dataCnt, bytes_written); }
+#else
+(
+ mach_port_t device,
+ dev_mode_t mode,
+ recnum_t recnum,
+ io_buf_ptr_t data,
+ mach_msg_type_number_t dataCnt,
+ int *bytes_written
+);
+#endif
+
+/* Routine device_write_inband */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_write_inband
+#if defined(LINTLIBRARY)
+ (device, mode, recnum, data, dataCnt, bytes_written)
+ mach_port_t device;
+ dev_mode_t mode;
+ recnum_t recnum;
+ io_buf_ptr_inband_t data;
+ mach_msg_type_number_t dataCnt;
+ int *bytes_written;
+{ return device_write_inband(device, mode, recnum, data, dataCnt, bytes_written); }
+#else
+(
+ mach_port_t device,
+ dev_mode_t mode,
+ recnum_t recnum,
+ io_buf_ptr_inband_t data,
+ mach_msg_type_number_t dataCnt,
+ int *bytes_written
+);
+#endif
+
+/* Routine device_read */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_read
+#if defined(LINTLIBRARY)
+ (device, mode, recnum, bytes_wanted, data, dataCnt)
+ mach_port_t device;
+ dev_mode_t mode;
+ recnum_t recnum;
+ int bytes_wanted;
+ io_buf_ptr_t *data;
+ mach_msg_type_number_t *dataCnt;
+{ return device_read(device, mode, recnum, bytes_wanted, data, dataCnt); }
+#else
+(
+ mach_port_t device,
+ dev_mode_t mode,
+ recnum_t recnum,
+ int bytes_wanted,
+ io_buf_ptr_t *data,
+ mach_msg_type_number_t *dataCnt
+);
+#endif
+
+/* Routine device_read_inband */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_read_inband
+#if defined(LINTLIBRARY)
+ (device, mode, recnum, bytes_wanted, data, dataCnt)
+ mach_port_t device;
+ dev_mode_t mode;
+ recnum_t recnum;
+ int bytes_wanted;
+ io_buf_ptr_inband_t data;
+ mach_msg_type_number_t *dataCnt;
+{ return device_read_inband(device, mode, recnum, bytes_wanted, data, dataCnt); }
+#else
+(
+ mach_port_t device,
+ dev_mode_t mode,
+ recnum_t recnum,
+ int bytes_wanted,
+ io_buf_ptr_inband_t data,
+ mach_msg_type_number_t *dataCnt
+);
+#endif
+
+/* Routine xxx_device_set_status */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t xxx_device_set_status
+#if defined(LINTLIBRARY)
+ (device, flavor, status, statusCnt)
+ mach_port_t device;
+ dev_flavor_t flavor;
+ dev_status_t status;
+ mach_msg_type_number_t statusCnt;
+{ return xxx_device_set_status(device, flavor, status, statusCnt); }
+#else
+(
+ mach_port_t device,
+ dev_flavor_t flavor,
+ dev_status_t status,
+ mach_msg_type_number_t statusCnt
+);
+#endif
+
+/* Routine xxx_device_get_status */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t xxx_device_get_status
+#if defined(LINTLIBRARY)
+ (device, flavor, status, statusCnt)
+ mach_port_t device;
+ dev_flavor_t flavor;
+ dev_status_t status;
+ mach_msg_type_number_t *statusCnt;
+{ return xxx_device_get_status(device, flavor, status, statusCnt); }
+#else
+(
+ mach_port_t device,
+ dev_flavor_t flavor,
+ dev_status_t status,
+ mach_msg_type_number_t *statusCnt
+);
+#endif
+
+/* Routine xxx_device_set_filter */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t xxx_device_set_filter
+#if defined(LINTLIBRARY)
+ (device, receive_port, receive_portPoly, priority, filter, filterCnt)
+ mach_port_t device;
+ mach_port_t receive_port;
+ mach_msg_type_name_t receive_portPoly;
+ int priority;
+ filter_array_t filter;
+ mach_msg_type_number_t filterCnt;
+{ return xxx_device_set_filter(device, receive_port, receive_portPoly, priority, filter, filterCnt); }
+#else
+(
+ mach_port_t device,
+ mach_port_t receive_port,
+ mach_msg_type_name_t receive_portPoly,
+ int priority,
+ filter_array_t filter,
+ mach_msg_type_number_t filterCnt
+);
+#endif
+
+/* Routine device_map */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_map
+#if defined(LINTLIBRARY)
+ (device, prot, offset, size, pager, unmap)
+ mach_port_t device;
+ vm_prot_t prot;
+ vm_offset_t offset;
+ vm_size_t size;
+ mach_port_t *pager;
+ int unmap;
+{ return device_map(device, prot, offset, size, pager, unmap); }
+#else
+(
+ mach_port_t device,
+ vm_prot_t prot,
+ vm_offset_t offset,
+ vm_size_t size,
+ mach_port_t *pager,
+ int unmap
+);
+#endif
+
+/* Routine device_set_status */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_set_status
+#if defined(LINTLIBRARY)
+ (device, flavor, status, statusCnt)
+ mach_port_t device;
+ dev_flavor_t flavor;
+ dev_status_t status;
+ mach_msg_type_number_t statusCnt;
+{ return device_set_status(device, flavor, status, statusCnt); }
+#else
+(
+ mach_port_t device,
+ dev_flavor_t flavor,
+ dev_status_t status,
+ mach_msg_type_number_t statusCnt
+);
+#endif
+
+/* Routine device_get_status */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_get_status
+#if defined(LINTLIBRARY)
+ (device, flavor, status, statusCnt)
+ mach_port_t device;
+ dev_flavor_t flavor;
+ dev_status_t status;
+ mach_msg_type_number_t *statusCnt;
+{ return device_get_status(device, flavor, status, statusCnt); }
+#else
+(
+ mach_port_t device,
+ dev_flavor_t flavor,
+ dev_status_t status,
+ mach_msg_type_number_t *statusCnt
+);
+#endif
+
+/* Routine device_set_filter */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t device_set_filter
+#if defined(LINTLIBRARY)
+ (device, receive_port, receive_portPoly, priority, filter, filterCnt)
+ mach_port_t device;
+ mach_port_t receive_port;
+ mach_msg_type_name_t receive_portPoly;
+ int priority;
+ filter_array_t filter;
+ mach_msg_type_number_t filterCnt;
+{ return device_set_filter(device, receive_port, receive_portPoly, priority, filter, filterCnt); }
+#else
+(
+ mach_port_t device,
+ mach_port_t receive_port,
+ mach_msg_type_name_t receive_portPoly,
+ int priority,
+ filter_array_t filter,
+ mach_msg_type_number_t filterCnt
+);
+#endif
+
+#endif /* not defined(_device_user_) */
diff --git a/eth-multiplexer/device_impl.c b/eth-multiplexer/device_impl.c
new file mode 100644
index 00000000..f9c8fc34
--- /dev/null
+++ b/eth-multiplexer/device_impl.c
@@ -0,0 +1,283 @@
+/*
+ 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 "ourdevice_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 */
+kern_return_t
+ds_xxx_device_set_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t statu_cnt)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_xxx_device_get_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t *statuscnt)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_xxx_device_set_filter (device_t device, mach_port_t rec,
+ int pri, filter_array_t filt, size_t len)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+/*
+ * 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;
+ int openstat;
+ int right_mode = 1;
+ 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;
+ /* check the mode */
+ openstat = pi->po->openstat;
+ if (mode & D_READ && !(openstat & O_READ))
+ right_mode = 0;
+ if (mode & D_WRITE && !(openstat & O_WRITE))
+ right_mode = 0;
+ ports_port_deref (pi);
+
+ if (dev)
+ {
+ if (!right_mode)
+ return EBADF;
+ *device = dev->dev_port;
+ *devicetype = MACH_MSG_TYPE_MAKE_SEND;
+ return 0;
+ }
+ return D_NO_SUCH_DEVICE;
+}
+
+kern_return_t
+ds_device_close (device_t device)
+{
+ return 0;
+}
+
+kern_return_t
+ds_device_write (device_t device, 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;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ {
+ vm_deallocate (mach_task_self (), 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 (), data, datalen);
+ ports_port_deref (vdev);
+ return ret;
+}
+
+kern_return_t
+ds_device_write_inband (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read_inband (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_map (device_t device, vm_prot_t prot, vm_offset_t offset,
+ vm_size_t size, memory_object_t *pager, int unmap)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_set_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t statuslen)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_get_status (device_t device, 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;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ 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);
+ ports_port_deref (vdev);
+ return ret;
+}
+
+kern_return_t
+ds_device_set_filter (device_t device, mach_port_t receive_port,
+ int priority, filter_array_t filter, size_t filterlen)
+{
+ mach_port_t tmp;
+ kern_return_t err;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ 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, receive_port, priority, filter, filterlen);
+out:
+ ports_port_deref (vdev);
+ return err;
+}
diff --git a/eth-multiplexer/device_impl.c~ b/eth-multiplexer/device_impl.c~
new file mode 100644
index 00000000..8deee668
--- /dev/null
+++ b/eth-multiplexer/device_impl.c~
@@ -0,0 +1,282 @@
+/*
+ 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 "ourdevice_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 */
+kern_return_t
+ds_xxx_device_set_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t statu_cnt)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_xxx_device_get_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t *statuscnt)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_xxx_device_set_filter (device_t device, mach_port_t rec,
+ int pri, filter_array_t filt, size_t len)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+/*
+ * 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;
+ int openstat;
+ int right_mode = 1;
+ 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);
+ }
+
+ dev = (struct vether_device *) pi->po->np->nn->ln;
+ /* check the mode */
+ openstat = pi->po->openstat;
+ if (mode & D_READ && !(openstat & O_READ))
+ right_mode = 0;
+ if (mode & D_WRITE && !(openstat & O_WRITE))
+ right_mode = 0;
+ ports_port_deref (pi);
+
+ if (dev)
+ {
+ if (!right_mode)
+ return EBADF;
+ *device = dev->dev_port;
+ *devicetype = MACH_MSG_TYPE_MAKE_SEND;
+ return 0;
+ }
+ return D_NO_SUCH_DEVICE;
+}
+
+kern_return_t
+ds_device_close (device_t device)
+{
+ return 0;
+}
+
+kern_return_t
+ds_device_write (device_t device, 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;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ {
+ vm_deallocate (mach_task_self (), 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 (), data, datalen);
+ ports_port_deref (vdev);
+ return ret;
+}
+
+kern_return_t
+ds_device_write_inband (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read_inband (device_t device, 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)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_map (device_t device, vm_prot_t prot, vm_offset_t offset,
+ vm_size_t size, memory_object_t *pager, int unmap)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_set_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t statuslen)
+{
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ if (vdev == NULL)
+ return D_NO_SUCH_DEVICE;
+ ports_port_deref (vdev);
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_get_status (device_t device, 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;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ 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);
+ ports_port_deref (vdev);
+ return ret;
+}
+
+kern_return_t
+ds_device_set_filter (device_t device, mach_port_t receive_port,
+ int priority, filter_array_t filter, size_t filterlen)
+{
+ mach_port_t tmp;
+ kern_return_t err;
+ struct vether_device *vdev = ports_lookup_port (port_bucket, device,
+ vdev_portclass);
+ 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, receive_port, priority, filter, filterlen);
+out:
+ ports_port_deref (vdev);
+ return err;
+}
diff --git a/eth-multiplexer/eth-multiplexer.prof_d b/eth-multiplexer/eth-multiplexer.prof_d
new file mode 100644
index 00000000..72fb1f38
--- /dev/null
+++ b/eth-multiplexer/eth-multiplexer.prof_d
@@ -0,0 +1 @@
+eth-multiplexer.prof: ethernet_p.o vdev_p.o multiplexer_p.o bpf_impl_p.o queue_p.o dev_stat_p.o netfs_impl_p.o notify_impl_p.o device_impl_p.o demuxer_p.o ourdeviceServer_p.o notifyServer_p.o ../libports/libports_p.a ../libfshelp/libfshelp_p.a ../libshouldbeinlibc/libshouldbeinlibc_p.a ../libnetfs/libnetfs_p.a
diff --git a/eth-multiplexer/ethernet.c b/eth-multiplexer/ethernet.c
new file mode 100644
index 00000000..5d4e9239
--- /dev/null
+++ b/eth-multiplexer/ethernet.c
@@ -0,0 +1,145 @@
+/*
+ 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;
+
+/* Accept ARP and IP packets. */
+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);
+
+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
+ short flags;
+ int ret;
+ size_t count;
+
+ debug ("set_promisc is called, is_promisc: %d\n", is_promisc);
+ count = sizeof (flags);
+ 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,
+ sizeof (flags));
+ 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.c~ b/eth-multiplexer/ethernet.c~
new file mode 100644
index 00000000..ea774a19
--- /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;
+
+/* Accept ARP and IP packets. */
+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);
+
+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);
+ 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
+ short flags;
+ int ret;
+ size_t count;
+
+ debug ("set_promisc is called, is_promisc: %d\n", is_promisc);
+ count = sizeof (flags);
+ 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,
+ sizeof (flags));
+ 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 00000000..04b41e38
--- /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/multiplexer.c b/eth-multiplexer/multiplexer.c
new file mode 100644
index 00000000..1d0b7ed5
--- /dev/null
+++ b/eth-multiplexer/multiplexer.c
@@ -0,0 +1,189 @@
+/*
+ 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 <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 "ethernet.h"
+#include "vdev.h"
+#include "ourdevice_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 = "eth-multiplexer 0.1";
+const char *argp_program_bug_address = "<bug-hurd@gnu.org>";
+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)
+{
+ int device_server (mach_msg_header_t *, mach_msg_header_t *);
+ int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (device_server (inp, outp)
+ || notify_server (inp, outp)
+ || ethernet_demuxer (inp, outp));
+}
+
+static any_t
+multiplexer_thread (any_t 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 };
+
+ 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. */
+ cthread_detach (cthread_fork (multiplexer_thread, 0));
+
+ 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;
+}
diff --git a/eth-multiplexer/multiplexer.c~ b/eth-multiplexer/multiplexer.c~
new file mode 100644
index 00000000..d3724602
--- /dev/null
+++ b/eth-multiplexer/multiplexer.c~
@@ -0,0 +1,190 @@
+/*
+ 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 <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 "ethernet.h"
+#include "vdev.h"
+#include "ourdevice_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 = "eth-multiplexer 0.1";
+const char *argp_program_bug_address = "<bug-hurd@gnu.org>";
+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)
+{
+ int device_server (mach_msg_header_t *, mach_msg_header_t *);
+ int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (device_server (inp, outp)
+ || notify_server (inp, outp)
+ || ethernet_demuxer (inp, outp));
+}
+
+static any_t
+multiplexer_thread (any_t 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 };
+
+ 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. */
+ cthread_detach (cthread_fork (multiplexer_thread, 0));
+
+ 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;
+ fprintf (stderr, "set it as a dir\n");
+ 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;
+}
diff --git a/eth-multiplexer/netfs_impl.c b/eth-multiplexer/netfs_impl.c
new file mode 100644
index 00000000..40015a83
--- /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;
+ 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*/
+ mutex_unlock (&dir->lock);
+
+ /*stop here*/
+ return err;
+ }
+
+ *node = lookup (name);
+ mutex_lock (&(*node)->lock);
+ 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;
+ 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.c~ b/eth-multiplexer/netfs_impl.c~
new file mode 100644
index 00000000..40faf7a0
--- /dev/null
+++ b/eth-multiplexer/netfs_impl.c~
@@ -0,0 +1,510 @@
+/*
+ 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;
+ 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*/
+ mutex_unlock (&dir->lock);
+
+ /*stop here*/
+ return err;
+ }
+
+ *node = lookup (name);
+ mutex_lock (&(*node)->lock);
+ 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;
+ 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 00000000..17c66f63
--- /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/netfs_impl.h~ b/eth-multiplexer/netfs_impl.h~
new file mode 100644
index 00000000..c2651eb6
--- /dev/null
+++ b/eth-multiplexer/netfs_impl.h~
@@ -0,0 +1,46 @@
+/*
+ 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;
+};
+
+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.defs b/eth-multiplexer/notify.defs
new file mode 100644
index 00000000..2014be5c
--- /dev/null
+++ b/eth-multiplexer/notify.defs
@@ -0,0 +1 @@
+#include <mach/notify.defs>
diff --git a/eth-multiplexer/notify_impl.c b/eth-multiplexer/notify_impl.c
new file mode 100644
index 00000000..33725bb6
--- /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 (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (mach_port_t notify,
+ mach_port_mscount_t mscount)
+{
+ return ports_do_mach_notify_no_senders (notify, mscount);
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_dead_name (mach_port_t notify,
+ 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/notify_impl.c~ b/eth-multiplexer/notify_impl.c~
new file mode 100644
index 00000000..4d31c061
--- /dev/null
+++ b/eth-multiplexer/notify_impl.c~
@@ -0,0 +1,70 @@
+/*
+ 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 (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (mach_port_t notify,
+ mach_port_mscount_t mscount)
+{
+ debug ("no senders notification");
+ return ports_do_mach_notify_no_senders (notify, mscount);
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_dead_name (mach_port_t notify,
+ 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/ourdevice.defs b/eth-multiplexer/ourdevice.defs
new file mode 100644
index 00000000..1b8ac442
--- /dev/null
+++ b/eth-multiplexer/ourdevice.defs
@@ -0,0 +1,383 @@
+# 1 "device.defs"
+# 1 "<built-in>"
+# 1 "<command-line>"
+# 1 "device.defs"
+# 1 "/usr/local/include/device/device.defs" 1 3
+# 39 "/usr/local/include/device/device.defs" 3
+subsystem
+
+
+
+ device 2800;
+
+# 1 "/usr/local/include/mach/std_types.defs" 1 3
+# 33 "/usr/local/include/mach/std_types.defs" 3
+type char = MACH_MSG_TYPE_CHAR;
+type short = MACH_MSG_TYPE_INTEGER_16;
+type int = MACH_MSG_TYPE_INTEGER_32;
+type int32 = MACH_MSG_TYPE_INTEGER_32;
+type int64 = MACH_MSG_TYPE_INTEGER_64;
+type boolean_t = MACH_MSG_TYPE_BOOLEAN;
+type unsigned = MACH_MSG_TYPE_INTEGER_32;
+type unsigned32 = MACH_MSG_TYPE_INTEGER_32;
+type unsigned64 = MACH_MSG_TYPE_INTEGER_64;
+
+
+# 1 "/usr/local/include/mach/machine/machine_types.defs" 1 3
+# 50 "/usr/local/include/mach/machine/machine_types.defs" 3
+type natural_t = unsigned32;
+# 59 "/usr/local/include/mach/machine/machine_types.defs" 3
+type integer_t = int32;
+# 45 "/usr/local/include/mach/std_types.defs" 2 3
+
+type kern_return_t = int;
+
+type pointer_t = ^array[] of MACH_MSG_TYPE_BYTE
+ ctype: vm_offset_t;
+
+
+type mach_port_t = MACH_MSG_TYPE_COPY_SEND;
+type mach_port_array_t = array[] of mach_port_t;
+
+type mach_port_name_t = MACH_MSG_TYPE_PORT_NAME
+ ctype: mach_port_t;
+type mach_port_name_array_t = array[] of mach_port_name_t
+ ctype: mach_port_array_t;
+
+type mach_port_right_t = natural_t;
+
+type mach_port_type_t = natural_t;
+type mach_port_type_array_t = array[] of mach_port_type_t;
+
+type mach_port_urefs_t = natural_t;
+type mach_port_delta_t = integer_t;
+type mach_port_seqno_t = natural_t;
+type mach_port_mscount_t = unsigned;
+type mach_port_msgcount_t = unsigned;
+type mach_port_rights_t = unsigned;
+type mach_msg_id_t = integer_t;
+type mach_msg_type_name_t = unsigned;
+type mach_msg_type_number_t = natural_t;
+
+type mach_port_move_receive_t = MACH_MSG_TYPE_MOVE_RECEIVE
+ ctype: mach_port_t;
+type mach_port_copy_send_t = MACH_MSG_TYPE_COPY_SEND
+ ctype: mach_port_t;
+type mach_port_make_send_t = MACH_MSG_TYPE_MAKE_SEND
+ ctype: mach_port_t;
+type mach_port_move_send_t = MACH_MSG_TYPE_MOVE_SEND
+ ctype: mach_port_t;
+type mach_port_make_send_once_t = MACH_MSG_TYPE_MAKE_SEND_ONCE
+ ctype: mach_port_t;
+type mach_port_move_send_once_t = MACH_MSG_TYPE_MOVE_SEND_ONCE
+ ctype: mach_port_t;
+
+type mach_port_receive_t = MACH_MSG_TYPE_PORT_RECEIVE
+ ctype: mach_port_t;
+type mach_port_send_t = MACH_MSG_TYPE_PORT_SEND
+ ctype: mach_port_t;
+type mach_port_send_once_t = MACH_MSG_TYPE_PORT_SEND_ONCE
+ ctype: mach_port_t;
+
+type mach_port_poly_t = polymorphic
+ ctype: mach_port_t;
+
+import <mach/std_types.h>;
+# 46 "/usr/local/include/device/device.defs" 2 3
+# 1 "/usr/local/include/mach/mach_types.defs" 1 3
+# 61 "/usr/local/include/mach/mach_types.defs" 3
+type mach_port_status_t = struct[9] of integer_t;
+
+type old_mach_port_status_t = struct[8] of integer_t;
+
+type task_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+
+ ;
+# 85 "/usr/local/include/mach/mach_types.defs" 3
+type thread_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+
+ ;
+
+type thread_state_t = array[*:1024] of natural_t;
+
+type task_array_t = ^array[] of task_t;
+type thread_array_t = ^array[] of thread_t;
+
+type vm_task_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+ ;
+
+type ipc_space_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+ ;
+
+type vm_address_t = natural_t;
+type vm_offset_t = natural_t;
+type vm_size_t = natural_t;
+type vm_prot_t = int;
+type vm_inherit_t = int;
+type vm_statistics_data_t = struct[13] of integer_t;
+type vm_machine_attribute_t = int;
+type vm_machine_attribute_val_t = int;
+
+type thread_info_t = array[*:1024] of natural_t;
+type thread_basic_info_data_t = struct[11] of integer_t;
+type thread_sched_info_data_t = struct[7] of integer_t;
+
+type task_info_t = array[*:1024] of natural_t;
+type task_basic_info_data_t = struct[8] of integer_t;
+type task_events_info = struct[7] of natural_t;
+type task_thread_times_info_data_t = struct[4] of integer_t;
+
+
+type memory_object_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+ ;
+
+type memory_object_control_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+ ;
+
+type memory_object_name_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+ ;
+
+type memory_object_copy_strategy_t = int;
+type memory_object_return_t = int;
+
+type machine_info_data_t = struct[5] of integer_t;
+type machine_slot_data_t = struct[8] of integer_t;
+
+type host_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+ ;
+
+type host_priv_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+ ;
+
+type host_info_t = array[*:1024] of natural_t;
+type host_basic_info_data_t = struct[5] of integer_t;
+type host_sched_info_data_t = struct[2] of integer_t;
+type host_load_info_data_t = struct[6] of integer_t;
+
+
+type processor_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+ ;
+
+type processor_array_t = ^array[] of processor_t;
+type processor_info_t = array[*:1024] of natural_t;
+type processor_basic_info_data_t = struct[5] of integer_t;
+
+
+type processor_set_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+
+ ;
+
+type processor_set_array_t = ^array[] of processor_set_t;
+
+type processor_set_name_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+
+ ;
+
+type processor_set_name_array_t = ^array[] of processor_set_name_t;
+
+type processor_set_info_t = array[*:1024] of natural_t;
+type processor_set_basic_info_data_t = struct[5] of integer_t;
+type processor_set_sched_info_data_t = struct[2] of integer_t;
+
+
+type kernel_version_t = (MACH_MSG_TYPE_STRING, 512*8);
+
+type kernel_boot_info_t = (MACH_MSG_TYPE_STRING, 4096*8);
+
+type time_value_t = struct[2] of integer_t;
+
+type emulation_vector_t = ^array[] of vm_offset_t;
+
+type xxx_emulation_vector_t = array[*:1024] of vm_offset_t
+ ctype: emulation_vector_t;
+
+
+type rpc_signature_info_t = array[*:1024] of int;
+# 250 "/usr/local/include/mach/mach_types.defs" 3
+import <mach/mach_types.h>;
+# 47 "/usr/local/include/device/device.defs" 2 3
+# 1 "/usr/local/include/device/device_types.defs" 1 3
+# 42 "/usr/local/include/device/device_types.defs" 3
+type recnum_t = unsigned32;
+type dev_mode_t = unsigned32;
+type dev_flavor_t = unsigned32;
+type dev_name_t = (MACH_MSG_TYPE_STRING_C, 8*128);
+type dev_status_t = array[*:1024] of int;
+type io_buf_ptr_t = ^array[] of MACH_MSG_TYPE_INTEGER_8;
+type io_buf_ptr_inband_t= array[*:128] of char;
+type filter_t = short;
+type filter_array_t = array[*:128] of filter_t;
+
+type device_t = mach_port_t
+ ctype: mach_port_t
+
+
+
+
+
+ ;
+
+import <device/device_types.h>;
+import <device/net_status.h>;
+# 48 "/usr/local/include/device/device.defs" 2 3
+
+serverprefix ds_;
+
+type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic
+ ctype: mach_port_t;
+
+routine device_open(
+ master_port : mach_port_t;
+ sreplyport reply_port : reply_port_t;
+ mode : dev_mode_t;
+ name : dev_name_t;
+ out device : mach_port_send_t
+ );
+
+routine device_close(
+ device : device_t
+ );
+
+routine device_write(
+ device : device_t;
+ sreplyport reply_port : reply_port_t;
+ in mode : dev_mode_t;
+ in recnum : recnum_t;
+ in data : io_buf_ptr_t;
+ out bytes_written : int
+ );
+
+routine device_write_inband(
+ device : device_t;
+ sreplyport reply_port : reply_port_t;
+ in mode : dev_mode_t;
+ in recnum : recnum_t;
+ in data : io_buf_ptr_inband_t;
+ out bytes_written : int
+ );
+
+routine device_read(
+ device : device_t;
+ sreplyport reply_port : reply_port_t;
+ in mode : dev_mode_t;
+ in recnum : recnum_t;
+ in bytes_wanted : int;
+ out data : io_buf_ptr_t
+ );
+
+routine device_read_inband(
+ device : device_t;
+ sreplyport reply_port : reply_port_t;
+ in mode : dev_mode_t;
+ in recnum : recnum_t;
+ in bytes_wanted : int;
+ out data : io_buf_ptr_inband_t
+ );
+
+
+routine xxx_device_set_status(
+ device : device_t;
+ in flavor : dev_flavor_t;
+ in status : dev_status_t, IsLong
+ );
+
+
+routine xxx_device_get_status(
+ device : device_t;
+ in flavor : dev_flavor_t;
+ out status : dev_status_t, IsLong
+ );
+
+
+routine xxx_device_set_filter(
+ device : device_t;
+ in receive_port : mach_port_send_t;
+ in priority : int;
+ in filter : filter_array_t, IsLong
+ );
+
+routine device_map(
+ device : device_t;
+ in prot : vm_prot_t;
+ in offset : vm_offset_t;
+ in size : vm_size_t;
+ out pager : memory_object_t;
+ in unmap : int
+ );
+
+routine device_set_status(
+ device : device_t;
+ in flavor : dev_flavor_t;
+ in status : dev_status_t
+ );
+
+routine device_get_status(
+ device : device_t;
+ in flavor : dev_flavor_t;
+ out status : dev_status_t, CountInOut
+ );
+
+routine device_set_filter(
+ device : device_t;
+ in receive_port : mach_port_send_t;
+ in priority : int;
+ in filter : filter_array_t
+ );
+# 1 "device.defs" 2
diff --git a/eth-multiplexer/queue.c b/eth-multiplexer/queue.c
new file mode 100644
index 00000000..a43a21b0
--- /dev/null
+++ b/eth-multiplexer/queue.c
@@ -0,0 +1,131 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Routines to implement queue package.
+ */
+
+#include "queue.h"
+
+
+
+/*
+ * Insert element at head of queue.
+ */
+void enqueue_head(
+ register queue_t que,
+ register queue_entry_t elt)
+{
+ elt->next = que->next;
+ elt->prev = que;
+ elt->next->prev = elt;
+ que->next = elt;
+}
+
+/*
+ * Insert element at tail of queue.
+ */
+void enqueue_tail(
+ register queue_t que,
+ register queue_entry_t elt)
+{
+ elt->next = que;
+ elt->prev = que->prev;
+ elt->prev->next = elt;
+ que->prev = elt;
+}
+
+/*
+ * Remove and return element at head of queue.
+ */
+queue_entry_t dequeue_head(
+ register queue_t que)
+{
+ register queue_entry_t elt;
+
+ if (que->next == que)
+ return((queue_entry_t)0);
+
+ elt = que->next;
+ elt->next->prev = que;
+ que->next = elt->next;
+ return(elt);
+}
+
+/*
+ * Remove and return element at tail of queue.
+ */
+queue_entry_t dequeue_tail(
+ register queue_t que)
+{
+ register queue_entry_t elt;
+
+ if (que->prev == que)
+ return((queue_entry_t)0);
+
+ elt = que->prev;
+ elt->prev->next = que;
+ que->prev = elt->prev;
+ return(elt);
+}
+
+/*
+ * Remove arbitrary element from queue.
+ * Does not check whether element is on queue - the world
+ * will go haywire if it isn't.
+ */
+
+/*ARGSUSED*/
+void remqueue(
+ queue_t que,
+ register queue_entry_t elt)
+{
+ elt->next->prev = elt->prev;
+ elt->prev->next = elt->next;
+}
+
+/*
+ * Routines to directly imitate the VAX hardware queue
+ * package.
+ */
+void insque(
+ register struct queue_entry *entry,
+ register struct queue_entry *pred)
+{
+ entry->next = pred->next;
+ entry->prev = pred;
+ (pred->next)->prev = entry;
+ pred->next = entry;
+}
+
+struct queue_entry
+*remque(
+ register struct queue_entry *elt)
+{
+ (elt->next)->prev = elt->prev;
+ (elt->prev)->next = elt->next;
+ return(elt);
+}
+
diff --git a/eth-multiplexer/queue.h b/eth-multiplexer/queue.h
new file mode 100644
index 00000000..f067f557
--- /dev/null
+++ b/eth-multiplexer/queue.h
@@ -0,0 +1,329 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon rights
+ * to redistribute these changes.
+ */
+/*
+ * File: queue.h
+ * Author: Avadis Tevanian, Jr.
+ * Date: 1985
+ *
+ * Type definitions for generic queues.
+ *
+ */
+
+#ifndef _KERN_QUEUE_H_
+#define _KERN_QUEUE_H_
+
+/*
+ * Queue of abstract objects. Queue is maintained
+ * within that object.
+ *
+ * Supports fast removal from within the queue.
+ *
+ * How to declare a queue of elements of type "foo_t":
+ * In the "*foo_t" type, you must have a field of
+ * type "queue_chain_t" to hold together this queue.
+ * There may be more than one chain through a
+ * "foo_t", for use by different queues.
+ *
+ * Declare the queue as a "queue_t" type.
+ *
+ * Elements of the queue (of type "foo_t", that is)
+ * are referred to by reference, and cast to type
+ * "queue_entry_t" within this module.
+ */
+
+/*
+ * A generic doubly-linked list (queue).
+ */
+
+struct queue_entry {
+ struct queue_entry *next; /* next element */
+ struct queue_entry *prev; /* previous element */
+};
+
+typedef struct queue_entry *queue_t;
+typedef struct queue_entry queue_head_t;
+typedef struct queue_entry queue_chain_t;
+typedef struct queue_entry *queue_entry_t;
+
+/*
+ * enqueue puts "elt" on the "queue".
+ * dequeue returns the first element in the "queue".
+ * remqueue removes the specified "elt" from the specified "queue".
+ */
+
+#define enqueue(queue,elt) enqueue_tail(queue, elt)
+#define dequeue(queue) dequeue_head(queue)
+
+void enqueue_head(queue_t, queue_entry_t);
+void enqueue_tail(queue_t, queue_entry_t);
+queue_entry_t dequeue_head(queue_t);
+queue_entry_t dequeue_tail(queue_t);
+void remqueue(queue_t, queue_entry_t);
+
+/*
+ * Macro: queue_init
+ * Function:
+ * Initialize the given queue.
+ * Header:
+ * void queue_init(q)
+ * queue_t q; *MODIFIED*
+ */
+#define queue_init(q) ((q)->next = (q)->prev = q)
+
+/*
+ * Macro: queue_first
+ * Function:
+ * Returns the first entry in the queue,
+ * Header:
+ * queue_entry_t queue_first(q)
+ * queue_t q; *IN*
+ */
+#define queue_first(q) ((q)->next)
+
+/*
+ * Macro: queue_next
+ * Function:
+ * Returns the entry after an item in the queue.
+ * Header:
+ * queue_entry_t queue_next(qc)
+ * queue_t qc;
+ */
+#define queue_next(qc) ((qc)->next)
+
+/*
+ * Macro: queue_last
+ * Function:
+ * Returns the last entry in the queue.
+ * Header:
+ * queue_entry_t queue_last(q)
+ * queue_t q; *IN*
+ */
+#define queue_last(q) ((q)->prev)
+
+/*
+ * Macro: queue_prev
+ * Function:
+ * Returns the entry before an item in the queue.
+ * Header:
+ * queue_entry_t queue_prev(qc)
+ * queue_t qc;
+ */
+#define queue_prev(qc) ((qc)->prev)
+
+/*
+ * Macro: queue_end
+ * Function:
+ * Tests whether a new entry is really the end of
+ * the queue.
+ * Header:
+ * boolean_t queue_end(q, qe)
+ * queue_t q;
+ * queue_entry_t qe;
+ */
+#define queue_end(q, qe) ((q) == (qe))
+
+/*
+ * Macro: queue_empty
+ * Function:
+ * Tests whether a queue is empty.
+ * Header:
+ * boolean_t queue_empty(q)
+ * queue_t q;
+ */
+#define queue_empty(q) queue_end((q), queue_first(q))
+
+
+/*----------------------------------------------------------------*/
+/*
+ * Macros that operate on generic structures. The queue
+ * chain may be at any location within the structure, and there
+ * may be more than one chain.
+ */
+
+/*
+ * Macro: queue_enter
+ * Function:
+ * Insert a new element at the tail of the queue.
+ * Header:
+ * void queue_enter(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_enter(head, elt, type, field) \
+{ \
+ register queue_entry_t prev; \
+ \
+ prev = (head)->prev; \
+ if ((head) == prev) { \
+ (head)->next = (queue_entry_t) (elt); \
+ } \
+ else { \
+ ((type)prev)->field.next = (queue_entry_t)(elt);\
+ } \
+ (elt)->field.prev = prev; \
+ (elt)->field.next = head; \
+ (head)->prev = (queue_entry_t) elt; \
+}
+
+/*
+ * Macro: queue_enter_first
+ * Function:
+ * Insert a new element at the head of the queue.
+ * Header:
+ * void queue_enter_first(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_enter_first(head, elt, type, field) \
+{ \
+ register queue_entry_t next; \
+ \
+ next = (head)->next; \
+ if ((head) == next) { \
+ (head)->prev = (queue_entry_t) (elt); \
+ } \
+ else { \
+ ((type)next)->field.prev = (queue_entry_t)(elt);\
+ } \
+ (elt)->field.next = next; \
+ (elt)->field.prev = head; \
+ (head)->next = (queue_entry_t) elt; \
+}
+
+/*
+ * Macro: queue_field [internal use only]
+ * Function:
+ * Find the queue_chain_t (or queue_t) for the
+ * given element (thing) in the given queue (head)
+ */
+#define queue_field(head, thing, type, field) \
+ (((head) == (thing)) ? (head) : &((type)(thing))->field)
+
+/*
+ * Macro: queue_remove
+ * Function:
+ * Remove an arbitrary item from the queue.
+ * Header:
+ * void queue_remove(q, qe, type, field)
+ * arguments as in queue_enter
+ */
+#define queue_remove(head, elt, type, field) \
+{ \
+ register queue_entry_t next, prev; \
+ \
+ next = (elt)->field.next; \
+ prev = (elt)->field.prev; \
+ \
+ if ((head) == next) \
+ (head)->prev = prev; \
+ else \
+ ((type)next)->field.prev = prev; \
+ \
+ if ((head) == prev) \
+ (head)->next = next; \
+ else \
+ ((type)prev)->field.next = next; \
+}
+
+/*
+ * Macro: queue_remove_first
+ * Function:
+ * Remove and return the entry at the head of
+ * the queue.
+ * Header:
+ * queue_remove_first(head, entry, type, field)
+ * entry is returned by reference
+ */
+#define queue_remove_first(head, entry, type, field) \
+{ \
+ register queue_entry_t next; \
+ \
+ (entry) = (type) ((head)->next); \
+ next = (entry)->field.next; \
+ \
+ if ((head) == next) \
+ (head)->prev = (head); \
+ else \
+ ((type)(next))->field.prev = (head); \
+ (head)->next = next; \
+}
+
+/*
+ * Macro: queue_remove_last
+ * Function:
+ * Remove and return the entry at the tail of
+ * the queue.
+ * Header:
+ * queue_remove_last(head, entry, type, field)
+ * entry is returned by reference
+ */
+#define queue_remove_last(head, entry, type, field) \
+{ \
+ register queue_entry_t prev; \
+ \
+ (entry) = (type) ((head)->prev); \
+ prev = (entry)->field.prev; \
+ \
+ if ((head) == prev) \
+ (head)->next = (head); \
+ else \
+ ((type)(prev))->field.next = (head); \
+ (head)->prev = prev; \
+}
+
+/*
+ * Macro: queue_assign
+ */
+#define queue_assign(to, from, type, field) \
+{ \
+ ((type)((from)->prev))->field.next = (to); \
+ ((type)((from)->next))->field.prev = (to); \
+ *to = *from; \
+}
+
+/*
+ * Macro: queue_iterate
+ * Function:
+ * iterate over each item in the queue.
+ * Generates a 'for' loop, setting elt to
+ * each item in turn (by reference).
+ * Header:
+ * queue_iterate(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_iterate(head, elt, type, field) \
+ for ((elt) = (type) queue_first(head); \
+ !queue_end((head), (queue_entry_t)(elt)); \
+ (elt) = (type) queue_next(&(elt)->field))
+
+#endif /* _KERN_QUEUE_H_ */
diff --git a/eth-multiplexer/test.c b/eth-multiplexer/test.c
new file mode 100644
index 00000000..bf80583f
--- /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 00000000..c90b0f85
--- /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 00000000..5e525b31
--- /dev/null
+++ b/eth-multiplexer/vdev.c
@@ -0,0 +1,307 @@
+/*
+ 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 <cthreads.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 struct mutex dev_list_lock = 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;
+ mutex_lock (&dev_list_lock);
+ for (vdev = dev_head; vdev; vdev = vdev->next)
+ {
+ if (strncmp (vdev->name, name, IFNAMSIZ) == 0)
+ break;
+ }
+ mutex_unlock (&dev_list_lock);
+ return vdev;
+}
+
+int
+foreach_dev_do (int (func) (struct vether_device *))
+{
+ struct vether_device *vdev;
+ int rval = 0;
+ mutex_lock (&dev_list_lock);
+ for (vdev = dev_head; vdev; vdev = vdev->next)
+ {
+ mutex_unlock (&dev_list_lock);
+ /* func() can stop the loop by returning <> 0 */
+ rval = func (vdev);
+ mutex_lock (&dev_list_lock);
+ if (rval)
+ break;
+ }
+ 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;
+ mutex_lock (&dev_list_lock);
+ for (vdev = dev_head; vdev; vdev = vdev->next)
+ {
+ remove_dead_filter (vdev, &vdev->if_rcv_port_list, dead_port);
+ remove_dead_filter (vdev, &vdev->if_snd_port_list, dead_port);
+ }
+ 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->if_rcv_port_list);
+ queue_init (&vdev->if_snd_port_list);
+
+ 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++;
+ 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 */
+ mutex_lock (&dev_list_lock);
+ *vdev->pprev = vdev->next;
+ if (vdev->next)
+ vdev->next->pprev = vdev->pprev;
+ dev_num--;
+ mutex_unlock (&dev_list_lock);
+
+ /* TODO Delete all filters in the interface,
+ * there shouldn't be any filters left */
+ destroy_filters (vdev);
+}
+
+/* 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->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 00000000..b8bab019
--- /dev/null
+++ b/eth-multiplexer/vdev.h
@@ -0,0 +1,78 @@
+/*
+ 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 "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;
+
+ queue_head_t if_rcv_port_list; /* input filter list */
+ queue_head_t if_snd_port_list; /* output filter 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