diff options
Diffstat (limited to 'eth-multiplexer')
-rw-r--r-- | eth-multiplexer/ChangeLog | 341 | ||||
-rw-r--r-- | eth-multiplexer/Makefile | 37 | ||||
-rw-r--r-- | eth-multiplexer/README | 27 | ||||
-rw-r--r-- | eth-multiplexer/demuxer.c | 41 | ||||
-rw-r--r-- | eth-multiplexer/dev_stat.c | 101 | ||||
-rw-r--r-- | eth-multiplexer/device.h | 336 | ||||
-rw-r--r-- | eth-multiplexer/device_impl.c | 284 | ||||
-rw-r--r-- | eth-multiplexer/ethernet.c | 144 | ||||
-rw-r--r-- | eth-multiplexer/ethernet.h | 39 | ||||
-rw-r--r-- | eth-multiplexer/multiplexer.c | 208 | ||||
-rw-r--r-- | eth-multiplexer/netfs_impl.c | 508 | ||||
-rw-r--r-- | eth-multiplexer/netfs_impl.h | 47 | ||||
-rw-r--r-- | eth-multiplexer/notify_impl.c | 69 | ||||
-rw-r--r-- | eth-multiplexer/test.c | 53 | ||||
-rw-r--r-- | eth-multiplexer/util.h | 91 | ||||
-rw-r--r-- | eth-multiplexer/vdev.c | 309 | ||||
-rw-r--r-- | eth-multiplexer/vdev.h | 79 |
17 files changed, 2714 insertions, 0 deletions
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/Makefile b/eth-multiplexer/Makefile new file mode 100644 index 00000000..a96619cf --- /dev/null +++ b/eth-multiplexer/Makefile @@ -0,0 +1,37 @@ +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 2008 Free Software Foundation, Inc. +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the GNU Hurd; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +dir := eth-multiplexer +makemode := server +target = eth-multiplexer + +#CFLAGS += -DDEBUG +SRCS = ethernet.c vdev.c multiplexer.c dev_stat.c netfs_impl.c notify_impl.c device_impl.c demuxer.c +MIGSTUBS = ourdeviceServer.o notifyServer.o +OBJS = $(SRCS:.c=.o) $(MIGSTUBS) +LCLHDRS = ethernet.h util.h vdev.h netfs_impl.h +DIST_FILES = ourdevice.defs notify.defs +HURDLIBS=ports fshelp shouldbeinlibc netfs bpf +OTHERLIBS = -lpthread + +CFLAGS += -I$(top_srcdir)/libbpf + +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/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.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..953fca70 --- /dev/null +++ b/eth-multiplexer/device_impl.c @@ -0,0 +1,284 @@ +/* + 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->port_list, receive_port, + priority, filter, filterlen); +out: + ports_port_deref (vdev); + return err; +} diff --git a/eth-multiplexer/ethernet.c b/eth-multiplexer/ethernet.c new file mode 100644 index 00000000..32c5589f --- /dev/null +++ b/eth-multiplexer/ethernet.c @@ -0,0 +1,144 @@ +/* + Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007, 2008 + Free Software Foundation, Inc. + + Written by Zheng Da + + Based on pfinet/ethernet.c, written by Michael I. Bushnell, p/BSG. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <string.h> +#include <error.h> +#include <assert.h> +#include <net/if.h> +#include <sys/ioctl.h> + +#include <hurd/ports.h> +#include <device/device.h> +#include <device/net_status.h> + +#include "ethernet.h" +#include "vdev.h" +#include "util.h" + +#define ETH_HLEN 14 + +static struct port_info *readpt; + +/* Port for writing message to the real network interface. */ +mach_port_t ether_port; +/* Port for receiving messages from the interface. */ +static mach_port_t readptname; + +/* The BPF instruction allows IP and ARP packets */ +static struct bpf_insn ether_filter[] = +{ + {NETF_IN|NETF_BPF, /* Header. */ 0, 0, 0}, + {40, 0, 0, 12}, + {21, 1, 0, 2054}, + {21, 0, 1, 2048}, + {6, 0, 0, 1500}, + {6, 0, 0, 0} +}; +static int ether_filter_len = sizeof (ether_filter) / sizeof (short); + +int ethernet_demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + struct net_rcv_msg *msg = (struct net_rcv_msg *) inp; + + if (inp->msgh_id != NET_RCV_MSG_ID) + return 0; + + broadcast_msg (msg); + /* The data from the underlying network is inside the message, + * so we don't need to deallocate the data. */ + return 1; +} + +int set_promisc (char *dev_name, mach_port_t ether_port, int is_promisc) +{ +#ifndef NET_FLAGS +#define NET_FLAGS (('n'<<16) + 4) +#endif + 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..87578ec5 --- /dev/null +++ b/eth-multiplexer/multiplexer.c @@ -0,0 +1,208 @@ +/* + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * The multiplexer server provides the virtual network interface. + * When it gets a packet, it forwards it to every other network interface, + * the ones that are created by itself or that it connects to. + * BPF is ported to the multiplexer to help deliver packets + * to the right pfinet. + */ + +#include <argz.h> +#include <argp.h> +#include <errno.h> +#include <error.h> +#include <stdlib.h> +#include <fcntl.h> + +#include <hurd.h> +#include <mach.h> +#include <version.h> +#include <device/device.h> +#include <hurd/ports.h> +#include <hurd/netfs.h> + +#include "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 void * +multiplexer_thread (void *arg) +{ + ports_manage_port_operations_one_thread (port_bucket, + multiplexer_demuxer, + 0); + return 0; +} + +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + switch (opt) + { + case 'i': + device_file = arg; + break; + case ARGP_KEY_ERROR: + case ARGP_KEY_SUCCESS: + case ARGP_KEY_INIT: + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + error_t err; + mach_port_t bootstrap; + mach_port_t master_device; + const struct argp argp = { options, parse_opt, 0, doc }; + pthread_t t; + + port_bucket = ports_create_bucket (); + other_portclass = ports_create_class (0, 0); + vdev_portclass = ports_create_class (destroy_vdev, 0); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + /* Open the network interface. */ + if (device_file) + { + master_device = file_name_lookup (device_file, 0, 0); + if (master_device == MACH_PORT_NULL) + error (1, errno, "file_name_lookup"); + + ethernet_open (device_file, master_device, port_bucket, + other_portclass); + } + + /* Prepare for the notification. */ + err = ports_create_port (other_portclass, port_bucket, + sizeof (struct port_info), ¬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. */ + pthread_create (&t, NULL, multiplexer_thread, NULL); + pthread_detach (t); + + err = maptime_map (0, 0, &multiplexer_maptime); + if (err) + error (4, err, "Cannot map time"); + + /* Initialize netfs and start the translator. */ + netfs_init (); + + root_file = netfs_startup (bootstrap, O_READ); + err = new_node (&root, &netfs_root_node); + if (err) + error (5, err, "Cannot create root node"); + + err = io_stat (root_file, &underlying_node_stat); + if (err) + error (6, err, "Cannot stat underlying node"); + + struct stat stat = underlying_node_stat; + /* If the underlying node is not a directory, increase its permissions */ + if(!S_ISDIR(stat.st_mode)) + { + if(stat.st_mode & S_IRUSR) + stat.st_mode |= S_IXUSR; + if(stat.st_mode & S_IRGRP) + stat.st_mode |= S_IXGRP; + if(stat.st_mode & S_IROTH) + stat.st_mode |= S_IXOTH; + } + + stat.st_mode &= ~(S_ITRANS | S_IFMT); + stat.st_mode |= S_IFDIR; + netfs_root_node->nn->ln->st = stat; + fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, + multiplexer_maptime); + + netfs_server_loop (); /* Never returns. */ + return 0; +} + +error_t +netfs_append_args (char **argz, size_t *argz_len) +{ + error_t err = 0; + +#define ADD_OPT(fmt, args...) \ + do { char buf[100]; \ + if (! err) { \ + snprintf (buf, sizeof buf, fmt , ##args); \ + err = argz_add (argz, argz_len, buf); } } while (0) + if (device_file) + ADD_OPT ("--interface=%s", device_file); +#undef ADD_OPT + return err; +} diff --git a/eth-multiplexer/netfs_impl.c b/eth-multiplexer/netfs_impl.c new file mode 100644 index 00000000..29ae072c --- /dev/null +++ b/eth-multiplexer/netfs_impl.c @@ -0,0 +1,508 @@ +/* + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <fcntl.h> +#include <dirent.h> +#include <stddef.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <ctype.h> + +#include <hurd/netfs.h> + +#include "netfs_impl.h" +#include "vdev.h" +#include "util.h" + +#define DIRENTS_CHUNK_SIZE (8*1024) +/* Returned directory entries are aligned to blocks this many bytes long. + * Must be a power of two. */ +#define DIRENT_ALIGN 4 +#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name) + +/* Length is structure before the name + the name + '\0', all + * padded to a four-byte alignment. */ +#define DIRENT_LEN(name_len) \ + ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \ + & ~(DIRENT_ALIGN - 1)) + +extern struct stat underlying_node_stat; + +int +is_num (char *str) +{ + for (; *str; str++) + { + if (!isdigit (*str)) + return 0; + } + return 1; +} + +/* Make a new virtual node. Always consumes the ports. */ +error_t +new_node (struct lnode *ln, struct node **np) +{ + error_t err = 0; + struct netnode *nn = calloc (1, sizeof *nn); + struct node *node; + + if (nn == 0) + return ENOMEM; + node = netfs_make_node (nn); + if (node == 0) + { + free (nn); + *np = NULL; + return ENOMEM; + } + if (ln) + ln->n = node; + nn->ln = ln; + *np = node; + return err; +} + +struct node * +lookup (char *name) +{ + struct lnode *ln = (struct lnode *) lookup_dev_by_name (name); + + char *copied_name = malloc (strlen (name) + 1); + strcpy (copied_name, name); + if (ln) + { + new_node (ln, &ln->n); + ln->n->nn->name = copied_name; + return ln->n; + } + else + { + struct node *n; + new_node (ln, &n); + n->nn->name = copied_name; + return n; + } +} + +/* Attempt to create a file named NAME in DIR for USER with MODE. Set *NODE + to the new node upon return. On any error, clear *NODE. *NODE should be + locked on success; no matter what, unlock DIR before returning. */ +error_t +netfs_attempt_create_file (struct iouser *user, struct node *dir, + char *name, mode_t mode, struct node **node) +{ + debug(""); + *node = 0; + pthread_mutex_unlock (&dir->lock); + return EOPNOTSUPP; +} + +/* Node NODE is being opened by USER, with FLAGS. NEWNODE is nonzero if we + just created this node. Return an error if we should not permit the open + to complete because of a permission restriction. */ +error_t +netfs_check_open_permissions (struct iouser *user, struct node *node, + int flags, int newnode) +{ + error_t err = 0; + + /*Cheks user's permissions*/ + if(flags & O_READ) + err = fshelp_access(&node->nn_stat, S_IREAD, user); + if(!err && (flags & O_WRITE)) + err = fshelp_access(&node->nn_stat, S_IWRITE, user); + if(!err && (flags & O_EXEC)) + err = fshelp_access(&node->nn_stat, S_IEXEC, user); + + debug("the mode of node: %o, return result: %d", + (node->nn_stat.st_mode & ~S_IFMT), err); + /*Return the result of the check*/ + return err; +} + +/* This should attempt a utimes call for the user specified by CRED on node + NODE, to change the atime to ATIME and the mtime to MTIME. */ +error_t +netfs_attempt_utimes (struct iouser *cred, struct node *node, + struct timespec *atime, struct timespec *mtime) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and O_EXEC) + in *TYPES for file NODE and user CRED. */ +error_t +netfs_report_access (struct iouser *cred, struct node *node, int *types) +{ + debug(""); + *types = 0; + return 0; +} + +/* Make sure that NP->nn_stat is filled with current information. CRED + identifies the user responsible for the operation. */ +error_t +netfs_validate_stat (struct node *node, struct iouser *cred) +{ + struct stat st; + + if (node->nn->ln) + st = node->nn->ln->st; + else + st = underlying_node_stat; + + debug("node: %p", node); + node->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0; + node->nn_stat = st; + return 0; +} + +/* This should sync the file NODE completely to disk, for the user CRED. If + WAIT is set, return only after sync is completely finished. */ +error_t +netfs_attempt_sync (struct iouser *cred, struct node *node, int wait) +{ + debug(""); + return 0; +} + +error_t +netfs_get_dirents (struct iouser *cred, struct node *dir, + int first_entry, int max_entries, char **data, + mach_msg_type_number_t *data_len, + vm_size_t max_data_len, int *data_entries) +{ + error_t err; + int count = 0; + char *data_p; + size_t size = (max_data_len == 0 || max_data_len > DIRENTS_CHUNK_SIZE + ? DIRENTS_CHUNK_SIZE : max_data_len); + debug (""); + int + add_dirent (const char * name, ino_t ino, int type) + { + /*If the required number of dirents has not been listed yet*/ + if((max_entries == -1) || (count < max_entries)) + { + struct dirent hdr; + size_t name_len = strlen(name); + size_t sz = DIRENT_LEN(name_len); + + /*If there is no room for this dirent*/ + if ((data_p - *data) + sz > size) + { + if (max_data_len > 0) + return 1; + else + /* Try to grow our return buffer. */ + { + error_t err; + vm_address_t extension = (vm_address_t)(*data + size); + err = vm_allocate (mach_task_self (), &extension, + DIRENTS_CHUNK_SIZE, 0); + if (err) + { + munmap (*data, size); + return 1; + } + size += DIRENTS_CHUNK_SIZE; + } + } + + /*setup the dirent*/ + hdr.d_ino = ino; + hdr.d_reclen = sz; + hdr.d_type = type; + hdr.d_namlen = name_len; + memcpy(data_p, &hdr, DIRENT_NAME_OFFS); + strcpy(data_p + DIRENT_NAME_OFFS, name); + data_p += sz; + + /*count the new dirent*/ + ++count; + } + return 0; + } + int add_each_dev (struct vether_device *dev) + { + struct lnode *ln = (struct lnode *) dev; + add_dirent (ln->vdev.name, ln->st.st_ino, DT_CHR); + return 0; + } + if (dir != netfs_root_node) + return ENOTDIR; + + *data = mmap (0, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); + err = ((void *) *data == (void *) -1) ? errno : 0; + if (!err) + { + data_p = *data; + if (first_entry < 2 + get_dev_num ()) + { + add_dirent (".", 2, DT_DIR); + add_dirent ("..", 2, DT_DIR); + foreach_dev_do (add_each_dev); + } + + vm_address_t alloc_end = (vm_address_t)(*data + size); + vm_address_t real_end = round_page (data_p); + if (alloc_end > real_end) + munmap ((caddr_t) real_end, alloc_end - real_end); + *data_entries = count; + debug ("first_entry is %d, count is %d", first_entry, count); + *data_len = data_p - *data; + } + return err; +} + +/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If + the name was not found, then return ENOENT. On any error, clear *NODE. + (*NODE, if found, should be locked, this call should unlock DIR no matter + what.) */ +error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, + char *name, struct node **node) +{ + error_t err = 0; + + debug ("dir: %p, file name: %s", dir, name); + + if (strcmp(name, ".") == 0) + { + netfs_nref(dir); + *node = dir; + return 0; + } + else if (strcmp(name, "..") == 0) + { + /*The supplied node is always root*/ + err = ENOENT; + *node = NULL; + + /*unlock the directory*/ + pthread_mutex_unlock (&dir->lock); + + /*stop here*/ + return err; + } + + *node = lookup (name); + pthread_mutex_lock (&(*node)->lock); + pthread_mutex_unlock (&dir->lock); + return 0; +} + +/* Delete NAME in DIR for USER. */ +error_t netfs_attempt_unlink (struct iouser *user, struct node *dir, + char *name) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Note that in this one call, neither of the specific nodes are locked. */ +error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir, + char *fromname, struct node *todir, + char *toname, int excl) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Attempt to create a new directory named NAME in DIR for USER with mode + MODE. */ +error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir, + char *name, mode_t mode) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Attempt to remove directory named NAME in DIR for USER. */ +error_t netfs_attempt_rmdir (struct iouser *user, + struct node *dir, char *name) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the owner to UID and the group to GID. */ +error_t netfs_attempt_chown (struct iouser *cred, struct node *node, + uid_t uid, uid_t gid) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should attempt a chauthor call for the user specified by CRED on node + NODE, to change the author to AUTHOR. */ +error_t netfs_attempt_chauthor (struct iouser *cred, struct node *node, + uid_t author) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning + of chmod, this function is also used to attempt to change files into other + types. If such a transition is attempted which is impossible, then return + EOPNOTSUPP. */ +error_t netfs_attempt_chmod (struct iouser *cred, struct node *node, + mode_t mode) +{ + error_t err = 0; + debug(""); + if (node->nn->ln == NULL) + return EOPNOTSUPP; + + mode &= ~S_ITRANS; + err = fshelp_isowner (&node->nn->ln->st, cred); + if (err) + return err; + mode |= node->nn->ln->st.st_mode & S_IFMT; + node->nn->ln->st.st_mode = mode; + fshelp_touch (&node->nn_stat, TOUCH_CTIME, multiplexer_maptime); + return err; +} + +/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */ +error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *node, + char *name) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or + S_IFCHR. */ +error_t netfs_attempt_mkdev (struct iouser *cred, struct node *node, + mode_t type, dev_t indexes) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Attempt to set the passive translator record for FILE to ARGZ (of length + ARGZLEN) for user CRED. */ +error_t netfs_set_translator (struct iouser *cred, struct node *node, + char *argz, size_t argzlen) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should attempt a chflags call for the user specified by CRED on node + NODE, to change the flags to FLAGS. */ +error_t netfs_attempt_chflags (struct iouser *cred, struct node *node, + int flags) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should attempt to set the size of the file NODE (for user CRED) to + SIZE bytes long. */ +error_t netfs_attempt_set_size (struct iouser *cred, struct node *node, + off_t size) +{ + debug(""); + return EOPNOTSUPP; +} + +/*Fetches the filesystem status information*/ +error_t +netfs_attempt_statfs (struct iouser *cred, struct node *node, + struct statfs *st) +{ + debug(""); + return EOPNOTSUPP; +} + +/* This should sync the entire remote filesystem. If WAIT is set, return + only after sync is completely finished. */ +error_t netfs_attempt_syncfs (struct iouser *cred, int wait) +{ + debug(""); + return 0; +} + +/* Create a link in DIR with name NAME to FILE for USER. Note that neither + DIR nor FILE are locked. If EXCL is set, do not delete the target, but + return EEXIST if NAME is already found in DIR. */ +error_t netfs_attempt_link (struct iouser *user, struct node *dir, + struct node *file, char *name, int excl) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Attempt to create an anonymous file related to DIR for USER with MODE. + Set *NODE to the returned file upon success. No matter what, unlock DIR. */ +error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir, + mode_t mode, struct node **node) +{ + debug(""); + *node = 0; + pthread_mutex_unlock (&dir->lock); + return EOPNOTSUPP; +} + +/* Read the contents of NODE (a symlink), for USER, into BUF. */ +error_t netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Read from the file NODE for user CRED starting at OFFSET and continuing for + up to *LEN bytes. Put the data at DATA. Set *LEN to the amount + successfully read upon return. */ +error_t netfs_attempt_read (struct iouser *cred, struct node *node, + off_t offset, size_t *len, void *data) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Write to the file NODE for user CRED starting at OFSET and continuing for up + to *LEN bytes from DATA. Set *LEN to the amount seccessfully written upon + return. */ +error_t netfs_attempt_write (struct iouser *cred, struct node *node, + off_t offset, size_t *len, void *data) +{ + debug(""); + return EOPNOTSUPP; +} + +/* Node NP is all done; free all its associated storage. */ +void +netfs_node_norefs (struct node *node) +{ + debug("node: %p", node); + if (node->nn->ln) + node->nn->ln->n = NULL; + free (node->nn->name); + free (node->nn); + free (node); +} + diff --git a/eth-multiplexer/netfs_impl.h b/eth-multiplexer/netfs_impl.h new file mode 100644 index 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/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/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..fd886615 --- /dev/null +++ b/eth-multiplexer/vdev.c @@ -0,0 +1,309 @@ +/* + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* This file implement the virtual network interface */ + +#include <string.h> +#include <stdio.h> +#include <netinet/ip.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <error.h> + +#include <pthread.h> + +#include "vdev.h" +#include "queue.h" +#include "bpf_impl.h" +#include "util.h" + +#define ETH_HLEN sizeof (struct ethhdr) + +static struct vether_device *dev_head; +static int dev_num; + +/* This lock is only used to protected the virtual device list. + * TODO every device structure should has its own lock to protect itself. */ +static pthread_mutex_t dev_list_lock = PTHREAD_MUTEX_INITIALIZER; + +mach_msg_type_t header_type = +{ + MACH_MSG_TYPE_BYTE, + 8, + NET_HDW_HDR_MAX, + TRUE, + FALSE, + FALSE, + 0 +}; + +mach_msg_type_t packet_type = +{ + MACH_MSG_TYPE_BYTE, /* name */ + 8, /* size */ + 0, /* number */ + TRUE, /* inline */ + FALSE, /* longform */ + FALSE /* deallocate */ +}; + +int +get_dev_num () +{ + return dev_num; +} + +struct vether_device * +lookup_dev_by_name (char *name) +{ + struct vether_device *vdev; + pthread_mutex_lock (&dev_list_lock); + for (vdev = dev_head; vdev; vdev = vdev->next) + { + if (strncmp (vdev->name, name, IFNAMSIZ) == 0) + break; + } + pthread_mutex_unlock (&dev_list_lock); + return vdev; +} + +int +foreach_dev_do (int (func) (struct vether_device *)) +{ + struct vether_device *vdev; + int rval = 0; + pthread_mutex_lock (&dev_list_lock); + for (vdev = dev_head; vdev; vdev = vdev->next) + { + pthread_mutex_unlock (&dev_list_lock); + /* func() can stop the loop by returning <> 0 */ + rval = func (vdev); + pthread_mutex_lock (&dev_list_lock); + if (rval) + break; + } + pthread_mutex_unlock (&dev_list_lock); + return rval; +} + +/* Remove all filters with the dead name. */ +int +remove_dead_port_from_dev (mach_port_t dead_port) +{ + struct vether_device *vdev; + pthread_mutex_lock (&dev_list_lock); + for (vdev = dev_head; vdev; vdev = vdev->next) + { + remove_dead_filter (&vdev->port_list, + &vdev->port_list.if_rcv_port_list, dead_port); + remove_dead_filter (&vdev->port_list, + &vdev->port_list.if_snd_port_list, dead_port); + } + pthread_mutex_unlock (&dev_list_lock); + return 0; +} + +/* Add a new virtual interface to the multiplexer. */ +struct vether_device * +add_vdev (char *name, int size, + struct port_class *class, struct port_bucket *bucket) +{ + error_t err; + struct vether_device *vdev; + + if (size < sizeof (*vdev)) + size = sizeof (*vdev); + err = ports_create_port (class, bucket, size, &vdev); + if (err) + return NULL; + + vdev->dev_port = ports_get_right (vdev); + ports_port_deref (vdev); + strncpy (vdev->name, name, IFNAMSIZ); + vdev->if_header_size = ETH_HLEN; + vdev->if_mtu = ETH_MTU; + vdev->if_header_format = HDR_ETHERNET; + vdev->if_address_size = ETH_ALEN; + vdev->if_flags = 0; + vdev->if_address[0] = 0x52; + vdev->if_address[1] = 0x54; + *(int *)(vdev->if_address + 2) = random (); + + queue_init (&vdev->port_list.if_rcv_port_list); + queue_init (&vdev->port_list.if_snd_port_list); + + pthread_mutex_lock (&dev_list_lock); + vdev->next = dev_head; + dev_head = vdev; + vdev->pprev = &dev_head; + if (vdev->next) + vdev->next->pprev = &vdev->next; + dev_num++; + pthread_mutex_unlock (&dev_list_lock); + + debug ("initialize the virtual device\n"); + return vdev; +} + +void +destroy_vdev (void *port) +{ + struct vether_device *vdev = (struct vether_device *)port; + + debug ("device %s is going to be destroyed\n", vdev->name); + /* Delete it from the virtual device list */ + pthread_mutex_lock (&dev_list_lock); + *vdev->pprev = vdev->next; + if (vdev->next) + vdev->next->pprev = vdev->pprev; + dev_num--; + pthread_mutex_unlock (&dev_list_lock); + + /* TODO Delete all filters in the interface, + * there shouldn't be any filters left */ + destroy_filters (&vdev->port_list); +} + +/* Test if there are devices existing in the list */ +int +has_vdev () +{ + return dev_head != NULL; +} + +/* Broadcast the packet to all virtual interfaces + * except the one the packet is from */ +int +broadcast_pack (char *data, int datalen, struct vether_device *from_vdev) +{ + int internal_deliver_pack (struct vether_device *vdev) + { + if (from_vdev == vdev) + return 0; + return deliver_pack (data, datalen, vdev); + } + + return foreach_dev_do (internal_deliver_pack); +} + +/* Create a message, and deliver it. */ +int +deliver_pack (char *data, int datalen, struct vether_device *vdev) +{ + struct net_rcv_msg msg; + int pack_size; + struct ethhdr *header; + struct packet_header *packet; + + pack_size = datalen - sizeof (struct ethhdr); + /* remember message sizes must be rounded up */ + msg.msg_hdr.msgh_size = (((mach_msg_size_t) (sizeof(struct net_rcv_msg) + - NET_RCV_MAX + pack_size)) + 3) & ~3; + + header = (struct ethhdr *) msg.header; + packet = (struct packet_header *) msg.packet; + msg.header_type = header_type; + memcpy (header, data, sizeof (struct ethhdr)); + msg.packet_type = packet_type; + memcpy (packet + 1, data + sizeof (struct ethhdr), pack_size); + packet->type = header->h_proto; + packet->length = pack_size + sizeof (struct packet_header); + msg.packet_type.msgt_number = packet->length; + + return deliver_msg (&msg, vdev); +} + +/* Broadcast the message to all virtual interfaces. */ +int +broadcast_msg (struct net_rcv_msg *msg) +{ + int rval = 0; + mach_msg_header_t header; + + int internal_deliver_msg (struct vether_device *vdev) + { + return deliver_msg (msg, vdev); + } + + /* Save the message header because deliver_msg will change it. */ + header = msg->msg_hdr; + rval = foreach_dev_do (internal_deliver_msg); + msg->msg_hdr = header; + return rval; +} + +/* + * Deliver the message to all right pfinet servers that + * connects to the virtual network interface. + */ +int +deliver_msg(struct net_rcv_msg *msg, struct vether_device *vdev) +{ + mach_msg_return_t err; + queue_head_t *if_port_list; + net_rcv_port_t infp, nextfp; + + msg->msg_hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0); + /* remember message sizes must be rounded up */ + msg->msg_hdr.msgh_local_port = MACH_PORT_NULL; + msg->msg_hdr.msgh_kind = MACH_MSGH_KIND_NORMAL; + msg->msg_hdr.msgh_id = NET_RCV_MSG_ID; + + if_port_list = &vdev->port_list.if_rcv_port_list; + FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input) + { + mach_port_t dest; + net_hash_entry_t entp, *hash_headp; + int ret_count; + + entp = (net_hash_entry_t) 0; + ret_count = bpf_do_filter (infp, + msg->packet + sizeof (struct packet_header), + msg->net_rcv_msg_packet_count, msg->header, + sizeof (struct ethhdr), &hash_headp, &entp); + if (entp == (net_hash_entry_t) 0) + dest = infp->rcv_port; + else + dest = entp->rcv_port; + + if (ret_count) + { + debug ("before delivering the packet\n"); + msg->msg_hdr.msgh_remote_port = dest; + err = mach_msg ((mach_msg_header_t *)msg, + MACH_SEND_MSG|MACH_SEND_TIMEOUT, + msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL, + 0, MACH_PORT_NULL); + if (err != MACH_MSG_SUCCESS) + { + mach_port_deallocate(mach_task_self (), + ((mach_msg_header_t *)msg)->msgh_remote_port); + error (0, err, "mach_msg"); + return -1; + } + debug ("after delivering the packet\n"); + } + } + FILTER_ITERATE_END + + return 0; +} + diff --git a/eth-multiplexer/vdev.h b/eth-multiplexer/vdev.h new file mode 100644 index 00000000..c8696785 --- /dev/null +++ b/eth-multiplexer/vdev.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#ifndef VDEV_H +#define VDEV_H + +#include <net/if.h> + +#include <hurd.h> +#include <mach.h> +#include <hurd/ports.h> +#include <device/net_status.h> + +#include <bpf_impl.h> + +#include "queue.h" +#include "util.h" + +#define MAX_SERVERS 10 +#define ETH_MTU 1500 + +struct vether_device +{ + /* The ports used by the socket server to send packets to the interface. */ + struct port_info dev_pi; + mach_port_t dev_port; + + char name[IFNAMSIZ]; + + short if_header_size; + short if_mtu; + short if_header_format; + short if_address_size; + short if_flags; + char if_address[ETH_ALEN]; + + struct vether_device *next; + struct vether_device **pprev; + + if_filter_list_t port_list; +}; + +typedef int (*dev_act_func) (struct vether_device *); + +int serv_connect (mach_port_t port); +int serv_disconnect (); +struct vether_device *lookup_dev_by_name (char *name); +int remove_dead_port_from_dev (mach_port_t dead_port); +struct vether_device *add_vdev (char *name, int size, + struct port_class *class, + struct port_bucket *bucket); +void destroy_vdev (void *port); +int has_vdev (); +int deliver_msg (struct net_rcv_msg *msg, struct vether_device *vdev); +int deliver_pack (char *data, int datalen, struct vether_device *vdev); +boolean_t all_dev_close (); +int broadcast_pack (char *data, int datalen, struct vether_device *from_vdev); +int broadcast_msg (struct net_rcv_msg *msg); +int get_dev_num (); +int foreach_dev_do (dev_act_func func); + +#endif |