diff -ur nat64.c nat64.c
--- nat64.c	2012-10-03 16:55:57.000000000 +0400
+++ nat64.c	2012-10-04 14:22:01.000000000 +0400
@@ -94,8 +94,7 @@
 	} __attribute__ ((__packed__)) header;
 	struct iovec iov[2];
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IP);
+	TUN_SET_PROTO(&header.pi,  ETH_P_IP);
 	header.ip4.ver_ihl = 0x45;
 	header.ip4.tos = tos;
 	header.ip4.length = htons(sizeof(header.ip4) + sizeof(header.icmp) +
@@ -156,6 +155,7 @@
 	}
 }
 
+
 static void xlate_header_4to6(struct pkt *p, struct ip6 *ip6,
 		int payload_length)
 {
@@ -266,8 +266,7 @@
 	if (dest)
 		dest->flags |= CACHE_F_SEEN_4TO6;
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IPV6);
+	TUN_SET_PROTO(&header.pi,  ETH_P_IPV6);
 
 	if (no_frag_hdr) {
 		iov[0].iov_base = &header;
@@ -514,8 +513,7 @@
 						sizeof(header.ip6_em)),
 				ip_checksum(p_em.data, p_em.data_len)));
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IPV6);
+	TUN_SET_PROTO(&header.pi,  ETH_P_IPV6);
 
 	iov[0].iov_base = &header;
 	iov[0].iov_len = sizeof(header);
@@ -566,8 +564,7 @@
 	} __attribute__ ((__packed__)) header;
 	struct iovec iov[2];
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IPV6);
+	TUN_SET_PROTO(&header.pi,  ETH_P_IPV6);
 	header.ip6.ver_tc_fl = htonl((0x6 << 28) | (tc << 20));
 	header.ip6.payload_length = htons(sizeof(header.icmp) + data_len);
 	header.ip6.next_header = 58;
@@ -588,6 +585,8 @@
 	if (writev(gcfg->tun_fd, iov, data_len ? 2 : 1) < 0)
 		slog(LOG_WARNING, "error writing packet to tun device: %s\n",
 				strerror(errno));
+
+	slog(LOG_WARNING, "Wrote somethinh\n");
 }
 
 static void host_send_icmp6_error(uint8_t type, uint8_t code, uint32_t word,
@@ -728,8 +727,7 @@
 	if (dest)
 		dest->flags |= CACHE_F_SEEN_6TO4;
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IP);
+	TUN_SET_PROTO(&header.pi, ETH_P_IP);
 
 	header.ip4.cksum = ip_checksum(&header.ip4, sizeof(header.ip4));
 
@@ -932,8 +930,7 @@
 							sizeof(header.ip4_em)),
 				ip_checksum(p_em.data, p_em.data_len));
 
-	header.pi.flags = 0;
-	header.pi.proto = htons(ETH_P_IP);
+	TUN_SET_PROTO(&header.pi, ETH_P_IP);
 
 	iov[0].iov_base = &header;
 	iov[0].iov_len = sizeof(header);
diff -ur tayga.c tayga.c
--- tayga.c	2012-10-03 16:55:57.000000000 +0400
+++ tayga.c	2012-10-04 15:13:49.000000000 +0400
@@ -84,6 +84,7 @@
 	}
 }
 
+#ifdef __Linux__
 static void tun_setup(int do_mktun, int do_rmtun)
 {
 	struct ifreq ifr;
@@ -161,6 +162,113 @@
 	slog(LOG_INFO, "Using tun device %s with MTU %d\n", gcfg->tundev,
 			gcfg->mtu);
 }
+#endif
+
+#ifdef __FreeBSD__
+static void tun_setup(int do_mktun, int do_rmtun)
+{
+	struct ifreq ifr;
+	int fd, do_rename = 0, multi_af;
+	char devname[64];
+
+	if (strncmp(gcfg->tundev, "tun", 3))
+		do_rename = 1;
+
+	if ((do_mktun || do_rmtun) && do_rename)
+	{
+		slog(LOG_CRIT,
+			"tunnel interface name needs to match tun[0-9]+ pattern "
+				"for --mktun to work\n");
+		exit(1);
+	}
+
+	snprintf(devname, sizeof(devname), "/dev/%s", do_rename ? "tun" : gcfg->tundev);
+
+	gcfg->tun_fd = open(devname, O_RDWR);
+	if (gcfg->tun_fd < 0) {
+		slog(LOG_CRIT, "Unable to open %s, aborting: %s\n",
+				devname, strerror(errno));
+		exit(1);
+	}
+
+	if (do_mktun) {
+		slog(LOG_NOTICE, "Created persistent tun device %s\n",
+				gcfg->tundev);
+		return;
+	} else if (do_rmtun) {
+
+		/* Close socket before removal */
+		close(gcfg->tun_fd);
+
+		fd = socket(PF_INET, SOCK_DGRAM, 0);
+		if (fd < 0) {
+			slog(LOG_CRIT, "Unable to create control socket, aborting: %s\n",
+					strerror(errno));
+			exit(1);
+		}
+
+		memset(&ifr, 0, sizeof(ifr));
+		strcpy(ifr.ifr_name, gcfg->tundev);
+		if (ioctl(fd, SIOCIFDESTROY, &ifr) < 0) {
+			slog(LOG_CRIT, "Unable to destroy interface %s, aborting: %s\n",
+					gcfg->tundev, strerror(errno));
+			exit(1);
+		}
+
+		close(fd);
+
+		slog(LOG_NOTICE, "Removed persistent tun device %s\n",
+				gcfg->tundev);
+		return;
+	}
+
+	/* Set multi-AF mode */
+	multi_af = 1;
+	if (ioctl(gcfg->tun_fd, TUNSIFHEAD, &multi_af) < 0) {
+			slog(LOG_CRIT, "Unable to set multi-AF on %s, "
+					"aborting: %s\n", gcfg->tundev,
+					strerror(errno));
+			exit(1);
+	}
+
+	slog(LOG_CRIT, "Multi-AF mode set on %s\n", gcfg->tundev);
+
+	set_nonblock(gcfg->tun_fd);
+
+	fd = socket(PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		slog(LOG_CRIT, "Unable to create socket, aborting: %s\n",
+				strerror(errno));
+		exit(1);
+	}
+
+	if (do_rename) {
+		memset(&ifr, 0, sizeof(ifr));
+		strcpy(ifr.ifr_name, fdevname(gcfg->tun_fd));
+		ifr.ifr_data = gcfg->tundev;
+		if (ioctl(fd, SIOCSIFNAME, &ifr) < 0) {
+			slog(LOG_CRIT, "Unable to rename interface %s to %s, aborting: %s\n",
+					fdevname(gcfg->tun_fd), gcfg->tundev,
+					strerror(errno));
+			exit(1);
+		}
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strcpy(ifr.ifr_name, gcfg->tundev);
+	if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+		slog(LOG_CRIT, "Unable to query MTU, aborting: %s\n",
+				strerror(errno));
+		exit(1);
+	}
+	close(fd);
+
+	gcfg->mtu = ifr.ifr_mtu;
+
+	slog(LOG_INFO, "Using tun device %s with MTU %d\n", gcfg->tundev,
+			gcfg->mtu);
+}
+#endif
 
 static void signal_handler(int signal)
 {
@@ -214,7 +322,7 @@
 	memset(p, 0, sizeof(struct pkt));
 	p->data = gcfg->recv_buf + sizeof(struct tun_pi);
 	p->data_len = ret - sizeof(struct tun_pi);
-	switch (ntohs(pi->proto)) {
+	switch (TUN_GET_PROTO(pi)) {
 	case ETH_P_IP:
 		handle_ip4(p);
 		break;
diff -ur tayga.h tayga.h
--- tayga.h	2012-10-03 16:55:57.000000000 +0400
+++ tayga.h	2012-10-04 14:26:09.000000000 +0400
@@ -31,14 +31,44 @@
 #include <syslog.h>
 #include <errno.h>
 #include <time.h>
+#ifdef __Linux__
 #include <linux/if.h>
 #include <linux/if_tun.h>
 #include <linux/if_ether.h>
+#endif
+#ifdef __FreeBSD__
+#include <net/if.h>
+#include <net/if_tun.h>
+#include <netinet/if_ether.h>
+#include <net/ethernet.h>
+#include <sys/uio.h>
+#endif
+
 
 #include "list.h"
 #include "config.h"
 
 
+#ifdef __Linux__
+#define	TUN_SET_PROTO(_pi, _af)			{ (_pi)->flags = 0; (_pi)->proto = htons(_af); }
+#define	TUN_GET_PROTO(_pi)			ntohs((_pi)->proto)
+#endif
+
+#ifdef __FreeBSD__
+#define s6_addr8  __u6_addr.__u6_addr8
+#define s6_addr16 __u6_addr.__u6_addr16
+#define s6_addr32 __u6_addr.__u6_addr32
+
+struct tun_pi {
+	int	proto;
+};
+
+#define ETH_P_IP AF_INET
+#define	ETH_P_IPV6 AF_INET6
+#define	TUN_SET_PROTO(_pi, _af)			{ (_pi)->proto = htonl(_af); }
+#define	TUN_GET_PROTO(_pi)			ntohl((_pi)->proto)
+#endif
+
 /* Configuration knobs */
 
 /* Number of seconds of silence before a map ages out of the cache */
