lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1406856100-21674-3-git-send-email-pmoody@google.com>
Date:	Thu, 31 Jul 2014 18:21:40 -0700
From:	Peter Moody <pmoody@...gle.com>
To:	linux-security-module@...r.kernel.org
Cc:	brandon.carpenter@...l.gov, casey@...aufler-ca.com,
	netdev@...r.kernel.org, Peter Moody <pmoody@...gle.com>
Subject: [PATCH 2/2] security: Hone LSM

This adds the Hone (Host/Network) process <-> packet correlation
module to the linux security subsystem. Hone aims to provide network
administrators with the ability to correlate network activity seen on
the network to the process which sent/received it.

Signed-off-by: Peter Moody <pmoody@...gle.com>
---
 include/linux/hone.h               |  50 +++
 security/Kconfig                   |   1 +
 security/Makefile                  |   2 +
 security/hone/Kconfig              |   8 +
 security/hone/Makefile             |   3 +
 security/hone/hone.h               | 164 ++++++++++
 security/hone/hone_event.c         | 625 +++++++++++++++++++++++++++++++++++++
 security/hone/hone_lsm.c           | 183 +++++++++++
 security/hone/hone_mmutil.c        | 106 +++++++
 security/hone/hone_mmutil.h        |  20 ++
 security/hone/hone_notify.c        | 450 ++++++++++++++++++++++++++
 security/hone/hone_pcapng.c        | 596 +++++++++++++++++++++++++++++++++++
 security/hone/hone_pcapng.h        |  30 ++
 security/hone/hone_ringbuf.c       |  51 +++
 security/hone/hone_ringbuf.h       |  34 ++
 security/hone/hone_socket_lookup.c | 264 ++++++++++++++++
 16 files changed, 2587 insertions(+)
 create mode 100644 include/linux/hone.h
 create mode 100644 security/hone/Kconfig
 create mode 100644 security/hone/Makefile
 create mode 100644 security/hone/hone.h
 create mode 100644 security/hone/hone_event.c
 create mode 100644 security/hone/hone_lsm.c
 create mode 100644 security/hone/hone_mmutil.c
 create mode 100644 security/hone/hone_mmutil.h
 create mode 100644 security/hone/hone_notify.c
 create mode 100644 security/hone/hone_pcapng.c
 create mode 100644 security/hone/hone_pcapng.h
 create mode 100644 security/hone/hone_ringbuf.c
 create mode 100644 security/hone/hone_ringbuf.h
 create mode 100644 security/hone/hone_socket_lookup.c

diff --git a/include/linux/hone.h b/include/linux/hone.h
new file mode 100644
index 0000000..7ad7ad8
--- /dev/null
+++ b/include/linux/hone.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#include <linux/skbuff.h>
+
+#ifndef _INCLUDE_LINUX_HONE_H
+#define _INCLUDE_LINUX_HONE_H
+
+#define PKTNOT_PACKET_IN 1
+#define PKTNOT_PACKET_OUT 2
+
+/* hone block types for pcapng blocks */
+#define HONE_IF_DESC_BLOCK	0x00000001
+#define HONE_IF_STATS_BLOCK	0x00000005
+#define HONE_PACKET_BLOCK	0x00000006
+#define HONE_PROCESS_BLOCK	0x00000101
+#define HONE_CONNECTION_BLOCK	0x00000102
+#define HONE_SECTION_HDR_BLOCK	0x0A0D0D0A
+
+/* ioctls for controlling hone. */
+#define HEIO_RESTART _IO(0xE0, 0x01)
+#define HEIO_GET_AT_HEAD _IO(0xE0, 0x03)
+#define HEIO_GET_SNAPLEN _IOR(0xE0, 0x04, int)
+#define HEIO_SET_SNAPLEN _IOW(0xE0, 0x05, int)
+#define HEIO_SET_FILTER_SOCK _IOW(0xE0, 0x06, int)
+
+#define HONE_PROCESS 1
+#define HONE_SOCKET 2
+#define HONE_PACKET 3
+#define HONE_USER 0x8000
+
+#define PROC_FORK 1
+#define PROC_EXEC 2
+#define PROC_EXIT 3
+#define PROC_KTHD 4
+
+void hone_exec_handler(int);
+void hone_exit_handler(void);
+void hone_fork_handler(struct task_struct *);
+void hone_raw_rcv_handler(struct sock *, struct sk_buff *);
+void hone_inet_create_handler(int, struct sock *);
+
+#endif
diff --git a/security/Kconfig b/security/Kconfig
index beb86b5..84d2b45 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -122,6 +122,7 @@ source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/yama/Kconfig
+source security/hone/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/Makefile b/security/Makefile
index 05f1c93..ff20918 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
+subdir-$(CONFIG_SECURITY_HONE)		+= hone
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -22,6 +23,7 @@ obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
+obj-$(CONFIG_SECURITY_HONE) 		+= hone/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/hone/Kconfig b/security/hone/Kconfig
new file mode 100644
index 0000000..bdaad6b
--- /dev/null
+++ b/security/hone/Kconfig
@@ -0,0 +1,8 @@
+config SECURITY_HONE
+       bool "HOst NEt corrleation engine support"
+       default n
+       help
+         This selects hone, a tool for correlating packets to
+         processes.
+
+         If you are unsure how to answer this question, answer N.
diff --git a/security/hone/Makefile b/security/hone/Makefile
new file mode 100644
index 0000000..b87c0a8
--- /dev/null
+++ b/security/hone/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_HONE)	:= hone.o
+hone-y := hone_lsm.o hone_notify.o hone_ringbuf.o hone_event.o \
+					hone_mmutil.o hone_pcapng.o hone_ringbuf.o hone_socket_lookup.o
diff --git a/security/hone/hone.h b/security/hone/hone.h
new file mode 100644
index 0000000..1533cf7
--- /dev/null
+++ b/security/hone/hone.h
@@ -0,0 +1,164 @@
+#ifndef _SECURITY_HONE_HONE_H
+#define _SECURITY_HONE_HONE_H
+
+#include <linux/hone.h>
+#include <linux/tcp.h>
+
+#define HONE_USER_HEAD (HONE_USER | 1)
+#define HONE_USER_TAIL (HONE_USER | 2)
+
+#define READER_HEAD 0x00000001
+#define READER_INIT 0x00000002
+#define READER_TAIL 0x00000004
+#define READER_FINISH 0x00000008
+#define READER_RESTART 0x0000000F
+#define READER_FILTER_PID 0x00000100
+
+struct guid_struct {
+	uint32_t data1;
+	uint16_t data2;
+	uint16_t data3;
+	uint8_t  data4[8];
+};
+
+struct device_info {
+	struct guid_struct host_guid;
+	bool host_guid_is_set;
+	const char *host_id;
+	const char *comment;
+	struct dentry *dir;
+	struct dentry *pcapng;
+	struct dentry *text;
+};
+
+struct statistics {
+	atomic64_t process;
+	atomic64_t socket;
+	atomic64_t packet;
+};
+
+struct reader_info {
+	unsigned int snaplen;
+	struct timespec boot_time;
+	struct timespec start_time;
+	struct statistics delivered;
+	struct statistics dropped;
+	atomic64_t filtered;
+};
+
+struct process_event {
+	union {
+		struct mm_struct *mm;
+		char *comm;
+	};
+	int event;
+	pid_t pid;
+	pid_t ppid;
+	pid_t tgid;
+	uid_t uid;
+	uid_t euid;
+	uid_t loginuid;
+	gid_t gid;
+	int retval;
+};
+
+struct socket_event {
+	unsigned long sock;
+	int event;
+	pid_t pid;
+	pid_t ppid;
+	pid_t tgid;
+	uid_t uid;
+	gid_t gid;
+};
+
+struct packet_event {
+	unsigned long sock;
+	int dir;
+	int len;
+	pid_t pid;
+	struct sock *sk;
+	struct sk_buff *skb;
+};
+
+struct user_event {
+	void *data;
+};
+
+struct hone_event {
+	int type;
+	union {
+		atomic_t users;
+		struct hone_event *next;
+	};
+	struct timespec ts;
+	union {
+		struct process_event process;
+		struct socket_event socket;
+		struct packet_event packet;
+		struct user_event user;
+	};
+};
+
+struct packet_args {
+	struct sock *sk;
+	struct sk_buff *skb;
+};
+
+#define STATISTICS_INIT {ATOMIC64_INIT(0), ATOMIC64_INIT(0), ATOMIC64_INIT(0)}
+#define DEFINE_STATISTICS(name) struct statistics name = STATISTICS_INIT
+
+static inline void init_statistics(struct statistics *stats)
+{
+	atomic64_set(&stats->process, 0);
+	atomic64_set(&stats->socket, 0);
+	atomic64_set(&stats->packet, 0);
+}
+
+extern void get_hone_statistics(struct statistics *received,
+				struct statistics *dropped,
+				struct timespec *ts);
+
+void free_hone_event(struct hone_event *event);
+
+int hone_notify_init(void);
+int hone_fs_init(void);
+
+int process_notifier_notify(unsigned long event, struct task_struct *task);
+int sock_notifier_notify(unsigned long event, struct sock *sk);
+int packet_notifier_notify(unsigned long event, struct packet_args *pargs);
+int hone_notifier_register(struct notifier_block *nb);
+int hone_notifier_unregister(struct notifier_block *nb);
+
+struct hone_event *__alloc_socket_event(unsigned long v, int val,
+					struct task_struct *task, gfp_t flags);
+struct hone_event *__alloc_process_event(struct task_struct *task, int type,
+                                         gfp_t flags);
+
+static inline void get_hone_event(struct hone_event *event)
+{
+	BUG_ON(unlikely(!atomic_read(&event->users)));
+	atomic_inc(&event->users);
+}
+
+static inline void put_hone_event(struct hone_event *event)
+{
+	BUG_ON(unlikely(!atomic_read(&event->users)));
+	if (atomic_dec_and_test(&event->users))
+		free_hone_event(event);
+}
+
+static inline void put_sock(struct sock *sk)
+{
+	if (sk->sk_state == TCP_TIME_WAIT)
+		inet_twsk_put(inet_twsk(sk));
+	else
+		sock_put(sk);
+}
+
+struct sock *lookup_v4_sock(const struct sk_buff *skb,
+			const struct net_device *indev);
+struct sock *lookup_v6_sock(const struct sk_buff *skb,
+			const struct net_device *indev);
+
+#endif
diff --git a/security/hone/hone_event.c b/security/hone/hone_event.c
new file mode 100644
index 0000000..b2339bc
--- /dev/null
+++ b/security/hone/hone_event.c
@@ -0,0 +1,625 @@
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/fdtable.h>
+#include <linux/fs.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <linux/ipv6.h>
+#include <linux/ip.h>
+
+#include <linux/hone.h>
+
+#include "hone.h"
+#include "hone_mmutil.h"
+#include "hone_pcapng.h"
+#include "hone_ringbuf.h"
+
+static struct device_info devinfo = {
+	.comment = NULL,
+	.host_id = NULL,
+	.host_guid_is_set = false
+};
+
+#ifndef CONFIG_HONE_DEFAULT_PAGEORDER
+	#ifdef CONFIG_64BIT
+		#define CONFIG_HONE_DEFAULT_PAGEORDER 3
+	#else
+		#define CONFIG_HONE_DEFAULT_PAGEORDER 2
+	#endif
+#endif
+
+static unsigned int pageorder = CONFIG_HONE_DEFAULT_PAGEORDER;
+#define size_of_pages(order) (PAGE_SIZE << (order))
+#define READ_BUFFER_PAGE_ORDER 5
+#define READ_BUFFER_SIZE size_of_pages(READ_BUFFER_PAGE_ORDER)
+
+struct hone_reader {
+	struct semaphore sem;
+	struct ring_buf ringbuf;
+	struct notifier_block nb;
+	struct reader_info info;
+	atomic_t flags;
+	char *buf;
+	struct sock *filter_sk;
+	struct hone_event *event;
+	size_t length, offset;
+	wait_queue_head_t event_wait_queue;
+
+	unsigned int (*format)(const struct device_info*,
+			const struct reader_info*,
+			struct hone_event *,
+			char *, unsigned int);
+};
+
+static struct hone_event head_event = {HONE_USER_HEAD, {ATOMIC_INIT(1)} };
+static struct hone_event tail_event = {HONE_USER_TAIL, {ATOMIC_INIT(1)} };
+
+#define reader_will_block(rdr)					\
+	(ring_is_empty(&(rdr)->ringbuf) && !(rdr)->event &&	\
+	 !(atomic_read(&(rdr)->flags) & READER_RESTART))
+
+static unsigned int format_as_text(const struct device_info *devinfo,
+				const struct reader_info *info,
+				struct hone_event *event, char *buf,
+				unsigned int buflen)
+{
+	static const char * const event_names[] = {
+		"????", "FORK", "EXEC", "EXIT", "KTHD"};
+	unsigned int n = 0;
+
+#define printbuf(fmt, ...)						\
+	({								\
+		n += snprintf(buf + n, buflen - n, fmt, ##__VA_ARGS__); \
+		if (n >= buflen)					\
+			goto out_long;					\
+		n;							\
+	})
+
+	switch (event->type) {
+	case HONE_PROCESS:
+	{
+		struct process_event *pev = &event->process;
+
+		printbuf("%lu.%09lu %s %d %d %d %d\n",
+			event->ts.tv_sec, event->ts.tv_nsec,
+			event_names[pev->event], pev->pid, pev->ppid, pev->euid,
+			pev->gid);
+
+		if (pev->mm) {
+			n--;
+			if (pev->event == PROC_KTHD)
+				printbuf(" [%s]", pev->comm);
+			else {
+				char *path, *argv;
+
+				printbuf(" \"");
+				path = mm_path(pev->mm, buf + n,
+					buflen - n - 3);
+
+				if (path) {
+					int pathlen = strlen(path);
+
+					memmove(buf + n, path, pathlen);
+					n += pathlen;
+				}
+
+				printbuf("\" ");
+				argv = buf + n;
+				n += mm_argv(pev->mm, buf + n, buflen - n - 1);
+				for ( ; argv < buf + n; argv++) {
+					if (*argv == '\0')
+						*argv = ' ';
+				}
+			}
+			printbuf("\n");
+		}
+		break;
+	}
+	case HONE_SOCKET:
+	{
+		struct socket_event *sockev = &event->socket;
+
+		printbuf("%lu.%09lu SOCK %c %d %d %d %d %08lx\n",
+			event->ts.tv_sec, event->ts.tv_nsec,
+			sockev->event ? 'C' : 'O', sockev->pid, sockev->ppid,
+			sockev->uid, sockev->gid, sockev->sock & 0xFFFFFFFF);
+	}
+		break;
+	case HONE_PACKET:
+	{
+		int offset;
+		struct iphdr _iph, *iph;
+
+		offset = skb_network_offset(event->packet.skb);
+		iph = skb_header_pointer(event->packet.skb, offset,
+					sizeof(_iph), &_iph);
+
+		printbuf("%lu.%09lu PAKT %c %08lx %u", event->ts.tv_sec,
+			event->ts.tv_nsec, event->packet.dir ? 'I' : 'O',
+			event->packet.sock & 0xFFFFFFFF, event->packet.pid);
+		if (!iph)
+			printbuf(" ? ? -> ?");
+		else if (iph->version == 4) {
+			if (iph->protocol == IPPROTO_TCP ||
+				iph->protocol == IPPROTO_UDP) {
+				struct udphdr _uh, *uh;
+
+				uh = skb_header_pointer(
+					event->packet.skb,
+					offset + (iph->ihl << 2),
+					sizeof(_uh), &_uh);
+				if (uh) {
+					printbuf(" %sv4 %pI4:%d -> %pI4:%d",
+						iph->protocol == IPPROTO_TCP
+						? "TCP" : "UDP",
+						&iph->saddr, ntohs(uh->source),
+						&iph->daddr, ntohs(uh->dest));
+				} else {
+					printbuf(" %sv4 ? -> ?",
+						iph->protocol == IPPROTO_TCP ?
+						"TCP" : "UDP");
+				}
+			} else {
+				printbuf(" %u %pI4 -> %pI4", iph->protocol,
+					&iph->saddr, &iph->daddr);
+			}
+		} else if (iph->version == 6) {
+			struct ipv6hdr _iph6, *iph6;
+
+			iph6 = skb_header_pointer(event->packet.skb, offset,
+						sizeof(_iph6), &_iph6);
+			if (iph6->nexthdr == IPPROTO_TCP ||
+				iph6->nexthdr == IPPROTO_UDP) {
+				struct udphdr _uh, *uh;
+
+				uh = skb_header_pointer(
+					event->packet.skb,
+					offset + sizeof(struct ipv6hdr),
+					sizeof(_uh), &_uh);
+				if (uh) {
+					printbuf(" %sv6 %pI6:%d -> %pI6:%d",
+						iph6->nexthdr == IPPROTO_TCP ?
+						"TCP" : "UDP",
+						&iph6->saddr, ntohs(uh->source),
+						&iph6->daddr, ntohs(uh->dest));
+				} else {
+					printbuf(" %sv6 ? -> ?",
+						iph6->nexthdr == IPPROTO_TCP ?
+						"TCP" : "UDP");
+				}
+			} else {
+				printbuf(" %u %pI6 -> %pI6", iph6->nexthdr,
+					&iph6->saddr, &iph6->daddr);
+			}
+		} else {
+			printbuf(" ?.%d ? -> ?", iph->version);
+		}
+		printbuf(" %u\n", event->packet.skb->len);
+	}
+	break;
+	case HONE_USER_HEAD:
+		if (devinfo->host_guid_is_set)
+			printbuf("%lu.%09lu HEAD %lu.%09lu {" GUID_FMT "}\n",
+				info->start_time.tv_sec,
+				info->start_time.tv_nsec,
+				info->boot_time.tv_sec, info->boot_time.tv_nsec,
+				GUID_TUPLE(&devinfo->host_guid));
+		else
+			printbuf("%lu.%09lu HEAD %lu.%09lu\n",
+				info->start_time.tv_sec,
+				info->start_time.tv_nsec,
+				info->boot_time.tv_sec,
+				info->boot_time.tv_nsec);
+		break;
+	case HONE_USER_TAIL:
+		printbuf("%lu.%09lu TAIL\n",
+			info->start_time.tv_sec, info->start_time.tv_nsec);
+		break;
+	default:
+		printbuf("%lu.%09lu ???? %d\n",
+			 event->ts.tv_sec, event->ts.tv_nsec, event->type);
+		break;
+
+	}
+
+#undef printbuf
+	return n;
+out_long:
+	snprintf(buf + buflen - 5, 5, "...\n");
+	return buflen;
+}
+
+static void free_hone_reader(struct hone_reader *reader)
+{
+	if (reader) {
+		if (reader->ringbuf.data) {
+			free_pages((unsigned long) (reader->ringbuf.data),
+				   reader->ringbuf.pageorder);
+			reader->ringbuf.data = NULL;
+		}
+		if (reader->buf) {
+			free_pages((unsigned long) (reader->buf),
+				   READ_BUFFER_PAGE_ORDER);
+			reader->buf = NULL;
+		}
+		kfree(reader);
+	}
+}
+
+static struct hone_reader *alloc_hone_reader(void)
+{
+	struct hone_reader *reader;
+	struct ring_buf *ring;
+
+	reader = kzalloc(sizeof(*reader), GFP_KERNEL);
+	if (!reader)
+		goto alloc_failed;
+
+	reader->buf = (typeof(reader->buf)) __get_free_pages(
+		GFP_KERNEL | __GFP_ZERO, READ_BUFFER_PAGE_ORDER);
+	if (!reader->buf)
+		goto alloc_failed;
+
+	ring = &reader->ringbuf;
+	ring->pageorder = pageorder;
+
+	ring->data = (typeof(ring->data)) __get_free_pages(
+		GFP_KERNEL | __GFP_ZERO, ring->pageorder);
+	if (!ring->data)
+		goto alloc_failed;
+	ring->length = size_of_pages(ring->pageorder) / sizeof(*(ring->data));
+
+	reader->format = format_as_pcapng;
+
+	atomic_set(&reader->flags, READER_HEAD | READER_INIT);
+	sema_init(&reader->sem, 1);
+	init_waitqueue_head(&reader->event_wait_queue);
+	return reader;
+
+alloc_failed:
+	free_hone_reader(reader);
+	return NULL;
+}
+
+static void inc_stats_counter(struct statistics *stats, int type)
+{
+	atomic64_t *counter;
+
+	switch(type) {
+	case HONE_PROCESS:
+		counter = &stats->process;
+		break;
+	case HONE_SOCKET:
+		counter = &stats->socket;
+		break;
+	case HONE_PACKET:
+		counter = &stats->packet;
+		break;
+	default:
+		return;
+	}
+	atomic64_inc(counter);
+}
+
+static inline int enqueue_event(struct hone_reader *reader,
+				struct hone_event *event)
+{
+	/* Ignore threads for now */
+	if (event->type == HONE_PROCESS &&
+		event->process.pid != event->process.tgid)
+		return 0;
+	/* Filter out packets for local socket, if set */
+	if (event->type == HONE_PACKET && reader->filter_sk &&
+	    event->packet.sock == (unsigned long) reader->filter_sk) {
+		atomic64_inc(&reader->info.filtered);
+		return 0;
+	}
+
+	get_hone_event(event);
+	if (ring_append(&reader->ringbuf, event)) {
+		inc_stats_counter(&reader->info.dropped, event->type);
+		put_hone_event(event);
+		return 0;
+	}
+	return 1;
+}
+
+static int hone_event_handler(struct notifier_block *nb, unsigned long val,
+			      void *v)
+{
+	struct hone_reader *reader =
+		container_of(nb, struct hone_reader, nb);
+
+	if (enqueue_event(reader, v))
+		wake_up_interruptible_all(&reader->event_wait_queue);
+	return 0;
+}
+
+static struct hone_event *__add_files(struct hone_reader *reader,
+				      struct hone_event *event,
+				      struct task_struct *task)
+{
+	struct files_struct *files;
+	struct file *file;
+	struct fdtable *fdt;
+	struct hone_event *sk_event;
+	struct socket *sock;
+	struct sock *sk;
+	unsigned long flags, set;
+	int i, fd, err;
+
+	files = get_files_struct(task);
+	if (!files)
+		return event;
+
+	spin_lock_irqsave(&files->file_lock, flags);
+
+	fdt = files_fdtable(files);
+	if (!fdt)
+		goto out;
+
+	for (i = 0; (fd = i * BITS_PER_LONG) < fdt->max_fds; i++) {
+		for (set = fdt->open_fds[i]; set; set >>= 1, fd++) {
+			if (!(set & 1))
+				continue;
+			file = fdt->fd[fd];
+			if (!file)
+				continue;
+
+			sock = sock_from_file(file, &err);
+			if (!sock)
+				continue;
+			sk = sock->sk;
+			if (!sk || (sk->sk_family != PF_INET &&
+				    sk->sk_family != PF_INET6))
+				continue;
+
+			sk_event = __alloc_socket_event((unsigned long) sk,
+							0, task, GFP_ATOMIC);
+			if (sk_event) {
+				sk_event->next = event;
+				event = sk_event;
+				event->ts = task->start_time;
+			} else {
+				atomic64_inc(&reader->info.dropped.socket);
+			}
+		}
+	}
+out:
+	spin_unlock_irqrestore(&files->file_lock, flags);
+	put_files_struct(files);
+	return event;
+}
+
+#define prev_task(p) \
+	list_entry_rcu((p)->tasks.prev, struct task_struct, tasks)
+
+static struct hone_event *add_current_tasks(struct hone_reader *reader,
+					    struct hone_event *event)
+{
+	struct hone_event *proc_event;
+	struct task_struct *task;
+
+	rcu_read_lock();
+	for (task = &init_task; (task = prev_task(task)) != &init_task; ) {
+		if (task->flags & PF_EXITING)
+			continue;
+		event = __add_files(reader, event, task);
+		proc_event =  __alloc_process_event(
+			task, task->flags & PF_FORKNOEXEC ?
+			PROC_FORK : PROC_EXEC,
+			GFP_ATOMIC);
+		if (proc_event) {
+			proc_event->next = event;
+			event = proc_event;
+			event->ts = task->start_time;
+		} else {
+			atomic64_inc(&reader->info.dropped.process);
+		}
+	}
+	rcu_read_unlock();
+	return event;
+}
+
+static void free_initial_events(struct hone_reader *reader)
+{
+	struct hone_event *event, *next;
+
+	for (event = reader->event; event; event = next) {
+		next = event->next;
+		free_hone_event(event);
+	}
+	reader->event = NULL;
+}
+
+static void add_initial_events(struct hone_reader *reader)
+{
+	free_initial_events(reader);
+	reader->event = add_current_tasks(reader, NULL);
+}
+
+static int hone_open(struct inode *inode, struct file *file)
+{
+	struct hone_reader *reader;
+	int err = -ENOMEM;
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		pr_err("no readonly failed\n");
+		return -EINVAL;
+	}
+
+	reader = alloc_hone_reader();
+	if (!reader) {
+		pr_err("reader alloc failed\n");
+		goto reader_failed;
+	}
+
+	if (file->f_dentry == devinfo.text)
+		reader->format = format_as_text;
+	file->private_data = reader;
+
+	getboottime(&reader->info.boot_time);
+	ktime_get_ts(&reader->info.start_time);
+	init_statistics(&reader->info.delivered);
+	init_statistics(&reader->info.dropped);
+	reader->nb.notifier_call = hone_event_handler;
+	err = hone_notifier_register(&reader->nb);
+	if (err) {
+		pr_err("hone_notifier_register() failed with error %d\n", err);
+		goto register_failed;
+	}
+	return 0;
+
+register_failed:
+	free_hone_reader(reader);
+reader_failed:
+	return err;
+}
+
+static int hone_release(struct inode *inode, struct file *file)
+{
+	struct hone_reader *reader = file->private_data;
+	struct hone_event *event;
+
+	hone_notifier_unregister(&reader->nb);
+	file->private_data = NULL;
+	while ((event = ring_pop(&reader->ringbuf)))
+		put_hone_event(event);
+	if (reader->filter_sk) {
+		sock_put(reader->filter_sk);
+		reader->filter_sk = NULL;
+	}
+	free_initial_events(reader);
+	free_hone_reader(reader);
+	return 0;
+}
+
+static ssize_t hone_read(struct file *file, char __user *buffer,
+			size_t length, loff_t *offset)
+{
+	struct hone_reader *reader = file->private_data;
+	size_t n, copied = 0;
+
+	if (!length)
+		return 0;
+
+	do {
+		while (!reader->offset && reader_will_block(reader)) {
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+			if (wait_event_interruptible(
+					reader->event_wait_queue,
+					!reader_will_block(reader)))
+				return -EINTR;
+		}
+
+		if (file->f_flags & O_NONBLOCK) {
+			if (down_trylock(&reader->sem))
+				return -EAGAIN;
+		} else if (down_interruptible(&reader->sem)) {
+			return -EINTR;
+		}
+
+		while (copied < length) {
+			if (!reader->offset) {
+				int flags;
+				struct hone_event *event;
+
+				void (*free_event)(struct hone_event *);
+
+				flags = atomic_read(&reader->flags);
+				if (flags & READER_TAIL) {
+					atomic_clear_mask(READER_TAIL,
+							   &reader->flags);
+					 event = &tail_event;
+					 free_event = NULL;
+				} else if (flags & READER_FINISH) {
+					if (!copied)
+						atomic_clear_mask(READER_FINISH,
+								&reader->flags);
+					up(&reader->sem);
+					return copied;
+				} else if (flags & READER_HEAD) {
+					atomic_clear_mask(READER_HEAD,
+							  &reader->flags);
+					event = &head_event;
+					free_event = NULL;
+				} else if (flags & READER_INIT) {
+					atomic_clear_mask(READER_INIT,
+							  &reader->flags);
+					add_initial_events(reader);
+					continue;
+				} else if (reader->event) {
+					event = reader->event;
+					reader->event = event->next;
+					free_event = free_hone_event;
+				} else {
+					event = ring_pop(&reader->ringbuf);
+					free_event = put_hone_event;
+				}
+
+				if (!event)
+					break;
+				reader->length = reader->format(
+					&devinfo, &reader->info,
+					event, reader->buf, READ_BUFFER_SIZE);
+				inc_stats_counter(&reader->info.delivered,
+						event->type);
+				if (free_event)
+					free_event(event);
+			}
+			n = min(reader->length - reader->offset,
+				length - copied);
+			if (copy_to_user(buffer + copied,
+					 reader->buf + reader->offset, n)) {
+				up(&reader->sem);
+				return -EFAULT;
+			}
+			copied += n;
+			reader->offset += n;
+			if (reader->offset >= reader->length)
+				reader->offset = 0;
+		}
+		up(&reader->sem);
+	} while (!copied);
+	return copied;
+}
+
+static unsigned int hone_poll(struct file *file,
+			struct poll_table_struct *wait)
+{
+	struct hone_reader *reader = file->private_data;
+
+	poll_wait(file, &reader->event_wait_queue, wait);
+	if (!reader_will_block(reader))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static const struct file_operations hone_ops = {
+	.open = hone_open,
+	.read = hone_read,
+	.release = hone_release,
+	.poll = hone_poll,
+};
+
+int __init hone_fs_init(void)
+{
+	devinfo.dir = securityfs_create_dir("hone", NULL);
+	if (IS_ERR(devinfo.dir))
+		return -1;
+	devinfo.pcapng = securityfs_create_file("pcapng", 0600,
+					devinfo.dir, NULL, &hone_ops);
+	if (!devinfo.pcapng) {
+		pr_err("could not create hone output file\n");
+		return -1;
+	}
+
+	devinfo.text = securityfs_create_file("text", 0600,
+					devinfo.dir, NULL, &hone_ops);
+	if (!devinfo.text) {
+		pr_err("could not create hone output file\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/security/hone/hone_lsm.c b/security/hone/hone_lsm.c
new file mode 100644
index 0000000..4f7e785
--- /dev/null
+++ b/security/hone/hone_lsm.c
@@ -0,0 +1,183 @@
+#include <linux/security.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/sched.h>
+#include <linux/binfmts.h>
+#include <linux/netfilter.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+#include "hone.h"
+
+void hone_task_post_create(struct task_struct *task)
+{
+	process_notifier_notify(PROC_FORK, task);
+}
+
+void hone_task_free(struct task_struct *task)
+{
+	process_notifier_notify(PROC_EXIT, task);
+}
+
+void hone_bprm_committing_creds(struct linux_binprm *bprm)
+{
+	process_notifier_notify(PROC_EXEC, current);
+}
+
+int hone_socket_post_create(struct socket *sock, int family,
+			int type, int protocol, int kern)
+{
+	if (likely(sock->sk)) {
+		sock->sk->sk_protinfo = (void *)(unsigned long)
+			(current->pid == current->tgid ?
+				current->pid : current->tgid);
+		sock_notifier_notify(0, sock->sk);
+	}
+	return 0;
+}
+
+int hone_socket_shutdown(struct socket *sock, int how)
+{
+	sock_notifier_notify(0xFFFFFFFF, sock->sk);
+	return 0;
+}
+
+int hone_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	struct packet_args pargs = {sk, skb};
+
+	switch (sk->sk_family) {
+	case PF_INET:
+	case PF_INET6:
+		packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	}
+	return 0;
+}
+
+static struct security_operations hone_ops = {
+	.name = "hone",
+
+	/* Process events. */
+	.task_post_create	= hone_task_post_create,
+	.task_free		= hone_task_free,
+	.bprm_committing_creds	= hone_bprm_committing_creds,
+
+	/* Socket events. */
+	.socket_post_create	= hone_socket_post_create,
+	.socket_shutdown	= hone_socket_shutdown,
+};
+
+static unsigned int nf_hook_v4_in(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct sock *sk = lookup_v4_sock(skb, indev);
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	if (sk)
+		put_sock(sk);
+	return NF_ACCEPT;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static unsigned int nf_hook_v6_in(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct sock *sk = lookup_v6_sock(skb, indev);
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	if (sk)
+		put_sock(sk);
+	return NF_ACCEPT;
+}
+#endif
+
+static unsigned int nf_hook_out(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct packet_args pargs = {skb->sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_OUT, &pargs);
+	return NF_ACCEPT;
+}
+
+static struct nf_hook_ops nf_inet_hooks[] = {
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_v4_in,
+		.owner = THIS_MODULE,
+		.pf = PF_INET,
+		.hooknum = NF_INET_LOCAL_IN,
+		.priority = INT_MAX,
+	},
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_out,
+		.owner = THIS_MODULE,
+		.pf = PF_INET,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = INT_MAX,
+	},
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_v6_in,
+		.owner = THIS_MODULE,
+		.pf = PF_INET6,
+		.hooknum = NF_INET_LOCAL_IN,
+		.priority = INT_MAX,
+	},
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_out,
+		.owner = THIS_MODULE,
+		.pf = PF_INET6,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = INT_MAX,
+	},
+#endif /* CONFIG_IPV6 */
+};
+
+void hone_raw_rcv_handler(struct sock *sk, struct sk_buff *skb)
+{
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+}
+
+static __init int hone_net_init(void)
+{
+	int err = nf_register_hooks(nf_inet_hooks, ARRAY_SIZE(
+					nf_inet_hooks));
+	if (err) {
+		pr_err("netfilter hook registration failed (%d)\n", err);
+		return -1;
+	}
+	return 0;
+}
+
+static __init int hone_init(void)
+{
+	int ret;
+
+	if (!security_module_enable(&hone_ops))
+		return 0;
+
+	if (register_security(&hone_ops))
+		panic("hone: kernel registration failed\n");
+
+	ret = hone_notify_init() || hone_net_init() || hone_fs_init();
+	if (!ret)
+		pr_info("hone: initialized\n");
+	return ret;
+}
+
+late_initcall(hone_init);
diff --git a/security/hone/hone_mmutil.c b/security/hone/hone_mmutil.c
new file mode 100644
index 0000000..bfdb72b
--- /dev/null
+++ b/security/hone/hone_mmutil.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Much of the code below is based on procfs code.
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+
+static int __mm_argv(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *pos;
+	unsigned long addr, size;
+
+	if (!buflen)
+		return 0;
+
+	pos = buf;
+	addr = mm->arg_start;
+	size = mm->arg_end - mm->arg_start;
+	if (size > buflen)
+		size = buflen;
+	while (size) {
+		struct page *page;
+		int bytes, offset;
+		void *maddr;
+
+		if (get_user_pages(NULL, mm, addr, 1, 0, 0, &page, NULL) <= 0)
+			break;
+
+		bytes = size;
+		offset = addr & (PAGE_SIZE - 1);
+		if (bytes > (PAGE_SIZE - offset))
+			bytes = PAGE_SIZE - offset;
+
+		maddr = kmap(page);
+		memcpy(pos, maddr + offset, bytes);
+		kunmap(page);
+		put_page(page);
+
+		size -= bytes;
+		pos += bytes;
+		addr += bytes;
+	}
+
+	if (pos == buf) {
+		*pos = '\0';
+		pos++;
+	} else if (*(pos - 1))
+		*(pos - 1) = '\0';
+	return pos - buf;
+}
+
+int mm_argv(struct mm_struct *mm, char *buf, int buflen)
+{
+	int argvlen;
+
+	down_read(&mm->mmap_sem);
+	argvlen = __mm_argv(mm, buf, buflen - 1);
+	up_read(&mm->mmap_sem);
+	buf[argvlen] = '\0';
+	return argvlen;
+}
+
+static char *__exe_path(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *path = NULL;
+
+	if (mm->exe_file) {
+		struct vfsmount *mnt;
+		struct dentry *dentry;
+
+		mnt = mntget(mm->exe_file->f_path.mnt);
+		dentry = dget(mm->exe_file->f_path.dentry);
+
+		if (mnt && dentry) {
+			struct path _p = {mnt, dentry};
+
+			path = d_path(&_p, buf, buflen);
+			dput(dentry);
+			mntput(mnt);
+		}
+	}
+	return path;
+}
+
+char *mm_path(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *path;
+
+	down_read(&mm->mmap_sem);
+	path = __exe_path(mm, buf, buflen);
+	up_read(&mm->mmap_sem);
+	return path;
+}
diff --git a/security/hone/hone_mmutil.h b/security/hone/hone_mmutil.h
new file mode 100644
index 0000000..321e7e6
--- /dev/null
+++ b/security/hone/hone_mmutil.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#ifndef _MMUTIL_H
+#define _MMUTIL_H
+
+#include <linux/mm_types.h>
+
+char *mm_path(struct mm_struct *mm, char *buf, int buflen);
+char *mm_path_old(struct mm_struct *mm, char *buf, int buflen);
+int mm_argv(struct mm_struct *mm, char *buf, int buflen);
+
+#endif /* _MMUTIL_H */
diff --git a/security/hone/hone_notify.c b/security/hone/hone_notify.c
new file mode 100644
index 0000000..08c2f8f
--- /dev/null
+++ b/security/hone/hone_notify.c
@@ -0,0 +1,450 @@
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/skbuff.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/uidgid.h>
+#include <net/sock.h>
+#include <linux/hone.h>
+
+#include "hone.h"
+
+/* Output */
+static RAW_NOTIFIER_HEAD(hone_notify_notifier_list);
+static DEFINE_RWLOCK(hone_notify_notifier_lock);
+
+/* Process list/Process lock. */
+static RAW_NOTIFIER_HEAD(hone_process_notifier_list);
+static DEFINE_RWLOCK(hone_process_notifier_lock);
+
+/* Socket list/Socket lock. */
+static RAW_NOTIFIER_HEAD(hone_socket_notifier_list);
+static DEFINE_RWLOCK(hone_socket_notifier_lock);
+
+/* Packet list/Packet lock. */
+static RAW_NOTIFIER_HEAD(hone_packet_notifier_list);
+static DEFINE_RWLOCK(hone_packet_notifier_lock);
+
+static struct kmem_cache *hone_cache;
+static struct kmem_cache *mmput_cache;
+static struct workqueue_struct *mmput_wq;
+struct delayed_mmput_struct {
+	struct work_struct ws;
+	struct mm_struct *mm;
+};
+
+static struct timespec start_time;
+static DEFINE_STATISTICS(hone_received);
+static DEFINE_STATISTICS(hone_dropped);
+
+#define copy_atomic64(dst, src) atomic64_set(&(dst), atomic64_read(&(src)))
+
+static void copy_statistics(const struct statistics *src,
+			struct statistics *dst)
+{
+	copy_atomic64(dst->process, src->process);
+	copy_atomic64(dst->socket, src->socket);
+	copy_atomic64(dst->packet, src->packet);
+}
+
+void get_hone_statistics(struct statistics *received,
+			struct statistics *dropped, struct timespec *ts)
+{
+	if (received)
+		copy_statistics(&hone_received, received);
+	if (dropped)
+		copy_statistics(&hone_dropped, dropped);
+	if (ts)
+		*ts = start_time;
+}
+
+#define notifier_call_chain_empty() \
+	(rcu_dereference(hone_notify_notifier_list.head) == NULL)
+
+static inline int hone_notifier_notify(struct hone_event *event)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_notify_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_notify_notifier_list, 0, event);
+	read_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+static void delayed_mmput(struct work_struct *work)
+{
+	struct delayed_mmput_struct *w = (struct delayed_mmput_struct *)work;
+
+	mmput(w->mm);
+	kmem_cache_free(mmput_cache, w);
+}
+
+static bool queue_mmput(struct mm_struct *mm)
+{
+	struct delayed_mmput_struct *delayed_mm =
+		kmem_cache_zalloc(mmput_cache, GFP_ATOMIC);
+
+	if (!delayed_mm)
+		return false;
+
+	delayed_mm->mm = mm;
+	INIT_WORK((struct work_struct *)delayed_mm,
+		delayed_mmput);
+
+	return queue_work(mmput_wq, (struct work_struct *)delayed_mm);
+}
+
+void free_hone_event(struct hone_event *event)
+{
+	if (event->type == HONE_PROCESS) {
+		if (event->process.mm) {
+			if (event->process.event == PROC_KTHD) {
+				kfree(event->process.comm);
+			} else {
+				if (unlikely(!queue_mmput(event->process.mm)))
+					BUG();
+			}
+			event->process.mm = NULL;
+		}
+	}
+	kmem_cache_free(hone_cache, event);
+}
+
+struct hone_event *alloc_hone_event(unsigned int type, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = kmem_cache_zalloc(hone_cache, flags);
+	if (!event)
+		return NULL;
+	event->type = type;
+	ktime_get_ts(&event->ts);
+	atomic_set(&event->users, 1);
+	return event;
+}
+
+struct hone_event *__alloc_process_event(
+	struct task_struct *task, int type, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = alloc_hone_event(HONE_PROCESS, flags);
+	if (event) {
+		struct process_event *pev = &event->process;
+		const struct cred *cred;
+
+		pev->event = (type != PROC_EXIT && task->flags & PF_KTHREAD) ?
+			PROC_KTHD : type;
+		if (unlikely(type == PROC_EXIT))
+			pev->retval = task->exit_code;
+		pev->pid = task->pid;
+		pev->ppid = task->real_parent->pid;
+		pev->tgid = task->tgid;
+		if (pev->event == PROC_KTHD) {
+			pev->comm = kstrndup(task->comm,
+					sizeof(task->comm), flags);
+			BUG_ON(unlikely(!pev->comm));
+		} else if (type == PROC_EXEC ||
+			(type == PROC_FORK && pev->ppid == 1)) {
+			pev->mm = get_task_mm(task);
+			BUG_ON(unlikely(!pev->mm));
+		}
+		pev->loginuid = __kuid_val(task->loginuid);
+		rcu_read_lock();
+		cred = __task_cred(task);
+		if (unlikely(!cred)) {
+			pev->uid = -1;
+			pev->euid = -1;
+		} else {
+			pev->uid = __kuid_val(cred->uid);
+			pev->euid = __kuid_val(cred->euid);
+		}
+		pev->gid = __kgid_val(cred->egid);
+		rcu_read_unlock();
+	}
+	return event;
+}
+
+int process_notifier_notify(unsigned long event, struct task_struct *task)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_process_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_process_notifier_list, event,
+					task);
+	read_unlock_irqrestore(&hone_process_notifier_lock, flags);
+	return result;
+}
+
+static int process_event_handler(struct notifier_block *nb,
+				 unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+
+	event = __alloc_process_event(v, val, GFP_ATOMIC);
+	if (event) {
+		atomic64_inc(&hone_received.process);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.process);
+	}
+	return 0;
+}
+
+static struct notifier_block process_nb = {
+	.notifier_call = process_event_handler,
+};
+
+/* Process sockets below here. */
+struct hone_event *__alloc_socket_event(unsigned long sock, int type,
+					struct task_struct *task, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = alloc_hone_event(HONE_SOCKET, flags);
+	if (event) {
+		struct socket_event *sockev = &event->socket;
+		const struct cred *cred;
+
+		/* Store pid with the socket */
+		((struct sock *)sock)->sk_protinfo =
+			(void *)(unsigned long)task->pid;
+		sockev->sock = sock;
+		sockev->event = type;
+		sockev->pid = task->pid;
+		sockev->ppid = task->real_parent->pid;
+		sockev->tgid = task->tgid;
+		rcu_read_lock();
+		cred = __task_cred(task);
+		if (unlikely(!cred)) {
+			sockev->uid = -1;
+			sockev->gid = -1;
+		} else {
+			sockev->uid = __kuid_val(cred->euid);
+			sockev->gid = __kgid_val(cred->egid);
+		}
+		rcu_read_unlock();
+	}
+	return event;
+}
+
+static int socket_event_handler(struct notifier_block *nb,
+				unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+	event = __alloc_socket_event((unsigned long) v, val, current,
+				GFP_ATOMIC);
+	if (event) {
+		atomic64_inc(&hone_received.socket);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.socket);
+	}
+	return 0;
+}
+
+static struct notifier_block socket_nb = {
+	.notifier_call = socket_event_handler,
+};
+
+int sock_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_chain_register(&hone_socket_notifier_list, nb);
+	write_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+int sock_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_socket_notifier_list, nb);
+	write_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+inline int sock_notifier_notify(unsigned long event, struct sock *sk)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_socket_notifier_list, event, sk);
+	read_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+static int packet_event_handler(struct notifier_block *nb,
+				unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+
+	event = alloc_hone_event(HONE_PACKET, GFP_ATOMIC);
+	if (event) {
+		struct packet_args *args = (typeof(args)) v;
+
+		event->packet.sock = (unsigned long) args->sk;
+		event->packet.sk = args->sk;
+		event->packet.pid =
+			(unsigned long)(args->sk ? args->sk->sk_protinfo : 0);
+		event->packet.skb = skb_clone(args->skb, GFP_ATOMIC);
+		event->packet.dir = (val == PKTNOT_PACKET_IN);
+		atomic64_inc(&hone_received.packet);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.packet);
+	}
+	return 0;
+}
+
+static struct notifier_block packet_nb = {
+	.notifier_call = packet_event_handler,
+};
+
+int packet_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_chain_register(&hone_packet_notifier_list, nb);
+	write_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+int packet_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_packet_notifier_list, nb);
+	write_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+int packet_notifier_notify(
+	unsigned long event, struct packet_args *pargs)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_packet_notifier_list,
+					event, pargs);
+	read_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+void register_notifiers(void)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_process_notifier_lock, flags);
+	/* TODO(pmoody): check return values. */
+	raw_notifier_chain_register(&hone_process_notifier_list,
+				&process_nb);
+	raw_notifier_chain_register(&hone_socket_notifier_list,
+				&socket_nb);
+	raw_notifier_chain_register(&hone_packet_notifier_list,
+				&packet_nb);
+	write_unlock_irqrestore(&hone_process_notifier_lock, flags);
+}
+
+void unregister_notifiers(void)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_process_notifier_lock, flags);
+	/* TODO(pmoody): check return values. */
+	raw_notifier_chain_unregister(&hone_process_notifier_list,
+				&process_nb);
+	raw_notifier_chain_unregister(&hone_socket_notifier_list,
+				&socket_nb);
+	raw_notifier_chain_unregister(&hone_packet_notifier_list,
+				&packet_nb);
+	write_unlock_irqrestore(&hone_process_notifier_lock, flags);
+}
+
+int hone_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_notify_notifier_lock, flags);
+	if (notifier_call_chain_empty())
+		register_notifiers();
+	result = raw_notifier_chain_register(&hone_notify_notifier_list, nb);
+	write_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+int hone_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_notify_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_notify_notifier_list, nb);
+	if (notifier_call_chain_empty())
+		unregister_notifiers();
+	write_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+int __init hone_notify_init(void)
+{
+	int err = -ENOMEM;
+
+	hone_cache = kmem_cache_create(
+		"hone_event", sizeof(struct hone_event), 0, 0, NULL);
+	if (!hone_cache) {
+		pr_err("kmem_cache_create() failed\n");
+		goto out_hone_cache;
+	}
+
+	mmput_cache = kmem_cache_create(
+		"hone_delayed_mmput", sizeof(struct delayed_mmput_struct),
+		0, 0, NULL);
+	if (!mmput_cache) {
+		pr_err("kmem_cache_create() failed on delayed_mm_cache\n");
+		goto out_mmput_cache;
+	}
+
+	mmput_wq = create_workqueue("hone_mmput");
+	if (!mmput_wq) {
+		err = -1;
+		goto out_workqueue;
+	}
+
+	return 0;
+
+out_workqueue:
+	kmem_cache_destroy(mmput_cache);
+out_mmput_cache:
+	kmem_cache_destroy(hone_cache);
+out_hone_cache:
+	return err;
+}
diff --git a/security/hone/hone_pcapng.c b/security/hone/hone_pcapng.c
new file mode 100644
index 0000000..0c5347c
--- /dev/null
+++ b/security/hone/hone_pcapng.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/rwsem.h>
+#include <linux/utsname.h>
+#include <linux/skbuff.h>
+#include <linux/hone.h>
+
+#include "hone.h"
+#include "hone_mmutil.h"
+
+#define PADLEN(x) (((x) & 0x3) ? 4 - ((x) & 3) : 0)
+#define OPT_SIZE(x) (((x) & 0x3) ? ((((x) >> 2) + 1) << 2) : x)
+#define block_set(BUF, TYPE, VAL) \
+	({ *((TYPE*) (BUF)) = (VAL); sizeof(TYPE); })
+
+static unsigned int block_opt_ptr(char *buf,
+		uint16_t code, const void *ptr, unsigned int length)
+{
+	char *pos = buf;
+	unsigned int padlen = PADLEN(length);
+
+	pos += block_set(pos, uint16_t, code);
+	pos += block_set(pos, uint16_t, length);
+	if (ptr)
+		memcpy(pos, ptr, length);
+	pos += length;
+	memset(pos, 0, padlen);
+	pos += padlen;
+	return (unsigned int) (pos - buf);
+}
+
+#define block_opt_t(BUF, CODE, TYPE, VAL) ({				\
+			TYPE _value = (VAL);				\
+			unsigned int _length =				\
+				block_opt_ptr(BUF, CODE, &_value,	\
+					sizeof(_value));		\
+			_length; })
+
+#define block_opt(BUF, CODE, VAL) block_opt_t(BUF, CODE, typeof(VAL), VAL)
+#define block_end_opt(BUF) block_opt_ptr(BUF, 0, NULL, 0)
+
+struct timestamp {
+	uint32_t ts_high;
+	uint32_t ts_low;
+};
+
+static void timespec_to_tstamp(struct timestamp *tstamp, struct timespec *ts)
+{
+	uint64_t val = (((uint64_t) ts->tv_sec) * 1000000LL) +
+		ts->tv_nsec / 1000;
+	tstamp->ts_high = val >> 32;
+	tstamp->ts_low = val & 0xFFFFFFFF;
+}
+
+/* Section Header Block {{{
+  0                   1                   2                   3
+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                   Block Type = 0x0A0D0D0A                     |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                      Byte-Order Magic                         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |          Major Version        |         Minor Version         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                                                               |
+   |                          Section Length                       |
+   |                                                               |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_sechdr_block(const struct device_info *devinfo,
+		char *buf, unsigned int buflen)
+{
+	static const char *user_app = "Hone ";
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+	int n;
+
+	/* Be sure to update this value if fields are added below. */
+#define SECHDR_BLOCK_MIN_LEN 56
+	if (buflen < SECHDR_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_SECTION_HDR_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0x1A2B3C4D);
+	pos += block_set(pos, uint16_t, 1);
+	pos += block_set(pos, uint16_t, 0);
+	pos += block_set(pos, uint64_t, -1);
+
+	n = buflen - (pos - buf) - 16;
+	if (devinfo->host_id && n > 0) {
+		snprintf(pos + 4, n, "%c%s", 0, devinfo->host_id);
+		pos += block_opt_ptr(pos, 257, NULL, strlen(pos + 5) + 1);
+	} else if (devinfo->host_guid_is_set) {
+		memcpy(pos + 4, "\x01\x00\x00\x00", 4);
+		memcpy(pos + 8, &devinfo->host_guid,
+			sizeof(devinfo->host_guid));
+		pos += block_opt_ptr(pos, 257, NULL, 20);
+	}
+	n = buflen - (pos - buf) - 16;
+	if (n > 0) {
+		struct new_utsname *uname;
+
+		down_read(&uts_sem);
+		uname = utsname();
+		snprintf(pos + 4, n, "%s %s %s %s %s",
+				uname->sysname, uname->nodename, uname->release,
+				uname->version, uname->machine);
+		up_read(&uts_sem);
+		pos[n] = '\0';
+		pos += block_opt_ptr(pos, 3, NULL, strlen(pos + 4));
+	}
+	n = buflen - (pos - buf) - 16;
+	if (n > 0)
+		pos += block_opt_ptr(pos, 4, user_app,
+				min(n, (typeof(n)) strlen(user_app)));
+	n = buflen - (pos - buf) - 16;
+	if (devinfo->comment && n > 0) {
+		unsigned int i, j;
+
+		for (i = 0, j = 4; devinfo->comment[i] && j < n; i++, j++) {
+			if (devinfo->comment[i] == '\\' &&
+				(!strncmp(devinfo->comment + i + 1, "040", 3) ||
+					!strncmp(devinfo->comment + i + 1, "x20", 3))) {
+				pos[j] = ' ';
+				i += 3;
+			} else
+				pos[j] = devinfo->comment[i];
+		}
+		n = j - 4;
+		if (n)
+			pos += block_opt_ptr(pos, 1, NULL, n);
+	}
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Interface Description Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000001                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |           LinkType            |           Reserved            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                            SnapLen                            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_ifdesc_block(const struct reader_info *info,
+		char *buf, int buflen)
+{
+	static const char *if_desc = "Hone Capture Pseudo-device";
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define IFDESC_BLOCK_MIN_LEN 56
+	if (buflen < IFDESC_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_IF_DESC_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint16_t, 101);
+	pos += block_set(pos, uint16_t, 0);
+	pos += block_set(pos, uint32_t, info->snaplen);
+	pos += block_opt_ptr(pos, 3, if_desc,
+			strlen(if_desc));
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Interface Statistics Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                   Block Type = 0x00000005                     |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                         Interface ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_ifstats_block(const struct reader_info *info,
+		char *buf, int buflen)
+{
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+	struct timespec ts;
+	struct timestamp tstamp, start_time;
+	struct statistics received, dropped;
+
+	get_hone_statistics(&received, &dropped, &ts);
+	set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec,
+			info->boot_time.tv_nsec + ts.tv_nsec);
+	timespec_to_tstamp(&start_time, &ts);
+	ktime_get_ts(&ts);
+	set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec,
+			info->boot_time.tv_nsec + ts.tv_nsec);
+	timespec_to_tstamp(&tstamp, &ts);
+
+	/* Be sure to update this value if fields are added below. */
+#define IFSTATS_BLOCK_MIN_LEN 196
+	if (buflen < IFSTATS_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_IF_STATS_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, struct timestamp, tstamp);
+	pos += block_opt_t(pos, 2, struct timestamp, start_time);
+	pos += block_opt_t(pos, 4, uint64_t, atomic64_read(&received.packet));
+	pos += block_opt_t(pos, 5, uint64_t, atomic64_read(&dropped.packet));
+	pos += block_opt_t(pos, 6, uint64_t, atomic64_read(&info->filtered));
+	pos += block_opt_t(pos, 7, uint64_t, atomic64_read(&info->dropped.packet));
+	pos += block_opt_t(pos, 8, uint64_t, atomic64_read(&info->delivered.packet));
+	pos += block_opt_t(pos, 257, uint64_t, atomic64_read(&received.process));
+	pos += block_opt_t(pos, 258, uint64_t, atomic64_read(&dropped.process));
+	pos += block_opt_t(pos, 259, uint64_t, atomic64_read(&info->dropped.process));
+	pos += block_opt_t(pos, 260, uint64_t, atomic64_read(&info->delivered.process));
+	pos += block_opt_t(pos, 261, uint64_t, atomic64_read(&received.socket));
+	pos += block_opt_t(pos, 262, uint64_t, atomic64_read(&dropped.socket));
+	pos += block_opt_t(pos, 263, uint64_t, atomic64_read(&info->dropped.socket));
+	pos += block_opt_t(pos, 264, uint64_t, atomic64_read(&info->delivered.socket));
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+static inline unsigned int maxoptlen(int buflen, unsigned int length)
+{
+	unsigned int alignlen = ((buflen - 16) >> 2) << 2;
+
+	if (unlikely(buflen < 0))
+		return 0;
+	return alignlen < length ? alignlen : length;
+}
+
+/* Process Event Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000101                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                          Process ID                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_process_block(struct process_event *event,
+		struct timestamp *tstamp, char *buf, size_t buflen)
+{
+	static const uint32_t event_map[] = {0, 1, 0, -1, 2};
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define PROCESS_BLOCK_MIN_LEN 56
+	if (buflen < PROCESS_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_PROCESS_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, event->tgid);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	if (event->event != PROC_EXEC)
+		pos += block_opt_t(pos, 2, uint32_t, event_map[event->event]);
+	pos += block_opt_t(pos, 5, uint32_t, event->ppid);
+	pos += block_opt_t(pos, 6, uint32_t, event->uid);
+	pos += block_opt_t(pos, 8, uint32_t, event->euid);
+	pos += block_opt_t(pos, 9, uint32_t, event->loginuid);
+	pos += block_opt_t(pos, 7, uint32_t, event->gid);
+	if (event->mm) {
+		char *tmp, *ptr;
+		unsigned int n, length;
+
+		ptr = pos + 4;
+		length = buflen - (pos - buf) - 16;
+		if (event->event == PROC_KTHD) {
+			n = strlen(event->comm);
+			length = maxoptlen(length, n + 2);
+			if (length) {
+				ptr[0] = '[';
+				if (length > 1)
+					memcpy(ptr + 1, event->comm,
+						length - 1);
+				if (length > n + 1)
+					ptr[length - 1] = ']';
+				pos += block_opt_ptr(pos, 3, NULL, length);
+			}
+		} else {
+			if (length > 0) {
+				tmp = mm_path(event->mm, ptr, length);
+				if (tmp) {
+					length = maxoptlen(length, strlen(tmp));
+					if (length) {
+						memmove(ptr, tmp, length);
+						pos += block_opt_ptr(pos, 3,
+								NULL, length);
+					}
+				}
+			}
+			ptr = pos + 4;
+			length = buflen - (pos - buf) - 16;
+			if (length > 0) {
+				n = mm_argv(event->mm, ptr, length);
+				if (n)
+					pos += block_opt_ptr(pos, 4, NULL,
+							maxoptlen(length, n));
+			}
+		}
+	}
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Connection Event Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000102                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                        Connection ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                          Process ID                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_connection_block(struct socket_event *event,
+		struct timestamp *tstamp, char *buf, size_t buflen)
+{
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define CONNECTION_BLOCK_MIN_LEN 40
+	if (buflen < CONNECTION_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_CONNECTION_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t,
+			event->sock & 0xFFFFFFFF);
+	pos += block_set(pos, uint32_t, event->tgid);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	if (event->event) {
+		pos += block_opt_t(pos, 2, uint32_t, -1);
+		pos += block_end_opt(pos);
+	}
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Enhanced Packet Block {{{
+   0                   1                   2                   3
+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000006                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                         Interface ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 |                         Captured Len                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 |                          Packet Len                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+28 /                                                               /
+   /                          Packet Data                          /
+   /           ( variable length, aligned to 32 bits )             /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_packet_block(struct packet_event *event,
+				unsigned int snaplen,
+				struct timestamp *tstamp,
+				char *buf, size_t buflen)
+{
+	char *pos = buf;
+	int offset;
+	unsigned int *length_top, *length_end, *length_cap, offlen;
+	struct sk_buff *skb = event->skb;
+
+	/* Be sure to update this value if fields are added below. */
+#define PACKET_BLOCK_MIN_LEN 52
+	if (buflen < PACKET_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_PACKET_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	length_cap = (typeof(length_cap)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, event->len);
+
+	/* packet data */
+	offset = skb_network_header(skb) - skb->data;
+	offlen = snaplen ? min(skb->len - offset, snaplen) : skb->len - offset;
+	*length_cap = maxoptlen(buflen - (pos - buf), offlen);
+	if (*length_cap) {
+		unsigned int n = *length_cap & 3 ? 4 - (*length_cap & 3) : 0;
+
+		if (skb_copy_bits(skb, offset, pos, *length_cap))
+			BUG();
+		pos += *length_cap;
+		memset(pos, 0, n);
+		pos += n;
+	}
+
+	if (event->sock)
+		pos += block_opt_t(pos, 257, uint32_t,
+				event->sock & 0xFFFFFFFF);
+	if (event->pid)
+		pos += block_opt_t(pos, 258, uint32_t, event->pid);
+	pos += block_opt_t(pos, 2, uint32_t, event->dir ? 1 : 2);
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+static void normalize_ts(struct timestamp *tstamp,
+			const struct timespec *boot_time,
+			const struct timespec *event_time)
+{
+	struct timespec ts;
+
+	/* The following is used instead of timespec_add()
+	   because it doesn't exist in older kernel versions. */
+	set_normalized_timespec(&ts, boot_time->tv_sec + event_time->tv_sec,
+			boot_time->tv_nsec + event_time->tv_nsec);
+	timespec_to_tstamp(tstamp, &ts);
+}
+
+unsigned int format_as_pcapng(
+	const struct device_info *devinfo, const struct reader_info *info,
+	struct hone_event *event, char *buf, unsigned int buflen)
+{
+	unsigned int n = 0;
+	struct timestamp tstamp;
+
+	switch (event->type) {
+	case HONE_PACKET:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_packet_block(
+			&event->packet, info->snaplen, &tstamp, buf, buflen);
+		break;
+	case HONE_PROCESS:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_process_block(&event->process, &tstamp, buf, buflen);
+		break;
+	case HONE_SOCKET:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_connection_block(&event->socket, &tstamp,
+					buf, buflen);
+		break;
+	case HONE_USER_HEAD:
+		n = format_sechdr_block(devinfo, buf, buflen);
+		n += format_ifdesc_block(info, buf + n, buflen - n);
+		break;
+	case HONE_USER_TAIL:
+		n = format_ifstats_block(info, buf + n, buflen - n);
+		break;
+	}
+
+	return n;
+}
+
+int parse_guid(struct guid_struct *guid, const char *input)
+{
+	int i, val;
+	const char *pos = input;
+	char *buf = (typeof(buf)) guid;
+
+	if (*pos == '{')
+		pos++;
+	for (i = 0; *pos && i < 32; pos++) {
+		if (*pos == '-') {
+			if (pos == input)
+				return -1;
+			continue;
+		}
+		if (*pos >= '0' && *pos <= '9')
+			val = *pos - '0';
+		else if (*pos >= 'a' && *pos <= 'f')
+			val = *pos - 'W';
+		else if (*pos >= 'A' && *pos <= 'F')
+			val = *pos - '7';
+		else
+			return -1;
+		if (i % 2) {
+			buf[i / 2] += val;
+			i++;
+		} else {
+			buf[i / 2] = val << 4;
+			i++;
+		}
+	}
+	if (i < 32)
+		return -1;
+	if (*input == '{') {
+		if (*pos != '}')
+			return -1;
+		pos++;
+	}
+	if (*pos)
+		return -1;
+	guid->data1 = ntohl(guid->data1);
+	guid->data2 = ntohs(guid->data2);
+	guid->data3 = ntohs(guid->data3);
+	return 0;
+}
diff --git a/security/hone/hone_pcapng.h b/security/hone/hone_pcapng.h
new file mode 100644
index 0000000..2987831c
--- /dev/null
+++ b/security/hone/hone_pcapng.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#ifndef _PCAPNG_H
+#define _PCAPNG_H
+
+#include <linux/atomic.h>
+#include <linux/time.h>
+
+#define HONE_USER_HEAD (HONE_USER | 1)
+#define HONE_USER_TAIL (HONE_USER | 2)
+
+#define GUID_FMT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+#define GUID_TUPLE(G) (G)->data1, (G)->data2, (G)->data3, \
+		(G)->data4[0], (G)->data4[1], (G)->data4[2], (G)->data4[3], \
+		(G)->data4[4], (G)->data4[5], (G)->data4[6], (G)->data4[7]
+
+unsigned int format_as_pcapng(
+		const struct device_info *devinfo, const struct reader_info *info,
+		struct hone_event *event, char *buf, unsigned int buflen);
+int parse_guid(struct guid_struct *guid, const char *input);
+
+#endif /* _PCAPNG_H */
diff --git a/security/hone/hone_ringbuf.c b/security/hone/hone_ringbuf.c
new file mode 100644
index 0000000..14a38f8
--- /dev/null
+++ b/security/hone/hone_ringbuf.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Implementation of lock-free ring buffer.
+ */
+
+#include <linux/atomic.h>
+
+#include "hone_ringbuf.h"
+
+int ring_append(struct ring_buf *ring, void *elem)
+{
+	unsigned int back;
+
+	for (;;) {
+		back = ring_back(ring);
+		if (back - ring_front(ring) >= ring->length)
+			return -1;
+		if ((unsigned int)
+			atomic_cmpxchg(&ring->back, back, back + 1) == back)
+			break;
+	}
+	ring->data[back % ring->length] = elem;
+	return 0;
+}
+
+void *ring_pop(struct ring_buf *ring)
+{
+	void *elem, **slot;
+	unsigned int front;
+
+	for (;;) {
+		front = ring_front(ring);
+		if (front == ring_back(ring))
+			return NULL;
+		slot = ring->data + (front % ring->length);
+		elem = *slot;
+		if (!elem)
+			continue;
+		if (cmpxchg(slot, elem, NULL) == elem)
+			break;
+	}
+	atomic_inc(&ring->front);
+	return elem;
+}
diff --git a/security/hone/hone_ringbuf.h b/security/hone/hone_ringbuf.h
new file mode 100644
index 0000000..a12311c
--- /dev/null
+++ b/security/hone/hone_ringbuf.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Implementation of lock-free ring buffer.
+ */
+
+#ifndef _RINGBUF_H
+#define _RINGBUF_H
+
+#include <linux/types.h>
+
+struct ring_buf {
+	atomic_t front;
+	atomic_t back;
+	unsigned int length;
+	unsigned int pageorder;
+	void **data;
+};
+
+#define ring_front(ring) ((unsigned int) atomic_read(&(ring)->front))
+#define ring_back(ring) ((unsigned int) atomic_read(&(ring)->back))
+#define ring_used(ring) (ring_back(ring) - ring_front(ring))
+#define ring_is_empty(ring) (ring_front(ring) == ring_back(ring))
+
+int ring_append(struct ring_buf *ring, void *elem);
+void *ring_pop(struct ring_buf *ring);
+
+#endif /* _RINGBUF_H */
diff --git a/security/hone/hone_socket_lookup.c b/security/hone/hone_socket_lookup.c
new file mode 100644
index 0000000..6b0f355
--- /dev/null
+++ b/security/hone/hone_socket_lookup.c
@@ -0,0 +1,264 @@
+/*
+ * Modifications copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+/*
+ * The following code was conveniently borrowed form the xt_socket
+ * iptables module and used with minor modifications.  Thanks guys!
+ *
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (C) 2007-2008 BalaBit IT Ltd.
+ * Author: Krisztian Kovacs
+ */
+
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+
+#include "hone.h"
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <net/ipv6.h>
+#include <net/inet6_hashtables.h>
+#endif
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#define XT_SOCKET_HAVE_CONNTRACK 1
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+static int extract_icmp4_fields(const struct sk_buff *skb, u8 *protocol,
+		__be32 *raddr, __be32 *laddr, __be16 *rport, __be16 *lport)
+{
+	unsigned int outside_hdrlen = ip_hdrlen(skb);
+	struct iphdr *inside_iph, _inside_iph;
+	struct icmphdr *icmph, _icmph;
+	__be16 *ports, _ports[2];
+
+	icmph = skb_header_pointer(skb, outside_hdrlen,
+				   sizeof(_icmph), &_icmph);
+	if (icmph == NULL)
+		return 1;
+
+	switch (icmph->type) {
+	case ICMP_DEST_UNREACH:
+	case ICMP_SOURCE_QUENCH:
+	case ICMP_REDIRECT:
+	case ICMP_TIME_EXCEEDED:
+	case ICMP_PARAMETERPROB:
+		break;
+	default:
+		return 1;
+	}
+
+	inside_iph = skb_header_pointer(skb, outside_hdrlen +
+					sizeof(struct icmphdr),
+					sizeof(_inside_iph), &_inside_iph);
+	if (inside_iph == NULL)
+		return 1;
+
+	if (inside_iph->protocol != IPPROTO_TCP &&
+	    inside_iph->protocol != IPPROTO_UDP)
+		return 1;
+
+	ports = skb_header_pointer(skb, outside_hdrlen +
+				   sizeof(struct icmphdr) +
+				   (inside_iph->ihl << 2),
+				   sizeof(_ports), &_ports);
+	if (ports == NULL)
+		return 1;
+
+	/* the inside IP packet is the one quoted from our side, thus
+	 * its saddr is the local address */
+	*protocol = inside_iph->protocol;
+	*laddr = inside_iph->saddr;
+	*lport = ports[0];
+	*raddr = inside_iph->daddr;
+	*rport = ports[1];
+
+	return 0;
+}
+
+struct sock *lookup_v4_sock(const struct sk_buff *skb,
+		const struct net_device *indev)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct sock *sk;
+	__be32 daddr = 0, saddr = 0;
+	__be16 dport = 0, sport = 0;
+	u8 protocol = 0;
+
+	if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
+		struct udphdr _hdr, *hp;
+
+		hp = skb_header_pointer(skb, ip_hdrlen(skb),
+					sizeof(_hdr), &_hdr);
+		if (!hp)
+			return NULL;
+
+		protocol = iph->protocol;
+		saddr = iph->saddr;
+		sport = hp->source;
+		daddr = iph->daddr;
+		dport = hp->dest;
+
+	} else if (iph->protocol == IPPROTO_ICMP) {
+		if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
+					&sport, &dport))
+			return NULL;
+	} else {
+		return NULL;
+	}
+
+#ifdef XT_SOCKET_HAVE_CONNTRACK
+	/* Do the lookup with the original socket address in case this is a
+	 * reply packet of an established SNAT-ted connection. */
+	{
+		enum ip_conntrack_info ctinfo;
+		struct nf_conn const *ct = nf_ct_get(skb, &ctinfo);
+
+		if (ct && !nf_ct_is_untracked(ct) &&
+			((iph->protocol != IPPROTO_ICMP &&
+				ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
+				(iph->protocol == IPPROTO_ICMP &&
+					ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) &&
+			(ct->status & IPS_SRC_NAT_DONE)) {
+
+			daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+			dport = (iph->protocol == IPPROTO_TCP) ?
+				ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port :
+				ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
+		}
+	}
+#endif
+
+	if (protocol == IPPROTO_TCP)
+		sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo,
+				saddr, sport, daddr, dport, indev->ifindex);
+	else
+		sk = udp4_lib_lookup(dev_net(skb->dev),
+				saddr, sport, daddr, dport, indev->ifindex);
+	if (!sk)
+		return NULL;
+
+	/* Ignore sockets listening on INADDR_ANY */
+	if (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->inet_rcv_saddr == 0) {
+		put_sock(sk);
+		return NULL;
+	}
+	return sk;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int extract_icmp6_fields(const struct sk_buff *skb,
+				unsigned int outside_hdrlen, int *protocol,
+				struct in6_addr **raddr,
+				struct in6_addr **laddr, __be16 *rport,
+				__be16 *lport)
+{
+	struct ipv6hdr *inside_iph, _inside_iph;
+	struct icmp6hdr *icmph, _icmph;
+	__be16 *ports, _ports[2], _ignore;
+	u8 inside_nexthdr;
+	int inside_hdrlen;
+
+	icmph = skb_header_pointer(skb, outside_hdrlen, sizeof(_icmph),
+				&_icmph);
+	if (!icmph)
+		return 1;
+	if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
+		return 1;
+
+	inside_iph = skb_header_pointer(
+		skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph),
+		&_inside_iph);
+	if (!inside_iph)
+		return 1;
+
+	inside_nexthdr = inside_iph->nexthdr;
+	inside_hdrlen = ipv6_skip_exthdr(
+		skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph),
+		&inside_nexthdr, &_ignore);
+	if (inside_hdrlen < 0)
+		/* hjm: Packet has no/incomplete transport layer headers. */
+		return 1;
+	if (inside_nexthdr != IPPROTO_TCP && inside_nexthdr != IPPROTO_UDP)
+		return 1;
+
+	ports = skb_header_pointer(skb, inside_hdrlen, sizeof(_ports), &_ports);
+	if (!ports)
+		return 1;
+
+	/* the inside IP packet is the one quoted from our side, thus
+	 * its saddr is the local address */
+	*protocol = inside_nexthdr;
+	*laddr = &inside_iph->saddr;
+	*lport = ports[0];
+	*raddr = &inside_iph->daddr;
+	*rport = ports[1];
+
+	return 0;
+}
+
+struct sock *lookup_v6_sock(const struct sk_buff *skb,
+			const struct net_device *indev)
+{
+	struct sock *sk;
+	struct in6_addr *daddr, *saddr;
+	__be16 dport, sport;
+	int thoff = 0, tproto;
+
+	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
+	if (tproto < 0)
+		/* unable to find transport header in IPv6 packet */
+		return NULL;
+
+	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
+		struct udphdr _hdr, *hp;
+		struct ipv6hdr *iph;
+
+		hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+		if (!hp)
+			return NULL;
+
+		iph = ipv6_hdr(skb);
+		saddr = &iph->saddr;
+		sport = hp->source;
+		daddr = &iph->daddr;
+		dport = hp->dest;
+	} else if (tproto == IPPROTO_ICMPV6) {
+		if (extract_icmp6_fields(skb, thoff, &tproto,
+					&saddr, &daddr, &sport, &dport))
+			return NULL;
+	} else {
+		return NULL;
+	}
+
+	if (tproto == IPPROTO_TCP)
+		sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo,
+				saddr, sport, daddr, dport, indev->ifindex);
+	else
+		sk = __udp6_lib_lookup(dev_net(skb->dev),
+				saddr, sport, daddr, dport, indev->ifindex,
+				&udp_table);
+
+	/* Ignore sockets listening on INADDR_ANY */
+	if (sk && sk->sk_state != TCP_TIME_WAIT && !inet_sk(sk)->inet_rcv_saddr) {
+		put_sock(sk);
+		return NULL;
+	}
+	/* TODO(pmoody): add pid information here. */
+	return sk;
+}
+#endif
-- 
2.0.0.526.g5318336

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ