summaryrefslogtreecommitdiff
path: root/libmachdev
diff options
context:
space:
mode:
Diffstat (limited to 'libmachdev')
-rw-r--r--libmachdev/Makefile38
-rw-r--r--libmachdev/block.c313
-rw-r--r--libmachdev/dev_hdr.h133
-rw-r--r--libmachdev/device_emul.h65
-rw-r--r--libmachdev/ds_routines.c482
-rw-r--r--libmachdev/ds_routines.h55
-rw-r--r--libmachdev/errno-base.h39
-rw-r--r--libmachdev/if_ether.h87
-rw-r--r--libmachdev/if_hdr.h165
-rw-r--r--libmachdev/io_req.h135
-rw-r--r--libmachdev/linux-errno.h109
-rw-r--r--libmachdev/mach_glue.h41
-rw-r--r--libmachdev/machdev.h33
-rw-r--r--libmachdev/misc.c50
-rw-r--r--libmachdev/net.c674
-rw-r--r--libmachdev/queue.c131
-rw-r--r--libmachdev/queue.h370
-rw-r--r--libmachdev/trivfs_server.c164
-rw-r--r--libmachdev/util.h35
-rw-r--r--libmachdev/vm_param.h7
20 files changed, 3126 insertions, 0 deletions
diff --git a/libmachdev/Makefile b/libmachdev/Makefile
new file mode 100644
index 00000000..728fe82e
--- /dev/null
+++ b/libmachdev/Makefile
@@ -0,0 +1,38 @@
+# Copyright (C) 2009 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 := libmachdev
+makemode := library
+libname = libmachdev
+
+SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \
+ device_replyUser.c ourdeviceServer.c notifyServer.c misc.c block.c
+LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \
+ util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \
+ errno-base.h
+installhdrs = machdev.h
+HURDLIBS = ports trivfs ddekit bpf
+OTHERLIBS = -lpthread
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+
+include ../Makeconf
+
+ourdevice.defs: device.defs
+ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@
+
+$(libname).so.$(hurd-version):
+ echo "INPUT ( $(libname).a )" > $@
diff --git a/libmachdev/block.c b/libmachdev/block.c
new file mode 100644
index 00000000..756a07bf
--- /dev/null
+++ b/libmachdev/block.c
@@ -0,0 +1,313 @@
+/*
+ * Linux block driver support.
+ *
+ * Copyright (C) 1996 The University of Utah and the Computer Systems
+ * Laboratory at the University of Utah (CSL)
+ *
+ * This program 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.
+ *
+ * This program 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "mach_U.h"
+
+#include <mach.h>
+#include <hurd.h>
+
+#define MACH_INCLUDE
+
+#include <ddekit/printf.h>
+
+#include "vm_param.h"
+#include "device_reply_U.h"
+#include "dev_hdr.h"
+#include "util.h"
+#include "mach_glue.h"
+
+/* for submit_bio(). But it might not be very proper to keep
+ * my own definitions of these macros. */
+#define READ 0
+#define WRITE 1
+
+/* One of these is associated with each open instance of a device. */
+struct block_data
+{
+ struct port_info port; /* device port */
+ struct emul_device device; /* generic device structure */
+ dev_mode_t mode;
+ struct block_device *dev;
+};
+
+/* Return a send right associated with network device ND. */
+static mach_port_t
+dev_to_port (void *nd)
+{
+ return (nd
+ ? ports_get_send_right (nd)
+ : MACH_PORT_NULL);
+}
+
+extern struct device_emulation_ops linux_block_emulation_ops;
+
+#define DISK_NAME_LEN 32
+
+/* Parse the device NAME.
+ Set *SLICE to be the DOS partition and
+ *PART the BSD/Mach partition, if any. */
+static char *
+translate_name (char *name, int *slice, int *part)
+{
+ char *p, *q, *end;
+ char *ret;
+ int disk_num;
+
+ /* Parse name into name, unit, DOS partition (slice) and partition. */
+ for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
+ ;
+ if (p == name || ! isdigit (*p))
+ return NULL;
+ end = p;
+ disk_num = strtol (p, &p, 0);
+ if (disk_num < 0 || disk_num > 26)
+ return NULL;
+// do
+// p++;
+// while (isdigit (*p));
+ if (*p)
+ {
+ q = p;
+ if (*q == 's' && isdigit (*(q + 1)))
+ {
+ q++;
+ do
+ *slice = *slice * 10 + *q++ - '0';
+ while (isdigit (*q));
+ if (! *q)
+ goto find_major;
+ }
+ if (! isalpha (*q) || *(q + 1))
+ return NULL;
+ *part = *q - 'a';
+ }
+
+find_major:
+ ret = malloc (DISK_NAME_LEN);
+ sprintf (ret, "hd%c", 'a' + disk_num);
+ return ret;
+}
+
+static io_return_t
+device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, char *name, device_t *devp,
+ mach_msg_type_name_t *devicePoly)
+{
+ io_return_t err = D_SUCCESS;
+ struct block_data *bd = NULL;
+ int slice, part;
+ char *dev_name = NULL;
+ int dev_err;
+
+ // TODO I need to check whether the device has been opened before.
+ // if it has been opened with the same `flag', return the same port,
+ // otherwise, return a different port.
+ // I need to have a reference to count the number of open.
+ dev_name = translate_name (name, &slice, &part);
+ if (dev_name == NULL)
+ return D_NO_SUCH_DEVICE;
+
+ err = create_device_port (sizeof (*bd), &bd);
+ if (err)
+ {
+ ddekit_printf ("after create_device_port: cannot create a port\n");
+ goto out;
+ }
+ bd->dev = open_block_dev (dev_name, slice, mode);
+ dev_err = (int) bd->dev;
+ if (dev_err < 0)
+ {
+ ddekit_printf ("open_block_dev %s fails with %d\n", dev_name, bd->dev);
+ err = linux_to_mach_error (dev_err);
+ goto out;
+ }
+ bd->device.emul_data = bd;
+ bd->device.emul_ops = &linux_block_emulation_ops;
+ bd->mode = mode;
+
+out:
+ free (dev_name);
+ if (err)
+ {
+ if (bd)
+ {
+ ports_destroy_right (bd);
+ bd = NULL;
+ }
+ }
+ else
+ {
+ *devp = ports_get_send_right (bd);
+ ports_port_deref (bd);
+ *devicePoly = MACH_MSG_TYPE_MOVE_SEND;
+ }
+ return err;
+}
+
+static io_return_t
+device_write (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, io_buf_ptr_t data, unsigned int count,
+ int *bytes_written)
+{
+ struct block_data *bd = d;
+ /* the number of pages that contain DATA. */
+ int npages = (((int) data + count) - ((int) data & ~PAGE_MASK)
+ + PAGE_MASK) / PAGE_SIZE;
+ io_return_t err = D_SUCCESS;
+ int i;
+ int writes = 0;
+
+ void write_done (int err)
+ {
+ int len = err ? 0 : count;
+ // TODO maybe I should send the reply as long as there is an error.
+ writes--;
+ if (writes == 0)
+ {
+ err = linux_to_mach_error (err);
+ ds_device_write_reply (reply_port, reply_port_type, err, len);
+ }
+ }
+
+ /* the data is at the beginning of a page. */
+ if ((int) data & ~PAGE_MASK)
+ return D_INVALID_OPERATION;
+
+ if ((bd->mode & D_WRITE) == 0)
+ return D_INVALID_OPERATION;
+
+ for (i = 0; i < npages; i++)
+ {
+ int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ?
+ count : PAGE_SIZE - ((int) data &~PAGE_MASK);
+
+ err = block_dev_rw (bd->dev, bn, data, size, WRITE, write_done);
+ if (err)
+ break;
+ bn += size >> 9;
+ data += size;
+ count -= size;
+ writes++;
+ }
+ if (writes)
+ return MIG_NO_REPLY;
+ return linux_to_mach_error (err);
+}
+
+static io_return_t
+device_read (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, int count, io_buf_ptr_t *data,
+ unsigned *bytes_read)
+{
+ struct block_data *bd = d;
+ io_return_t err = D_SUCCESS;
+ int i;
+ int reads = 0;
+ char *buf;
+ int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE;
+ int rest = count;
+
+ void read_done (int err)
+ {
+ int len = err ? 0 : count;
+ reads--;
+ if (reads == 0)
+ {
+ err = linux_to_mach_error (err);
+ ds_device_read_reply (reply_port, reply_port_type, err, buf, len);
+ }
+ }
+
+ if ((bd->mode & D_READ) == 0)
+ return D_INVALID_OPERATION;
+
+ if (count == 0)
+ return 0;
+
+ *data = 0;
+ buf = mmap (NULL, npages * PAGE_SIZE, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (buf == MAP_FAILED)
+ return errno;
+
+ ddekit_printf ("read %d pages.\n", npages);
+ for (i = 0; i < npages; i++)
+ {
+ int size = rest > PAGE_SIZE ? PAGE_SIZE : rest;
+ ddekit_printf ("read %d bytes starting from %d\n", size, bn);
+
+ err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE,
+ size, READ, read_done);
+ if (err)
+ break;
+ bn += size >> 9;
+ rest -= size;
+ reads++;
+ }
+ // TODO when should I deallocate the buffer?
+ if (reads)
+ return MIG_NO_REPLY;
+ return linux_to_mach_error (err);
+}
+
+static io_return_t
+device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *count)
+{
+ struct block_data *bd = (struct block_data *) d;
+ return D_SUCCESS;
+}
+
+struct device_emulation_ops linux_block_emulation_ops =
+{
+ NULL,
+ NULL,
+ NULL,
+ dev_to_port,
+ device_open,
+ NULL,
+ device_write,
+ NULL,
+ device_read,
+ NULL,
+ NULL,
+ device_get_status,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void register_block()
+{
+ extern void reg_dev_emul (struct device_emulation_ops *ops);
+ reg_dev_emul (&linux_block_emulation_ops);
+}
diff --git a/libmachdev/dev_hdr.h b/libmachdev/dev_hdr.h
new file mode 100644
index 00000000..79edc43a
--- /dev/null
+++ b/libmachdev/dev_hdr.h
@@ -0,0 +1,133 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,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/89
+ */
+
+/*
+ * Mach device emulation definitions (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+#ifndef _DEVICE_DEV_HDR_H_
+#define _DEVICE_DEV_HDR_H_
+
+#include <mach.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <pthread.h>
+
+#include "device_emul.h"
+
+/*
+ * Operations list for major device types.
+ */
+struct dev_ops {
+ char * d_name; /* name for major device */
+ int (*d_open)(); /* open device */
+ int (*d_close)(); /* close device */
+ int (*d_read)(); /* read */
+ int (*d_write)(); /* write */
+ int (*d_getstat)(); /* get status/control */
+ int (*d_setstat)(); /* set status/control */
+ vm_offset_t (*d_mmap)(); /* map memory */
+ int (*d_async_in)();/* asynchronous input setup */
+ int (*d_reset)(); /* reset device */
+ int (*d_port_death)();
+ /* clean up reply ports */
+ int d_subdev; /* number of sub-devices per
+ unit */
+ int (*d_dev_info)(); /* driver info for kernel */
+};
+typedef struct dev_ops *dev_ops_t;
+
+/* This structure is associated with each open device port.
+ * The port representing the device points to this structure. */
+struct emul_device
+{
+ struct device_emulation_ops *emul_ops;
+ void *emul_data;
+};
+
+typedef struct emul_device *emul_device_t;
+
+#define DEVICE_NULL ((device_t) 0)
+
+/*
+ * Generic device header. May be allocated with the device,
+ * or built when the device is opened.
+ */
+struct mach_device {
+ struct port_info port;
+ struct emul_device dev; /* the real device structure */
+};
+typedef struct mach_device *mach_device_t;
+#define MACH_DEVICE_NULL ((mach_device_t)0)
+
+/*
+ * To find and remove device entries
+ */
+mach_device_t device_lookup(char *); /* by name */
+
+/*
+ * To find and remove port-to-device mappings
+ */
+void dev_port_enter(mach_device_t);
+void dev_port_remove(mach_device_t);
+
+/*
+ * To call a routine on each device
+ */
+boolean_t dev_map(boolean_t (*)(), mach_port_t);
+
+/*
+ * To lock and unlock state and open-count
+ */
+#define device_lock(device) pthread_mutex_lock(&(device)->lock)
+#define device_unlock(device) pthread_mutex_unlock(&(device)->lock)
+
+#endif /* _DEVICE_DEV_HDR_H_ */
diff --git a/libmachdev/device_emul.h b/libmachdev/device_emul.h
new file mode 100644
index 00000000..e27799cb
--- /dev/null
+++ b/libmachdev/device_emul.h
@@ -0,0 +1,65 @@
+/*
+ * Mach device emulation definitions (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+#ifndef _I386AT_DEVICE_EMUL_H_
+#define _I386AT_DEVICE_EMUL_H_
+
+#include <mach.h>
+
+/* Each emulation layer provides these operations. */
+struct device_emulation_ops
+{
+ void (*init) (void);
+ void (*reference) (void *);
+ void (*dealloc) (void *);
+ mach_port_t (*dev_to_port) (void *);
+ io_return_t (*open) (mach_port_t, mach_msg_type_name_t,
+ dev_mode_t, char *, device_t *,
+ mach_msg_type_name_t *type);
+ io_return_t (*close) (void *);
+ io_return_t (*write) (void *, mach_port_t, mach_msg_type_name_t,
+ dev_mode_t, recnum_t, io_buf_ptr_t, unsigned, int *);
+ io_return_t (*write_inband) (void *, mach_port_t, mach_msg_type_name_t,
+ dev_mode_t, recnum_t, io_buf_ptr_inband_t,
+ unsigned, int *);
+ io_return_t (*read) (void *, mach_port_t, mach_msg_type_name_t,
+ dev_mode_t, recnum_t, int, io_buf_ptr_t *, unsigned *);
+ io_return_t (*read_inband) (void *, mach_port_t, mach_msg_type_name_t,
+ dev_mode_t, recnum_t, int, char *, unsigned *);
+ io_return_t (*set_status) (void *, dev_flavor_t, dev_status_t,
+ mach_msg_type_number_t);
+ io_return_t (*get_status) (void *, dev_flavor_t, dev_status_t,
+ mach_msg_type_number_t *);
+ io_return_t (*set_filter) (void *, mach_port_t, int, filter_t [], unsigned);
+ io_return_t (*map) (void *, vm_prot_t, vm_offset_t,
+ vm_size_t, mach_port_t *, boolean_t);
+ void (*no_senders) (mach_no_senders_notification_t *);
+ io_return_t (*write_trap) (void *, dev_mode_t,
+ recnum_t, vm_offset_t, vm_size_t);
+ io_return_t (*writev_trap) (void *, dev_mode_t,
+ recnum_t, io_buf_vec_t *, vm_size_t);
+};
+
+#endif /* _I386AT_DEVICE_EMUL_H_ */
diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c
new file mode 100644
index 00000000..63457553
--- /dev/null
+++ b/libmachdev/ds_routines.c
@@ -0,0 +1,482 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1991,1990,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/89
+ */
+
+/*
+ * Mach device server routines (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+
+#include <hurd.h>
+#include <mach.h>
+
+#include <ddekit/thread.h>
+
+#include "vm_param.h"
+#include "device_reply_U.h"
+#include "io_req.h"
+#include "dev_hdr.h"
+#include "util.h"
+#include "queue.h"
+#include "mach_glue.h"
+
+static struct port_bucket *port_bucket;
+static struct port_class *dev_class;
+
+#define NUM_EMULATION num_emul
+#define MAX_NUM_EMULATION 32
+
+/* List of emulations. */
+static struct device_emulation_ops *emulation_list[MAX_NUM_EMULATION];
+static int num_emul;
+
+boolean_t is_master_device (mach_port_t port);
+
+static inline void
+mach_device_deallocate (void *device)
+{
+ ports_port_deref (device);
+}
+
+static inline void
+mach_device_reference (mach_device_t device)
+{
+ ports_port_ref (device);
+}
+
+static inline emul_device_t
+mach_convert_port_to_device (device_t device)
+{
+ mach_device_t dev = ports_lookup_port (port_bucket, device, dev_class);
+ if (dev == NULL)
+ return NULL;
+
+ return &dev->dev;
+}
+
+static inline void *
+device_to_pi (emul_device_t device)
+{
+ return ((void *) device) - (int) &((mach_device_t) 0)->dev;
+}
+
+/*
+ * What follows is the interface for the native Mach devices.
+ */
+
+static inline mach_port_t
+mach_convert_device_to_port (mach_device_t device)
+{
+ if (device == NULL)
+ return MACH_PORT_NULL;
+
+ // TODO I have to somehow dereference it when it is called at the first time.
+ return ports_get_right (device);
+}
+
+/* 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)
+{
+ 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)
+{
+ 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)
+{
+ return D_INVALID_OPERATION;
+}
+
+io_return_t
+ds_device_intr_register (mach_port_t master_port, int irq,
+ int id, mach_port_t receive_port)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_intr_enable (mach_port_t master_port,
+ int line, char status)
+{
+ return D_INVALID_OPERATION;
+}
+
+io_return_t
+ds_device_open (mach_port_t open_port, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ char *name, device_t *devp, mach_msg_type_name_t *devicePoly)
+{
+ int i;
+ io_return_t err;
+
+ /* Open must be called on the master device port. */
+ if (!is_master_device (open_port))
+ return D_INVALID_OPERATION;
+
+ /* There must be a reply port. */
+ if (! MACH_PORT_VALID (reply_port))
+ {
+ fprintf (stderr, "ds_* invalid reply port\n");
+ return MIG_NO_REPLY;
+ }
+
+ /* Call each emulation's open routine to find the device. */
+ for (i = 0; i < NUM_EMULATION; i++)
+ {
+ err = (*emulation_list[i]->open) (reply_port, reply_port_type,
+ mode, name, devp, devicePoly);
+ if (err != D_NO_SUCH_DEVICE)
+ break;
+ }
+
+ return err;
+}
+
+io_return_t
+ds_device_close (device_t dev)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ ret = (device->emul_ops->close
+ ? (*device->emul_ops->close) (device->emul_data)
+ : D_SUCCESS);
+ mach_device_deallocate (device_to_pi (device));
+
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_write (device_t dev, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t recnum, io_buf_ptr_t data, unsigned int count,
+ int *bytes_written)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ if (data == 0)
+ return D_INVALID_SIZE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->write)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->write) (device->emul_data, reply_port,
+ reply_port_type, mode, recnum,
+ data, count, bytes_written);
+ ports_port_deref (device_to_pi (device));
+
+ return ret;
+}
+
+io_return_t
+ds_device_write_inband (device_t dev, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, recnum_t recnum,
+ io_buf_ptr_inband_t data, unsigned count,
+ int *bytes_written)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ if (data == 0)
+ return D_INVALID_SIZE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->write_inband)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->write_inband) (device->emul_data, reply_port,
+ reply_port_type, mode, recnum,
+ data, count, bytes_written);
+ ports_port_deref (device_to_pi (device));
+
+ return ret;
+}
+
+io_return_t
+ds_device_read (device_t dev, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t recnum, int count, io_buf_ptr_t *data,
+ unsigned *bytes_read)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->read)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->read) (device->emul_data, reply_port,
+ reply_port_type, mode, recnum,
+ count, data, bytes_read);
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_read_inband (device_t dev, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t recnum, int count, char *data,
+ unsigned *bytes_read)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->read_inband)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->read_inband) (device->emul_data, reply_port,
+ reply_port_type, mode, recnum,
+ count, data, bytes_read);
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_set_status (device_t dev, dev_flavor_t flavor,
+ dev_status_t status, mach_msg_type_number_t status_count)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->set_status)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->set_status) (device->emul_data, flavor,
+ status, status_count);
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *status_count)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->get_status)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->get_status) (device->emul_data, flavor,
+ status, status_count);
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_set_filter (device_t dev, mach_port_t receive_port, int priority,
+ filter_t *filter, unsigned filter_count)
+{
+ emul_device_t device;
+ io_return_t ret;
+
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ device = mach_convert_port_to_device (dev);
+ if (device == NULL)
+ return D_INVALID_OPERATION;
+
+ if (! device->emul_ops->set_filter)
+ {
+ ports_port_deref (device_to_pi (device));
+ return D_INVALID_OPERATION;
+ }
+
+ ret = (*device->emul_ops->set_filter) (device->emul_data, receive_port,
+ priority, filter, filter_count);
+ ports_port_deref (device_to_pi (device));
+ return ret;
+}
+
+io_return_t
+ds_device_map (device_t dev, vm_prot_t prot, vm_offset_t offset,
+ vm_size_t size, mach_port_t *pager, boolean_t unmap)
+{
+ /* Refuse if device is dead or not completely open. */
+ if (dev == MACH_PORT_NULL)
+ return D_NO_SUCH_DEVICE;
+
+ return D_INVALID_OPERATION;
+}
+
+int create_device_port (int size, void *result)
+{
+ return ports_create_port (dev_class, port_bucket,
+ size, result);
+}
+
+void mach_device_init()
+{
+ int i;
+
+ port_bucket = ports_create_bucket ();
+ dev_class = ports_create_class (0, 0);
+
+ for (i = 0; i < NUM_EMULATION; i++) {
+ if (emulation_list[i]->init)
+ emulation_list[i]->init();
+ }
+}
+
+static int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ int ret;
+ extern int device_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ ret = device_server (inp, outp) || notify_server (inp, outp);
+ return ret;
+}
+
+void reg_dev_emul (struct device_emulation_ops *ops)
+{
+ emulation_list[num_emul++] = ops;
+}
+
+void * ds_server(void *arg)
+{
+ /* This thread calls Linux functions,
+ * so I need to make it known to the Linux environment. */
+ l4dde26_process_from_ddekit (ddekit_thread_myself ());
+
+ /* Launch. */
+ do
+ {
+ ports_manage_port_operations_one_thread (port_bucket, demuxer, 0);
+ } while (1);
+
+ return NULL;
+}
diff --git a/libmachdev/ds_routines.h b/libmachdev/ds_routines.h
new file mode 100644
index 00000000..e314e80e
--- /dev/null
+++ b/libmachdev/ds_routines.h
@@ -0,0 +1,55 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,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: 8/89
+ *
+ * Device service utility routines.
+ */
+
+#ifndef DS_ROUTINES_H
+#define DS_ROUTINES_H
+
+#include <mach.h>
+
+#include "io_req.h"
+
+/*
+ * Map for device IO memory.
+ */
+//vm_map_t device_io_map;
+
+kern_return_t device_read_alloc(io_req_t, vm_size_t);
+kern_return_t device_write_get(io_req_t, boolean_t *);
+boolean_t device_write_dealloc(io_req_t);
+
+boolean_t ds_open_done(io_req_t);
+boolean_t ds_read_done(io_req_t);
+boolean_t ds_write_done(io_req_t);
+
+void iowait (io_req_t ior);
+
+#endif /* DS_ROUTINES_H */
diff --git a/libmachdev/errno-base.h b/libmachdev/errno-base.h
new file mode 100644
index 00000000..65115978
--- /dev/null
+++ b/libmachdev/errno-base.h
@@ -0,0 +1,39 @@
+#ifndef _ASM_GENERIC_ERRNO_BASE_H
+#define _ASM_GENERIC_ERRNO_BASE_H
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+
+#endif
diff --git a/libmachdev/if_ether.h b/libmachdev/if_ether.h
new file mode 100644
index 00000000..29974674
--- /dev/null
+++ b/libmachdev/if_ether.h
@@ -0,0 +1,87 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version: @(#)if_ether.h 1.0.1a 02/08/94
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@cymru.net>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *
+ * This program 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 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+
+/*
+ * These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
+#define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */
+#define ETH_P_PUP 0x0400 /* Xerox PUP packet */
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
+#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
+#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
+#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
+#define ETH_P_LAT 0x6004 /* DEC LAT */
+#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
+#define ETH_P_CUST 0x6006 /* DEC Customer use */
+#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_ATALK 0x809B /* Appletalk DDP */
+#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
+#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
+
+/*
+ * Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
+#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
+#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
+#define ETH_P_802_2 0x0004 /* 802.2 frames */
+#define ETH_P_SNAP 0x0005 /* Internal only */
+#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
+#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
+
+/*
+ * This is an Ethernet frame header.
+ */
+
+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 */
+};
+
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/libmachdev/if_hdr.h b/libmachdev/if_hdr.h
new file mode 100644
index 00000000..b20f7e35
--- /dev/null
+++ b/libmachdev/if_hdr.h
@@ -0,0 +1,165 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,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.
+ */
+/*
+ * Taken from (bsd)net/if.h. Modified for MACH kernel.
+ */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the Laboratory may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if.h 7.3 (Berkeley) 6/27/88
+ */
+
+#ifndef _IF_HDR_
+#define _IF_HDR_
+
+#include <queue.h>
+#include <pthread.h>
+#include <hurd/bpf_impl.h>
+
+#if 0
+/*
+ * Queue for network output and filter input.
+ */
+struct ifqueue {
+ queue_head_t ifq_head; /* queue of io_req_t */
+ int ifq_len; /* length of queue */
+ int ifq_maxlen; /* maximum length of queue */
+ int ifq_drops; /* number of packets dropped
+ because queue full */
+ decl_simple_lock_data(,
+ ifq_lock) /* lock for queue and counters */
+};
+#endif
+
+/*
+ * Header for network interface drivers.
+ */
+struct ifnet {
+ short if_unit; /* unit number */
+ short if_flags; /* up/down, broadcast, etc. */
+ short if_timer; /* time until if_watchdog called */
+ short if_mtu; /* maximum transmission unit */
+ short if_header_size; /* length of header */
+ short if_header_format; /* format of hardware header */
+ short if_address_size; /* length of hardware address */
+ short if_alloc_size; /* size of read buffer to allocate */
+ char *if_address; /* pointer to hardware address */
+// struct ifqueue if_snd; /* output queue */
+ if_filter_list_t port_list;
+ pthread_mutex_t if_rcv_port_list_lock;/* lock for input filter list */
+ pthread_mutex_t if_snd_port_list_lock;/* lock for output filter list */
+/* statistics */
+ int if_ipackets; /* packets received */
+ int if_ierrors; /* input errors */
+ int if_opackets; /* packets sent */
+ int if_oerrors; /* output errors */
+ int if_collisions; /* collisions on csma interfaces */
+ int if_rcvdrops; /* packets received but dropped */
+};
+
+#define IFF_UP 0x0001 /* interface is up */
+#define IFF_BROADCAST 0x0002 /* interface can broadcast */
+#define IFF_DEBUG 0x0004 /* turn on debugging */
+#define IFF_LOOPBACK 0x0008 /* is a loopback net */
+#define IFF_POINTOPOINT 0x0010 /* point-to-point link */
+#define IFF_RUNNING 0x0040 /* resources allocated */
+#define IFF_NOARP 0x0080 /* no address resolution protocol */
+#define IFF_PROMISC 0x0100 /* receive all packets */
+#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */
+#define IFF_BRIDGE 0x0100 /* support token ring routing field */
+#define IFF_SNAP 0x0200 /* support extended sap header */
+
+/* internal flags only: */
+#define IFF_CANTCHANGE (IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING)
+
+/*
+ * Output queues (ifp->if_snd)
+ * have queues of messages stored on ifqueue structures. Entries
+ * are added to and deleted from these structures by these macros, which
+ * should be called with ipl raised to splimp().
+ * XXX locking XXX
+ */
+
+#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen)
+#define IF_DROP(ifq) ((ifq)->ifq_drops++)
+#define IF_ENQUEUE(ifq, ior) { \
+ simple_lock(&(ifq)->ifq_lock); \
+ enqueue_tail(&(ifq)->ifq_head, (queue_entry_t)ior); \
+ (ifq)->ifq_len++; \
+ simple_unlock(&(ifq)->ifq_lock); \
+}
+#define IF_PREPEND(ifq, ior) { \
+ simple_lock(&(ifq)->ifq_lock); \
+ enqueue_head(&(ifq)->ifq_head, (queue_entry_t)ior); \
+ (ifq)->ifq_len++; \
+ simple_unlock(&(ifq)->ifq_lock); \
+}
+
+#define IF_DEQUEUE(ifq, ior) { \
+ simple_lock(&(ifq)->ifq_lock); \
+ if (((ior) = (io_req_t)dequeue_head(&(ifq)->ifq_head)) != 0) \
+ (ifq)->ifq_len--; \
+ simple_unlock(&(ifq)->ifq_lock); \
+}
+
+#define IFQ_MAXLEN 50
+
+#define IFQ_INIT(ifq) { \
+ queue_init(&(ifq)->ifq_head); \
+ simple_lock_init(&(ifq)->ifq_lock); \
+ (ifq)->ifq_len = 0; \
+ (ifq)->ifq_maxlen = IFQ_MAXLEN; \
+ (ifq)->ifq_drops = 0; \
+}
+
+#define IFNET_SLOWHZ 1 /* granularity is 1 second */
+
+#endif /* _IF_HDR_ */
diff --git a/libmachdev/io_req.h b/libmachdev/io_req.h
new file mode 100644
index 00000000..9c810542
--- /dev/null
+++ b/libmachdev/io_req.h
@@ -0,0 +1,135 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988 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: 10/88
+ */
+
+#ifndef _IO_REQ_
+#define _IO_REQ_
+
+#include <mach.h>
+#include <pthread.h>
+
+#include "dev_hdr.h"
+
+/*
+ * IO request element, queued on device for delayed replies.
+ */
+typedef struct io_req *io_req_t;
+struct io_req {
+ struct io_req * io_next; /* next, ... */
+ struct io_req * io_prev; /* prev pointers: link in done,
+ defered, or in-progress list */
+ mach_device_t io_device; /* pointer to open-device structure */
+ char * io_dev_ptr; /* pointer to driver structure -
+ filled in by driver if necessary */
+ int io_unit; /* unit number ('minor') of device */
+ int io_op; /* IO operation */
+ dev_mode_t io_mode; /* operation mode (wait, truncate) */
+ recnum_t io_recnum; /* starting record number for
+ random-access devices */
+
+ union io_un {
+ io_buf_ptr_t data; /* data, for IO requests */
+ } io_un;
+#define io_data io_un.data
+
+ long io_count; /* amount requested */
+ long io_alloc_size; /* amount allocated */
+ long io_residual; /* amount NOT done */
+ io_return_t io_error; /* error code */
+ /* call when done - returns TRUE if IO really finished */
+ boolean_t (*io_done)(io_req_t);
+ mach_port_t io_reply_port; /* reply port, for asynchronous
+ messages */
+ mach_msg_type_name_t io_reply_port_type;
+ /* send or send-once right? */
+ struct io_req * io_link; /* forward link (for driver header) */
+ struct io_req * io_rlink; /* reverse link (for driver header) */
+// vm_map_copy_t io_copy; /* vm_map_copy obj. for this op. */
+ long io_total; /* total op size, for write */
+ pthread_mutex_t io_req_lock;
+// decl_simple_lock_data(,io_req_lock)
+ /* Lock for this structure */
+ long io_physrec; /* mapping to the physical block
+ number */
+ long io_rectotal; /* total number of blocks to move */
+};
+
+/*
+ * LOCKING NOTE: Operations on io_req's are in general single threaded by
+ * the invoking code, obviating the need for a lock. The usual IO_CALL
+ * path through the code is: Initiating thread hands io_req to device driver,
+ * driver passes it to io_done thread, io_done thread sends reply message. No
+ * locking is needed in this sequence. Unfortunately, a synchronous wait
+ * for a buffer requires a lock to avoid problems if the wait and interrupt
+ * happen simultaneously on different processors.
+ */
+
+#define ior_lock(ior) pthread_mutex_lock(&(ior)->io_req_lock)
+#define ior_unlock(ior) pthread_mutex_unlock(&(ior)->io_req_lock)
+
+/*
+ * Flags and operations
+ */
+
+#define IO_WRITE 0x00000000 /* operation is write */
+#define IO_READ 0x00000001 /* operation is read */
+#define IO_OPEN 0x00000002 /* operation is open */
+#define IO_DONE 0x00000100 /* operation complete */
+#define IO_ERROR 0x00000200 /* error on operation */
+#define IO_BUSY 0x00000400 /* operation in progress */
+#define IO_WANTED 0x00000800 /* wakeup when no longer BUSY */
+#define IO_BAD 0x00001000 /* bad disk block */
+#define IO_CALL 0x00002000 /* call io_done_thread when done */
+#define IO_INBAND 0x00004000 /* mig call was inband */
+#define IO_INTERNAL 0x00008000 /* internal, device-driver specific */
+#define IO_LOANED 0x00010000 /* ior loaned by another module */
+
+#define IO_SPARE_START 0x00020000 /* start of spare flags */
+
+/*
+ * Standard completion routine for io_requests.
+ */
+void iodone(io_req_t);
+
+/*
+ * Macros to allocate and free IORs - will convert to zones later.
+ */
+#define io_req_alloc(ior,size) \
+ MACRO_BEGIN \
+ (ior) = (io_req_t)malloc(sizeof(struct io_req)); \
+ pthread_mutex_init(&(ior)->io_req_lock, NULL); \
+ MACRO_END
+
+#define io_req_free(ior) \
+ (free(ior))
+
+
+//zone_t io_inband_zone; /* for inband reads */
+
+#endif /* _IO_REQ_ */
diff --git a/libmachdev/linux-errno.h b/libmachdev/linux-errno.h
new file mode 100644
index 00000000..be764a89
--- /dev/null
+++ b/libmachdev/linux-errno.h
@@ -0,0 +1,109 @@
+#ifndef _ASM_GENERIC_ERRNO_H
+#define _ASM_GENERIC_ERRNO_H
+
+#include <errno-base.h>
+
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Function not implemented */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+
+#define EDEADLOCK EDEADLK
+
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale NFS file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+#define ECANCELED 125 /* Operation Canceled */
+#define ENOKEY 126 /* Required key not available */
+#define EKEYEXPIRED 127 /* Key has expired */
+#define EKEYREVOKED 128 /* Key has been revoked */
+#define EKEYREJECTED 129 /* Key was rejected by service */
+
+/* for robust mutexes */
+#define EOWNERDEAD 130 /* Owner died */
+#define ENOTRECOVERABLE 131 /* State not recoverable */
+
+#endif
diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h
new file mode 100644
index 00000000..7b122583
--- /dev/null
+++ b/libmachdev/mach_glue.h
@@ -0,0 +1,41 @@
+#ifndef __MACH_GLUE_H__
+#define __MACH_GLUE_H__
+
+/* network */
+#include <arpa/inet.h>
+
+#include <ddekit/thread.h>
+
+struct sk_buff;
+struct net_device;
+void skb_done_queue(struct sk_buff *skb);
+struct sk_buff *skb_done_dequeue();
+void *skb_reply(struct sk_buff *skb);
+
+int netdev_flags(struct net_device *dev);
+char *netdev_addr(struct net_device *dev);
+char *netdev_name (struct net_device *dev);
+unsigned int netdev_mtu (struct net_device *dev);
+unsigned short netdev_header_len (struct net_device *dev);
+unsigned short netdev_type (struct net_device *dev);
+unsigned char netdev_addr_len (struct net_device *dev);
+
+int dev_change_flags (struct net_device *dev, short flags);
+int linux_pkg_xmit (char *pkg_data, int len, void *del_data,
+ int (*del_func) (struct sk_buff *, void *),
+ struct net_device *dev);
+struct net_device *search_netdev (char *name);
+void kfree_skb (struct sk_buff *skb);
+int dev_open(struct net_device *dev);
+void *l4dde26_register_rx_callback(void *cb);
+void skb_done_head_init();
+
+/* block device */
+struct block_device;
+struct block_device *open_block_dev (char *name, int part, dev_mode_t mode);
+int block_dev_rw (struct block_device *dev, int sectornr,
+ char *data, int count, int rw, void (*write_done) (int err));
+
+int l4dde26_process_from_ddekit(ddekit_thread_t *t);
+
+#endif
diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h
new file mode 100644
index 00000000..b9186fba
--- /dev/null
+++ b/libmachdev/machdev.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2010 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. */
+
+/* This file declares interfaces used by driver programs. */
+
+#ifndef __MACHDEV_H__
+#define __MACHDEV_H__
+
+void * ds_server(void *);
+void mach_device_init(void);
+void register_net(void);
+void register_block(void);
+void trivfs_server(void);
+int trivfs_init(void);
+
+#endif
diff --git a/libmachdev/misc.c b/libmachdev/misc.c
new file mode 100644
index 00000000..977159bd
--- /dev/null
+++ b/libmachdev/misc.c
@@ -0,0 +1,50 @@
+#include <mach.h>
+#include <device/device.h>
+
+#include <ddekit/printf.h>
+
+#include "linux-errno.h"
+
+int
+linux_to_mach_error (int err)
+{
+ switch (err)
+ {
+ case 0:
+ return D_SUCCESS;
+
+ case -EPERM:
+ return D_INVALID_OPERATION;
+
+ case -EIO:
+ return D_IO_ERROR;
+
+ case -ENXIO:
+ return D_NO_SUCH_DEVICE;
+
+ case -EACCES:
+ return D_INVALID_OPERATION;
+
+ case -EFAULT:
+ return D_INVALID_SIZE;
+
+ case -EBUSY:
+ return D_ALREADY_OPEN;
+
+ case -EINVAL:
+ return D_INVALID_SIZE;
+
+ case -EROFS:
+ return D_READ_ONLY;
+
+ case -EWOULDBLOCK:
+ return D_WOULD_BLOCK;
+
+ case -ENOMEM:
+ return D_NO_MEMORY;
+
+ default:
+ ddekit_printf ("linux_to_mach_error: unknown code %d\n", err);
+ return D_IO_ERROR;
+ }
+}
diff --git a/libmachdev/net.c b/libmachdev/net.c
new file mode 100644
index 00000000..501c9bb7
--- /dev/null
+++ b/libmachdev/net.c
@@ -0,0 +1,674 @@
+/*
+ * Linux network driver support.
+ *
+ * Copyright (C) 1996 The University of Utah and the Computer Systems
+ * Laboratory at the University of Utah (CSL)
+ *
+ * This program 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.
+ *
+ * This program 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Shantanu Goel, University of Utah CSL
+ */
+
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Ethernet-type device handling.
+ *
+ * Version: @(#)eth.c 1.0.7 05/25/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Florian La Roche, <rzsfl@rz.uni-sb.de>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ * Fixes:
+ * Mr Linux : Arp problems
+ * Alan Cox : Generic queue tidyup (very tiny here)
+ * Alan Cox : eth_header ntohs should be htons
+ * Alan Cox : eth_rebuild_header missing an htons and
+ * minor other things.
+ * Tegge : Arp bug fixes.
+ * Florian : Removed many unnecessary functions, code cleanup
+ * and changes for new arp and skbuff.
+ * Alan Cox : Redid header building to reflect new format.
+ * Alan Cox : ARP only when compiled with CONFIG_INET
+ * Greg Page : 802.2 and SNAP stuff.
+ * Alan Cox : MAC layer pointers/new format.
+ * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding.
+ * Alan Cox : Protect against forwarding explosions with
+ * older network drivers and IFF_ALLMULTI
+ *
+ * This program 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 of the License, or (at your option) any later version.
+ */
+#include <assert.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <error.h>
+
+#include "mach_U.h"
+
+#include <mach.h>
+#include <hurd.h>
+
+#define MACH_INCLUDE
+
+#include "vm_param.h"
+#include "device_reply_U.h"
+#include "dev_hdr.h"
+#include "if_ether.h"
+#include "util.h"
+#include "mach_glue.h"
+#include "if_hdr.h"
+
+#define ether_header ethhdr
+
+extern int linux_intr_pri;
+extern struct port_bucket *port_bucket;
+extern struct port_class *dev_class;
+
+/* One of these is associated with each instance of a device. */
+struct net_data
+{
+ struct port_info port; /* device port */
+ struct emul_device device; /* generic device structure */
+ struct ifnet ifnet; /* Mach ifnet structure (needed for filters) */
+ struct net_device *dev; /* Linux network device structure */
+ struct net_data *next;
+};
+
+struct skb_reply
+{
+ mach_port_t reply;
+ mach_msg_type_name_t reply_type;
+ int pkglen;
+};
+
+static struct net_data *nd_head;
+
+/* Forward declarations. */
+
+extern struct device_emulation_ops linux_net_emulation_ops;
+
+static int print_packet_size = 1;
+
+static mach_msg_type_t header_type =
+{
+ MACH_MSG_TYPE_BYTE,
+ 8,
+ NET_HDW_HDR_MAX,
+ TRUE,
+ FALSE,
+ FALSE,
+ 0
+};
+
+static mach_msg_type_t packet_type =
+{
+ MACH_MSG_TYPE_BYTE, /* name */
+ 8, /* size */
+ 0, /* number */
+ TRUE, /* inline */
+ FALSE, /* longform */
+ FALSE /* deallocate */
+};
+
+static struct net_data *search_nd (struct net_device *dev)
+{
+ struct net_data *nd = nd_head;
+
+ //TODO protected by locks.
+ while (nd)
+ {
+ if (nd->dev == dev)
+ return nd;
+ nd = nd->next;
+ }
+ return NULL;
+}
+
+/* Linux kernel network support routines. */
+
+/* actions before freeing the sk_buff SKB.
+ * If it returns 1, the packet will be deallocated later. */
+static int
+pre_kfree_skb (struct sk_buff *skb, void *data)
+{
+ struct skb_reply *reply = data;
+ extern void wakeup_io_done_thread ();
+
+ /* Queue sk_buff on done list if there is a
+ page list attached or we need to send a reply.
+ Wakeup the iodone thread to process the list. */
+ if (reply && MACH_PORT_VALID (reply->reply))
+ {
+ if (MACH_PORT_VALID (reply->reply))
+ {
+ ds_device_write_reply (reply->reply, reply->reply_type,
+ 0, reply->pkglen);
+ reply->reply = MACH_PORT_NULL;
+ }
+ }
+ /* deallocate skb_reply before freeing the packet. */
+ free (data);
+ return 0;
+}
+
+/*
+ * Deliver the message to all right pfinet servers that
+ * connects to the virtual network interface.
+ */
+int
+deliver_msg(struct net_rcv_msg *msg, if_filter_list_t *ifp)
+{
+ 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 = &ifp->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)
+ {
+ 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)
+ {
+ /* TODO: remove from filter */
+ }
+ }
+ }
+ FILTER_ITERATE_END
+
+ return 0;
+}
+
+/* Accept packet SKB received on an interface. */
+static void
+netif_rx_handle (char *data, int len, struct net_device *dev)
+{
+ int pack_size;
+ net_rcv_msg_t net_msg;
+ struct ether_header *eh;
+ struct packet_header *ph;
+ struct net_data *nd;
+
+ if (print_packet_size)
+ printf ("netif_rx: length %d\n", len);
+
+ nd = search_nd(dev);
+ assert (nd);
+
+ /* Allocate a kernel message buffer. */
+ net_msg = malloc (sizeof (*net_msg));
+ if (!net_msg)
+ return;
+
+ pack_size = len - sizeof (struct ethhdr);
+ /* remember message sizes must be rounded up */
+ net_msg->msg_hdr.msgh_size = (((mach_msg_size_t) (sizeof(struct net_rcv_msg)
+ - NET_RCV_MAX + pack_size)) + 3) & ~3;
+
+ /* Copy packet into message buffer. */
+ eh = (struct ether_header *) (net_msg->header);
+ ph = (struct packet_header *) (net_msg->packet);
+ memcpy (eh, data, sizeof (struct ether_header));
+ /* packet is prefixed with a struct packet_header,
+ see include/device/net_status.h. */
+ memcpy (ph + 1, data + sizeof (struct ether_header), pack_size);
+ ph->type = eh->h_proto;
+ ph->length = pack_size + sizeof (struct packet_header);
+
+ net_msg->sent = FALSE; /* Mark packet as received. */
+
+ net_msg->header_type = header_type;
+ net_msg->packet_type = packet_type;
+ net_msg->net_rcv_msg_packet_count = ph->length;
+ deliver_msg (net_msg, &nd->ifnet.port_list);
+ free (net_msg);
+}
+
+/* Mach device interface routines. */
+
+/* Return a send right associated with network device ND. */
+static mach_port_t
+dev_to_port (void *nd)
+{
+ return (nd
+ ? ports_get_send_right (nd)
+ : MACH_PORT_NULL);
+}
+
+/*
+ * Initialize send and receive queues on an interface.
+ */
+void if_init_queues(ifp)
+ register struct ifnet *ifp;
+{
+// IFQ_INIT(&ifp->if_snd);
+ queue_init(&ifp->port_list.if_rcv_port_list);
+ queue_init(&ifp->port_list.if_snd_port_list);
+ pthread_mutex_init(&ifp->if_rcv_port_list_lock, NULL);
+ pthread_mutex_init(&ifp->if_snd_port_list_lock, NULL);
+}
+
+static io_return_t
+device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, char *name, device_t *devp,
+ mach_msg_type_name_t *devicePoly)
+{
+ io_return_t err = D_SUCCESS;
+ struct net_device *dev;
+ struct net_data *nd;
+ struct ifnet *ifp;
+
+ /* Search for the device. */
+ dev = search_netdev (name);
+ if (!dev)
+ {
+ fprintf (stderr, "after search_netdev: cannot find %s\n", name);
+ return D_NO_SUCH_DEVICE;
+ }
+
+ /* Allocate and initialize device data if this is the first open. */
+ nd = search_nd (dev);
+ if (!nd)
+ {
+ char *name;
+
+ err = create_device_port (sizeof (*nd), &nd);
+ if (err)
+ {
+ fprintf (stderr, "after create_device_port: cannot create a port\n");
+ goto out;
+ }
+
+ nd->dev = dev;
+ nd->device.emul_data = nd;
+ nd->device.emul_ops = &linux_net_emulation_ops;
+ nd->next = nd_head;
+ nd_head = nd;
+
+ ifp = &nd->ifnet;
+ name = netdev_name (dev);
+ ifp->if_unit = name[strlen (name) - 1] - '0';
+ ifp->if_flags = IFF_UP | IFF_RUNNING;
+ ifp->if_mtu = netdev_mtu (dev);
+ ifp->if_header_size = netdev_header_len (dev);
+ ifp->if_header_format = netdev_type (dev);
+ ifp->if_address_size = netdev_addr_len (dev);
+ ifp->if_address = netdev_addr (dev);
+ if_init_queues (ifp);
+
+ if ((err = dev_open(dev)) < 0)
+ {
+ fprintf (stderr, "after dev_open: cannot open the device\n");
+ err = linux_to_mach_error (err);
+ }
+
+ out:
+ if (err)
+ {
+ if (nd)
+ {
+ ports_destroy_right (nd);
+ nd = NULL;
+ }
+ }
+ else
+ {
+#if 0
+ /* IPv6 heavily relies on multicasting (especially router and
+ neighbor solicits and advertisements), so enable reception of
+ those multicast packets by setting `LINUX_IFF_ALLMULTI'. */
+ dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING | LINUX_IFF_ALLMULTI;
+ skb_queue_head_init (&dev->buffs[0]);
+
+ if (dev->set_multicast_list)
+ dev->set_multicast_list (dev);
+#endif
+ }
+ if (MACH_PORT_VALID (reply_port))
+ ds_device_open_reply (reply_port, reply_port_type,
+ err, dev_to_port (nd));
+ return MIG_NO_REPLY;
+ }
+
+ *devp = ports_get_right (nd);
+ *devicePoly = MACH_MSG_TYPE_COPY_SEND;
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_write (void *d, mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t bn, io_buf_ptr_t data, unsigned int count,
+ int *bytes_written)
+{
+ struct net_data *nd = d;
+ struct net_device *dev = nd->dev;
+ struct skb_reply *skb_reply = malloc (sizeof (*skb_reply));
+ error_t err;
+
+ if (skb_reply == NULL)
+ return D_NO_MEMORY;
+
+ skb_reply->pkglen = count;
+ skb_reply->reply = reply_port;
+ skb_reply->reply_type = reply_port_type;
+
+ err = linux_pkg_xmit (data, count, skb_reply, pre_kfree_skb, dev);
+ vm_deallocate (mach_task_self (), (vm_address_t) data, count);
+ if (err)
+ return linux_to_mach_error (err);
+
+ /* Send packet to filters. */
+ // TODO should I deliver the packet to other network stacks?
+#if 0
+ {
+ struct packet_header *packet;
+ struct ether_header *header;
+ ipc_kmsg_t kmsg;
+
+ kmsg = net_kmsg_get ();
+
+ if (kmsg != IKM_NULL)
+ {
+ /* Suitable for Ethernet only. */
+ header = (struct ether_header *) (net_kmsg (kmsg)->header);
+ packet = (struct packet_header *) (net_kmsg (kmsg)->packet);
+ memcpy (header, skb->data, sizeof (struct ether_header));
+
+ /* packet is prefixed with a struct packet_header,
+ see include/device/net_status.h. */
+ memcpy (packet + 1, skb->data + sizeof (struct ether_header),
+ skb->len - sizeof (struct ether_header));
+ packet->length = skb->len - sizeof (struct ether_header)
+ + sizeof (struct packet_header);
+ packet->type = header->ether_type;
+ net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent. */
+ s = splimp ();
+ net_packet (&dev->net_data->ifnet, kmsg, packet->length,
+ ethernet_priority (kmsg));
+ splx (s);
+ }
+ }
+#endif
+
+ return MIG_NO_REPLY;
+}
+
+/*
+ * Other network operations
+ */
+static io_return_t
+net_getstat(ifp, flavor, status, count)
+ struct ifnet *ifp;
+ dev_flavor_t flavor;
+ dev_status_t status; /* pointer to OUT array */
+ natural_t *count; /* OUT */
+{
+#define ETHERMTU 1500
+ 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 = ETH_ALEN;
+ addr_int_count = (addr_byte_count + (sizeof(int)-1))
+ / sizeof(int);
+
+ if (*count < addr_int_count)
+ {
+ /* XXX debug hack. */
+ printf ("net_getstat: count: %d, addr_int_count: %d\n",
+ *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);
+}
+
+static io_return_t
+device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *count)
+{
+ struct net_data *net = (struct net_data *) d;
+
+ if (flavor == NET_FLAGS)
+ {
+ if (*count != sizeof(short))
+ return D_INVALID_SIZE;
+
+ *(short *) status = netdev_flags (net->dev);
+ return D_SUCCESS;
+ }
+
+#if 0
+ if(flavor >= SIOCIWFIRST && flavor <= SIOCIWLAST)
+ {
+ /* handle wireless ioctl */
+ if(! IW_IS_GET(flavor))
+ return D_INVALID_OPERATION;
+
+ if(*count * sizeof(int) < sizeof(struct ifreq))
+ return D_INVALID_OPERATION;
+
+ struct net_data *nd = d;
+ struct linux_device *dev = nd->dev;
+
+ if(! dev->do_ioctl)
+ return D_INVALID_OPERATION;
+
+ int result;
+
+ if (flavor == SIOCGIWRANGE || flavor == SIOCGIWENCODE
+ || flavor == SIOCGIWESSID || flavor == SIOCGIWNICKN
+ || flavor == SIOCGIWSPY)
+ {
+ /*
+ * These ioctls require an `iw_point' as their argument (i.e.
+ * they want to return some data to userspace.
+ * Therefore supply some sane values and carry the data back
+ * to userspace right behind the `struct iwreq'.
+ */
+ struct iw_point *iwp = &((struct iwreq *) status)->u.data;
+ iwp->length = *count * sizeof (dev_status_t) - sizeof (struct ifreq);
+ iwp->pointer = (void *) status + sizeof (struct ifreq);
+
+ result = dev->do_ioctl (dev, (struct ifreq *) status, flavor);
+
+ *count = ((sizeof (struct ifreq) + iwp->length)
+ / sizeof (dev_status_t));
+ if (iwp->length % sizeof (dev_status_t))
+ (*count) ++;
+ }
+ else
+ {
+ *count = sizeof(struct ifreq) / sizeof(int);
+ result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
+ }
+
+ return result ? D_IO_ERROR : D_SUCCESS;
+ }
+ else
+#endif
+ {
+ /* common get_status request */
+ return net_getstat (&net->ifnet, flavor, status, count);
+ }
+}
+
+static io_return_t
+device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t count)
+{
+ if (flavor == NET_FLAGS)
+ {
+ if (count != 1)
+ return D_INVALID_SIZE;
+
+ int flags = *(int *) status;
+ struct net_data *net = (struct net_data *) d;
+
+ dev_change_flags (net->dev, flags);
+
+ return D_SUCCESS;
+ }
+ return D_INVALID_OPERATION;
+
+#if 0
+ if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST)
+ return D_INVALID_OPERATION;
+
+ if(! IW_IS_SET(flavor))
+ return D_INVALID_OPERATION;
+
+ if(count * sizeof(int) < sizeof(struct ifreq))
+ return D_INVALID_OPERATION;
+
+ struct net_data *nd = d;
+ struct linux_device *dev = nd->dev;
+
+ if(! dev->do_ioctl)
+ return D_INVALID_OPERATION;
+
+ if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID
+ || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY)
+ && ((struct iwreq *) status)->u.data.pointer)
+ {
+ struct iw_point *iwp = &((struct iwreq *) status)->u.data;
+
+ /* safety check whether the status array is long enough ... */
+ if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length)
+ return D_INVALID_OPERATION;
+
+ /* make sure, iwp->pointer points to the correct address */
+ if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq);
+ }
+
+ int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
+ return result ? D_IO_ERROR : D_SUCCESS;
+#endif
+}
+
+
+static io_return_t
+device_set_filter (void *d, mach_port_t port, int priority,
+ filter_t * filter, unsigned filter_count)
+{
+ return net_set_filter (&((struct net_data *) d)->ifnet.port_list,
+ port, priority, filter, filter_count);
+}
+
+/* Do any initialization required for network devices. */
+static void linux_net_emulation_init ()
+{
+ skb_done_head_init();
+ l4dde26_register_rx_callback(netif_rx_handle);
+}
+
+struct device_emulation_ops linux_net_emulation_ops =
+{
+ linux_net_emulation_init,
+ NULL,
+ NULL,
+ dev_to_port,
+ device_open,
+ NULL,
+ device_write,
+ NULL,
+ NULL,
+ NULL,
+ device_set_status,
+ device_get_status,
+ device_set_filter,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void register_net()
+{
+ extern void reg_dev_emul (struct device_emulation_ops *ops);
+ reg_dev_emul (&linux_net_emulation_ops);
+}
diff --git a/libmachdev/queue.c b/libmachdev/queue.c
new file mode 100644
index 00000000..a43a21b0
--- /dev/null
+++ b/libmachdev/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/libmachdev/queue.h b/libmachdev/queue.h
new file mode 100644
index 00000000..86ef74dc
--- /dev/null
+++ b/libmachdev/queue.h
@@ -0,0 +1,370 @@
+/*
+ * 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_
+
+#include <pthread.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);
+void insque(queue_entry_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))
+
+
+
+/*----------------------------------------------------------------*/
+/*
+ * Define macros for queues with locks.
+ */
+struct mpqueue_head {
+ struct queue_entry head; /* header for queue */
+ pthread_mutex_t lock; /* lock for queue */
+};
+
+typedef struct mpqueue_head mpqueue_head_t;
+
+#define round_mpq(size) (size)
+
+#define mpqueue_init(q) \
+ { \
+ queue_init(&(q)->head); \
+ pthread_mutex_init(&(q)->lock, NULL); \
+ }
+
+#define mpenqueue_tail(q, elt) \
+ pthread_mutex_lock(&(q)->lock); \
+ enqueue_tail(&(q)->head, elt); \
+ pthread_mutex_unlock(&(q)->lock);
+
+#define mpdequeue_head(q, elt) \
+ pthread_mutex_lock(&(q)->lock); \
+ if (queue_empty(&(q)->head)) \
+ *(elt) = 0; \
+ else \
+ *(elt) = dequeue_head(&(q)->head); \
+ pthread_mutex_unlock(&(q)->lock);
+
+/*
+ * Old queue stuff, will go away soon.
+ */
+
+#endif /* _KERN_QUEUE_H_ */
diff --git a/libmachdev/trivfs_server.c b/libmachdev/trivfs_server.c
new file mode 100644
index 00000000..4565c3d7
--- /dev/null
+++ b/libmachdev/trivfs_server.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <pciaccess.h>
+#include <error.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd.h>
+
+static struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+boolean_t
+is_master_device (mach_port_t port)
+{
+ struct port_info *pi = ports_lookup_port (port_bucket, port,
+ trivfs_protid_portclasses[0]);
+ if (pi == NULL)
+ return FALSE;
+
+ ports_port_deref (pi);
+ return TRUE;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys, 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)
+
+#undef ADD_OPT
+ return err;
+}
+
+int trivfs_init()
+{
+ port_bucket = ports_create_bucket ();
+ trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
+ trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
+ return 0;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+
+ count = ports_count_class (trivfs_protid_portclasses[0]);
+
+ if (count && !(flags & FSYS_GOAWAY_FORCE))
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+ return EBUSY;
+ }
+
+ pci_system_cleanup ();
+ exit (0);
+}
+
+static int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ int ret;
+ extern int device_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ ret = device_server (inp, outp) || notify_server (inp, outp)
+ || trivfs_demuxer (inp, outp);
+ return ret;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *stat)
+{
+}
+
+void trivfs_server()
+{
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ int err;
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "must be started as a translator");
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_portclasses[0], port_bucket,
+ trivfs_protid_portclasses[0], port_bucket, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (1, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ {
+ ports_manage_port_operations_one_thread (port_bucket, demuxer, 0);
+ } while (trivfs_goaway (fsys, 0));
+}
diff --git a/libmachdev/util.h b/libmachdev/util.h
new file mode 100644
index 00000000..1c62b0d6
--- /dev/null
+++ b/libmachdev/util.h
@@ -0,0 +1,35 @@
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <stdio.h>
+
+#define panic(format, ...) do \
+{ \
+ char buf[1024]; \
+ snprintf (buf, 1024, "devnode: %s", format); \
+ fprintf (stderr , buf, ## __VA_ARGS__); \
+ fflush (stderr); \
+ abort (); \
+} while (0)
+
+#define DEBUG
+
+#ifdef DEBUG
+
+#define debug(format, ...) do \
+{ \
+ char buf[1024]; \
+ snprintf (buf, 1024, "pcnet32: %s: %s\n", __func__, format); \
+ fprintf (stderr , buf, ## __VA_ARGS__); \
+ fflush (stderr); \
+} while (0)
+
+#else
+
+#define debug(format, ...) do {} while (0)
+
+#endif
+
+int linux_to_mach_error (int err);
+
+#endif
diff --git a/libmachdev/vm_param.h b/libmachdev/vm_param.h
new file mode 100644
index 00000000..7b615c8a
--- /dev/null
+++ b/libmachdev/vm_param.h
@@ -0,0 +1,7 @@
+#ifndef __VM_PARAM_H__
+#define __VM_PARAM_H__
+
+#define PAGE_SIZE __vm_page_size
+#define PAGE_MASK (PAGE_SIZE-1)
+
+#endif