--- bridge.c.orig	2011-11-22 13:09:01.003927305 +0700
+++ bridge.c	2011-11-22 14:44:27.682677017 +0700
@@ -28,8 +28,13 @@
 #include <sys/ioctl.h>
 #ifdef linux
 #include <pcap-bpf.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
 #else
 #include <net/bpf.h>
+#ifdef __OpenBSD__
+#include <net/if.h>
+#endif
 #endif
 #include <fcntl.h>
 #include <errno.h>
@@ -70,8 +75,6 @@
 #define ETHERTYPE_MOPRC 0x6002
 #define ETHERTYPE_LOOPBACK 0x9000
 
-#define MAX(a,b) (a>b?a:b)
-
 /* This is a very simple and small program for bpf that just
    filters out anything by any protocol that we *know* we're
    not interested in.
@@ -112,6 +115,9 @@
   struct in_addr addr;
   short port;
   int passive;
+#if defined(linux) || defined(__OpenBSD__)
+  int tap;
+#endif
   int anyport;
   int fd;
   int types[MAXTYP];
@@ -213,6 +219,68 @@
     }
 
     strcpy(bridge[bcnt].name,name);
+#if defined(linux) || defined(__OpenBSD__)
+    if (strncmp(dst, "@tun", 4) == 0) {
+      struct ifreq ifr;
+#ifndef linux
+      char path[32];
+
+      snprintf(path, sizeof(path), "/dev/%s", dst + 1);
+      if ((bridge[bcnt].fd = open(path, O_RDWR | O_NONBLOCK)) < 0) {
+        fprintf(stderr, "Error opening tap device %s\n", path);
+        exit(1);
+      }
+#else
+      if ((bridge[bcnt].fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0) {
+        fprintf(stderr, "Error opening tun control device");
+        exit(1);
+      }
+#endif
+
+      bzero(&ifr, sizeof(ifr));
+#ifndef linux
+      strlcpy(ifr.ifr_name, dst + 1, sizeof(ifr.ifr_name));
+
+      if (ioctl(sd, SIOCGIFFLAGS, &ifr) < 0) {
+        fprintf(stderr, "Error getting %s flags.\n", dst + 1);
+        exit(1);
+      }
+
+      ifr.ifr_flags |= IFF_LINK0;
+      if (ioctl(sd, SIOCSIFFLAGS, &ifr) < 0) {
+        fprintf(stderr, "Error switching %s to L2 mode\n", dst + 1);
+        exit(1);
+      }
+#else
+      strncpy(ifr.ifr_name, dst + 1, sizeof(ifr.ifr_name) - 1);
+
+      ifr.ifr_flags |= IFF_TAP | IFF_NO_PI;
+      if (ioctl(bridge[bcnt].fd, TUNSETIFF, &ifr) < 0) {
+        fprintf(stderr, "Error setting flags for %s\n", ifr.ifr_name);
+        exit(1);
+      }
+#endif
+
+      ifr.ifr_flags |= IFF_UP;
+      if (ioctl(sd, SIOCSIFFLAGS, &ifr) < 0) {
+        fprintf(stderr, "Error bringing %s up\n", dst + 1);
+        exit(1);
+      }
+
+#ifndef linux
+      strlcpy(bridge[bcnt].host, dst, sizeof(bridge[bcnt].host));
+#else
+      bzero(bridge[bcnt].host, sizeof(bridge[bcnt].host));
+      strncpy(bridge[bcnt].host, dst, sizeof(bridge[bcnt].host) - 1);
+#endif
+      bridge[bcnt].addr.s_addr = 0;
+      bridge[bcnt].port = 0;
+      bridge[bcnt].tap = 1;
+      found = -1;
+      goto add;
+    } else
+      bridge[bcnt].tap = 0;
+#endif
     p = index(dst,':');
     if (p == NULL) {		/* Assume local descriptor */
       struct bpf_program pgm;
@@ -248,6 +316,13 @@
 	perror("BIOCSHDRCMPLT");
 	exit(1);
       }
+#ifdef __OpenBSD__
+      i = BPF_DIRECTION_OUT;
+      if (ioctl(bridge[bcnt].fd,BIOCSDIRFILT,&i)) {
+        perror("BIOCSDIRFILT");
+        exit(1);
+      }
+#endif
 #endif
 
       found = -1;
@@ -268,6 +343,9 @@
       }
     }
     if (found) {
+#if defined(linux) || defined(__OpenBSD__)
+add:
+#endif
       for (i=0; i<MAXTYP; i++) bridge[bcnt].types[i] = 0;
 
       bridge[bcnt].rcount = 0;
@@ -677,6 +755,20 @@
     for (i=0; i<bcnt; i++) {
       if (FD_ISSET(bridge[i].fd,&fds)) {
 	d.source = i;
+#if defined(linux) || defined(__OpenBSD__)
+        if (bridge[i].tap) {
+          char pkt[1518];
+          ssize_t len;
+
+          if ((len = read(bridge[i].fd, pkt, sizeof(pkt))) > 0) {
+            d.data = pkt;
+            d.len = len;
+            process_packet(&d);
+          }
+
+          continue;
+        }
+#endif
 	if (bridge[i].addr.s_addr == 0) {
 	  struct pcap_pkthdr h;
 	  d.data = (char *)pcap_next(bridge[i].pcap, &h);
