summaryrefslogtreecommitdiff
path: root/tap-mac/tuntap/src
diff options
context:
space:
mode:
Diffstat (limited to 'tap-mac/tuntap/src')
-rw-r--r--tap-mac/tuntap/src/lock.cc201
-rw-r--r--tap-mac/tuntap/src/lock.h160
-rw-r--r--tap-mac/tuntap/src/mem.cc76
-rw-r--r--tap-mac/tuntap/src/mem.h48
-rw-r--r--tap-mac/tuntap/src/tap/Info.plist36
-rw-r--r--tap-mac/tuntap/src/tap/Makefile60
-rw-r--r--tap-mac/tuntap/src/tap/kmod.cc93
-rw-r--r--tap-mac/tuntap/src/tap/tap.cc452
-rw-r--r--tap-mac/tuntap/src/tap/tap.h103
-rw-r--r--tap-mac/tuntap/src/tun/Info.plist36
-rw-r--r--tap-mac/tuntap/src/tun/Makefile59
-rw-r--r--tap-mac/tuntap/src/tun/kmod.cc93
-rw-r--r--tap-mac/tuntap/src/tun/tun.cc424
-rw-r--r--tap-mac/tuntap/src/tun/tun.h123
-rw-r--r--tap-mac/tuntap/src/tun/tun_inet6_proto.c87
-rw-r--r--tap-mac/tuntap/src/tun/tun_inet_proto.c87
-rw-r--r--tap-mac/tuntap/src/tun/tun_ioctls.h38
-rw-r--r--tap-mac/tuntap/src/tuntap.cc962
-rw-r--r--tap-mac/tuntap/src/tuntap.h301
-rw-r--r--tap-mac/tuntap/src/tuntap_mgr.cc372
-rw-r--r--tap-mac/tuntap/src/util.h46
21 files changed, 3857 insertions, 0 deletions
diff --git a/tap-mac/tuntap/src/lock.cc b/tap-mac/tuntap/src/lock.cc
new file mode 100644
index 00000000..0da48be2
--- /dev/null
+++ b/tap-mac/tuntap/src/lock.cc
@@ -0,0 +1,201 @@
+/*
+ * ip tunnel/ethertap device for MacOSX.
+ *
+ * Locking implementation.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "lock.h"
+
+extern "C" {
+
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+}
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+/* class tt_lock */
+lck_grp_t *tt_lock::tt_lck_grp = NULL;
+
+bool
+tt_lock::initialize()
+{
+ /* init if necessary */
+ if (tt_lck_grp == NULL) {
+ dprintf("initing lock group\n");
+ tt_lck_grp = lck_grp_alloc_init("tuntap locks", LCK_GRP_ATTR_NULL);
+
+ if (tt_lck_grp == NULL) {
+ /* if something fails, the lock won't work */
+ log(LOG_ERR, "tuntap: could not allocate locking group\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+tt_lock::shutdown()
+{
+ /* free the locking group */
+ if (tt_lck_grp != NULL) {
+ dprintf("freeing lock group\n");
+ lck_grp_free(tt_lck_grp);
+ tt_lck_grp = NULL;
+ }
+}
+
+/* tt_mutex */
+tt_mutex::tt_mutex()
+{
+ /* fail if locking group not initialized */
+ if (tt_lck_grp == NULL)
+ return;
+
+ /* allocate the lock */
+ lck = lck_rw_alloc_init(tt_lck_grp, NULL);
+
+ if (lck == NULL)
+ log(LOG_ERR, "tuntap: could not allocate mutex\n");
+}
+
+tt_mutex::~tt_mutex()
+{
+ /* if the lock doesn't exist, this will be a no-op */
+ if (lck == NULL)
+ return;
+
+ /* free the lock */
+ lck_rw_free(lck, tt_lck_grp);
+}
+
+void
+tt_mutex::lock()
+{
+ if (lck != NULL)
+ lck_rw_lock_exclusive(lck);
+}
+
+void
+tt_mutex::unlock()
+{
+ if (lck != NULL)
+ lck_rw_unlock_exclusive(lck);
+}
+
+void
+tt_mutex::sleep(void *cond)
+{
+ if (lck != NULL)
+ lck_rw_sleep(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE);
+}
+
+void
+tt_mutex::sleep(void *cond, uint64_t timeout)
+{
+ if (lck != NULL)
+ lck_rw_sleep_deadline(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE, timeout);
+}
+
+void
+tt_mutex::wakeup(void *cond)
+{
+ if (lck != NULL)
+ ::wakeup(cond);
+}
+
+/* tt_gate */
+tt_gate::tt_gate()
+ : ticket_number(0),
+ population(0)
+{
+}
+
+void
+tt_gate::enter()
+{
+ /* just try to grab the lock, increase the ticket number and the population */
+ auto_lock l(&slock);
+ ticket_number++;
+ population++;
+}
+
+void
+tt_gate::exit()
+{
+ auto_lock l(&slock);
+ ticket_number--;
+ population--;
+}
+
+bool
+tt_gate::is_anyone_in()
+{
+ return population != 0;
+}
+
+unsigned int
+tt_gate::get_ticket_number()
+{
+ return ticket_number;
+}
+
+void
+tt_gate::lock()
+{
+ slock.lock();
+}
+
+void
+tt_gate::unlock()
+{
+ slock.unlock();
+}
+
+void
+tt_gate::sleep(void* cond)
+{
+ slock.sleep(cond);
+}
+
+void
+tt_gate::sleep(void* cond, uint64_t timeout)
+{
+ slock.sleep(cond, timeout);
+}
+
+void
+tt_gate::wakeup(void* cond)
+{
+ slock.wakeup(cond);
+}
+
diff --git a/tap-mac/tuntap/src/lock.h b/tap-mac/tuntap/src/lock.h
new file mode 100644
index 00000000..51d3299a
--- /dev/null
+++ b/tap-mac/tuntap/src/lock.h
@@ -0,0 +1,160 @@
+/*
+ * ip tunnel/ethertap device for MacOSX.
+ *
+ * Locking is not as straightforward for Tiger. So declare our own locking class.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __LOCK_H__
+#define __LOCK_H__
+
+extern "C" {
+
+#include <kern/locks.h>
+#include <sys/param.h>
+
+}
+
+/* our own locking class. declares the common interface of the locking primitives. */
+class tt_lock {
+
+ protected:
+ /* locking group */
+ static lck_grp_t *tt_lck_grp;
+
+ public:
+ /* be virtual */
+ virtual ~tt_lock() { };
+
+ /* static intialization (inits the locking group) */
+ static bool initialize();
+ static void shutdown();
+
+ /* locking */
+ virtual void lock() = 0;
+ virtual void unlock() = 0;
+
+ /* monitor primitives */
+ virtual void sleep(void* cond) = 0;
+ virtual void sleep(void* cond, uint64_t) = 0;
+ virtual void wakeup(void* cond) = 0;
+};
+
+/* simple mutex */
+class tt_mutex : public tt_lock {
+
+ private:
+ /* underlying darwin lock */
+ lck_rw_t *lck;
+
+ public:
+ tt_mutex();
+ virtual ~tt_mutex();
+
+ void lock();
+ void unlock();
+
+ /* monitor primitives */
+ void sleep(void* cond);
+ void sleep(void* cond, uint64_t);
+ void wakeup(void* cond);
+};
+
+/* A very special locking class that we use to track threads that enter and leave the character
+ * device service functions. They call enter() before entering the actual service routinge and
+ * exit() when done. enter() only permits them to pass when the gate isn't locked. Furthermore, the
+ * gate assigns ticket numbers to everyone that passes the gate, so you can check whether more
+ * threads came through. See tuntap_mgr::shutdown() for how we use that stuff.
+ */
+class tt_gate : public tt_lock {
+
+ private:
+ /* synchronization lock */
+ tt_mutex slock;
+ /* ticket number */
+ unsigned int ticket_number;
+ /* count of threads that are in */
+ unsigned int population;
+
+ public:
+ /* construct a new gate */
+ tt_gate();
+
+ /* enter - pass the gate */
+ void enter();
+ /* exit - pass the gate */
+ void exit();
+
+ /* check whether anyone is in */
+ bool is_anyone_in();
+ /* gets the next ticket number */
+ unsigned int get_ticket_number();
+
+ /* lock the gate */
+ void lock();
+ /* unlock the gate */
+ void unlock();
+
+ /* monitor primitives */
+ void sleep(void* cond);
+ void sleep(void* cond, uint64_t);
+ void wakeup(void* cond);
+};
+
+/* auto_lock and auto_rwlock serve as automatic lock managers: Create an object, passing the
+ * tt_[rw]lock you want to lock to have it grab the lock. When the object goes out of scope, the
+ * destructor of the class will release the lock.
+ */
+class auto_lock {
+
+ protected:
+ /* the lock we hold */
+ tt_lock *l;
+
+ public:
+ auto_lock(tt_lock *m)
+ : l(m)
+ {
+ lock();
+ }
+
+ ~auto_lock()
+ {
+ unlock();
+ }
+
+ void lock()
+ {
+ l->lock();
+ }
+
+ void unlock()
+ {
+ l->unlock();
+ }
+};
+
+#endif /* __LOCK_H__ */
+
diff --git a/tap-mac/tuntap/src/mem.cc b/tap-mac/tuntap/src/mem.cc
new file mode 100644
index 00000000..cd3264fa
--- /dev/null
+++ b/tap-mac/tuntap/src/mem.cc
@@ -0,0 +1,76 @@
+/*
+ * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface.
+ *
+ * Memory management implementation.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "mem.h"
+
+extern "C" {
+
+#include <libkern/OSMalloc.h>
+
+}
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+static int inited = 0;
+static OSMallocTag tag;
+
+void
+mem_initialize(const char* name) {
+
+ if (!inited) {
+ tag = OSMalloc_Tagalloc(name, OSMT_DEFAULT);
+ inited = 1;
+ }
+}
+
+void
+mem_shutdown() {
+
+ if (inited) {
+ OSMalloc_Tagfree(tag);
+ inited = 0;
+ }
+}
+
+void *
+mem_alloc(uint32_t size) {
+
+ return OSMalloc(size, tag);
+}
+
+void
+mem_free(void *addr, uint32_t size) {
+
+ OSFree(addr, size, tag);
+}
+
diff --git a/tap-mac/tuntap/src/mem.h b/tap-mac/tuntap/src/mem.h
new file mode 100644
index 00000000..4d06fd8c
--- /dev/null
+++ b/tap-mac/tuntap/src/mem.h
@@ -0,0 +1,48 @@
+/*
+ * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface.
+ *
+ * Memory management.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+extern "C" {
+
+#include <stdint.h>
+
+}
+
+/* Memory manager initalization and shutdown */
+void mem_initialize(const char *name);
+void mem_shutdown();
+
+/* Memory allocation functions */
+void *mem_alloc(uint32_t size);
+void mem_free(void *addr, uint32_t size);
+
+#endif /* __MEM_H__ */
+
diff --git a/tap-mac/tuntap/src/tap/Info.plist b/tap-mac/tuntap/src/tap/Info.plist
new file mode 100644
index 00000000..bb9b03fd
--- /dev/null
+++ b/tap-mac/tuntap/src/tap/Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>@@CFBUNDLEDEVELOPMENTREGION@@</string>
+ <key>CFBundleExecutable</key>
+ <string>@@CFBUNDLEEXECUTABLE@@</string>
+ <key>CFBundleIdentifier</key>
+ <string>@@CFBUNDLEIDENTIFIER@@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@@CFBUNDLEEXECUTABLE@@</string>
+ <key>CFBundlePackageType</key>
+ <string>@@CFBUNDLEPACKAGETYPE@@</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@@CFBUNDLEVERSION@@</string>
+ <key>CFBundleSignature</key>
+ <string>@@CFBUNDLESIGNATURE@@</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.mach</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.bsd</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.libkern</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.unsupported</key>
+ <string>8.0</string>
+ </dict>
+</dict>
+</plist>
+
diff --git a/tap-mac/tuntap/src/tap/Makefile b/tap-mac/tuntap/src/tap/Makefile
new file mode 100644
index 00000000..a69b967e
--- /dev/null
+++ b/tap-mac/tuntap/src/tap/Makefile
@@ -0,0 +1,60 @@
+#
+# ethertap driver for MacOSX
+#
+# Makefile
+#
+# (c) 2004, 2005, 2006, 2007, 2008 Mattias Nissler
+#
+
+OBJS = ../tuntap.o ../tuntap_mgr.o ../lock.o ../mem.o kmod.o tap.o
+KMOD_BIN = tap
+BUNDLE_DIR = ../..
+BUNDLE_NAME = tap.kext
+
+TAP_KEXT_VERSION = $(TUNTAP_VERSION)
+
+BUNDLE_REGION = English
+BUNDLE_IDENTIFIER = com.zerotier.tap
+BUNDLE_SIGNATURE = ????
+BUNDLE_PACKAGETYPE = KEXT
+BUNDLE_VERSION = $(TAP_KEXT_VERSION)
+
+INCLUDE = -I.. -I/System/Library/Frameworks/Kernel.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Kernel.framework/Headers
+CFLAGS = -Wall -mkernel -force_cpusubtype_ALL \
+ -fno-builtin -fno-stack-protector -arch i386 -arch x86_64 \
+ -DKERNEL -D__APPLE__ -DKERNEL_PRIVATE -DTUNTAP_VERSION=\"$(TUNTAP_VERSION)\" \
+ -DTAP_KEXT_VERSION=\"$(TAP_KEXT_VERSION)\"
+CCFLAGS = $(CFLAGS)
+LDFLAGS = -Wall -mkernel -nostdlib -r -lcc_kext -arch i386 -arch x86_64 -Xlinker -kext
+
+#CCP = g++
+CCP = $(HOME)/Code/llvm-g++-Xcode4.6.2/bin/llvm-g++
+
+CC = gcc
+
+all: $(KMOD_BIN) bundle
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+.cc.o:
+ $(CCP) $(CCFLAGS) $(INCLUDE) -c $< -o $@
+
+$(KMOD_BIN): $(OBJS)
+ $(CCP) $(LDFLAGS) -o $(KMOD_BIN) $(OBJS)
+
+bundle: $(KMOD_BIN)
+ rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME)
+ mkdir -p $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS
+ cp $(KMOD_BIN) $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS
+ sed -e "s/@@CFBUNDLEEXECUTABLE@@/$(KMOD_BIN)/" \
+ -e "s/@@CFBUNDLEDEVELOPMENTREGION@@/$(BUNDLE_REGION)/" \
+ -e "s/@@CFBUNDLEIDENTIFIER@@/$(BUNDLE_IDENTIFIER)/" \
+ -e "s/@@CFBUNDLESIGNATURE@@/$(BUNDLE_SIGNATURE)/" \
+ -e "s/@@CFBUNDLEPACKAGETYPE@@/$(BUNDLE_PACKAGETYPE)/" \
+ -e "s/@@CFBUNDLEVERSION@@/$(BUNDLE_VERSION)/" \
+ Info.plist > $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/Info.plist
+
+clean:
+ -rm -f $(OBJS) $(KMOD_BIN)
+ -rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME)
+
diff --git a/tap-mac/tuntap/src/tap/kmod.cc b/tap-mac/tuntap/src/tap/kmod.cc
new file mode 100644
index 00000000..f9c4a40e
--- /dev/null
+++ b/tap-mac/tuntap/src/tap/kmod.cc
@@ -0,0 +1,93 @@
+/*
+ * ethertap device for MacOSX.
+ *
+ * Kext definition (it is a mach kmod really...)
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tap.h"
+#include "mem.h"
+
+extern "C" {
+
+#include <sys/param.h>
+
+#include <mach/kmod.h>
+
+static tap_manager *mgr;
+
+/*
+ * start function. called when the kext gets loaded.
+ */
+static kern_return_t tap_module_start(struct kmod_info *ki, void *data)
+{
+ mem_initialize(TAP_FAMILY_NAME);
+
+ /* initialize locking */
+ if (!tt_lock::initialize())
+ return KMOD_RETURN_FAILURE;
+
+ /* create a tap manager that will handle the rest */
+ mgr = new tap_manager();
+
+ if (mgr != NULL) {
+ if (mgr->initialize(TAP_IF_COUNT, (char *) TAP_FAMILY_NAME))
+ return KMOD_RETURN_SUCCESS;
+
+ delete mgr;
+ mgr = NULL;
+ /* clean up locking */
+ tt_lock::shutdown();
+ }
+
+ return KMOD_RETURN_FAILURE;
+}
+
+/*
+ * stop function. called when the kext should be unloaded. unloading can be prevented by
+ * returning failure
+ */
+static kern_return_t tap_module_stop(struct kmod_info *ki, void *data)
+{
+ if (mgr != NULL) {
+ if (!mgr->shutdown())
+ return KMOD_RETURN_FAILURE;
+
+ delete mgr;
+ mgr = NULL;
+ }
+
+ /* clean up locking */
+ tt_lock::shutdown();
+
+ mem_shutdown();
+
+ return KMOD_RETURN_SUCCESS;
+}
+
+KMOD_DECL(tap, TAP_KEXT_VERSION)
+
+}
+
diff --git a/tap-mac/tuntap/src/tap/tap.cc b/tap-mac/tuntap/src/tap/tap.cc
new file mode 100644
index 00000000..149f1e71
--- /dev/null
+++ b/tap-mac/tuntap/src/tap/tap.cc
@@ -0,0 +1,452 @@
+/*
+ * ethertap device for macosx.
+ *
+ * tap_interface class definition
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tap.h"
+
+extern "C" {
+
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#include <sys/sockio.h>
+#include <sys/random.h>
+#include <sys/kern_event.h>
+
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/dlil.h>
+#include <net/ethernet.h>
+
+}
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+// These declarations are missing in the Kernel.framework headers, put present in userspace :-/
+#pragma pack(4)
+struct ifmediareq {
+ char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ int ifm_current; /* current media options */
+ int ifm_mask; /* don't care mask */
+ int ifm_status; /* media status */
+ int ifm_active; /* active options */
+ int ifm_count; /* # entries in ifm_ulist array */
+ int *ifm_ulist; /* media words */
+};
+
+struct ifmediareq64 {
+ char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ int ifm_current; /* current media options */
+ int ifm_mask; /* don't care mask */
+ int ifm_status; /* media status */
+ int ifm_active; /* active options */
+ int ifm_count; /* # entries in ifm_ulist array */
+ user64_addr_t ifmu_ulist __attribute__((aligned(8)));
+};
+
+struct ifmediareq32 {
+ char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ int ifm_current; /* current media options */
+ int ifm_mask; /* don't care mask */
+ int ifm_status; /* media status */
+ int ifm_active; /* active options */
+ int ifm_count; /* # entries in ifm_ulist array */
+ user32_addr_t ifmu_ulist; /* 32-bit pointer */
+};
+#pragma pack()
+
+#define SIOCGIFMEDIA32 _IOWR('i', 56, struct ifmediareq32) /* get net media */
+#define SIOCGIFMEDIA64 _IOWR('i', 56, struct ifmediareq64) /* get net media (64-bit) */
+
+
+static unsigned char ETHER_BROADCAST_ADDR[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/* members */
+bool
+tap_interface::initialize(unsigned short major, unsigned short unit)
+{
+ this->unit = unit;
+ this->family_name = TAP_FAMILY_NAME;
+ this->family = IFNET_FAMILY_ETHERNET;
+ this->type = IFT_ETHER;
+ bzero(unique_id, UIDLEN);
+ snprintf(unique_id, UIDLEN, "%s%d", family_name, unit);
+
+ dprintf("tap: starting interface %s%d\n", TAP_FAMILY_NAME, unit);
+
+ /* register character device */
+ if (!tuntap_interface::register_chardev(major))
+ return false;
+
+ return true;
+}
+
+void
+tap_interface::shutdown()
+{
+ dprintf("tap: shutting down tap interface %s%d\n", TAP_FAMILY_NAME, unit);
+
+ unregister_chardev();
+}
+
+int
+tap_interface::initialize_interface()
+{
+ struct sockaddr_dl lladdr;
+ lladdr.sdl_len = sizeof(lladdr);
+ lladdr.sdl_family = AF_LINK;
+ lladdr.sdl_alen = ETHER_ADDR_LEN;
+ lladdr.sdl_nlen = lladdr.sdl_slen = 0;
+
+ /* generate a random MAC address */
+ read_random(LLADDR(&lladdr), ETHER_ADDR_LEN);
+
+ /* clear multicast bit and set local assignment bit (see IEEE 802) */
+ (LLADDR(&lladdr))[0] &= 0xfe;
+ (LLADDR(&lladdr))[0] |= 0x02;
+
+ dprintf("tap: random tap address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (LLADDR(&lladdr))[0] & 0xff,
+ (LLADDR(&lladdr))[1] & 0xff,
+ (LLADDR(&lladdr))[2] & 0xff,
+ (LLADDR(&lladdr))[3] & 0xff,
+ (LLADDR(&lladdr))[4] & 0xff,
+ (LLADDR(&lladdr))[5] & 0xff);
+
+ /* register interface */
+ if (!tuntap_interface::register_interface(&lladdr, ETHER_BROADCAST_ADDR, ETHER_ADDR_LEN))
+ return EIO;
+
+ /* Set link level address. Yes, we need to do that again. Darwin sucks. */
+ errno_t err = ifnet_set_lladdr(ifp, LLADDR(&lladdr), ETHER_ADDR_LEN);
+ if (err)
+ dprintf("tap: failed to set lladdr on %s%d: %d\n", family_name, unit, err);
+
+ /* set mtu */
+ ifnet_set_mtu(ifp, TAP_MTU);
+ /* set header length */
+ ifnet_set_hdrlen(ifp, sizeof(struct ether_header));
+ /* add the broadcast flag */
+ ifnet_set_flags(ifp, IFF_BROADCAST, IFF_BROADCAST);
+
+ /* we must call bpfattach(). Otherwise we deadlock BPF while unloading. Seems to be a bug in
+ * the kernel, see bpfdetach() in net/bpf.c, it will return without releasing the lock if
+ * the interface wasn't attached. I wonder what they were smoking while writing it ;-)
+ */
+ bpfattach(ifp, DLT_EN10MB, ifnet_hdrlen(ifp));
+
+ return 0;
+}
+
+void
+tap_interface::shutdown_interface()
+{
+ dprintf("tap: shutting down network interface of device %s%d\n", TAP_FAMILY_NAME, unit);
+
+ /* detach all protocols */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used) {
+ errno_t err = ifnet_detach_protocol(ifp, attached_protos[i].proto);
+ if (err)
+ log(LOG_WARNING, "tap: could not detach protocol %d from %s%d\n",
+ attached_protos[i].proto, TAP_FAMILY_NAME, unit);
+ }
+ }
+
+ cleanup_interface();
+ unregister_interface();
+}
+
+errno_t
+tap_interface::if_ioctl(u_int32_t cmd, void *arg)
+{
+ dprintf("tap: if_ioctl cmd: %d (%x)\n", cmd & 0xff, cmd);
+
+ switch (cmd) {
+ case SIOCSIFLLADDR:
+ {
+ /* set ethernet address */
+ struct sockaddr *ea = &(((struct ifreq *) arg)->ifr_addr);
+
+ dprintf("tap: SIOCSIFLLADDR family %d len %d\n",
+ ea->sa_family, ea->sa_len);
+
+ /* check if it is really an ethernet address */
+ if (ea->sa_family != AF_LINK || ea->sa_len != ETHER_ADDR_LEN)
+ return EINVAL;
+
+ /* ok, copy */
+ errno_t err = ifnet_set_lladdr(ifp, ea->sa_data, ETHER_ADDR_LEN);
+ if (err) {
+ dprintf("tap: failed to set lladdr on %s%d: %d\n",
+ family_name, unit, err);
+ return err;
+ }
+
+ /* Generate a LINK_ON event. This necessary for configd to re-read
+ * the interface data and refresh the MAC address. Not doing so
+ * would result in the DHCP client using a stale MAC address...
+ */
+ generate_link_event(KEV_DL_LINK_ON);
+
+ return 0;
+ }
+
+ case SIOCGIFMEDIA32:
+ case SIOCGIFMEDIA64:
+ {
+ struct ifmediareq *ifmr = (struct ifmediareq*) arg;
+ user_addr_t list = USER_ADDR_NULL;
+
+ ifmr->ifm_current = IFM_ETHER;
+ ifmr->ifm_mask = 0;
+ ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+ ifmr->ifm_active = IFM_ETHER;
+ ifmr->ifm_count = 1;
+
+ if (cmd == SIOCGIFMEDIA64)
+ list = ((struct ifmediareq64*) ifmr)->ifmu_ulist;
+ else
+ list = CAST_USER_ADDR_T(
+ ((struct ifmediareq32*) ifmr)->ifmu_ulist);
+
+ if (list != USER_ADDR_NULL)
+ return copyout(&ifmr->ifm_current, list, sizeof(int));
+
+ return 0;
+ }
+
+ default:
+ /* let our superclass handle it */
+ return tuntap_interface::if_ioctl(cmd, arg);
+ }
+
+ return EOPNOTSUPP;
+}
+
+errno_t
+tap_interface::if_demux(mbuf_t m, char *header, protocol_family_t *proto)
+{
+ struct ether_header *eh = (struct ether_header *) header;
+ unsigned char lladdr[ETHER_ADDR_LEN];
+
+ dprintf("tap: if_demux\n");
+
+ /* size check */
+ if (mbuf_len(m) < sizeof(struct ether_header))
+ return ENOENT;
+
+ /* catch broadcast and multicast (stolen from bsd/net/ether_if_module.c) */
+ if (eh->ether_dhost[0] & 1) {
+ if (memcmp(ETHER_BROADCAST_ADDR, eh->ether_dhost, ETHER_ADDR_LEN) == 0) {
+ /* broadcast */
+ dprintf("tap: broadcast packet.\n");
+ mbuf_setflags_mask(m, MBUF_BCAST, MBUF_BCAST);
+ } else {
+ /* multicast */
+ dprintf("tap: multicast packet.\n");
+ mbuf_setflags_mask(m, MBUF_MCAST, MBUF_MCAST);
+ }
+ } else {
+ /* check wether the packet has our address */
+ ifnet_lladdr_copy_bytes(ifp, lladdr, ETHER_ADDR_LEN);
+ if (memcmp(lladdr, eh->ether_dhost, ETHER_ADDR_LEN) != 0)
+ mbuf_setflags_mask(m, MBUF_PROMISC, MBUF_PROMISC);
+ }
+
+ /* find the protocol */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used && attached_protos[i].type == eh->ether_type) {
+ *proto = attached_protos[i].proto;
+ return 0;
+ }
+ }
+
+ dprintf("tap: if_demux() failed to find proto.\n");
+
+ /* no matching proto found */
+ return ENOENT;
+}
+
+errno_t
+tap_interface::if_framer(mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr,
+ const char *frame_type)
+{
+ struct ether_header *eh;
+ mbuf_t nm = *m;
+ errno_t err;
+
+ dprintf("tap: if_framer\n");
+
+ /* prepend the ethernet header */
+ err = mbuf_prepend(&nm, sizeof (struct ether_header), MBUF_WAITOK);
+ if (err) {
+ dprintf("tap: could not prepend data to mbuf: %d\n", err);
+ return err;
+ }
+ *m = nm;
+
+ /* fill the header */
+ eh = (struct ether_header *) mbuf_data(*m);
+ memcpy(eh->ether_dhost, dest_linkaddr, ETHER_ADDR_LEN);
+ ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, ETHER_ADDR_LEN);
+ eh->ether_type = *((u_int16_t *) frame_type);
+
+ return 0;
+}
+
+errno_t
+tap_interface::if_add_proto(protocol_family_t proto, const struct ifnet_demux_desc *desc,
+ u_int32_t ndesc)
+{
+ errno_t err;
+
+ dprintf("tap: if_add_proto proto %d\n", proto);
+
+ for (unsigned int i = 0; i < ndesc; i++) {
+ /* try to add the protocol */
+ err = add_one_proto(proto, desc[i]);
+ if (err != 0) {
+ /* if that fails, remove everything stored so far */
+ if_del_proto(proto);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+errno_t
+tap_interface::if_del_proto(protocol_family_t proto)
+{
+ dprintf("tap: if_del_proto proto %d\n", proto);
+
+ /* delete all matching entries in attached_protos */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].proto == proto)
+ attached_protos[i].used = false;
+ }
+
+ return 0;
+}
+
+errno_t
+tap_interface::if_check_multi(const struct sockaddr *maddr)
+{
+ dprintf("tap: if_check_multi family %d\n", maddr->sa_family);
+
+ /* see whether it is a ethernet address with the multicast bit set */
+ if (maddr->sa_family == AF_LINK) {
+ struct sockaddr_dl *dlmaddr = (struct sockaddr_dl *) maddr;
+ if (LLADDR(dlmaddr)[0] & 0x01)
+ return 0;
+ else
+ return EADDRNOTAVAIL;
+ }
+
+ return EOPNOTSUPP;
+}
+
+errno_t
+tap_interface::add_one_proto(protocol_family_t proto, const struct ifnet_demux_desc &dd)
+{
+ int free = -1;
+ u_int16_t dt;
+
+ /* we only support DLIL_DESC_ETYPE2 */
+ if (dd.type != DLIL_DESC_ETYPE2 || dd.datalen != 2) {
+ log(LOG_WARNING, "tap: tap only supports DLIL_DESC_ETYPE2 protocols.\n");
+ return EINVAL;
+ }
+
+ dt = *((u_int16_t *) (dd.data));
+
+ /* see if the protocol is already registered */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used) {
+ if (dt == attached_protos[i].type) {
+ /* already registered */
+ if (attached_protos[i].proto == proto) {
+ /* matches the old entry */
+ return 0;
+ } else
+ return EEXIST;
+ }
+ } else if (free == -1)
+ free = i;
+ }
+
+ /* did we find a free entry? */
+ if (free == -1)
+ /* is ENOBUFS correct? */
+ return ENOBUFS;
+
+ /* ok, save information */
+ attached_protos[free].used = true;
+ attached_protos[free].type = dt;
+ attached_protos[free].proto = proto;
+
+ return 0;
+}
+
+/* This code is shamelessly stolen from if_bond.c */
+void
+tap_interface::generate_link_event(u_int32_t code)
+{
+ struct {
+ struct kern_event_msg header;
+ u_int32_t unit;
+ char if_name[IFNAMSIZ];
+ } event;
+
+ bzero(&event, sizeof(event));
+ event.header.total_size = sizeof(event);
+ event.header.vendor_code = KEV_VENDOR_APPLE;
+ event.header.kev_class = KEV_NETWORK_CLASS;
+ event.header.kev_subclass = KEV_DL_SUBCLASS;
+ event.header.event_code = code;
+ event.header.event_data[0] = family;
+ event.unit = (u_int32_t) unit;
+ strncpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
+
+ ifnet_event(ifp, &event.header);
+}
+
+/* tap_manager members */
+tuntap_interface *
+tap_manager::create_interface()
+{
+ return new tap_interface();
+}
+
diff --git a/tap-mac/tuntap/src/tap/tap.h b/tap-mac/tuntap/src/tap/tap.h
new file mode 100644
index 00000000..b3070676
--- /dev/null
+++ b/tap-mac/tuntap/src/tap/tap.h
@@ -0,0 +1,103 @@
+/*
+ * ethertap device for MacOSX.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __TAP_H__
+#define __TAP_H__
+
+#include "tuntap.h"
+
+#define TAP_FAMILY_NAME ((char *) "zt")
+
+#define TAP_IF_COUNT 16 /* max number of tap interfaces */
+
+#define TAP_MTU 4000
+
+#define TAP_LLADDR tap_lladdr
+
+/* the mac address of our interfaces. note that the last byte will be replaced by the unit number */
+extern u_char tap_lladdr[];
+
+/* tap manager */
+class tap_manager : public tuntap_manager {
+
+ protected:
+ /* just define the interface creation method */
+ virtual tuntap_interface *create_interface();
+
+};
+
+/* the tap network interface */
+class tap_interface : public tuntap_interface {
+
+ protected:
+ /* maximum number of protocols that can be attached */
+ static const unsigned int MAX_ATTACHED_PROTOS = 8;
+
+ /* information about attached protocols for demuxing is stored here */
+ struct {
+ /* whether this entry is used */
+ bool used;
+ /* type in the ethernet header */
+ u_int16_t type;
+ /* protocol passed to add_proto */
+ protocol_family_t proto;
+ } attached_protos[MAX_ATTACHED_PROTOS];
+
+ /* initializes the interface */
+ virtual bool initialize(unsigned short major, unsigned short unit);
+
+ /* shuts the interface down */
+ virtual void shutdown();
+
+ /* called when the character device is opened in order to intialize the network
+ * interface.
+ */
+ virtual int initialize_interface();
+ /* called when the character device is closed to shutdown the network interface */
+ virtual void shutdown_interface();
+
+ /* override interface routines */
+ virtual errno_t if_ioctl(u_int32_t cmd, void *arg);
+ virtual errno_t if_demux(mbuf_t m, char *header, protocol_family_t *proto);
+ virtual errno_t if_framer(mbuf_t *m, const struct sockaddr *dest,
+ const char *dest_linkaddr, const char *frame_type);
+ virtual errno_t if_add_proto(protocol_family_t proto,
+ const struct ifnet_demux_desc *ddesc, u_int32_t ndesc);
+ virtual errno_t if_del_proto(protocol_family_t proto);
+ virtual errno_t if_check_multi(const struct sockaddr *maddr);
+
+ /* if_add_proto helper */
+ errno_t add_one_proto(protocol_family_t proto, const struct ifnet_demux_desc &dd);
+
+ /* generates a kernel event */
+ void generate_link_event(u_int32_t code);
+
+ friend class tap_manager;
+};
+
+#endif /* __TAP_H__ */
+
diff --git a/tap-mac/tuntap/src/tun/Info.plist b/tap-mac/tuntap/src/tun/Info.plist
new file mode 100644
index 00000000..bb9b03fd
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>@@CFBUNDLEDEVELOPMENTREGION@@</string>
+ <key>CFBundleExecutable</key>
+ <string>@@CFBUNDLEEXECUTABLE@@</string>
+ <key>CFBundleIdentifier</key>
+ <string>@@CFBUNDLEIDENTIFIER@@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@@CFBUNDLEEXECUTABLE@@</string>
+ <key>CFBundlePackageType</key>
+ <string>@@CFBUNDLEPACKAGETYPE@@</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@@CFBUNDLEVERSION@@</string>
+ <key>CFBundleSignature</key>
+ <string>@@CFBUNDLESIGNATURE@@</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.mach</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.bsd</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.libkern</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.unsupported</key>
+ <string>8.0</string>
+ </dict>
+</dict>
+</plist>
+
diff --git a/tap-mac/tuntap/src/tun/Makefile b/tap-mac/tuntap/src/tun/Makefile
new file mode 100644
index 00000000..9ca6794d
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/Makefile
@@ -0,0 +1,59 @@
+#
+# ip tunnel/ethertap driver for MacOSX
+#
+# Makefile
+#
+# (c) 2004, 2005, 2006, 2007, 2008 Mattias Nissler
+#
+
+OBJS = ../tuntap.o ../tuntap_mgr.o ../lock.o ../mem.o \
+ kmod.o tun_inet_proto.o tun_inet6_proto.o tun.o
+KMOD_BIN = tun
+BUNDLE_DIR = ../..
+BUNDLE_NAME = tun.kext
+
+TUN_KEXT_VERSION = $(TUNTAP_VERSION)
+
+BUNDLE_REGION = English
+BUNDLE_IDENTIFIER = foo.tun
+BUNDLE_SIGNATURE = ????
+BUNDLE_PACKAGETYPE = KEXT
+BUNDLE_VERSION = $(TUN_KEXT_VERSION)
+
+INCLUDE = -I.. -I/System/Library/Frameworks/Kernel.framework/Headers
+CFLAGS = -Wall -mkernel -force_cpusubtype_ALL \
+ -fno-builtin -fno-stack-protector -arch i386 -arch x86_64 \
+ -DKERNEL -D__APPLE__ -DKERNEL_PRIVATE -DTUNTAP_VERSION=\"$(TUNTAP_VERSION)\" \
+ -DTUN_KEXT_VERSION=\"$(TUN_KEXT_VERSION)\"
+CCFLAGS = $(CFLAGS)
+LDFLAGS = -Wall -mkernel -nostdlib -r -lcc_kext -arch i386 -arch x86_64 -Xlinker -kext
+
+CCP = g++
+CC = gcc
+
+all: $(KMOD_BIN) bundle
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+.cc.o:
+ $(CCP) $(CCFLAGS) $(INCLUDE) -c $< -o $@
+
+$(KMOD_BIN): $(OBJS)
+ $(CCP) $(LDFLAGS) -o $(KMOD_BIN) $(OBJS)
+
+bundle: $(KMOD_BIN)
+ rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME)
+ mkdir -p $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS
+ cp $(KMOD_BIN) $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/MacOS
+ sed -e "s/@@CFBUNDLEEXECUTABLE@@/$(KMOD_BIN)/" \
+ -e "s/@@CFBUNDLEDEVELOPMENTREGION@@/$(BUNDLE_REGION)/" \
+ -e "s/@@CFBUNDLEIDENTIFIER@@/$(BUNDLE_IDENTIFIER)/" \
+ -e "s/@@CFBUNDLESIGNATURE@@/$(BUNDLE_SIGNATURE)/" \
+ -e "s/@@CFBUNDLEPACKAGETYPE@@/$(BUNDLE_PACKAGETYPE)/" \
+ -e "s/@@CFBUNDLEVERSION@@/$(BUNDLE_VERSION)/" \
+ Info.plist > $(BUNDLE_DIR)/$(BUNDLE_NAME)/Contents/Info.plist
+
+clean:
+ -rm -f $(OBJS) $(KMOD_BIN)
+ -rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME)
+
diff --git a/tap-mac/tuntap/src/tun/kmod.cc b/tap-mac/tuntap/src/tun/kmod.cc
new file mode 100644
index 00000000..1c085506
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/kmod.cc
@@ -0,0 +1,93 @@
+/*
+ * ip tunnel device for MacOSX.
+ *
+ * Kext definition (it is a mach kmod really...)
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tun.h"
+#include "mem.h"
+
+extern "C" {
+
+#include <sys/param.h>
+
+#include <mach/kmod.h>
+
+static tun_manager *mgr;
+
+/*
+ * start function. called when the kext gets loaded.
+ */
+static kern_return_t tun_module_start(struct kmod_info *ki, void *data)
+{
+ mem_initialize(TUN_FAMILY_NAME);
+
+ /* initialize locking */
+ if (!tt_lock::initialize())
+ return KMOD_RETURN_FAILURE;
+
+ /* create a tun manager that will handle the rest */
+ mgr = new tun_manager();
+
+ if (mgr != NULL) {
+ if (mgr->initialize(TUN_IF_COUNT, TUN_FAMILY_NAME))
+ return KMOD_RETURN_SUCCESS;
+
+ delete mgr;
+ mgr = NULL;
+ /* clean up locking */
+ tt_lock::shutdown();
+ }
+
+ return KMOD_RETURN_FAILURE;
+}
+
+/*
+ * stop function. called when the kext should be unloaded. unloading can be prevented by
+ * returning failure
+ */
+static kern_return_t tun_module_stop(struct kmod_info *ki, void *data)
+{
+ if (mgr != NULL) {
+ if (!mgr->shutdown())
+ return KMOD_RETURN_FAILURE;
+
+ delete mgr;
+ mgr = NULL;
+ }
+
+ /* clean up locking */
+ tt_lock::shutdown();
+
+ mem_shutdown();
+
+ return KMOD_RETURN_SUCCESS;
+}
+
+KMOD_DECL(tun, TUN_KEXT_VERSION)
+
+}
+
diff --git a/tap-mac/tuntap/src/tun/tun.cc b/tap-mac/tuntap/src/tun/tun.cc
new file mode 100644
index 00000000..91694388
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/tun.cc
@@ -0,0 +1,424 @@
+/*
+ * ip tunnel device for MacOSX.
+ *
+ * tun_interface class definition
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tun.h"
+
+extern "C" {
+
+#include <sys/syslog.h>
+#include <sys/param.h>
+
+#include <net/if_types.h>
+#include <net/kpi_protocol.h>
+
+#include <netinet/ip.h>
+
+}
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+/* members */
+bool
+tun_interface::initialize(unsigned short major, unsigned short unit)
+{
+ this->unit = unit;
+ this->family_name = TUN_FAMILY_NAME;
+ this->family = IFNET_FAMILY_TUN;
+ this->type = IFT_OTHER;
+ bzero(unique_id, UIDLEN);
+ snprintf(unique_id, UIDLEN, "%s%d", family_name, unit);
+
+ dprintf("tun: starting interface %s%d\n", family_name, unit);
+
+ /* register character device */
+ if (!tuntap_interface::register_chardev(major))
+ return false;
+
+ return true;
+}
+
+void
+tun_interface::shutdown()
+{
+ dprintf("tun: shutting down interface %s%d\n", family_name, unit);
+
+ unregister_chardev();
+}
+
+int
+tun_interface::initialize_interface()
+{
+ prepend_af = false;
+
+ /* register interface */
+ if (!tuntap_interface::register_interface(NULL, NULL, 0))
+ return EIO;
+
+ /* set mtu */
+ ifnet_set_mtu(ifp, TUN_MTU);
+ /* set header length */
+ ifnet_set_hdrlen(ifp, 0);
+ /* add the pointopoint flag */
+ ifnet_set_flags(ifp, IFF_POINTOPOINT, IFF_POINTOPOINT);
+
+ /* we must call bpfattach(). Otherwise we deadlock BPF while unloading. Seems to be a bug in
+ * the kernel, see bpfdetach() in net/bpf.c, it will return without releasing the lock if
+ * the interface wasn't attached. I wonder what they were smoking while writing it ;-)
+ */
+ bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
+
+ return 0;
+}
+
+void
+tun_interface::shutdown_interface()
+{
+ dprintf("tun: shutting down network interface of %s%d\n", family_name, unit);
+
+ /* detach all protocols */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used) {
+ errno_t err = ifnet_detach_protocol(ifp, attached_protos[i].proto);
+ if (err)
+ log(LOG_WARNING, "tun: could not detach protocol %d from %s%d\n",
+ attached_protos[i].proto, family_name, unit);
+ }
+ }
+
+ cleanup_interface();
+ unregister_interface();
+}
+
+void
+tun_interface::notify_bpf(mbuf_t mb, bool out)
+{
+ auto_lock l(&bpf_lock);
+
+ if ((out && bpf_mode == BPF_MODE_OUTPUT)
+ || (!out && bpf_mode == BPF_MODE_INPUT)
+ || (bpf_mode == BPF_MODE_INPUT_OUTPUT)) {
+ /* see wether AF is prepended */
+ if (!prepend_af) {
+ mbuf_t dummy_mb;
+ struct ip *iphdr;
+ u_int32_t af;
+ u_int8_t ipv;
+ errno_t err;
+
+ /* see what we have: IPv4 or IPv6 */
+ iphdr = (struct ip*) mbuf_data(mb);
+#ifdef _IP_VHL
+ ipv = IP_VHL_V(iphdr->ip_vhl);
+#else
+ ipv = iphdr->ip_v;
+#endif
+ if (ipv == 4)
+ af = AF_INET;
+ else if (ipv == 6)
+ af = AF_INET6;
+ else {
+ /* what to do? */
+ log(LOG_WARNING, "tun: unsupported IP version %d.\n", ipv);
+ return;
+ }
+
+ /* prepend a dummy header */
+ err = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &dummy_mb);
+ if (err) {
+ log(LOG_WARNING, "tun: could not allocate temporary mbuf: %d\n",
+ err);
+ return;
+ }
+
+ mbuf_setnext(dummy_mb, mb);
+ mbuf_setlen(dummy_mb, sizeof(u_int32_t));
+ *((u_int32_t *) mbuf_data(dummy_mb)) = htonl(af);
+
+ /* call bpf */
+ (*bpf_callback)(ifp, dummy_mb);
+
+ /* free the dummy mbuf */
+ mbuf_free(dummy_mb);
+ } else {
+ /* just pass it through */
+ (*bpf_callback)(ifp, mb);
+ }
+ }
+}
+
+int
+tun_interface::cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p)
+{
+ int error;
+
+ /* if the superclass handles it, we're done */
+ error = tuntap_interface::cdev_ioctl(cmd, data, fflag, p);
+ if (!error)
+ return 0;
+
+ switch (cmd) {
+ case TUNSIFHEAD:
+ prepend_af = *((int *) data) ? true : false;
+ /* adjust header length. see tuntap_interface::cdev_write */
+ ifnet_set_hdrlen(ifp, prepend_af ? sizeof(u_int32_t) : 0);
+ return 0;
+ case TUNGIFHEAD:
+ *((int *) data) = prepend_af;
+ return 0;
+ }
+
+ return ENOTTY;
+}
+
+errno_t
+tun_interface::if_demux(mbuf_t m, char *header, protocol_family_t *proto)
+{
+ u_int32_t family;
+
+ dprintf("tun: demux\n");
+
+ /* size check */
+ if (mbuf_len(m) < sizeof(u_int32_t))
+ return ENOENT;
+
+ /* if we are prepending AF for output, we expect to also have it at the beginning of
+ * incoming packets */
+ if (!prepend_af) {
+ struct ip *iphdr = (struct ip*) mbuf_data(m);
+ u_int8_t ipv;
+
+ dprintf("tun_demux: m: %p data: %p\n", m, mbuf_data(m));
+
+#ifdef _IPVHL
+ ipv = IP_VHL_V(iphdr->ip_vhl);
+#else
+ ipv = iphdr->ip_v;
+#endif
+
+ if (ipv == 4)
+ family = AF_INET;
+ else if (ipv == 6)
+ family = AF_INET6;
+ else {
+ /* what to do? */
+ log(LOG_WARNING, "tun: unsupported IP version %d\n", ipv);
+ return ENOENT;
+ }
+ } else {
+ family = ntohl(*((u_int32_t *) header));
+ }
+
+ /* find the protocol entry */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used && attached_protos[i].family == family) {
+ *proto = attached_protos[i].proto;
+ return 0;
+ }
+ }
+
+ log(LOG_WARNING, "tun: no protocol found for family %d\n", family);
+
+ return ENOENT;
+}
+
+errno_t
+tun_interface::if_framer(mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr,
+ const char *frame_type)
+{
+ dprintf("tun: framer\n");
+
+ /* check whether to prepend family field */
+ if (prepend_af) {
+ errno_t err;
+ mbuf_t nm = *m;
+
+ /* get space */
+ err = mbuf_prepend(&nm, sizeof(u_int32_t), MBUF_WAITOK);
+ if (err) {
+ dprintf("tun: could not prepend data to mbuf: %d\n", err);
+ return err;
+ }
+ *m = nm;
+
+ *((u_int32_t *) mbuf_data(*m)) = htonl(dest->sa_family);
+ }
+
+ return 0;
+}
+
+errno_t
+tun_interface::if_add_proto(protocol_family_t proto, const struct ifnet_demux_desc *desc,
+ u_int32_t ndesc)
+{
+ errno_t err;
+
+ dprintf("tun: if_add_proto proto %d\n", proto);
+
+ for (unsigned int i = 0; i < ndesc; i++) {
+ /* try to add the protocol */
+ err = add_one_proto(proto, desc[i]);
+ if (err != 0) {
+ /* if that fails, remove everything stored so far */
+ if_del_proto(proto);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+errno_t
+tun_interface::if_del_proto(protocol_family_t proto)
+{
+ dprintf("tun: if_del_proto proto %d\n", proto);
+
+ /* delete all matching entries in attached_protos */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].proto == proto)
+ attached_protos[i].used = false;
+ }
+
+ return 0;
+}
+
+errno_t
+tun_interface::if_check_multi(const struct sockaddr *maddr)
+{
+ dprintf("tun: check_multi family %d\n", maddr->sa_family);
+
+ /* see whether it is an IPv4 multicast address */
+ if (maddr->sa_family == AF_INET) {
+ struct sockaddr_in *imaddr = (struct sockaddr_in *) maddr;
+
+ if (IN_MULTICAST(ntohl(imaddr->sin_addr.s_addr)))
+ return 0;
+ else
+ return EADDRNOTAVAIL;
+ } else if (maddr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *imaddr = (struct sockaddr_in6 *) maddr;
+
+ if (IN6_IS_ADDR_MULTICAST(&imaddr->sin6_addr))
+ return 0;
+ else
+ return EADDRNOTAVAIL;
+ }
+
+ return EOPNOTSUPP;
+}
+
+errno_t
+tun_interface::add_one_proto(protocol_family_t proto, const struct ifnet_demux_desc &dd)
+{
+ int free = -1;
+
+ /* see if the protocol is already registered */
+ for (unsigned int i = 0; i < MAX_ATTACHED_PROTOS; i++) {
+ if (attached_protos[i].used) {
+ if (dd.type == attached_protos[i].family) {
+ /* already registered */
+ if (attached_protos[i].proto == proto) {
+ /* matches the old entry */
+ return 0;
+ } else
+ return EEXIST;
+ }
+ } else if (free == -1)
+ free = i;
+ }
+
+ /* did we find a free entry? */
+ if (free == -1)
+ /* is ENOBUFS correct? */
+ return ENOBUFS;
+
+ dprintf("tun: adding proto family %d proto %d\n", dd.type, proto);
+
+ /* ok, save information */
+ attached_protos[free].used = true;
+ attached_protos[free].family = dd.type;
+ attached_protos[free].proto = proto;
+
+ return 0;
+}
+
+/* tun_manager members */
+tuntap_interface *
+tun_manager::create_interface()
+{
+ return new tun_interface();
+}
+
+bool
+tun_manager::shutdown()
+{
+ if (tuntap_inited) {
+ if (tuntap_manager::shutdown())
+ tuntap_inited = false;
+ else
+ return false;
+ }
+
+ /* unregister INET and INET6 protocol families */
+ proto_unregister_plumber(PF_INET, IFNET_FAMILY_TUN);
+ proto_unregister_plumber(PF_INET6, IFNET_FAMILY_TUN);
+
+ return true;
+}
+
+bool
+tun_manager::initialize(unsigned int count, char *family)
+{
+ errno_t err;
+
+ tuntap_inited = false;
+
+ /* register INET and INET6 protocol families */
+ err = proto_register_plumber(PF_INET, IFNET_FAMILY_TUN, tun_inet_attach, tun_inet_detach);
+ if (err) {
+ log(LOG_ERR, "tun: could not register PF_INET protocol family: %d\n", err);
+ return false;
+ }
+
+ err = proto_register_plumber(PF_INET6, IFNET_FAMILY_TUN, tun_inet6_attach,
+ tun_inet6_detach);
+ if (err) {
+ log(LOG_ERR, "tun: could not register PF_INET6 protocol family: %d\n", err);
+ return false;
+ }
+
+ tuntap_inited = true;
+
+ /* have the superclass handle the rest */
+ return tuntap_manager::initialize(count, family);
+}
+
diff --git a/tap-mac/tuntap/src/tun/tun.h b/tap-mac/tuntap/src/tun/tun.h
new file mode 100644
index 00000000..8546dc8f
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/tun.h
@@ -0,0 +1,123 @@
+/*
+ * ip tunnel device for MacOSX.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __TUN_H__
+#define __TUN_H__
+
+#include "tuntap.h"
+
+#define TUN_FAMILY_NAME ((char *) "tun")
+#define TUN_IF_COUNT 16 /* max number of tun interfaces */
+#define TUN_MTU 1500
+
+#include "tun_ioctls.h"
+
+extern "C" {
+
+errno_t tun_inet_attach(ifnet_t ifp, protocol_family_t proto);
+void tun_inet_detach(ifnet_t ifp, protocol_family_t proto);
+errno_t tun_inet6_attach(ifnet_t ifp, protocol_family_t proto);
+void tun_inet6_detach(ifnet_t ifp, protocol_family_t proto);
+
+}
+
+/* tun_manager */
+class tun_manager : public tuntap_manager {
+
+ protected:
+ /* create an interface */
+ virtual tuntap_interface *create_interface();
+
+ /* whether we need to call tuntap_manager::shutdown() */
+ bool tuntap_inited;
+
+ public:
+ /* special initalize */
+ virtual bool initialize(unsigned int count, char *family);
+
+ /* special shutdown */
+ virtual bool shutdown();
+
+};
+
+/* the tun network interface */
+class tun_interface : public tuntap_interface {
+
+ protected:
+ /* maximum number of protocols that can be attached */
+ static const unsigned int MAX_ATTACHED_PROTOS = 8;
+
+ /* information about attached protocols for demuxing is stored here */
+ struct {
+ /* whether this entry is used */
+ bool used;
+ /* protocol family (this is equal to proto, but keep it seperated from
+ * Apple's KPI stuff...) */
+ u_int32_t family;
+ /* protocol passed to add_proto */
+ protocol_family_t proto;
+ } attached_protos[MAX_ATTACHED_PROTOS];
+
+ /* whether the address family field is prepended to each packet */
+ bool prepend_af;
+
+ /* intializes the interface */
+ virtual bool initialize(unsigned short major, unsigned short int unit);
+
+ /* shutdown the interface */
+ virtual void shutdown();
+
+ /* called when the character device is opened in order to intialize the network
+ * interface.
+ */
+ virtual int initialize_interface();
+ /* called when the character device is closed to shutdown the network interface */
+ virtual void shutdown_interface();
+
+ /* override interface routines */
+ virtual errno_t if_demux(mbuf_t m, char *header, protocol_family_t *proto);
+ virtual errno_t if_framer(mbuf_t *m, const struct sockaddr *dest,
+ const char *dest_linkaddr, const char *frame_type);
+ virtual errno_t if_add_proto(protocol_family_t proto,
+ const struct ifnet_demux_desc *desc, u_int32_t ndesc);
+ virtual errno_t if_del_proto(protocol_family_t proto);
+ virtual errno_t if_check_multi(const struct sockaddr *maddr);
+
+ /* helper to if_add_proto */
+ virtual errno_t add_one_proto(protocol_family_t proto,
+ const struct ifnet_demux_desc &dd);
+
+ /* override notify_bpf because we might need to prepend an address header */
+ virtual void notify_bpf(mbuf_t mb, bool out);
+
+ /* need to override cdev_ioctl to get our special ioctls */
+ virtual int cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p);
+
+};
+
+#endif /* __TUN_H__ */
+
diff --git a/tap-mac/tuntap/src/tun/tun_inet6_proto.c b/tap-mac/tuntap/src/tun/tun_inet6_proto.c
new file mode 100644
index 00000000..4461d4d9
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/tun_inet6_proto.c
@@ -0,0 +1,87 @@
+/*
+ * ip tunnel device for MacOSX. This is the protocol module for PF_INET.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/kpi_mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+
+#include <net/kpi_protocol.h>
+#include <net/kpi_interface.h>
+
+static errno_t
+tun_inet6_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t m, char *header)
+{
+ /* input the packet */
+ return proto_input(PF_INET6, m);
+}
+
+static errno_t
+tun_inet6_pre_output(ifnet_t ifp, protocol_family_t proto, mbuf_t *packet,
+ const struct sockaddr *dest, void *route, char *frame_type, char *dst_addr)
+{
+
+ /* check wether the destination address is an inet address */
+ if (dest->sa_family != AF_INET6)
+ return EAFNOSUPPORT;
+
+ /* place the address family as frame type */
+ *((uint32_t *) frame_type) = htonl(AF_INET6);
+
+ return 0;
+}
+
+errno_t
+tun_inet6_attach(ifnet_t ifp, protocol_family_t proto)
+{
+ struct ifnet_attach_proto_param pr;
+ struct ifnet_demux_desc ddesc[1];
+
+ /* fill out pr and attach the protocol */
+ ddesc[0].type = AF_INET6;
+ ddesc[0].data = NULL;
+ ddesc[0].datalen = 0;
+ pr.demux_array = ddesc;
+ pr.demux_count = 1;
+ pr.input = tun_inet6_input;
+ pr.pre_output = tun_inet6_pre_output;
+ pr.event = NULL;
+ pr.ioctl = NULL;
+ pr.detached = NULL;
+ pr.resolve = NULL;
+ pr.send_arp = NULL;
+
+ return ifnet_attach_protocol(ifp, proto, &pr);
+}
+
+void
+tun_inet6_detach(ifnet_t ifp, protocol_family_t proto)
+{
+ /* just detach the protocol */
+ ifnet_detach_protocol(ifp, proto);
+}
+
diff --git a/tap-mac/tuntap/src/tun/tun_inet_proto.c b/tap-mac/tuntap/src/tun/tun_inet_proto.c
new file mode 100644
index 00000000..38ecd26b
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/tun_inet_proto.c
@@ -0,0 +1,87 @@
+/*
+ * ip tunnel device for MacOSX. This is the protocol module for PF_INET.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/kpi_mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+
+#include <net/kpi_protocol.h>
+#include <net/kpi_interface.h>
+
+static errno_t
+tun_inet_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t m, char *header)
+{
+ /* input the packet */
+ return proto_input(PF_INET, m);
+}
+
+static errno_t
+tun_inet_pre_output(ifnet_t ifp, protocol_family_t proto, mbuf_t *packet,
+ const struct sockaddr *dest, void *route, char *frame_type, char *dst_addr)
+{
+
+ /* check wether the destination address is an inet address */
+ if (dest->sa_family != AF_INET)
+ return EAFNOSUPPORT;
+
+ /* place the address family as frame type */
+ *((uint32_t *) frame_type) = htonl(AF_INET);
+
+ return 0;
+}
+
+errno_t
+tun_inet_attach(ifnet_t ifp, protocol_family_t proto)
+{
+ struct ifnet_attach_proto_param pr;
+ struct ifnet_demux_desc ddesc[1];
+
+ /* fill out pr and attach the protocol */
+ ddesc[0].type = AF_INET;
+ ddesc[0].data = NULL;
+ ddesc[0].datalen = 0;
+ pr.demux_array = ddesc;
+ pr.demux_count = 1;
+ pr.input = tun_inet_input;
+ pr.pre_output = tun_inet_pre_output;
+ pr.event = NULL;
+ pr.ioctl = NULL;
+ pr.detached = NULL;
+ pr.resolve = NULL;
+ pr.send_arp = NULL;
+
+ return ifnet_attach_protocol(ifp, proto, &pr);
+}
+
+void
+tun_inet_detach(ifnet_t ifp, protocol_family_t proto)
+{
+ /* just detach the protocol */
+ ifnet_detach_protocol(ifp, proto);
+}
+
diff --git a/tap-mac/tuntap/src/tun/tun_ioctls.h b/tap-mac/tuntap/src/tun/tun_ioctls.h
new file mode 100644
index 00000000..13501e53
--- /dev/null
+++ b/tap-mac/tuntap/src/tun/tun_ioctls.h
@@ -0,0 +1,38 @@
+/*
+ * ip tunnel device for MacOSX.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __TUN_IOCTLS_H__
+#define __TUN_IOCTLS_H__
+
+/* Tun supports prepending a four byte address family field to each packet. These ioctls allow you
+ * to switch it on/off. Pass 1 as parameter to switch it on, pass 0 for off.
+ */
+#define TUNSIFHEAD _IOW('t', 96, int)
+#define TUNGIFHEAD _IOR('t', 97, int)
+
+#endif /* __TUN_IOCTLS_H__ */
+
diff --git a/tap-mac/tuntap/src/tuntap.cc b/tap-mac/tuntap/src/tuntap.cc
new file mode 100644
index 00000000..941de94c
--- /dev/null
+++ b/tap-mac/tuntap/src/tuntap.cc
@@ -0,0 +1,962 @@
+/*
+ * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface.
+ *
+ * tuntap_interface class definition
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tuntap.h"
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+extern "C" {
+
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#include <sys/fcntl.h>
+#include <sys/kpi_socket.h>
+
+#include <vm/vm_kern.h>
+
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_arp.h>
+
+#include <miscfs/devfs/devfs.h>
+
+}
+
+extern "C" {
+
+/* interface service functions that delegate to the appropriate tuntap_interface instance */
+errno_t
+tuntap_if_output(ifnet_t ifp, mbuf_t m)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_output(m);
+ }
+
+ if (m != NULL)
+ mbuf_freem_list(m);
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_ioctl(cmd, arg);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t))
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_set_bpf_tap(mode, cb);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_demux(m, header, proto);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr,
+ const char *frame_type)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_framer(m, dest, dest_linkaddr, frame_type);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, const struct ifnet_demux_desc *ddesc,
+ u_int32_t ndesc)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_add_proto(proto, ddesc, ndesc);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_del_proto(proto);
+ }
+
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr* maddr)
+{
+ if (ifp != NULL)
+ {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ return ttif->if_check_multi(maddr);
+ }
+
+ return ENODEV;
+}
+
+void
+tuntap_if_detached(ifnet_t ifp)
+{
+ if (ifp != NULL) {
+ tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
+ if (ttif != NULL)
+ ttif->if_detached();
+ }
+}
+
+errno_t
+tuntap_if_noop_output(ifnet_t, mbuf_t)
+{
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_noop_demux(ifnet_t, mbuf_t, char*, protocol_family_t*)
+{
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_noop_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc*, u_int32_t)
+{
+ return ENODEV;
+}
+
+errno_t
+tuntap_if_noop_del_proto(ifnet_t, protocol_family_t)
+{
+ return ENODEV;
+}
+
+} /* extern "C" */
+
+/* tuntap_mbuf_queue */
+tuntap_mbuf_queue::tuntap_mbuf_queue()
+{
+ head = tail = NULL;
+ size = 0;
+}
+
+tuntap_mbuf_queue::~tuntap_mbuf_queue()
+{
+ clear();
+}
+
+bool
+tuntap_mbuf_queue::enqueue(mbuf_t mb)
+{
+ if (size == QUEUE_SIZE)
+ return false;
+
+ mbuf_setnextpkt(mb, NULL);
+
+ if (head == NULL)
+ head = tail = mb;
+ else {
+ mbuf_setnextpkt(tail, mb);
+ tail = mb;
+ }
+ size++;
+
+ return true;
+}
+
+mbuf_t
+tuntap_mbuf_queue::dequeue()
+{
+ mbuf_t ret;
+
+ /* check wether there is a packet in the queue */
+ if (head == NULL)
+ return NULL;
+
+ /* fetch it */
+ ret = head;
+ head = mbuf_nextpkt(head);
+ mbuf_setnextpkt(ret, NULL);
+ size--;
+
+ return ret;
+}
+
+void
+tuntap_mbuf_queue::clear()
+{
+ /* free mbufs that are in the queue */
+ if (head != NULL)
+ mbuf_freem_list(head);
+
+ head = NULL;
+ tail = NULL;
+ size = 0;
+}
+
+/* tuntap_interface members */
+tuntap_interface::tuntap_interface()
+{
+ /* initialize the members */
+ ifp = NULL;
+ open = false;
+ block_io = true;
+ dev_handle = NULL;
+ pid = 0;
+ selthreadclear(&rsel);
+ bpf_mode = BPF_MODE_DISABLED;
+ bpf_callback = NULL;
+ bzero(unique_id, UIDLEN);
+ in_ioctl = false;
+}
+
+tuntap_interface::~tuntap_interface()
+{
+}
+
+bool
+tuntap_interface::register_chardev(unsigned short major)
+{
+ /* register character device */
+ dev_handle = devfs_make_node(makedev(major, unit), DEVFS_CHAR, 0, 0, 0660, "%s%d",
+ family_name, (int) unit);
+
+ if (dev_handle == NULL) {
+ log(LOG_ERR, "tuntap: could not make /dev/%s%d\n", family_name, (int) unit);
+ return false;
+ }
+
+ return true;
+}
+
+void
+tuntap_interface::unregister_chardev()
+{
+ dprintf("unregistering character device\n");
+
+ /* unregister character device */
+ if (dev_handle != NULL)
+ devfs_remove(dev_handle);
+ dev_handle = NULL;
+}
+
+bool
+tuntap_interface::register_interface(const struct sockaddr_dl* lladdr, void *bcaddr,
+ u_int32_t bcaddrlen)
+{
+ struct ifnet_init_params ip;
+ errno_t err;
+
+ dprintf("register_interface\n");
+
+ /* initialize an initialization info struct */
+ ip.uniqueid_len = UIDLEN;
+ ip.uniqueid = unique_id;
+ ip.name = family_name;
+ ip.unit = unit;
+ ip.family = family;
+ ip.type = type;
+ ip.output = tuntap_if_output;
+ ip.demux = tuntap_if_demux;
+ ip.add_proto = tuntap_if_add_proto;
+ ip.del_proto = tuntap_if_del_proto;
+ ip.check_multi = tuntap_if_check_multi;
+ ip.framer = tuntap_if_framer;
+ ip.softc = this;
+ ip.ioctl = tuntap_if_ioctl;
+ ip.set_bpf_tap = tuntap_if_set_bpf_tap;
+ ip.detach = tuntap_if_detached;
+ ip.event = NULL;
+ ip.broadcast_addr = bcaddr;
+ ip.broadcast_len = bcaddrlen;
+
+ dprintf("tuntap: tuntap_if_check_multi is at 0x%08x\n", (void*) tuntap_if_check_multi);
+
+ /* allocate the interface */
+ err = ifnet_allocate(&ip, &ifp);
+ if (err) {
+ log(LOG_ERR, "tuntap: could not allocate interface for %s%d: %d\n", family_name,
+ (int) unit, err);
+ ifp = NULL;
+ return false;
+ }
+
+ /* activate the interface */
+ err = ifnet_attach(ifp, lladdr);
+ if (err) {
+ log(LOG_ERR, "tuntap: could not attach interface %s%d: %d\n", family_name,
+ (int) unit, err);
+ ifnet_release(ifp);
+ ifp = NULL;
+ return false;
+ }
+
+ dprintf("setting interface flags\n");
+
+ /* set interface flags */
+ ifnet_set_flags(ifp, IFF_RUNNING | IFF_MULTICAST | IFF_SIMPLEX, (u_int16_t) ~0UL);
+
+ dprintf("flags: %x\n", ifnet_flags(ifp));
+
+ return true;
+}
+
+void
+tuntap_interface::unregister_interface()
+{
+ errno_t err;
+
+ dprintf("unregistering network interface\n");
+
+ if (ifp != NULL) {
+ interface_detached = false;
+
+ /* detach interface */
+ err = ifnet_detach(ifp);
+ if (err)
+ log(LOG_ERR, "tuntap: error detaching interface %s%d: %d\n",
+ family_name, unit, err);
+
+ dprintf("interface detaching\n");
+
+ /* Wait until the interface has completely been detached. */
+ detach_lock.lock();
+ while (!interface_detached)
+ detach_lock.sleep(&interface_detached);
+ detach_lock.unlock();
+
+ dprintf("interface detached\n");
+
+ /* release the interface */
+ ifnet_release(ifp);
+
+ ifp = NULL;
+ }
+
+ dprintf("network interface unregistered\n");
+}
+
+void
+tuntap_interface::cleanup_interface()
+{
+ errno_t err;
+ ifaddr_t *addrs;
+ ifaddr_t *a;
+ struct ifreq ifr;
+
+ /* mark the interface down */
+ ifnet_set_flags(ifp, 0, IFF_UP | IFF_RUNNING);
+
+ /* Unregister all interface addresses. This works around a deficiency in the Darwin kernel.
+ * If we don't remove all IP addresses that are attached to the interface it can happen that
+ * the IP code fails to clean them up itself. When the interface is recycled, the IP code
+ * might then think some addresses are still attached to the interface...
+ */
+
+ err = ifnet_get_address_list(ifp, &addrs);
+ if (!err) {
+
+ /* Execute a SIOCDIFADDR ioctl for each address. For technical reasons, we can only
+ * do that with a socket of the appropriate family. So try to create a dummy socket.
+ * I know this is a little expensive, but better than crashing...
+ *
+ * This really sucks.
+ */
+ for (a = addrs; *a != NULL; a++) {
+ /* initialize the request parameters */
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
+ ifnet_name(ifp), ifnet_unit(ifp));
+ ifaddr_address(*a, &(ifr.ifr_addr), sizeof(ifr.ifr_addr));
+ if (ifr.ifr_addr.sa_family != AF_INET)
+ continue;
+
+ dprintf("trying to delete address of family %d\n", ifr.ifr_addr.sa_family);
+
+ do_sock_ioctl(ifr.ifr_addr.sa_family, SIOCDIFADDR, &ifr);
+ }
+
+ /* release the address list */
+ ifnet_free_address_list(addrs);
+ }
+}
+
+bool
+tuntap_interface::idle()
+{
+ return !(open);
+}
+
+void
+tuntap_interface::notify_bpf(mbuf_t mb, bool out)
+{
+ auto_lock l(&bpf_lock);
+
+ if ((out && bpf_mode == BPF_MODE_OUTPUT)
+ || (!out && bpf_mode == BPF_MODE_INPUT)
+ || (bpf_mode == BPF_MODE_INPUT_OUTPUT))
+ (*bpf_callback)(ifp, mb);
+}
+
+void
+tuntap_interface::do_sock_ioctl(sa_family_t af, unsigned long cmd, void* arg) {
+ if (in_ioctl) {
+ log(LOG_ERR, "tuntap: ioctl recursion detected, aborting.\n");
+ return;
+ }
+
+ socket_t sock;
+ errno_t err = sock_socket(af, SOCK_RAW, 0, NULL, NULL, &sock);
+ if (err) {
+ log(LOG_ERR, "tuntap: failed to create socket: %d\n", err);
+ return;
+ }
+
+ in_ioctl = true;
+
+ /* issue the ioctl */
+ err = sock_ioctl(sock, cmd, arg);
+ if (err)
+ log(LOG_ERR, "tuntap: socket ioctl %d failed: %d\n", cmd, err);
+
+ in_ioctl = false;
+
+ /* get rid of the socket */
+ sock_close(sock);
+}
+
+/* character device service methods */
+int
+tuntap_interface::cdev_open(int flags, int devtype, proc_t p)
+{
+ dprintf("tuntap: cdev_open()\n");
+
+ /* grab the lock so that there can only be one thread inside */
+ auto_lock l(&lock);
+
+ /* check wether it is already open */
+ if (open)
+ return EBUSY;
+
+ /* bring the network interface up */
+ int error = initialize_interface();
+ if (error)
+ return error;
+
+ open = true;
+ pid = proc_pid(p);
+
+ return 0;
+}
+
+int
+tuntap_interface::cdev_close(int flags, int devtype, proc_t p)
+{
+ dprintf("tuntap: cdev_close()\n");
+
+ auto_lock l(&lock);
+
+ if (open) {
+ open = false;
+
+ /* shut down the network interface */
+ shutdown_interface();
+
+ /* clear the queue */
+ send_queue.clear();
+
+ /* wakeup the cdev thread and notify selects */
+ wakeup(this);
+ selwakeup(&rsel);
+
+ return 0;
+ }
+
+ return EBADF;
+}
+
+int
+tuntap_interface::cdev_read(uio_t uio, int ioflag)
+{
+ auto_lock l(&lock);
+
+ unsigned int nb = 0;
+ int error;
+
+ dprintf("tuntap: cdev read\n");
+
+ if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
+ return EIO;
+
+ /* fetch a new mbuf from the queue if necessary */
+ mbuf_t cur_mbuf = NULL;
+ while (cur_mbuf == NULL) {
+ dprintf("tuntap: fetching new mbuf\n");
+
+ cur_mbuf = send_queue.dequeue();
+ if (cur_mbuf == NULL) {
+ /* nothing in queue, block or return */
+ if (!block_io) {
+ dprintf("tuntap: aborting (nbio)\n");
+ return EWOULDBLOCK;
+ } else {
+ /* block */
+ dprintf("tuntap: waiting\n");
+ /* release the lock while waiting */
+ l.unlock();
+ error = msleep(this, NULL, PZERO | PCATCH, "tuntap", NULL);
+
+ l.lock();
+
+ if (error)
+ return error;
+
+ /* see whether the device was closed in the meantime */
+ if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
+ return EIO;
+
+ }
+ }
+ }
+
+ /* notify bpf */
+ notify_bpf(cur_mbuf, true);
+
+ /* output what we have */
+ do {
+ dprintf("tuntap: got new mbuf: %p uio_resid: %d\n", cur_mbuf, uio_resid(uio));
+
+ /* now we have an mbuf */
+ int chunk_len = min(mbuf_len(cur_mbuf), uio_resid(uio));
+ error = uiomove((char *) mbuf_data(cur_mbuf), chunk_len, uio);
+ if (error) {
+ mbuf_freem(cur_mbuf);
+ return error;
+ }
+ nb += chunk_len;
+
+ dprintf("tuntap: moved %d bytes to userspace uio_resid: %d\n", chunk_len,
+ uio_resid(uio));
+
+ /* update cur_mbuf */
+ cur_mbuf = mbuf_free(cur_mbuf);
+
+ } while (uio_resid(uio) > 0 && cur_mbuf != NULL);
+
+ /* update statistics */
+ ifnet_stat_increment_out(ifp, 1, nb, 0);
+
+ /* still data left? forget about that ;-) */
+ if (cur_mbuf != NULL)
+ mbuf_freem(cur_mbuf);
+
+ dprintf("tuntap: read done\n");
+
+ return 0;
+}
+
+int
+tuntap_interface::cdev_write(uio_t uio, int ioflag)
+{
+ auto_lock l(&lock);
+
+ if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
+ return EIO;
+
+ dprintf("tuntap: cdev write. uio_resid: %d\n", uio_resid(uio));
+
+ /* pack the data into an mbuf chain */
+ mbuf_t first, mb;
+
+ /* first we need an mbuf having a header */
+ mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &first);
+ if (first == NULL) {
+ log(LOG_ERR, "tuntap: could not get mbuf.\n");
+ return ENOMEM;
+ }
+ mbuf_setlen(first, 0);
+
+ unsigned int mlen = mbuf_maxlen(first);
+ unsigned int chunk_len;
+ unsigned int copied = 0;
+ int error;
+
+ /* stuff the data into the mbuf(s) */
+ mb = first;
+ while (uio_resid(uio) > 0) {
+ /* copy a chunk. enforce mtu (don't know if this is correct behaviour) */
+ chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen));
+ error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio);
+ if (error) {
+ log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error);
+ mbuf_freem(first);
+ return error;
+ }
+
+ dprintf("tuntap: copied %d bytes, uio_resid %d\n", chunk_len,
+ uio_resid(uio));
+
+ mlen -= chunk_len;
+ mbuf_setlen(mb, mbuf_len(mb) + chunk_len);
+ copied += chunk_len;
+
+ /* if done, break the loop */
+ if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp))
+ break;
+
+ /* allocate a new mbuf if the current is filled */
+ if (mlen == 0) {
+ mbuf_t next;
+ mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &next);
+ if (next == NULL) {
+ log(LOG_ERR, "tuntap: could not get mbuf.\n");
+ mbuf_freem(first);
+ return ENOMEM;
+ }
+ mbuf_setnext(mb, next);
+ mb = next;
+ mbuf_setlen(mb, 0);
+ mlen = mbuf_maxlen(mb);
+ }
+ }
+
+ /* fill in header info */
+ mbuf_pkthdr_setrcvif(first, ifp);
+ mbuf_pkthdr_setlen(first, copied);
+ mbuf_pkthdr_setheader(first, mbuf_data(first));
+ mbuf_set_csum_performed(first, 0, 0);
+
+ /* update statistics */
+ ifnet_stat_increment_in(ifp, 1, copied, 0);
+
+ dprintf("tuntap: mbuf chain constructed. first: %p mb: %p len: %d data: %p\n",
+ first, mb, mbuf_len(first), mbuf_data(first));
+
+ /* notify bpf */
+ notify_bpf(first, false);
+
+ /* need to adjust the data pointer to point directly behind the linklevel header. The header
+ * itself is later accessed via m_pkthdr.header. Well, if something is ugly, here is it.
+ */
+ mbuf_adj(first, ifnet_hdrlen(ifp));
+
+ /* pass the packet over to the network stack */
+ error = ifnet_input(ifp, first, NULL);
+
+ if (error) {
+ log(LOG_ERR, "tuntap: could not input packet into network stack.\n");
+ mbuf_freem(first);
+ return error;
+ }
+
+ return 0;
+}
+
+int
+tuntap_interface::cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p)
+{
+ auto_lock l(&lock);
+
+ dprintf("tuntap: cdev ioctl: %d\n", (int) (cmd & 0xff));
+
+ switch (cmd) {
+ case FIONBIO:
+ /* set i/o mode */
+ block_io = *((int *) data) ? false : true;
+ return 0;
+ case FIOASYNC:
+ /* don't allow switching it on */
+ if (*((int *) data))
+ return ENOTTY;
+ return 0;
+ }
+
+ return ENOTTY;
+}
+
+int
+tuntap_interface::cdev_select(int which, void *wql, proc_t p)
+{
+ auto_lock l(&lock);
+
+ int ret = 0;
+
+ dprintf("tuntap: select. which: %d\n", which);
+
+ switch (which) {
+ case FREAD:
+ /* check wether data is available */
+ {
+ if (!send_queue.empty())
+ ret = 1;
+ else {
+ dprintf("tuntap: select: waiting\n");
+ selrecord(p, &rsel, wql);
+ }
+ }
+ break;
+ case FWRITE:
+ /* we are always writeable */
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/* interface service methods */
+errno_t
+tuntap_interface::if_output(mbuf_t m)
+{
+ mbuf_t pkt;
+
+ dprintf("tuntap: if output\n");
+
+ /* just to be sure */
+ if (m == NULL)
+ return 0;
+
+ if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) {
+ mbuf_freem_list(m);
+ return EHOSTDOWN;
+ }
+
+ /* check whether packet has a header */
+ if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) {
+ log(LOG_ERR, "tuntap: packet to be output has no mbuf header.\n");
+ mbuf_freem_list(m);
+ return EINVAL;
+ }
+
+ /* put the packet(s) into the output queue */
+ while (m != NULL) {
+ /* keep pointer, iterate */
+ pkt = m;
+ m = mbuf_nextpkt(m);
+ mbuf_setnextpkt(pkt, NULL);
+
+ auto_lock l(&lock);
+
+ if (!send_queue.enqueue(pkt)) {
+ mbuf_freem(pkt);
+ mbuf_freem_list(m);
+ return ENOBUFS;
+ }
+ }
+
+ /* protect the wakeup calls with the lock, not sure they are safe. */
+ {
+ auto_lock l(&lock);
+
+ /* wakeup the cdev thread and notify selects */
+ wakeup(this);
+ selwakeup(&rsel);
+ }
+
+ return 0;
+}
+
+errno_t
+tuntap_interface::if_ioctl(u_int32_t cmd, void *arg)
+{
+ dprintf("tuntap: if ioctl: %d\n", (int) (cmd & 0xff));
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ {
+ dprintf("tuntap: if_ioctl: SIOCSIFADDR\n");
+
+ /* Unfortunately, ifconfig sets the address family field of an INET
+ * netmask to zero, which makes early mDNSresponder versions ignore
+ * the interface. Fix that here. This one is of the category "ugly
+ * workaround". Dumb Darwin...
+ *
+ * Meanwhile, Apple has fixed mDNSResponder, and recent versions of
+ * Leopard don't need this hack anymore. However, Tiger still has a
+ * broken version so we leave the hack in for now.
+ *
+ * TODO: Revisit when dropping Tiger support.
+ *
+ * Btw. If you configure other network interfaces using ifconfig,
+ * you run into the same problem. I still don't know how to make the
+ * tap devices show up in the network configuration panel...
+ */
+ ifaddr_t ifa = (ifaddr_t) arg;
+ if (ifa == NULL)
+ return 0;
+
+ sa_family_t af = ifaddr_address_family(ifa);
+ if (af != AF_INET)
+ return 0;
+
+ struct ifaliasreq ifra;
+ int sa_size = sizeof(struct sockaddr);
+ if (ifaddr_address(ifa, &ifra.ifra_addr, sa_size)
+ || ifaddr_dstaddress(ifa, &ifra.ifra_broadaddr, sa_size)
+ || ifaddr_netmask(ifa, &ifra.ifra_mask, sa_size)) {
+ log(LOG_WARNING,
+ "tuntap: failed to parse interface address.\n");
+ return 0;
+ }
+
+ // Check that the address family fields match. If not, issue another
+ // SIOCAIFADDR to fix the entry.
+ if (ifra.ifra_addr.sa_family != af
+ || ifra.ifra_broadaddr.sa_family != af
+ || ifra.ifra_mask.sa_family != af) {
+ log(LOG_INFO, "tuntap: Fixing address family for %s%d\n",
+ family_name, unit);
+
+ snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "%s%d",
+ family_name, unit);
+ ifra.ifra_addr.sa_family = af;
+ ifra.ifra_broadaddr.sa_family = af;
+ ifra.ifra_mask.sa_family = af;
+
+ do_sock_ioctl(af, SIOCAIFADDR, &ifra);
+ }
+
+ return 0;
+ }
+
+ case SIOCSIFFLAGS:
+ return 0;
+
+ case SIOCGIFSTATUS:
+ {
+ struct ifstat *stat = (struct ifstat *) arg;
+ int len;
+ char *p;
+
+ if (stat == NULL)
+ return EINVAL;
+
+ /* print status */
+ len = strlen(stat->ascii);
+ p = stat->ascii + len;
+ if (open) {
+ snprintf(p, IFSTATMAX - len, "\topen (pid %u)\n", pid);
+ } else {
+ snprintf(p, IFSTATMAX - len, "\tclosed\n");
+ }
+
+ return 0;
+ }
+
+ case SIOCSIFMTU:
+ {
+ struct ifreq *ifr = (struct ifreq *) arg;
+
+ if (ifr == NULL)
+ return EINVAL;
+
+ ifnet_set_mtu(ifp, ifr->ifr_mtu);
+
+ return 0;
+ }
+
+ case SIOCDIFADDR:
+ return 0;
+
+ }
+
+ return EOPNOTSUPP;
+}
+
+errno_t
+tuntap_interface::if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t))
+{
+ dprintf("tuntap: mode %d\n", mode);
+
+ auto_lock l(&bpf_lock);
+
+ bpf_callback = cb;
+ bpf_mode = mode;
+
+ return 0;
+}
+
+errno_t
+tuntap_interface::if_check_multi(const struct sockaddr *maddr)
+{
+ dprintf("tuntap: if_check_multi\n");
+
+ return EOPNOTSUPP;
+}
+
+void
+tuntap_interface::if_detached()
+{
+ dprintf("tuntap: if_detached\n");
+
+ /* wake unregister_interface() */
+ detach_lock.lock();
+ interface_detached = true;
+ detach_lock.wakeup(&interface_detached);
+ detach_lock.unlock();
+
+ dprintf("if_detached done\n");
+}
+
diff --git a/tap-mac/tuntap/src/tuntap.h b/tap-mac/tuntap/src/tuntap.h
new file mode 100644
index 00000000..f10d4a06
--- /dev/null
+++ b/tap-mac/tuntap/src/tuntap.h
@@ -0,0 +1,301 @@
+/*
+ * ip tunnel/ethertap device for MacOSX.
+ *
+ * The class tuntaptap_interface contains the common functionality of tuntap_interface and
+ * tap_interface.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __TUNTAP_H__
+#define __TUNTAP_H__
+
+#include "util.h"
+#include "lock.h"
+
+extern "C" {
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/systm.h>
+#include <sys/kpi_mbuf.h>
+
+#include <kern/locks.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+#include <net/kpi_interface.h>
+
+}
+
+extern "C" {
+
+errno_t tuntap_if_output(ifnet_t ifp, mbuf_t m);
+errno_t tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg);
+errno_t tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t));
+errno_t tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto);
+errno_t tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest,
+ const char *dest_linkaddr, const char *frame_type);
+errno_t tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto,
+ const struct ifnet_demux_desc *ddesc, u_int32_t ndesc);
+errno_t tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto);
+errno_t tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr *maddr);
+void tuntap_if_detached(ifnet_t ifp);
+
+}
+
+/* forward declaration */
+class tuntap_interface;
+
+/* both interface families have their manager object that will create, initialize, shutdown and
+ * delete interfaces. This is (mostly) generic so it can be used both for tun and tap. The only
+ * exception is the interface creation, therefore this class is abstract. tun and tap have their own
+ * versions that simply fill in create_interface().
+ */
+class tuntap_manager {
+
+ protected:
+ /* manager cdev gate */
+ tt_gate cdev_gate;
+ /* interface count */
+ unsigned int count;
+ /* an array holding all the interface instances */
+ tuntap_interface **tuntaps;
+ /* the major device number */
+ int dev_major;
+ /* family name */
+ char *family;
+
+ /* wether static members are initialized */
+ static bool statics_initialized;
+
+ /* major-to-manager-map */
+ static const int MAX_CDEV = 256;
+ static tuntap_manager *mgr_map[MAX_CDEV];
+
+ /* initializes static members */
+ void initialize_statics();
+
+ public:
+ /* sets major device number, allocates the interface table. */
+ bool initialize(unsigned int count, char *family);
+
+ /* tries to shutdown the family. returns true if successful. the manager object may
+ * not be deleted if this wasn't called successfully.
+ */
+ bool shutdown();
+
+ /* the destructor deletes allocated memory and unregisters the character device
+ * switch */
+ virtual ~tuntap_manager();
+
+ /* here are the cdev routines for the class. They will figure out the manager object
+ * and call the service methods declared below.
+ */
+ static int cdev_open(dev_t dev, int flags, int devtype, proc_t p);
+ static int cdev_close(dev_t dev, int flags, int devtype, proc_t p);
+ static int cdev_read(dev_t dev, uio_t uio, int ioflag);
+ static int cdev_write(dev_t dev, uio_t uio, int ioflag);
+ static int cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag,
+ proc_t p);
+ static int cdev_select(dev_t dev, int which, void *wql, proc_t p);
+
+ protected:
+ /* Here are the actual service routines that will do the required things (creating
+ * interfaces and such) and forward to the interface's implementation.
+ */
+ int do_cdev_open(dev_t dev, int flags, int devtype, proc_t p);
+ int do_cdev_close(dev_t dev, int flags, int devtype, proc_t p);
+ int do_cdev_read(dev_t dev, uio_t uio, int ioflag);
+ int do_cdev_write(dev_t dev, uio_t uio, int ioflag);
+ int do_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p);
+ int do_cdev_select(dev_t dev, int which, void *wql, proc_t p);
+
+ /* abstract method that will create an interface. Implemented by tun and tap */
+ virtual tuntap_interface *create_interface() = 0;
+
+ /* makes sure there is one idle interface available (if nothing fails */
+ void ensure_idle_device();
+
+};
+
+/* a class implementing a mbuf packet queue. On Darwin 7 we had struct ifqueue, but that is now
+ * internal to the kernel for Darwin 8. So lets have our own.
+ */
+class tuntap_mbuf_queue {
+
+ private:
+ /* output end of the queue. dequeueing takes mbufs from here */
+ mbuf_t head;
+ /* input end. new mbufs are appended here. */
+ mbuf_t tail;
+
+ /* size */
+ unsigned int size;
+
+ /* maximum queue size */
+ static const unsigned int QUEUE_SIZE = 128;
+
+ public:
+ /* initialize new empty queue */
+ tuntap_mbuf_queue();
+ ~tuntap_mbuf_queue();
+
+ /* is the queue full? */
+ bool full() { return size == QUEUE_SIZE; }
+ /* is it emtpy? */
+ bool empty() { return size == 0; }
+
+ /* enqueue an mbuf. returns true if there was space left, so the mbuf could be
+ * queued, false otherwise */
+ bool enqueue(mbuf_t mb);
+
+ /* tries to dequeue the next mbuf. If the queue is empty, NULL is returned */
+ mbuf_t dequeue();
+
+ /* makes the queue empty, discarding any queue packets */
+ void clear();
+};
+
+class tuntap_interface {
+
+ protected:
+ /* interface number */
+ unsigned int unit;
+ /* family name */
+ char *family_name;
+ /* family identifier */
+ ifnet_family_t family;
+ /* interface type */
+ u_int32_t type;
+ /* id string */
+ static const unsigned int UIDLEN = 20;
+ char unique_id[UIDLEN];
+
+ /* synchronization */
+ tt_mutex lock;
+ tt_mutex bpf_lock;
+ tt_mutex detach_lock;
+
+ /* the interface structure registered */
+ ifnet_t ifp;
+ /* whether the device has been opened */
+ bool open;
+ /* whether we are doing blocking i/o */
+ bool block_io;
+ /* whether the interface has properly been detached */
+ bool interface_detached;
+ /* handle to the devfs node for the character device */
+ void *dev_handle;
+ /* the pid of the process that opened the cdev, if any */
+ pid_t pid;
+ /* read select info */
+ struct selinfo rsel;
+ /* bpf mode, wether filtering is on or off */
+ bpf_tap_mode bpf_mode;
+ /* bpf callback. called when packet arrives/leaves */
+ int (*bpf_callback)(ifnet_t, mbuf_t);
+ /* pending packets queue (for output), must be accessed with the lock held */
+ tuntap_mbuf_queue send_queue;
+ /* whether an ioctl that we issued is currently being processed */
+ bool in_ioctl;
+
+ /* protected constructor. initializes most of the members */
+ tuntap_interface();
+ virtual ~tuntap_interface();
+
+ /* initialize the device */
+ virtual bool initialize(unsigned short major, unsigned short unit) = 0;
+
+ /* character device management */
+ virtual bool register_chardev(unsigned short major);
+ virtual void unregister_chardev();
+
+ /* network interface management */
+ virtual bool register_interface(const struct sockaddr_dl *lladdr,
+ void *bcaddr, u_int32_t bcaddrlen);
+ virtual void unregister_interface();
+ virtual void cleanup_interface();
+
+ /* called when the character device is opened in order to intialize the network
+ * interface.
+ */
+ virtual int initialize_interface() = 0;
+ /* called when the character device is closed to shutdown the network interface */
+ virtual void shutdown_interface() = 0;
+
+ /* check wether the interface is idle (so it can be brought down) */
+ virtual bool idle();
+
+ /* shut it down */
+ virtual void shutdown() = 0;
+
+ /* notifies BPF of a packet coming through */
+ virtual void notify_bpf(mbuf_t mb, bool out);
+
+ /* executes a socket ioctl through a temporary socket */
+ virtual void do_sock_ioctl(sa_family_t af, unsigned long cmd, void* arg);
+
+ /* character device service methods. Called by the manager */
+ virtual int cdev_open(int flags, int devtype, proc_t p);
+ virtual int cdev_close(int flags, int devtype, proc_t p);
+ virtual int cdev_read(uio_t uio, int ioflag);
+ virtual int cdev_write(uio_t uio, int ioflag);
+ virtual int cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p);
+ virtual int cdev_select(int which, void *wql, proc_t p);
+
+ /* interface functions. friends and implementation methods */
+ friend errno_t tuntap_if_output(ifnet_t ifp, mbuf_t m);
+ friend errno_t tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg);
+ friend errno_t tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode,
+ int (*cb)(ifnet_t, mbuf_t));
+ friend errno_t tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header,
+ protocol_family_t *proto);
+ friend errno_t tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest,
+ const char *dest_linkaddr, const char *frame_type);
+ friend errno_t tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto,
+ const struct ifnet_demux_desc *ddesc, u_int32_t ndesc);
+ friend errno_t tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto);
+ friend errno_t tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr *maddr);
+ friend void tuntap_if_detached(ifnet_t ifp);
+
+ virtual errno_t if_output(mbuf_t m);
+ virtual errno_t if_ioctl(u_int32_t cmd, void *arg);
+ virtual errno_t if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t));
+ virtual errno_t if_demux(mbuf_t m, char *header, protocol_family_t *proto) = 0;
+ virtual errno_t if_framer(mbuf_t *m, const struct sockaddr *dest,
+ const char *dest_linkaddr, const char *frame_type) = 0;
+ virtual errno_t if_add_proto(protocol_family_t proto,
+ const struct ifnet_demux_desc *ddesc, u_int32_t ndesc) = 0;
+ virtual errno_t if_del_proto(protocol_family_t proto) = 0;
+ virtual errno_t if_check_multi(const struct sockaddr *maddr);
+ virtual void if_detached();
+
+ /* tuntap_manager feeds us with cdev input, so it is our friend */
+ friend class tuntap_manager;
+};
+
+#endif /* __TUNTAP_H__ */
+
diff --git a/tap-mac/tuntap/src/tuntap_mgr.cc b/tap-mac/tuntap/src/tuntap_mgr.cc
new file mode 100644
index 00000000..f41394e9
--- /dev/null
+++ b/tap-mac/tuntap/src/tuntap_mgr.cc
@@ -0,0 +1,372 @@
+/*
+ * ip tunnel/ethertap device for MacOSX.
+ *
+ * tuntap_manager definition.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "tuntap.h"
+#include "mem.h"
+
+extern "C" {
+
+#include <sys/conf.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+
+#include <vm/vm_kern.h>
+
+#include <miscfs/devfs/devfs.h>
+
+}
+
+#if 0
+#define dprintf(...) log(LOG_INFO, __VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+/* cdevsw for tuntap_manager */
+static struct cdevsw mgr_cdevsw =
+{
+ tuntap_manager::cdev_open,
+ tuntap_manager::cdev_close,
+ tuntap_manager::cdev_read,
+ tuntap_manager::cdev_write,
+ tuntap_manager::cdev_ioctl,
+ eno_stop,
+ eno_reset,
+ NULL,
+ tuntap_manager::cdev_select,
+ eno_mmap,
+ eno_strat,
+ eno_getc,
+ eno_putc,
+ 0
+};
+
+/* tuntap_manager members */
+tuntap_manager *tuntap_manager::mgr_map[MAX_CDEV];
+
+bool tuntap_manager::statics_initialized = false;
+
+/* static initializer */
+void
+tuntap_manager::initialize_statics()
+{
+ dprintf("initializing mgr_map\n");
+
+ /* initialize the major-to-manager map */
+ for (int i = 0; i < MAX_CDEV; i++)
+ mgr_map[i] = NULL;
+
+ statics_initialized = true;
+}
+
+bool
+tuntap_manager::initialize(unsigned int count, char *family)
+{
+ this->count = count;
+ this->family = family;
+ this->tuntaps = NULL;
+
+ if (!statics_initialized)
+ initialize_statics();
+
+ /* make sure noone can access the character devices until we are done */
+ auto_lock l(&cdev_gate);
+
+ /* register the switch for the tap character devices */
+ dev_major = cdevsw_add(-1, &mgr_cdevsw);
+ if (dev_major == -1) {
+ log(LOG_ERR, "%s: could not register character device switch.\n", family);
+ return false;
+ }
+
+ /* allocate memory for the interface instance table */
+ tuntaps = (tuntap_interface **) mem_alloc(count * sizeof(tuntap_interface *));
+ if (tuntaps == NULL)
+ {
+ log(LOG_ERR, "%s: no memory!\n", family);
+ return false;
+ }
+
+ bzero(tuntaps, count * sizeof(tuntap_interface *));
+
+ /* Create the interfaces. This will only add the character devices. The network devices will
+ * be created upon open()ing the corresponding character devices.
+ */
+ for (int i = 0; i < (int) count; i++)
+ {
+ tuntaps[i] = create_interface();
+
+ if (tuntaps[i] != NULL)
+ {
+ if (tuntaps[i]->initialize(dev_major, i))
+ {
+ continue;
+ }
+
+ /* error here. current interface needs to be shut down */
+ i++;
+ }
+
+ /* something went wrong. clean up. */
+ while (--i >= 0)
+ {
+ tuntaps[i]->shutdown();
+ delete tuntaps[i];
+ }
+
+ return false;
+ }
+
+ /* register the new family in the mgr switch */
+ mgr_map[dev_major] = this;
+
+ log(LOG_INFO, "%s kernel extension version %s <mattias.nissler@gmx.de>\n",
+ family, TUNTAP_VERSION);
+
+ return true;
+}
+
+bool
+tuntap_manager::shutdown()
+{
+ bool ok = true;
+
+ /* we halt the whole thing while we check whether we can shutdown */
+ auto_lock l(&cdev_gate);
+
+ /* anyone in? */
+ if (cdev_gate.is_anyone_in()) {
+ dprintf("tuntap_mgr: won't shutdown, threads still behind the gate.");
+ ok = false;
+ } else {
+ /* query the interfaces to see if shutting down is ok */
+ if (tuntaps != NULL) {
+ for (unsigned int i = 0; i < count; i++) {
+ if (tuntaps[i] != NULL)
+ ok &= tuntaps[i]->idle();
+ }
+
+ /* if yes, do it now */
+ if (ok) {
+ for (unsigned int i = 0; i < count; i++) {
+ if (tuntaps[i] != NULL) {
+ tuntaps[i]->shutdown();
+ delete tuntaps[i];
+ tuntaps[i] = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ /* unregister the character device switch */
+ if (ok) {
+ if (dev_major != -1 && cdevsw_remove(dev_major, &mgr_cdevsw) == -1) {
+ log(LOG_WARNING,
+ "%s: character device switch got lost. strange.\n", family);
+ }
+ mgr_map[dev_major] = NULL;
+ dev_major = -1;
+
+ /* at this point there is still a chance that some thread hangs at the cdev_gate in
+ * one of the cdev service functions. I can't imagine any way that would aviod this.
+ * So lets unblock the gate such that they fail.
+ */
+ unsigned int old_number;
+ do {
+ old_number = cdev_gate.get_ticket_number();
+
+ dprintf("tuntap_manager: waiting for other threads to give up.\n");
+
+ /* wait one second */
+ cdev_gate.sleep(&cdev_gate, 1000000);
+
+ } while (cdev_gate.get_ticket_number() != old_number);
+
+ /* I hope it is safe to unload now. */
+
+ } else {
+ log(LOG_WARNING, "%s: won't unload, at least one interface is busy.\n", family);
+ }
+
+ dprintf("tuntap manager: shutdown %s\n", ok ? "ok" : "failed");
+
+ return ok;
+}
+
+tuntap_manager::~tuntap_manager()
+{
+ dprintf("freeing interface table\n");
+
+ /* free memory */
+ if (tuntaps != NULL)
+ mem_free(tuntaps, count * sizeof(tuntap_interface *));
+}
+
+/* service method dispatchers */
+int
+tuntap_manager::cdev_open(dev_t dev, int flags, int devtype, proc_t p)
+{
+ return (mgr_map[major(dev)] == NULL ? ENOENT
+ : mgr_map[major(dev)]->do_cdev_open(dev, flags, devtype, p));
+}
+
+int
+tuntap_manager::cdev_close(dev_t dev, int flags, int devtype, proc_t p)
+{
+ return (mgr_map[major(dev)] == NULL ? EBADF
+ : mgr_map[major(dev)]->do_cdev_close(dev, flags, devtype, p));
+}
+
+int
+tuntap_manager::cdev_read(dev_t dev, uio_t uio, int ioflag)
+{
+ return (mgr_map[major(dev)] == NULL ? EBADF
+ : mgr_map[major(dev)]->do_cdev_read(dev, uio, ioflag));
+}
+
+int
+tuntap_manager::cdev_write(dev_t dev, uio_t uio, int ioflag)
+{
+ return (mgr_map[major(dev)] == NULL ? EBADF
+ : mgr_map[major(dev)]->do_cdev_write(dev, uio, ioflag));
+}
+
+int
+tuntap_manager::cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p)
+{
+ return (mgr_map[major(dev)] == NULL ? EBADF
+ : mgr_map[major(dev)]->do_cdev_ioctl(dev, cmd, data, fflag, p));
+}
+
+int
+tuntap_manager::cdev_select(dev_t dev, int which, void *wql, proc_t p)
+{
+ return (mgr_map[major(dev)] == NULL ? EBADF
+ : mgr_map[major(dev)]->do_cdev_select(dev, which, wql, p));
+}
+
+/* character device service methods */
+int
+tuntap_manager::do_cdev_open(dev_t dev, int flags, int devtype, proc_t p)
+{
+ int dmin = minor(dev);
+ int error = ENOENT;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_open(flags, devtype, p);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
+int
+tuntap_manager::do_cdev_close(dev_t dev, int flags, int devtype, proc_t p)
+{
+ int dmin = minor(dev);
+ int error = EBADF;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_close(flags, devtype, p);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
+int
+tuntap_manager::do_cdev_read(dev_t dev, uio_t uio, int ioflag)
+{
+ int dmin = minor(dev);
+ int error = EBADF;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_read(uio, ioflag);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
+int
+tuntap_manager::do_cdev_write(dev_t dev, uio_t uio, int ioflag)
+{
+ int dmin = minor(dev);
+ int error = EBADF;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_write(uio, ioflag);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
+int
+tuntap_manager::do_cdev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, proc_t p)
+{
+ int dmin = minor(dev);
+ int error = EBADF;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_ioctl(cmd, data, fflag, p);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
+int
+tuntap_manager::do_cdev_select(dev_t dev, int which, void *wql, proc_t p)
+{
+ int dmin = minor(dev);
+ int error = EBADF;
+
+ cdev_gate.enter();
+
+ if (dmin < (int) count && dmin >= 0 && tuntaps[dmin] != NULL)
+ error = tuntaps[dmin]->cdev_select(which, wql, p);
+
+ cdev_gate.exit();
+
+ return error;
+}
+
diff --git a/tap-mac/tuntap/src/util.h b/tap-mac/tuntap/src/util.h
new file mode 100644
index 00000000..0f6955e8
--- /dev/null
+++ b/tap-mac/tuntap/src/util.h
@@ -0,0 +1,46 @@
+/*
+ * ip tunnel/ethertap device for MacOSX.
+ *
+ * Some utilities and misc stuff.
+ */
+/*
+ * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+extern "C" {
+
+/* In Darwin 8 (OS X Tiger) there is a problem with struct selinfo. It was made `private' to the
+ * kernel, so its definition is not available from the headers in Kernel.framework. However, we need
+ * to declare something :-(
+ */
+struct selinfo {
+ char data[128]; /* should be enough... */
+};
+
+} /* extern "C" */
+
+#endif /* __UTIL_H__ */
+