diff options
Diffstat (limited to 'eth-multiplexer')
39 files changed, 6197 insertions, 0 deletions
diff --git a/eth-multiplexer/.DS_Store b/eth-multiplexer/.DS_Store Binary files differnew file mode 100644 index 00000000..4e8d087c --- /dev/null +++ b/eth-multiplexer/.DS_Store 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 Binary files differnew file mode 100644 index 00000000..f4475c71 --- /dev/null +++ b/eth-multiplexer/core 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", ðer_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", ðer_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), ¬ify_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), ¬ify_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 |