Initial revision
diff --git a/sgsnemu/tun.c b/sgsnemu/tun.c
new file mode 100644
index 0000000..72ea264
--- /dev/null
+++ b/sgsnemu/tun.c
@@ -0,0 +1,128 @@
+/* 
+ *  OpenGGSN - Gateway GPRS Support Node
+ *  Copyright (C) 2002 Mondru AB.
+ * 
+ *  The contents of this file may be used under the terms of the GNU
+ *  General Public License Version 2, provided that the above copyright
+ *  notice and this permission notice is included in all copies or
+ *  substantial portions of the software.
+ * 
+ *  The initial developer of the original code is
+ *  Jens Jakobsen <jj@openggsn.org>
+ * 
+ *  Contributor(s):
+ * 
+ */
+
+/*
+ * tun.c: Contains all TUN functionality. Should be able to handle multiple
+ * tunnels in the same program. Each tunnel is identified by the socket. 
+ * I suppose that no other state information than the socket is needed.
+ *
+ *  - tun_newtun: Initialise TUN tunnel.
+ *  - tun_freetun: Free a device previously created with tun_newtun.
+ *  - tun_encaps: Encapsulate packet in TUN tunnel and send off
+ *  - tun_decaps: Extract packet from TUN tunnel and call function to
+ *    ship it off as GTP encapsulated packet. 
+ *
+ * TODO:
+ *  - Do we need to handle fragmentation?
+ */
+
+
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <errno.h>
+#include <linux/if_tun.h>
+
+
+#include "tun.h"
+
+
+int tun_newtun(struct tun_t **tun)
+{
+  struct ifreq ifr;
+
+  if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
+    syslog(LOG_ERR, "%s %d. calloc(nmemb=%d, size=%d) failed: Error = %s(%d)",
+	   __FILE__, __LINE__, 1, sizeof(struct tun_t), 
+	   strerror(errno), errno);
+    return EOF;
+  }
+
+  if (((*tun)->fd  = open("/dev/net/tun", O_RDWR)) < 0) {
+    syslog(LOG_ERR, "TUN: open() failed");
+    return -1;
+  }
+
+  memset(&ifr, 0, sizeof(ifr));
+  ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
+  strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
+
+  if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
+    syslog(LOG_ERR, "TUN: ioctl() failed");
+    close((*tun)->fd);
+    return -1;
+  } 
+
+  ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
+
+  strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
+
+  return (*tun)->fd;
+}
+
+int tun_freetun(struct tun_t *tun)
+{
+  if (close(tun->fd)) {
+    syslog(LOG_ERR, "%s %d. close(fd=%d) failed: Error = %s", 
+	   __FILE__, __LINE__, tun->fd, strerror(errno));
+    return EOF;
+  }
+  free(tun);
+  return 0;
+}
+
+
+int tun_decaps(struct tun_t *tun, 
+	       int (*cb) (void *cl, struct tun_t*, void *pack, unsigned len),
+	       void *cl)
+{
+	unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ];
+	int status;
+
+
+	if ((status = read(tun->fd, buffer, sizeof(buffer))) <= 0) {
+		syslog(LOG_ERR, "TUN: read(fd=%d,buffer=%lx,len=%d) from network failed: status = %d error = %s",
+		       tun->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
+		return -1;
+	}
+
+	/* Need to include code to verify packet src and dest addresses */
+	return cb(cl, tun, buffer, status);
+}
+
+int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
+{
+	return write(tun->fd, pack, len);
+}