Subject: [RFC 2/4] NetLabel

From: Paul Moore <[email-masked]>
Date: Thu, 25 May 2006 16:06:27 -0400

This patch is the core NetLabel subsystem.

 include/linux/netlink.h            |    1
 include/net/netlabel.h             |  355 +++++++++++++++
 net/Kconfig                        |    2
 net/Makefile                       |    1
 net/ipv4/Makefile                  |    1
 net/netlabel/Kconfig               |   47 +
 net/netlabel/Makefile              |   15
 net/netlabel/netlabel_domainhash.c |  629 ++++++++++++++++++++++++++
 net/netlabel/netlabel_domainhash.h |   64 ++
 net/netlabel/netlabel_kapi.c       |  374 +++++++++++++++
 net/netlabel/netlabel_mgmt.c       |  686 +++++++++++++++++++++++++++++
 net/netlabel/netlabel_mgmt.h       |  265 +++++++++++
 net/netlabel/netlabel_unlabeled.c  |  289 ++++++++++++
 net/netlabel/netlabel_unlabeled.h  |   90 +++
 net/netlabel/netlabel_user.c       |  166 +++++++
 net/netlabel/netlabel_user.h       |   42 +
 16 files changed, 3027 insertions(+)

--- linux-2.6.16.i686/include/linux/netlink.h	2006-05-23 11:34:52.000000000 -0400
+++ linux-2.6.16.i686-cipso/include/linux/netlink.h	2006-05-23 15:48:49.000000000 -0400
@@ -21,6 +21,7 @@
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
 #define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
 #define NETLINK_GENERIC		16
+#define NETLINK_NETLABEL	17	/* Network packet labeling */
 
 #define MAX_LINKS 32		
 
--- linux-2.6.16.i686/include/net/netlabel.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/include/net/netlabel.h	2006-05-17 11:04:14.000000000 -0400
@@ -0,0 +1,355 @@
+/*
+ * NetLabel System
+ *
+ * The NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_H
+#define _NETLABEL_H
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+
+/*
+ * NetLabel - A management interface for maintaining network packet label
+ *            mapping tables for explicit packet labling protocols.
+ *
+ * Network protocols such as CIPSO and RIPSO require a label translation layer
+ * to convert the label on the packet into something meaningful on the host
+ * machine.  In the current Linux implementation these mapping tables live
+ * inside the kernel; NetLabel provides a mechanism for user space applications
+ * to manage these mapping tables.
+ *
+ * NetLabel makes use of NETLINK as a transport layer to send messages between
+ * kernel and user space.  The general format of a NetLabel message is shown
+ * below:
+ *
+ *  +----------+------------------+--------- --- -- -
+ *  | nlmsghdr | subsystem header | payload
+ *  +----------+------------------+--------- --- -- -
+ *
+ * The 'nlmsghdr' struct should be dealt with like any other NETLINK 'nlmsghdr'
+ * struct.  The subsystem header structure is dependent on the subsystem
+ * specified in the 'nlmsghdr->nlmsg_type' and should be defined below,
+ * supporting functions should be defined in the corresponding
+ * net/netlabel/netlabel_<subsys>.h|c file.
+ *
+ */
+
+/*
+ * NetLabel NETLINK protocol
+ */
+
+#define NETLBL_VER_STR              "0.11"
+#define NETLBL_VER_DATE             "04122006"
+
+/* NetLabel NETLINK groups */
+#define NETLBL_NLGRP_NONE           0x00000000
+#define NETLBL_NLGRP_MAX            0xffffffff
+
+/* NetLabel NETLINK types */
+#define NETLBL_NLTYPE_NONE          0
+#define NETLBL_NLTYPE_MGMT          1
+#define NETLBL_NLTYPE_RIPSO         2
+#define NETLBL_NLTYPE_CIPSOV4       3
+#define NETLBL_NLTYPE_CIPSOV6       4
+#define NETLBL_NLTYPE_UNLABELED     5
+
+/* Generic return codes */
+#define NETLBL_E_OK         0
+#define NETLBL_E_ERR        1
+#define NETLBL_E_BADCMD     16
+
+/*
+ * Helper functions
+ */
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u8(unsigned char *buffer, const u8 val)
+{
+	*(u8 *)buffer = val;
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u32(unsigned char *buffer, const u32 val)
+{
+	*(u32 *)buffer = val;
+}
+
+/**
+ * netlbl_put_str - Write a string into a buffer
+ * @buffer: the buffer
+ * @val: the string
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_str(unsigned char *buffer, const char *val)
+{
+	strcpy((char *)buffer, val);
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer.
+ *
+ */
+static inline void netlbl_put_hdr(unsigned char *buffer,
+				  const u32 msg_type,
+				  const u16 msg_len,
+				  const u16 msg_flags, 
+				  const u32 msg_pid, 
+				  const u32 msg_seq)
+{
+	struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+	hdr->nlmsg_len = msg_len;
+	hdr->nlmsg_type = msg_type;
+	hdr->nlmsg_flags = msg_flags;
+	hdr->nlmsg_seq = msg_seq;
+	hdr->nlmsg_pid = msg_pid;
+}
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u8(unsigned char **buffer, const u8 val)
+{
+	netlbl_put_u8(*buffer, val);
+	*buffer += sizeof(u8);
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u32(unsigned char **buffer, const u32 val)
+{
+	netlbl_put_u32(*buffer, val);
+	*buffer += sizeof(u32);
+}
+
+/**
+ * netlbl_put_u8 - Write a string into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_str(unsigned char **buffer, const char *val)
+{
+	netlbl_put_str(*buffer, val);
+	*buffer += strlen(val) + 1;
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer and increment the ptr
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer and
+ * then increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_putinc_hdr(unsigned char **buffer,
+				     const u32 msg_type,
+				     const u16 msg_len,
+				     const u16 msg_flags, 
+				     const u32 msg_pid, 
+				     const u32 msg_seq)
+{
+	netlbl_put_hdr(*buffer, 
+		       msg_type, 
+		       msg_len, 
+		       msg_flags, 
+		       msg_pid, 
+		       msg_seq);
+	*buffer += NLMSG_HDRLEN;
+}
+
+/**
+ * netlbl_get_u8 - Read a u8 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u8 netlbl_get_u8(const unsigned char *buffer)
+{
+	return *(u8 *)buffer;
+}
+
+/**
+ * netlbl_get_u32 - Read a u32 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u32 netlbl_get_u32(const unsigned char *buffer)
+{
+	return *(u32 *)buffer;
+}
+
+/**
+ * netlbl_getinc_u8 - Read a u8 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u8 netlbl_getinc_u8(unsigned char **buffer)
+{
+	u8 val = netlbl_get_u8(*buffer);
+	*buffer += sizeof(u8);
+	return val;
+}
+
+/**
+ * netlbl_getinc_u32 - Read a u32 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u32 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u32 netlbl_getinc_u32(unsigned char **buffer)
+{
+	u32 val = netlbl_get_u32(*buffer);
+	*buffer += sizeof(u32);
+	return val;
+}
+
+/*
+ * NetLabel - Kernel API for accessing the network packet label mappings.
+ *
+ * The following functions are provided for use by other kernel modules,
+ * specifically kernel LSM modules, to provide a consistent, transparent API
+ * for dealing with explicit packet labeling protocols such as CIPSO and
+ * RIPSO.  The functions defined here are implemented in the 
+ * net/netlabel/netlabel_kapi.c file.
+ *
+ */
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map;
+
+/* Domain mapping operations */
+int netlbl_domhsh_remove(const char *domain);
+
+/* LSM security attributes */
+struct netlbl_lsm_cache {
+	void (*free) (const void *data);
+	void *data;
+};
+struct netlbl_lsm_secattr {
+	char *domain;
+
+	u32 mls_lvl;
+	unsigned char *mls_cat;
+	u32 mls_cat_len;
+
+	struct netlbl_lsm_cache cache;
+
+	u32 set_domain:1, 
+	    set_mls_lvl:1,
+	    set_mls_cat:1,
+	    set_cache:1,
+	    unused:28;
+};
+
+/* LSM security attribute operations */
+struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags);
+void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr);
+int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr);
+void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr);
+
+/* LSM protocol operations */
+int netlbl_socket_setattr(const struct socket *sock,
+			  const struct netlbl_lsm_secattr *secattr);
+int netlbl_socket_peekattr(const struct socket *sock, 
+			   struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_getattr(const struct sk_buff *skb, 
+			  struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_err(struct sk_buff *skb, int error);
+
+/* LSM label mapping cache operations */
+int netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb, 
+		     const struct netlbl_lsm_secattr *secattr);
+
+#endif /* _NETLABEL_H */
--- linux-2.6.16.i686/net/ipv4/Makefile	2006-05-23 11:34:55.000000000 -0400
+++ linux-2.6.16.i686-cipso/net/ipv4/Makefile	2006-05-23 15:52:36.000000000 -0400
@@ -42,6 +42,7 @@ obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybl
 obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o
 obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o
 obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+obj-$(CONFIG_NETLABEL_CIPSOV4) += cipso_ipv4.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
 		      xfrm4_output.o
--- linux-2.6.16.i686/net/Kconfig	2006-05-23 11:35:14.000000000 -0400
+++ linux-2.6.16.i686-cipso/net/Kconfig	2006-05-23 15:51:35.000000000 -0400
@@ -228,6 +228,8 @@ source "net/tux/Kconfig"
 config WIRELESS_EXT
 	bool
 
+source "net/netlabel/Kconfig"
+
 endif   # if NET
 endmenu # Networking
 
--- linux-2.6.16.i686/net/Makefile	2006-05-23 11:35:14.000000000 -0400
+++ linux-2.6.16.i686-cipso/net/Makefile	2006-05-23 15:52:03.000000000 -0400
@@ -47,6 +47,7 @@ obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
+obj-$(CONFIG_NETLABEL)		+= netlabel/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
--- linux-2.6.16.i686/net/netlabel/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/Kconfig	2006-05-23 10:42:38.000000000 -0400
@@ -0,0 +1,47 @@
+#
+# NetLabel configuration
+#
+
+config NETLABEL
+	tristate "NetLabel subsystem support"
+	depends on NET && SECURITY
+	default n
+	---help---
+	  NetLabel provides support for network packet labeling protocols.  For
+	  more information see Documentation/netlabel.
+
+	  If you are unsure, say N.
+
+config NETLABEL_CIPSOV4
+	tristate "CIPSO for IPv4"
+	depends on NETLABEL
+	default n
+	---help---
+	  The Commercial IP Security Option (CIPSO) is commonly used in
+	  trusted multi-level security networks.  This implementation is based
+	  on the IETF draft draft-ietf-cipso-ipsecurity-01.txt and FIPS-188.
+
+	  If you are unsure say N.
+
+config NETLABEL_UNLABELED
+	tristate "Unlabeled packets"
+	depends on NETLABEL
+	default y
+	---help---
+	  This adds support for sending and receiving unlabeled packets through
+	  the NetLabel system.
+
+	  If you are unsure say Y.
+
+config NETLABEL_UNLABELED_DEFAULT
+	bool "Enable unlabeled traffic by default"
+	depends on NETLABEL_UNLABELED
+	default y
+	---help---
+	  Enabling this option allows unlabeled (i.e. normal) network traffic
+	  on the system without any user configuration at bootup.  Disabling
+	  this option means the user must configure the NetLabel subsystem
+	  before any type of network traffic can be sent or received on the
+	  system.
+
+	  If you are unsure say Y.
--- linux-2.6.16.i686/net/netlabel/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/Makefile	2006-05-12 11:04:00.000000000 -0400
@@ -0,0 +1,15 @@
+#
+# Makefile for the NetLabel subsystem.
+#
+# Feb 9, 2006, Paul Moore <[email-masked]>
+#
+
+# base objects
+obj-y	:= netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+
+# management objects
+obj-y	+= netlabel_mgmt.o
+
+# protocol modules
+obj-$(CONFIG_NETLABEL_UNLABELED)	+= netlabel_unlabeled.o
+obj-$(CONFIG_NETLABEL_CIPSOV4)		+= netlabel_cipso_v4.o
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_domainhash.c	2006-05-24 11:09:41.000000000 -0400
@@ -0,0 +1,629 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
+
+struct netlbl_domhsh_tbl {
+	struct list_head *tbl;
+	u32 size;
+};
+
+/* Domain hash table */
+/* XXX - updates should be so rare that having one spinlock for the entire
+   hash table should be okay */
+DEFINE_SPINLOCK(netlbl_domhsh_lock);
+static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
+
+/* Default domain mapping */
+DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
+static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
+
+/*
+ * Domain Hash Table Helper Functions
+ */
+
+/**
+ * netlbl_domhsh_free_entry - Frees a domain hash table entry
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to a hash table entry can be released
+ * safely.
+ *
+ */
+static void netlbl_domhsh_free_entry(struct rcu_head *entry)
+{
+	struct netlbl_dom_map *ptr;
+
+	ptr = container_of(entry, struct netlbl_dom_map, rcu);
+	if (ptr->domain)
+		kfree(ptr->domain);
+	kfree(ptr);
+}
+
+/**
+ * netlbl_domhsh_hash - Hashing function for the domain hash table
+ * @domain: the domain name to hash
+ *
+ * Description:
+ * This is the hashing function for the domain hash table, it returns the
+ * correct bucket number for the domain.  The caller is responsibile for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+static inline u32 netlbl_domhsh_hash(const char *domain)
+{
+	char *p;
+	char *keyp = (char *)domain;
+	u32 size;
+	u32 val = 0;
+
+	/* This is taken (with slight modification) from 
+	   security/selinux/ss/symtab.c:symhash() */
+
+	size = strlen(keyp);
+	for (p = keyp; (p - keyp) < size; p++)
+		val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ (*p);
+	return val & (rcu_dereference(netlbl_domhsh)->size - 1);
+}
+
+/**
+ * netlbl_domhsh_search - Search for a domain entry
+ * @domain: the domain
+ * @def: return default if no match is found
+ *
+ * Description:
+ * Searches the domain hash table and returns a pointer to the hash table
+ * entry if found, otherwise NULL is returned.  If @def is non-zero and a
+ * match is not found in the domain hash table the default mapping is returned
+ * if it exists.  The caller is responsibile for the rcu hash table locks
+ * (i.e. the caller much call rcu_read_[un]lock()).
+ *
+ */
+static inline struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, 
+							  const u32 def)
+{
+	u32 bkt;
+	struct netlbl_dom_map *iter;
+
+	if (domain != NULL) {
+		bkt = netlbl_domhsh_hash(domain);
+		list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list)
+			if (strcmp(iter->domain, domain) == 0 && iter->valid)
+				return iter;
+	}
+
+	if (def != 0) {
+		iter = rcu_dereference(netlbl_domhsh_def);
+		if (iter != NULL && iter->valid)
+			return iter;
+	}
+
+	return NULL;
+}
+
+/*
+ * Domain Hash Table Functions
+ */
+
+/**
+ * netlbl_domhsh_init - Init for the domain hash
+ * @size: the number of bits to use for the hash buckets
+ *
+ * Description:
+ * Initializes the domain hash table, should be called only by
+ * netlbl_user_init() during module load.  Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+int netlbl_domhsh_init(const u32 size)
+{
+	u32 iter;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+
+	BUG_ON(netlbl_domhsh);
+	BUG_ON(netlbl_domhsh_def);
+	if (size <= 0)
+		return -EINVAL;
+
+	hsh_tbl = kmalloc(sizeof(struct netlbl_domhsh_tbl), GFP_KERNEL);
+	if (hsh_tbl == NULL)
+		return -ENOMEM;
+	hsh_tbl->size = 1 << size;
+	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
+			       sizeof(struct list_head),
+			       GFP_KERNEL);
+	if (hsh_tbl->tbl == NULL) {
+		kfree(hsh_tbl);
+		return -ENOMEM;
+	}
+	for (iter = 0; iter < hsh_tbl->size; iter++)
+		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
+
+	rcu_read_lock();
+	spin_lock(&netlbl_domhsh_lock);
+	rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
+	spin_unlock(&netlbl_domhsh_lock);
+	rcu_read_unlock();
+
+	return 0;
+}
+
+/**
+ * netlbl_domhsh_exit - Cleanup for the domain hash
+ *
+ * Description:
+ * Clears and frees the domain hash table.  No real serious effort is made
+ * towards locking but that shouldn't be an issue since we should only be
+ * called when the module is being unloaded.  Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+int netlbl_domhsh_exit(void)
+{
+	u32 iter_bkt;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+	struct netlbl_dom_map *iter_list;
+
+	BUG_ON(!netlbl_domhsh);
+
+	rcu_read_lock();
+	iter_list = rcu_dereference(netlbl_domhsh_def);
+	spin_lock(&netlbl_domhsh_def_lock);
+	rcu_assign_pointer(netlbl_domhsh_def, NULL);
+	spin_unlock(&netlbl_domhsh_def_lock);
+	rcu_read_unlock();
+
+	if (iter_list) {
+		synchronize_rcu();
+		netlbl_domhsh_free_entry(&iter_list->rcu);
+	}
+
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	spin_lock(&netlbl_domhsh_lock);
+	rcu_assign_pointer(netlbl_domhsh, NULL);
+	spin_unlock(&netlbl_domhsh_lock);
+	rcu_read_unlock();
+
+	synchronize_rcu();
+
+	/* PM - it probably doesn't matter, but do we need to use the rcu list
+	   functions here since we are the only one who has access to the
+	   list now? */
+	for (iter_bkt = 0; iter_bkt < hsh_tbl->size; iter_bkt++)
+		list_for_each_entry_rcu(iter_list,
+					&hsh_tbl->tbl[iter_bkt], list) {
+			iter_list->valid = 0;
+			list_del_rcu(&iter_list->list);
+			netlbl_domhsh_free_entry(&iter_list->rcu);
+		}
+	kfree(hsh_tbl->tbl);
+	kfree(hsh_tbl);
+
+	return 0;
+}
+
+/**
+ * netlbl_domhsh_add - Adds a entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new entry to the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry)
+{
+	int ret_val = -EPERM;
+	u32 bkt;
+
+	BUG_ON(entry == NULL);
+
+	switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = 0;
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
+						  entry->domain);
+		break;
+#endif
+	default:
+		BUG();
+	}
+	if (ret_val != 0)
+		return ret_val;
+
+	entry->valid = 1;
+	INIT_RCU_HEAD(&entry->rcu);
+
+	rcu_read_lock();
+	if (entry->domain != NULL &&
+	    netlbl_domhsh_search(entry->domain, 0) == NULL) {
+		bkt = netlbl_domhsh_hash(entry->domain);
+		spin_lock(&netlbl_domhsh_lock);
+		list_add_tail_rcu(&entry->list, &netlbl_domhsh->tbl[bkt]);
+		spin_unlock(&netlbl_domhsh_lock);
+	} else if (entry->domain == NULL &&
+		   rcu_dereference(netlbl_domhsh_def) == NULL) {
+		INIT_LIST_HEAD(&entry->list);
+		spin_lock(&netlbl_domhsh_def_lock);
+		rcu_assign_pointer(netlbl_domhsh_def, entry);
+		spin_unlock(&netlbl_domhsh_def_lock);
+	} else {
+		rcu_read_unlock();
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+						       entry->domain) != 0)
+				BUG();
+			break;
+#endif
+		default:
+			BUG();
+		}
+		return -EPERM;
+	}
+	rcu_read_unlock();
+
+	return 0;
+}
+
+/**
+ * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new default entry to the domain hash table and handles any updates
+ * to the lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry)
+{
+	return netlbl_domhsh_add(entry);
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain)
+{
+	int ret_val = -EPERM;
+	struct netlbl_dom_map *entry;
+
+	rcu_read_lock();
+	if (domain != NULL)
+		entry = netlbl_domhsh_search(domain, 0);
+	else
+		entry = netlbl_domhsh_search(domain, 1);
+	if (entry == NULL)
+		goto remove_return;
+	switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+					       entry->domain) != 0)
+			goto remove_return;
+		break;
+#endif
+	default:
+		BUG();
+	}
+	if (entry != rcu_dereference(netlbl_domhsh_def)) {
+		spin_lock(&netlbl_domhsh_lock);
+		entry->valid = 0;
+		list_del_rcu(&entry->list);
+		spin_unlock(&netlbl_domhsh_lock);
+	} else {
+		spin_lock(&netlbl_domhsh_def_lock);
+		entry->valid = 0;
+		rcu_assign_pointer(netlbl_domhsh_def, NULL);
+		spin_unlock(&netlbl_domhsh_def_lock);
+	}
+	call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+
+	ret_val = 0;
+
+remove_return:
+	rcu_read_unlock();
+	return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove_default - Removes the default entry from the table
+ *
+ * Description:
+ * Removes/resets the default entry for the domain hash table and handles any
+ * updates to the lower level protocol handler (i.e. CIPSO).  Returns zero on
+ * success, non-zero on failure.
+ *
+ */
+int netlbl_domhsh_remove_default(void)
+{
+	return netlbl_domhsh_remove(NULL);
+}
+
+/**
+ * netlbl_domhsh_getentry - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain,
+ * return a pointer to a copy of the entry or NULL.  The caller is responsibile
+ * for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
+{
+	return netlbl_domhsh_search(domain, 1);
+}
+
+/**
+ * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff
+ *
+ * Description:
+ * Dump the domain hash table into a buffer suitable for returning to an
+ * application in response to a NetLabel management DOMAIN message.  This
+ * function may fail if another process is growing the hash table at the same
+ * time.  The returned sk_buff has room at the front of the sk_buff for
+ * a nlmsghdr struct and a netlbl_mgmt_msghdr struct.  See netlabel.h for the
+ * DOMAIN message format.  Returns a pointer to a sk_buff on success, NULL on
+ * error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump(void)
+{
+	struct sk_buff *skb;
+	unsigned char *buf;
+	u32 buf_len;
+	u32 bkt_iter;
+	u32 dom_cnt = 0;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+	struct netlbl_dom_map *list_iter;
+	u32 tmp_len;
+
+	/* XXX - This is kinda ugly as we have to go through the table once to
+	   determine how large of a buffer we need, drop the locks, allocate
+	   the buffer, grab the locks, and finally fill the buffer.  The
+	   problem is that there is that open window where the table could
+	   grow and we will end up short on space. */
+
+	buf_len = 4;
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+		list_for_each_entry_rcu(list_iter,
+					&hsh_tbl->tbl[bkt_iter], list) {
+			buf_len += 9 + strlen(list_iter->domain);
+			switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+			case NETLBL_NLTYPE_UNLABELED:
+				break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+			case NETLBL_NLTYPE_CIPSOV4:
+				buf_len += 8;
+				break;
+#endif
+			default:
+				rcu_read_unlock();
+				BUG();
+			}
+			dom_cnt++;
+		}
+	rcu_read_unlock();
+
+	skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+				    buf_len), GFP_KERNEL);
+	if (skb == NULL)
+		return NULL;
+	skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	tmp_len = skb_tailroom(skb);
+	if (tmp_len < buf_len)
+		goto dump_failure;
+	buf = skb_put(skb, buf_len);
+	buf_len -= 4;
+	netlbl_putinc_u32(&buf, dom_cnt);
+
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+		list_for_each_entry_rcu(list_iter,
+					&hsh_tbl->tbl[bkt_iter], list) {
+			tmp_len = strlen(list_iter->domain) + 1;
+			if (buf_len < tmp_len + 8) {
+				rcu_read_unlock();
+				goto dump_failure;
+			}
+			buf_len -= tmp_len + 8;
+			netlbl_putinc_u32(&buf, tmp_len);
+			netlbl_putinc_str(&buf, list_iter->domain);
+			netlbl_putinc_u32(&buf, list_iter->type);
+			switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+			case NETLBL_NLTYPE_UNLABELED:
+				break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+			case NETLBL_NLTYPE_CIPSOV4:
+				if (buf_len < 8) {
+					rcu_read_unlock();
+					goto dump_failure;
+				}
+				buf_len -= 8;
+				netlbl_putinc_u32(&buf,
+					    list_iter->type_def.cipsov4->type);
+				netlbl_putinc_u32(&buf,
+					    list_iter->type_def.cipsov4->doi);
+				break;
+#endif
+			default:
+				rcu_read_unlock();
+				BUG();
+			}
+		}
+	rcu_read_unlock();
+
+	return skb;
+
+dump_failure:
+	kfree_skb(skb);
+	return NULL;
+}
+
+/**
+ * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff
+ *
+ * Description:
+ * Dump the default domain mapping into a buffer suitable for returning to an
+ * application in response to a NetLabel management DEFDOMAIN message.  This
+ * function may fail if another process is changing the default domain mapping
+ * at the same time.  The returned sk_buff has room at the front of the
+ * skb_buff for a nlmsghdr struct and a netlbl_mgmt_msghdr struct.  See
+ * netlabel.h for the DEFDOMAIN message format.  Returns a pointer to a
+ * sk_buff on success, NULL on error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump_default(void)
+{
+	struct sk_buff *skb;
+	unsigned char *buf;
+	u32 buf_len;
+	u32 tmp_len;
+	struct netlbl_dom_map *entry;
+
+	/* XXX - This is kinda ugly as we have to go look at the default 
+	   mapping once to determine how large of a buffer we need, drop the
+	   locks, allocate the buffer, grab the locks, and finally fill the
+	   buffer.  The problem is that there is that open window where the
+	   default mapping could change on us, if that is the case we fail. */
+
+	buf_len = 4;
+	rcu_read_lock();
+	entry = rcu_dereference(netlbl_domhsh_def);
+	if (entry != NULL)
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			buf_len += 8;
+			break;
+#endif
+		default:
+			BUG();
+		}
+	rcu_read_unlock();
+
+	skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+				    buf_len), GFP_KERNEL);
+	if (skb == NULL)
+		return NULL;
+	skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	tmp_len = skb_tailroom(skb);
+	if (tmp_len < buf_len)
+		goto dump_default_failure;
+	buf = skb_put(skb, buf_len);
+
+	rcu_read_lock();
+	if (entry != rcu_dereference(netlbl_domhsh_def)) {
+		rcu_read_unlock();
+		goto dump_default_failure;
+	}
+	buf_len -= 4;
+	if (entry != NULL) {
+		netlbl_putinc_u32(&buf, entry->type);
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (buf_len < 8) {
+				rcu_read_unlock();
+				goto dump_default_failure;
+			}
+			buf_len -= 8;
+			netlbl_putinc_u32(&buf, entry->type_def.cipsov4->type);
+			netlbl_putinc_u32(&buf, entry->type_def.cipsov4->doi);
+			break;
+#endif
+		default:
+			rcu_read_unlock();
+			BUG();
+		}
+	} else
+		netlbl_putinc_u32(&buf, NETLBL_NLTYPE_NONE);
+	rcu_read_unlock();
+
+	return skb;
+
+dump_default_failure:
+	kfree_skb(skb);
+	return NULL;
+}
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_domainhash.h	2006-05-12 15:39:28.000000000 -0400
@@ -0,0 +1,64 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_DOMAINHASH_H
+#define _NETLABEL_DOMAINHASH_H
+
+/* Domain hash table size */
+/* XXX - currently this number is an uneducated guess */
+#define NETLBL_DOMHSH_BITSIZE       7
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map {
+	char *domain;
+	u32 type;
+	union {
+		struct cipso_v4_doi *cipsov4;
+	} type_def;
+
+	u32 valid;
+	struct list_head list;
+	struct rcu_head rcu;
+};
+
+/* init/exit functions */
+int netlbl_domhsh_init(const u32 size);
+int netlbl_domhsh_exit(void);
+
+/* Manipulate the domain hash table */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry);
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry);
+int netlbl_domhsh_remove_default(void);
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct sk_buff *netlbl_domhsh_dump(void);
+struct sk_buff *netlbl_domhsh_dump_default(void);
+
+#endif
--- linux-2.6.16.i686/net/netlabel/netlabel_kapi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_kapi.c	2006-05-25 11:30:04.000000000 -0400
@@ -0,0 +1,374 @@
+/*
+ * NetLabel Kernel API
+ *
+ * This file defines the kernel API for the NetLabel system.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <net/ip.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_unlabeled.h"
+
+/*
+ * LSM Functions
+ */
+
+/**
+ * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct
+ * @flags: the memory allocation flags
+ *
+ * Description:
+ * Allocate and initialize a netlbl_lsm_secattr struct.  Returns a valid
+ * pointer on success, or NULL on failure.
+ *
+ */
+struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags)
+{
+	return kzalloc(sizeof(struct netlbl_lsm_secattr), flags);
+}
+
+/**
+ * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
+ * @secattr: the struct to free
+ *
+ * Description:
+ * Frees @secattr including all of the internal buffers.
+ *
+ */
+void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	if (secattr->set_domain)
+		kfree(secattr->domain);
+	if (secattr->set_mls_cat)
+		kfree(secattr->mls_cat);
+	if (secattr->set_cache && secattr->cache.free)
+		secattr->cache.free(secattr->cache.data);
+	kfree(secattr);
+}
+
+/**
+ * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
+ * @secattr: the struct to initialize
+ *
+ * Description:
+ * Initialize an already allocated netlbl_lsm_secattr struct.  Returns zero on
+ * success, negative values on error.
+ *
+ */
+int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	memset(secattr, 0, sizeof(struct netlbl_lsm_secattr));
+	return 0;
+}
+
+/**
+ * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
+ * @secattr: the struct to clear
+ *
+ * Description:
+ * Destroys the @secattr struct, including freeing all of the internal buffers.
+ * On return the struct is suitable for reuse.
+ *
+ */
+void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	if (secattr->set_domain)
+		kfree(secattr->domain);
+	if (secattr->set_mls_cat)
+		kfree(secattr->mls_cat);
+	if (secattr->set_cache && secattr->cache.free)
+		secattr->cache.free(secattr->cache.data);
+	memset(secattr, 0, sizeof(struct netlbl_lsm_secattr));
+}
+
+/**
+ * netlbl_socket_setattr - Label a socket using the correct protocol
+ * @sock: the socket to label
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given socket using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_setattr(const struct socket *sock, 
+			  const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	struct netlbl_dom_map *dom_entry;
+
+	BUG_ON(sock == NULL || sock->sk == NULL ||
+	       sock->sk->sk_family != PF_INET || secattr == NULL ||
+	       secattr->set_domain == 0);
+
+	rcu_read_lock();
+	dom_entry = netlbl_domhsh_getentry(secattr->domain);
+	if (dom_entry == NULL) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+	switch (dom_entry->type) {
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = cipso_v4_setopt(sock,
+					  dom_entry->type_def.cipsov4,
+					  secattr);
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = 0;
+		break;
+#endif
+	default:
+		ret_val = -ENOENT;
+	}
+	rcu_read_unlock();
+
+	return ret_val;
+}
+
+/**
+ * netlbl_socket_peekattr - Get the security attributes on a queued packet
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Peek at the incoming packet queue of @sock and return the security
+ * attributes of the first packet in the queue.  If there are no packets in
+ * the queue or no packets with security attributes return -ENOMSG.  Otherwise
+ * return zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_peekattr(const struct socket *sock, 
+			   struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+	struct sk_buff_head *sock_queue;
+	struct sk_buff *skb;
+	struct sk_buff *skb_tmp = NULL;
+
+	BUG_ON(sock == NULL || sock->sk == NULL || 
+	       sock->sk->sk_family != PF_INET || secattr == NULL);
+
+	sock_queue = &sock->sk->sk_receive_queue;
+	/* XXX - We could just take the lock here and do a skb_peek() but we
+	         might end up holding the lock for a long time so grab the
+		 lock, do a peek, and clone the result */
+	spin_lock(&sock_queue->lock);
+	skb = skb_peek(sock_queue);
+	if (skb != NULL)
+		skb_tmp = skb_clone(skb, GFP_ATOMIC);
+	spin_unlock(&sock_queue->lock);
+	if (skb_tmp != NULL) {
+		ret_val = netlbl_skbuff_getattr(skb_tmp, secattr);
+		kfree_skb(skb_tmp);
+	} else
+		ret_val = -ENOMEM;
+
+	return ret_val;
+}
+
+/**
+ * netlbl_skbuff_getattr - Determine the security attributes of a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given packet to see if a recognized form of packet labeling
+ * is present, if so it parses the packet label and returns the security
+ * attributes in @secattr.  The caller must set the @secattr->lsm_type field
+ * before calling this function so we know what information to return.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_skbuff_getattr(const struct sk_buff *skb, 
+			  struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+
+	BUG_ON(skb == NULL || secattr == NULL);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	if (CIPSO_V4_OPTEXIST(skb)) {
+		ret_val = cipso_v4_getopt(skb, secattr);
+		goto skbuff_read_return;
+	}
+#endif
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+	ret_val = netlbl_unlabel_getattr(skb, secattr);
+#endif
+
+skbuff_read_return:
+	return ret_val;
+}
+
+/**
+ * netlbl_skbuff_err - Handle a LSM error on a sk_buff
+ * @skb: the packet
+ * @error: the error code
+ *
+ * Description:
+ * Deal with a LSM problem when handling the packet in @skb, typically this is
+ * a permission denied problem (-EACCES).  The correct action is determined
+ * according to the packet's labeling protocol.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_skbuff_err(struct sk_buff *skb, int error)
+{
+	BUG_ON(skb == NULL || error == 0);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	if (CIPSO_V4_OPTEXIST(skb))
+		return cipso_v4_error(skb, error, 0);
+#endif
+
+	return -ENOMSG;
+}
+
+/**
+ * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
+ *
+ * Description:
+ * For all of the NetLabel protocols that support some form of label mapping
+ * cache, invalidate the cache.  Returns zero on success, negative values on
+ * error.
+ *
+ */
+int netlbl_cache_invalidate(void)
+{
+	return cipso_v4_cache_invalidate();
+}
+
+/**
+ * netlbl_cache_add - Add an entry to a NetLabel protocol cache
+ * @skb: the packet
+ * @secattr: the packet's security attributes
+ *
+ * Description:
+ * Add the LSM security attributes for the given packet to the underlying
+ * NetLabel protocol's label mapping cache.  Returns zero on success, negative
+ * values on error.
+ *
+ */
+int netlbl_cache_add(const struct sk_buff *skb,
+		     const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+
+	BUG_ON(skb == NULL || secattr == NULL);
+
+	if (secattr->set_cache != 1)
+		return -ENOMSG;
+
+	if (CIPSO_V4_OPTEXIST(skb))
+		ret_val = cipso_v4_cache_add(skb, secattr);
+
+	return ret_val;
+}
+
+/*
+ * Netfilter Functions
+ */
+
+/* XXX - TBD */
+
+/*
+ * Module Functions
+ */
+
+/**
+ * netlbl_init - Init for the NetLabel module
+ *
+ * Description:
+ * Perform the initialization of the NetLabel module before first use.
+ *
+ */
+static int __init netlbl_init(void)
+{
+	printk(KERN_INFO "NetLabel: Initializing (v%s %s)\n",
+	       NETLBL_VER_STR, NETLBL_VER_DATE);
+	printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
+	       (1 << NETLBL_DOMHSH_BITSIZE));
+	printk(KERN_INFO "NetLabel:  protocols ="
+#ifdef CONFIG_NETLABEL_UNLABELED
+	       " UNLABELED"
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	       " CIPSOv4"
+#endif
+	       "\n");
+
+	if (netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE) != 0)
+		return -ENOMEM;
+	if (netlbl_netlink_init() != 0) {
+		netlbl_domhsh_exit();
+		return -ENOMEM;
+	}
+
+#ifdef CONFIG_NETLABEL_UNLABELED_DEFAULT
+	if (netlbl_unlabel_defconf() != 0) {
+		netlbl_netlink_exit();
+		netlbl_domhsh_exit();
+		return -ENOMEM;
+	}
+	printk(KERN_INFO "NetLabel:  unlabeled traffic allowed by default\n");
+#endif
+
+	return 0;
+}
+
+/**
+ * netlbl_exit - Cleanup for the NetLabel module
+ * 
+ * Description:
+ * Perform any cleanup required before removing the NetLabel module.
+ *
+ */
+static void __exit netlbl_exit(void)
+{
+	printk(KERN_INFO "NetLabel: Exiting\n");
+
+	netlbl_netlink_exit();
+	netlbl_domhsh_exit();
+}
+
+module_init(netlbl_init);
+module_exit(netlbl_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Moore <[email-masked]>");
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_mgmt.c	2006-05-17 18:23:24.000000000 -0400
@@ -0,0 +1,686 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_mgmt.h"
+
+/*
+ * Local Prototypes
+ */
+
+static int netlbl_mgmt_send_ack(const struct nlmsghdr *nl_hdr,
+				const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_mgmt_put_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_mgmt_put_hdr(unsigned char *buffer, const u32 opcode)
+{
+	((struct netlbl_mgmt_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_mgmt_putinc_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_mgmt_putinc_hdr(unsigned char **buffer, 
+					  const u32 opcode)
+{
+	netlbl_mgmt_put_hdr(*buffer, opcode);
+	*buffer += sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_payload_len - Return the length of the payload
+ * @nl_hdr: NETLINK message header
+ *
+ * Description:
+ * This function returns the length of the NetLabel management payload.
+ *
+ */
+static inline u32 netlbl_mgmt_payload_len(const struct nlmsghdr *nl_hdr)
+{
+	if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_mgmt_msghdr))
+		return 0;
+	return nlmsg_len(nl_hdr) - sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_payload_data - Returns a pointer to the start of the data
+ * @nl_hdr: NETLINK message header
+ *
+ * Description:
+ * This function returns a pointer to the start of the NetLabel management
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_mgmt_payload_data(
+	const struct nlmsghdr *nl_hdr)
+{
+	return nlmsg_data(nl_hdr) + sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table.  See netlabel.h for a description of the message format.
+ * Returns zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_add(const struct nlmsghdr *nl_hdr,
+			   const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(nl_hdr);
+	u32 count;
+	struct netlbl_dom_map *entry = NULL;
+	u32 iter;
+	u32 tmp_val;
+	u32 rcu_locked = 0;
+
+	if (msg_len < 4)
+		goto add_failure;
+	count = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) {
+		if (msg_len < 4)
+			goto add_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		if (tmp_val == 0)
+			goto add_failure;
+		entry = kzalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL);
+		if (entry == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+
+		if (msg_len < tmp_val)
+			goto add_failure;
+		entry->domain = kmalloc(tmp_val, GFP_KERNEL);
+		if (entry->domain == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		strncpy(entry->domain, msg_ptr, tmp_val);
+		entry->domain[tmp_val - 1] = '\0';
+		msg_ptr += tmp_val;
+		msg_len -= tmp_val;
+
+		if (msg_len < 4)
+			goto add_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		entry->type = tmp_val;
+		switch (tmp_val) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (msg_len < 8)
+				goto add_failure;
+			msg_ptr += 4;
+			tmp_val = netlbl_getinc_u32(&msg_ptr);
+			msg_len -= 8;
+			/* XXX - we should be holding a rcu_read_lock() here
+			   while we hold the result but since the entry
+			   will always be deleted when the CIPSO DOI
+			   is deleted we aren't going to keep the lock */
+			rcu_read_lock();
+			entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+			if (entry->type_def.cipsov4 == NULL) {
+				rcu_read_unlock();
+				goto add_failure;
+			}
+			rcu_locked = 1;
+			break;
+#endif
+		default:
+			goto add_failure;
+		}
+
+		ret_val = netlbl_domhsh_add(entry);
+		if (rcu_locked) {
+			rcu_read_unlock();
+			rcu_locked = 0;
+		}
+		if (ret_val != 0)
+			goto add_failure;
+	}
+
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_OK);
+	return 0;
+
+add_failure:
+	if (entry) {
+		if (entry->domain)
+			kfree(entry->domain);
+		kfree(entry);
+	}
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_remove - Handle a REMOVE message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVE message and remove the specified domain
+ * mappings.  Returns zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_remove(const struct nlmsghdr *nl_hdr,
+			      const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(nl_hdr);
+	u32 count;
+	u32 iter;
+	u32 tmp_val;
+
+	if (msg_len < 4)
+		goto remove_failure;
+	count = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	for (iter = 0; iter < count && msg_len > 0; iter++) {
+		if (msg_len < 4)
+			goto remove_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		if (tmp_val == 0 ||
+		    msg_len < tmp_val || msg_ptr[tmp_val - 1] != '\0')
+			goto remove_failure;
+		ret_val = netlbl_domhsh_remove(msg_ptr);
+		msg_ptr += tmp_val;
+		msg_len -= tmp_val;
+		if (ret_val != 0)
+			goto remove_failure;
+	}
+
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_OK);
+	return 0;
+
+remove_failure:
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_list - Handle a LIST message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LIST message and dumps the domain hash table in a
+ * form suitable for use in a kernel generated LIST message.  Returns
+ * zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_list(const struct nlmsghdr *nl_hdr,
+			    const unsigned char *msg)
+{
+	int ret_val = -ENOMEM;
+	struct sk_buff *skb;
+	unsigned char *buf_ptr;
+
+	skb = netlbl_domhsh_dump();
+	if (skb == NULL)
+		goto list_return;
+	buf_ptr = skb_push(skb, 
+			   NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	if (buf_ptr == NULL) {
+		kfree_skb(skb);
+		ret_val = -EAGAIN;
+		goto list_return;
+	}
+	netlbl_putinc_hdr(&buf_ptr,
+			  NETLBL_NLTYPE_MGMT,
+			  skb->len, 0, nl_hdr->nlmsg_pid, 0);
+	netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LIST);
+
+	ret_val = netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+list_return:
+	if (ret_val != 0)
+		netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_adddef - Handle an ADDDEF message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADDDEF message and respond accordingly.  Returns
+ * zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_adddef(const struct nlmsghdr *nl_hdr,
+			      const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(nl_hdr);
+	u32 type;
+	struct netlbl_dom_map *entry = NULL;
+	u32 tmp_val;
+	u32 rcu_locked = 0;
+
+	if (msg_len < 4)
+		goto adddef_failure;
+	type = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	entry = kzalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL);
+	if (entry == NULL) {
+		ret_val = -ENOMEM;
+		goto adddef_failure;
+	}
+	entry->type = type;
+
+	switch (type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (msg_len < 8)
+			goto adddef_failure;
+		msg_ptr += 4;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 8;
+		/* XXX - we should be holding a rcu_read_lock here while we
+		   hold the result but since the entry will always be
+		   deleted when the CIPSO DOI is deleted we are going
+		   to skip the lock */
+		rcu_read_lock();
+		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+		if (entry->type_def.cipsov4 == NULL) {
+			rcu_read_unlock();
+			goto adddef_failure;
+		}
+		rcu_locked = 1;
+		break;
+#endif
+	default:
+		ret_val = -EINVAL;
+		goto adddef_failure;
+	}
+
+	ret_val = netlbl_domhsh_add_default(entry);
+	if (rcu_locked) {
+		rcu_read_unlock();
+		rcu_locked = 0;
+	}
+	if (ret_val != 0)
+		goto adddef_failure;
+
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_OK);
+	return 0;
+
+adddef_failure:
+	if (entry)
+		kfree(entry);
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_removedef - Handle a REMOVEDEF message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVEDEF message and remove the default domain
+ * mapping.  Returns zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_removedef(const struct nlmsghdr *nl_hdr,
+				 const unsigned char *msg)
+{
+	int ret_val;
+
+	ret_val = netlbl_domhsh_remove_default();
+	if (ret_val == 0)
+		netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_OK);
+	else
+		netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_listdef - Handle a LISTDEF message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LISTDEF message and dumps the default domain
+ * mapping in a form suitable for use in a kernel generated LISTDEF message.
+ * Returns zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_listdef(const struct nlmsghdr *nl_hdr,
+			       const unsigned char *msg)
+{
+	int ret_val = -ENOMEM;
+	struct sk_buff *skb;
+	unsigned char *buf_ptr;
+
+	skb = netlbl_domhsh_dump_default();
+	if (skb == NULL)
+		goto listdef_return;
+	buf_ptr = skb_push(skb, 
+			   NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	if (buf_ptr == NULL) {
+		kfree_skb(skb);
+		ret_val = -EAGAIN;
+		goto listdef_return;
+	}
+	netlbl_putinc_hdr(&buf_ptr,
+			  NETLBL_NLTYPE_MGMT,
+			  skb->len, 0, nl_hdr->nlmsg_pid, 0);
+	netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LISTDEF);
+
+	ret_val = netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+listdef_return:
+	if (ret_val != 0)
+		netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_modules - Handle a MODULES message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated MODULES message and respond accordingly.  Returns
+ * zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_modules(const struct nlmsghdr *nl_hdr,
+			       const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	u32 mod_count = 0;
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nl_mgmt_hdr;
+	unsigned char *data;
+
+	if (netlbl_mgmt_payload_len(nl_hdr) < 4)
+		goto nlmsg_failure;
+	mod_count = netlbl_get_u32(msg);
+	if (mod_count != 0)
+		goto nlmsg_failure;
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+	mod_count += 1;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	mod_count += 1;
+#endif
+
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 4 + mod_count * 4;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL) {
+		ret_val = -ENOMEM;
+		goto nlmsg_failure;
+	}
+
+	nl_mgmt_hdr = NLMSG_PUT(skb,
+				nl_hdr->nlmsg_pid,
+				0, NETLBL_NLTYPE_MGMT, data_size);
+	nl_mgmt_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_mgmt_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_MODULES);
+	netlbl_putinc_u32(&data, mod_count);
+#ifdef CONFIG_NETLABEL_UNLABELED
+	netlbl_putinc_u32(&data, NETLBL_NLTYPE_UNLABELED);
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	netlbl_putinc_u32(&data, NETLBL_NLTYPE_CIPSOV4);
+#endif
+
+	return netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/**
+ * netlbl_mgmt_version - Handle a VERSION message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated VERSION message and respond accordingly.  Returns
+ * zero on success and non-zero on error.
+ *
+ */
+static int netlbl_mgmt_version(const struct nlmsghdr *nl_hdr,
+			       const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	u32 str_len;
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nl_mgmt_hdr;
+	unsigned char *data;
+
+	if (netlbl_mgmt_payload_len(nl_hdr) < 4)
+		goto nlmsg_failure;
+	str_len = netlbl_get_u32(msg);
+	if (str_len != 0)
+		goto nlmsg_failure;
+
+	str_len = strlen(NETLBL_VER_STR) + 1;
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 4 + str_len;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL) {
+		ret_val = -ENOMEM;
+		goto nlmsg_failure;
+	}
+
+	nl_mgmt_hdr = NLMSG_PUT(skb,
+				nl_hdr->nlmsg_pid,
+				0, NETLBL_NLTYPE_MGMT, data_size);
+	nl_mgmt_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_mgmt_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_VERSION);
+	netlbl_putinc_u32(&data, str_len);
+	netlbl_putinc_str(&data, NETLBL_VER_STR);
+
+	return netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_ERR);
+	return ret_val;
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_mgmt_send_ack - Send an ACK message
+ * @nl_hdr: NETLINK message header
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @nl_hdr.  Returns negative values on error. 
+ *
+ */
+static int netlbl_mgmt_send_ack(const struct nlmsghdr *nl_hdr, 
+				const u32 ret_code)
+{
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_ack_hdr;
+	unsigned char *data;
+
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 8;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	nl_ack_hdr = NLMSG_PUT(skb,
+			       nl_hdr->nlmsg_pid,
+			       0, NETLBL_NLTYPE_MGMT, data_size);
+	nl_ack_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_ack_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_ACK);
+	netlbl_putinc_u32(&data, nl_hdr->nlmsg_seq);
+	netlbl_putinc_u32(&data, ret_code);
+
+	return netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+nlmsg_failure:
+	kfree_skb(skb);
+	return -EPERM;
+}
+
+/**
+ * netlbl_mgmt_rcv - Process incoming NetLabel packets
+ * @nl_hdr: NETLINK message header
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming NetLabel
+ * management traffic and dispatching it to the correct functions.
+ *
+ */
+void netlbl_mgmt_rcv(const struct nlmsghdr *nl_hdr, const unsigned char *msg)
+{
+	struct netlbl_mgmt_msghdr *nl_mgmt_hdr;
+
+	if (nl_hdr == NULL ||
+	    msg == NULL ||
+	    nlmsg_len(nl_hdr) < sizeof(struct netlbl_mgmt_msghdr))
+		return;
+
+	nl_mgmt_hdr = (struct netlbl_mgmt_msghdr *)msg;
+	switch (nl_mgmt_hdr->opcode) {
+	case NL_MGMT_ADD:
+		netlbl_mgmt_add(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_REMOVE:
+		netlbl_mgmt_remove(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_LIST:
+		netlbl_mgmt_list(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_ADDDEF:
+		netlbl_mgmt_adddef(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_REMOVEDEF:
+		netlbl_mgmt_removedef(nl_hdr, 
+				      netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_LISTDEF:
+		netlbl_mgmt_listdef(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_MODULES:
+		netlbl_mgmt_modules(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	case NL_MGMT_VERSION:
+		netlbl_mgmt_version(nl_hdr, netlbl_mgmt_payload_data(nl_hdr));
+		break;
+	default:
+		netlbl_mgmt_send_ack(nl_hdr, NETLBL_MGMT_E_BADCMD);
+		return;
+	}
+}
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_mgmt.h	2006-05-16 12:17:42.000000000 -0400
@@ -0,0 +1,265 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_MGMT_H
+#define _NETLABEL_MGMT_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the management interface,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ *   Sent by the kernel in response to an applications message, applications
+ *   should never send this message.
+ *
+ *   +----------------------+-----------------------+
+ *   | seq number (32 bits) | return code (32 bits) |
+ *   +----------------------+-----------------------+
+ *
+ *     seq number:  the sequence number of the original message, taken from the
+ *                  nlmsghdr structure
+ *     return code: values specified in NETLBL_MGMT_E_*
+ *
+ * o ADD:
+ *   Sent by an application to add a domain mapping to the NetLabel system.
+ *   The kernel should respond with an ACK.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o REMOVE:
+ *   Sent by an application to remove a domain mapping from the NetLabel
+ *   system.  The kernel should ACK this message.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *
+ * o LIST:
+ *   This message can be sent either from an application or by the kernel in
+ *   response to an application generated LIST message.  When sent by an
+ *   application there is no payload.  The kernel should respond to a LIST
+ *   message either with a LIST message on success or an ACK message on
+ *   failure.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o ADDDEF:
+ *   Sent by an application to set the default domain mapping for the NetLabel
+ *   system.  The kernel should respond with an ACK.
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o REMOVEDEF:
+ *   Sent by an application to remove the default domain mapping from the
+ *   NetLabel system, there is no payload.  The kernel should ACK this message.
+ *
+ * o LISTDEF:
+ *   This message can be sent either from an application or by the kernel in
+ *   response to an application generated LISTDEF message.  When sent by an
+ *   application there is no payload.  The kernel should respond to a
+ *   LISTDEF message either with a LISTDEF message on success or an ACK message
+ *   on failure.
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o MODULES:
+ *   Sent by an application to request a list of configured NetLabel modules
+ *   in the kernel.  This message type is also used by the kernel to respond
+ *   to an application's MODULES message.
+ *
+ *   +-------------------+
+ *   | modules (32 bits) | ...
+ *   +-------------------+
+ *
+ *     modules: the number of modules in the message, if this is an application
+ *              generated message and the value is zero then return a list of
+ *              the configured modules
+ *
+ *   +------------------+
+ *   | module (32 bits) | ... repeated
+ *   +------------------+
+ *
+ *     module: the module number as defined by NETLBL_NLTYPE_*
+ *
+ * o VERSION:
+ *   Sent by an application to request the NetLabel version string.  This
+ *   message type is also used by the kernel to respond to an VERSION request.
+ *
+ *   +--------------------------+
+ *   | version length (32 bits) | ...
+ *   +--------------------------+
+ *
+ *     version length: the length of the version string, if this is an
+ *                     application generated message and the value is zero then
+ *                     return the correct version string
+ *
+ *   +---------------------------+
+ *   | version string (variable) |
+ *   +---------------------------+
+ *
+ *     version string: the version string, NULL terminated
+ *
+ */
+
+/* MGMT message header */
+struct netlbl_mgmt_msghdr {
+	enum { NL_MGMT_NOOP,
+	       NL_MGMT_ACK,
+	       NL_MGMT_ADD,
+	       NL_MGMT_REMOVE,
+	       NL_MGMT_LIST,
+	       NL_MGMT_ADDDEF,
+	       NL_MGMT_REMOVEDEF,
+	       NL_MGMT_LISTDEF,
+	       NL_MGMT_MODULES,
+	       NL_MGMT_VERSION
+	} opcode;
+};
+
+/* MGMT ACK return codes */
+#define NETLBL_MGMT_E_OK         NETLBL_E_OK
+#define NETLBL_MGMT_E_ERR        NETLBL_E_ERR
+#define NETLBL_MGMT_E_BADCMD     NETLBL_E_BADCMD
+
+/* Process NetLabel management messages */
+void netlbl_mgmt_rcv(const struct nlmsghdr *nl_hdr, const unsigned char *msg);
+
+#endif
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_unlabeled.c	2006-05-23 10:53:04.000000000 -0400
@@ -0,0 +1,289 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system.  The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_user.h"
+#include "netlabel_domainhash.h"
+#include "netlabel_unlabeled.h"
+
+/* Accept unlabeled packets flag */
+static atomic_t netlabel_unlabel_accept_flg = ATOMIC_INIT(0);
+
+/*
+ * Local Prototypes
+ */
+
+static int netlbl_unlabel_send_ack(const struct nlmsghdr *nl_hdr,
+				   const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_unlabel_put_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_unlabel_put_hdr(unsigned char *buffer,
+					  const u32 opcode)
+{
+	((struct netlbl_unlabel_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_unlabel_putinc_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_unlabel_putinc_hdr(unsigned char **buffer, 
+					     const u32 opcode)
+{
+	netlbl_unlabel_put_hdr(*buffer, opcode);
+	*buffer += sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_len - Return the length of the payload
+ * @nl_hdr: NETLINK message header
+ *
+ * Description:
+ * This function returns the length of the NetLabel unlabeled payload.
+ *
+ */
+static inline u32 netlbl_unlabel_payload_len(const struct nlmsghdr *nl_hdr)
+{
+	if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_unlabel_msghdr))
+		return 0;
+	return nlmsg_len(nl_hdr) - sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_data - Returns a pointer to the start of the data
+ * @nl_hdr: NETLINK message header
+ *
+ * Description:
+ * This function returns a pointer to the start of the NetLabel unlabeled
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_unlabel_payload_data(
+	const struct nlmsghdr *nl_hdr)
+{
+	return nlmsg_data(nl_hdr) + sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_unlabel_accept - Handle an ACCEPT message
+ * @nl_hdr: NETLINK message header
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ACCEPT message and set the accept flag accordingly.
+ * Returns zero on success, negative values on error.
+ *
+ */
+static int netlbl_unlabel_accept(const struct nlmsghdr *nl_hdr, 
+				 const unsigned char *msg)
+{
+	u32 value;
+
+	if (netlbl_unlabel_payload_len(nl_hdr) == 4) {
+		value = netlbl_get_u32(msg);
+		if (value == 1 || value == 0) {
+			atomic_set(&netlabel_unlabel_accept_flg, value);
+			netlbl_unlabel_send_ack(nl_hdr, NETLBL_UNLABEL_E_OK);
+			return 0;
+		}
+	}
+
+	netlbl_unlabel_send_ack(nl_hdr, NETLBL_UNLABEL_E_ERR);
+	return -EINVAL;
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_unlabel_send_ack - Send an ACK message
+ * @nl_hdr: NETLINK message header
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @nl_hdr.  Returns negative values on error. 
+ *
+ */
+static int netlbl_unlabel_send_ack(const struct nlmsghdr *nl_hdr,
+				   const u32 ret_code)
+{
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_ack_hdr;
+	unsigned char *data;
+
+	data_size = sizeof(struct netlbl_unlabel_msghdr) + 8;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	nl_ack_hdr = NLMSG_PUT(skb,
+			       nl_hdr->nlmsg_pid,
+			       0, NETLBL_NLTYPE_UNLABELED, data_size);
+	nl_ack_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_ack_hdr);
+	netlbl_unlabel_putinc_hdr(&data, NL_UNL_ACK);
+	netlbl_putinc_u32(&data, nl_hdr->nlmsg_seq);
+	netlbl_putinc_u32(&data, ret_code);
+
+	return netlbl_netlink_snd(skb, nl_hdr->nlmsg_pid);
+
+nlmsg_failure:
+	kfree_skb(skb);
+	return -EPERM;
+}
+
+/**
+ * netlbl_unlabel_rcv - Process incoming NetLabel packets
+ * @nl_hdr: NETLINK message header
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming Unlabeled
+ * NetLabel traffic and dispatching it to the correct Unlabeled functions.
+ *
+ */
+void netlbl_unlabel_rcv(const struct nlmsghdr *nl_hdr,
+			const unsigned char *msg)
+{
+	struct netlbl_unlabel_msghdr *nl_unl_hdr;
+
+	if (nl_hdr == NULL ||
+	    msg == NULL ||
+	    nlmsg_len(nl_hdr) < sizeof(struct netlbl_unlabel_msghdr))
+		return;
+
+	nl_unl_hdr = (struct netlbl_unlabel_msghdr *)msg;
+	switch (nl_unl_hdr->opcode) {
+	case NL_UNL_ACCEPT:
+		netlbl_unlabel_accept(nl_hdr,
+				      netlbl_unlabel_payload_data(nl_hdr));
+		break;
+	default:
+		netlbl_unlabel_send_ack(nl_hdr, NETLBL_UNLABEL_E_BADCMD);
+		return;
+	}
+}
+
+/*
+ * NetLabel KAPI Hooks
+ */
+
+/**
+ * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Determine the security attributes, if any, for an unlabled packet and return
+ * them in @secattr.  Returns zero on success and negative values on failure.
+ *
+ */
+int netlbl_unlabel_getattr(const struct sk_buff *skb,
+			   struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(skb == NULL || secattr == NULL);
+
+	if (atomic_read(&netlabel_unlabel_accept_flg) == 1) {
+		memset(secattr, 0, sizeof(struct netlbl_lsm_secattr));
+		return 0;
+	}
+
+	return -ENOMSG;
+}
+
+/**
+ * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
+ *
+ * Description:
+ * Set the default NetLabel configuration to allow incoming unlabeled packets
+ * and to send unlabeled network traffic by default.
+ *
+ */
+int netlbl_unlabel_defconf(void)
+{
+	int ret_val;
+	struct netlbl_dom_map *entry;
+
+	entry = kzalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL);
+	if (entry == NULL)
+		return -ENOMEM;
+	entry->type = NETLBL_NLTYPE_UNLABELED;
+	ret_val = netlbl_domhsh_add_default(entry);
+	if (ret_val != 0)
+		return ret_val;
+
+	atomic_set(&netlabel_unlabel_accept_flg, 1);
+
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Moore <[email-masked]>");
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_unlabeled.h	2006-05-23 10:50:18.000000000 -0400
@@ -0,0 +1,90 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system.  The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_UNLABELED_H
+#define _NETLABEL_UNLABELED_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the Unlabeled subsystem,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ *   Sent by the kernel in response to an applications message, applications
+ *   should never send this message.
+ *
+ *   +----------------------+-----------------------+
+ *   | seq number (32 bits) | return code (32 bits) |
+ *   +----------------------+-----------------------+
+ *
+ *     seq number:  the sequence number of the original message, taken from the
+ *                  nlmsghdr structure
+ *     return code: values specified in NETLBL_UNLABEL_E_*
+ *
+ * o ACCEPT
+ *   This message is sent from an application to specify if the kernel should
+ *   allow unlabled packets to pass if they do not match any of the static
+ *   mappings defined in the unlabeled module.
+ *
+ *   +-----------------+
+ *   | allow (32 bits) |
+ *   +-----------------+
+ *
+ *     allow: if true (1) then allow the packets to pass, if false (0) then
+ *            reject the packets
+ *
+ */
+
+/* Unlabeled message header */
+struct netlbl_unlabel_msghdr {
+	enum { NL_UNL_NOOP,
+	       NL_UNL_ACK,
+	       NL_UNL_ACCEPT
+	} opcode;
+};
+
+/* Unlabeled ACK return codes */
+#define NETLBL_UNLABEL_E_OK         NETLBL_E_OK
+#define NETLBL_UNLABEL_E_ERR        NETLBL_E_ERR
+#define NETLBL_UNLABEL_E_BADCMD     NETLBL_E_BADCMD
+
+/* Process Unlabeled NetLabel messages */
+void netlbl_unlabel_rcv(const struct nlmsghdr *nl_hdr, 
+			const unsigned char *msg);
+
+/* Process Unlabeled incoming network packets */
+int netlbl_unlabel_getattr(const struct sk_buff *skb,
+			   struct netlbl_lsm_secattr *secattr);
+
+/* Set the default configuration to allow Unlabeled packets */
+int netlbl_unlabel_defconf(void);
+
+#endif
--- linux-2.6.16.i686/net/netlabel/netlabel_user.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_user.c	2006-05-17 18:24:33.000000000 -0400
@@ -0,0 +1,166 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_unlabeled.h"
+#include "netlabel_cipso_v4.h"
+#include "netlabel_user.h"
+
+/* NETLINK socket */
+/* PM - do we need a lock (or something) around this? */
+static struct sock *netlbl_nl = NULL;
+
+/*
+ * NetLabel Functions
+ */
+
+/**
+ * netlbl_netlink_rcv - Catch incoming NETLINK packets
+ * @sk: the NETLINK socket
+ * @len: absolutely no clue, socket queue length maybe?
+ *
+ * Description:
+ * Receives the NETLINK packet, inspects the packet to determine the correct
+ * NetLabel subsystem and hands the packet off to the correct handler.
+ *
+ */
+static void netlbl_netlink_rcv(struct sock *sk, const int len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_hdr;
+
+	/* XXX - should this use netlink_run_queue() instead? */
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+		nl_hdr = (struct nlmsghdr *)skb->data;
+		switch (nl_hdr->nlmsg_type) {
+		case NETLBL_NLTYPE_MGMT:
+			netlbl_mgmt_rcv(nl_hdr, nlmsg_data(nl_hdr));
+			break;
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			netlbl_unlabel_rcv(nl_hdr, nlmsg_data(nl_hdr));
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			netlbl_cipsov4_rcv(nl_hdr, nlmsg_data(nl_hdr));
+			break;
+#endif
+		}
+		nlmsg_free(skb);
+	}
+}
+
+/**
+ * netlbl_netlink_init - Initialize the netlink socket
+ *
+ * Description:
+ * Create the netlink socket and do any other setup required.  Returns zero on
+ * success and non-zero on failure.
+ *
+ */
+int netlbl_netlink_init(void)
+{
+	BUG_ON(netlbl_nl);
+	/* XXX - it might be a good idea to spawn a thread here at startup to
+	   handle the updates to the label mapping databases and have the
+	   netlbl_netlink_rcv() function simply poke the thread but i am unsure
+	   and this approach is much simpler so it wins for now */
+	netlbl_nl = netlink_kernel_create(NETLINK_NETLABEL,
+					  NETLBL_NLGRP_MAX,
+					  netlbl_netlink_rcv, THIS_MODULE);
+	if (netlbl_nl == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * netlbl_exit - Release the netlink socket
+ * 
+ * Description:
+ * Close the netlink socket and do any other cleanup required.  Returns zero on
+ * success and non-zero on failure.
+ *
+ */
+int netlbl_netlink_exit(void)
+{
+	BUG_ON(!netlbl_nl);
+	/* XXX - if we do have a worker thread, see the above comment in 
+	   netlbl_netlink_init(), we should handle any cleanup here
+	   before we go away */
+	sock_release(netlbl_nl->sk_socket);
+
+	return 0;
+}
+
+/* 
+ * NETLINK I/O Functions
+ */
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: destination PID
+ *
+ * Description:
+ * Sends a unicast NetLabel message over the NETLINK socket.
+ *
+ */
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid)
+{
+	return nlmsg_unicast(netlbl_nl, skb, pid);
+}
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: sending PID
+ * @group: multicast group id
+ *
+ * Description:
+ * Sends a multicast NetLabel message over the NETLINK socket to all members
+ * of @group except @pid.
+ *
+ */
+int netlbl_netlink_snd_multicast(struct sk_buff *skb, 
+				 const u32 pid, 
+				 const u32 group)
+{
+	return nlmsg_multicast(netlbl_nl, skb, pid, group);
+}
--- linux-2.6.16.i686/net/netlabel/netlabel_user.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-cipso/net/netlabel/netlabel_user.h	2006-05-12 15:42:55.000000000 -0400
@@ -0,0 +1,42 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <[email-masked]>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_USER_H
+#define _NETLABEL_USER_H
+
+/* NetLabel NETLINK I/O functions */
+int netlbl_netlink_init(void);
+int netlbl_netlink_exit(void);
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid);
+int netlbl_netlink_snd_multicast(struct sk_buff *skb, 
+				 const u32 pid,
+				 const u32 group);
+
+#endif