summaryrefslogtreecommitdiff
path: root/ext/tap-mac/tuntap/src/tap
diff options
context:
space:
mode:
Diffstat (limited to 'ext/tap-mac/tuntap/src/tap')
-rw-r--r--ext/tap-mac/tuntap/src/tap/Info.plist36
-rw-r--r--ext/tap-mac/tuntap/src/tap/Makefile60
-rw-r--r--ext/tap-mac/tuntap/src/tap/kmod.cc93
-rw-r--r--ext/tap-mac/tuntap/src/tap/tap.cc452
-rw-r--r--ext/tap-mac/tuntap/src/tap/tap.h103
5 files changed, 744 insertions, 0 deletions
diff --git a/ext/tap-mac/tuntap/src/tap/Info.plist b/ext/tap-mac/tuntap/src/tap/Info.plist
new file mode 100644
index 00000000..bb9b03fd
--- /dev/null
+++ b/ext/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/ext/tap-mac/tuntap/src/tap/Makefile b/ext/tap-mac/tuntap/src/tap/Makefile
new file mode 100644
index 00000000..ee1f5457
--- /dev/null
+++ b/ext/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++
+#CC = gcc
+CCP = ../../../../llvm-g++-Xcode4.6.2/bin/llvm-g++
+CC = ../../../../llvm-g++-Xcode4.6.2/bin/llvm-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/ext/tap-mac/tuntap/src/tap/kmod.cc b/ext/tap-mac/tuntap/src/tap/kmod.cc
new file mode 100644
index 00000000..f9c4a40e
--- /dev/null
+++ b/ext/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/ext/tap-mac/tuntap/src/tap/tap.cc b/ext/tap-mac/tuntap/src/tap/tap.cc
new file mode 100644
index 00000000..149f1e71
--- /dev/null
+++ b/ext/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/ext/tap-mac/tuntap/src/tap/tap.h b/ext/tap-mac/tuntap/src/tap/tap.h
new file mode 100644
index 00000000..0ef9e159
--- /dev/null
+++ b/ext/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 2800
+
+#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__ */
+