Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2890

kernel-2.6.18-238.el5.src.rpm

Date: Wed, 27 Sep 2006 22:59:53 -0400
From: Eric Paris <eparis@redhat.com>
Subject: [RHEL5 PATCH] Update netlabel code for labeled networking support

Upstream is currently in the middle of a huge labeled networking
discussion (labeled networking in this case means carrying SELinux
labels across the network) and what all is needed.  We seem to have
almost everything we need in linus's 2.6.19 kernel to meet certification
AND actually be useful but I know there will be one more patch to come
along shorty to properly reconcile labels from secmark, netlabel/IPSEC
labeling, and CIPSO labeling.  This patch set bring us up to date with
the latest upstream in this area.  Without these bug fixes and updates
we won't be able to meet needs of our government customers in RHEL5.
The attached patch is the mashing together of 10 upstream patches.  I
can give all seperately here if needed but will include links to all
below.

This is BZ 208119  There has been little testing on these patches other
than upstream, although I hope to get results from testing on my RHEL5
kernel tomorrow.

-Eric

Patch1:
Thomas Graf: [NETLINK]: Extend netlink messaging interface
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=fe4944e59c357f945f81bc67edb7ed1392e875ad

Patch2:
Thomas Graf: [NETLINK]: Improve string attribute validation
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a5531a5d852008be40811496029012f4ad3093d1

Patch3:
Paul More: NetLabel: correct improper handling of non-NetLabel peer contexts
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=14a72f53fb1bb5d5c2bdd8cf172219519664729a

Patch4:
Paul Moore: NetLabel: make the CIPSOv4 cache spinlocks bottom half safe
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=609c92feea5652809319bb77f19d24a44615687d

Patch5:
Paul Moore: NetLabel: change the SELinux permissions
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=df2115c3134d0d1a18c1f37f5192394e7f64d1e0

Patch6:
Paul Moore: Netlink: add nla_for_each_nested() to the interface list
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=22acb19a91d2b551ea37647747972e5286284b22

Patch7:
Paul Moore: Netlink: add nla_validate_nested()
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4fe5d5c07ab615a52fd1b0ceba5aeed7c612821a

Patch8:
Paul Moore: NetLabel: rework the Netlink attribute handling (part 1)
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=fcd48280643e92ec6cb29a04e9079dd7b6b5bfef

Patch9:
Paul Moore: NetLabel: rework the Netlink attribute handling (part 2)
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=fd3858554b62c3af6b7664b5c58ad864c87116c9

Patch10:
Paul Moore: NetLabel: update docs with website information
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4cc6773508299377099aa30cf30e6a2196c5872d

[NETLINK]: Extend netlink messaging interface

Adds:
 nlmsg_get_pos()                 return current position in message
 nlmsg_trim()                    trim part of message
 nla_reserve_nohdr(skb, len)     reserve room for an attribute w/o hdr
 nla_put_nohdr(skb, len, data)   add attribute w/o hdr
 nla_find_nested()               find attribute in nested attributes

Fixes nlmsg_new() to take allocation flags and consider size.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---

--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -35,6 +35,8 @@
  *   nlmsg_put()			add a netlink message to an skb
  *   nlmsg_put_answer()			callback based nlmsg_put()
  *   nlmsg_end()			finanlize netlink message
+ *   nlmsg_get_pos()			return current position in message
+ *   nlmsg_trim()			trim part of message
  *   nlmsg_cancel()			cancel message construction
  *   nlmsg_free()			free a netlink message
  *
@@ -80,8 +82,10 @@
  *   struct nlattr			netlink attribtue header
  *
  * Attribute Construction:
- *   nla_reserve(skb, type, len)	reserve skb tailroom for an attribute
+ *   nla_reserve(skb, type, len)	reserve room for an attribute
+ *   nla_reserve_nohdr(skb, len)	reserve room for an attribute w/o hdr
  *   nla_put(skb, type, len, data)	add attribute to skb
+ *   nla_put_nohdr(skb, len, data)	add attribute w/o hdr
  *
  * Attribute Construction for Basic Types:
  *   nla_put_u8(skb, type, value)	add u8 attribute to skb
@@ -139,6 +143,7 @@
  *   nla_next(nla, remaining)		get next netlink attribute
  *   nla_validate()			validate a stream of attributes
  *   nla_find()				find attribute in stream of attributes
+ *   nla_find_nested()			find attribute in nested attributes
  *   nla_parse()			parse and validate stream of attrs
  *   nla_parse_nested()			parse nested attribuets
  *   nla_for_each_attr()		loop over all attributes
@@ -203,12 +208,18 @@ extern int		nla_memcmp(const struct nlat
 extern int		nla_strcmp(const struct nlattr *nla, const char *str);
 extern struct nlattr *	__nla_reserve(struct sk_buff *skb, int attrtype,
 				      int attrlen);
+extern void *		__nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
 extern struct nlattr *	nla_reserve(struct sk_buff *skb, int attrtype,
 				    int attrlen);
+extern void *		nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
 extern void		__nla_put(struct sk_buff *skb, int attrtype,
 				  int attrlen, const void *data);
+extern void		__nla_put_nohdr(struct sk_buff *skb, int attrlen,
+					const void *data);
 extern int		nla_put(struct sk_buff *skb, int attrtype,
 				int attrlen, const void *data);
+extern int		nla_put_nohdr(struct sk_buff *skb, int attrlen,
+				      const void *data);
 
 /**************************************************************************
  * Netlink Messages
@@ -453,12 +464,13 @@ static inline struct nlmsghdr *nlmsg_put
 /**
  * nlmsg_new - Allocate a new netlink message
  * @size: maximum size of message
+ * @flags: the type of memory to allocate.
  *
  * Use NLMSG_GOODSIZE if size isn't know and you need a good default size.
  */
-static inline struct sk_buff *nlmsg_new(int size)
+static inline struct sk_buff *nlmsg_new(int size, gfp_t flags)
 {
-	return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+	return alloc_skb(size, flags);
 }
 
 /**
@@ -480,6 +492,32 @@ static inline int nlmsg_end(struct sk_bu
 }
 
 /**
+ * nlmsg_get_pos - return current position in netlink message
+ * @skb: socket buffer the message is stored in
+ *
+ * Returns a pointer to the current tail of the message.
+ */
+static inline void *nlmsg_get_pos(struct sk_buff *skb)
+{
+	return skb->tail;
+}
+
+/**
+ * nlmsg_trim - Trim message to a mark
+ * @skb: socket buffer the message is stored in
+ * @mark: mark to trim to
+ *
+ * Trims the message to the provided mark. Returns -1.
+ */
+static inline int nlmsg_trim(struct sk_buff *skb, void *mark)
+{
+	if (mark)
+		skb_trim(skb, (unsigned char *) mark - skb->data);
+
+	return -1;
+}
+
+/**
  * nlmsg_cancel - Cancel construction of a netlink message
  * @skb: socket buffer the message is stored in
  * @nlh: netlink message header
@@ -489,9 +527,7 @@ static inline int nlmsg_end(struct sk_bu
  */
 static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	skb_trim(skb, (unsigned char *) nlh - skb->data);
-
-	return -1;
+	return nlmsg_trim(skb, nlh);
 }
 
 /**
@@ -631,6 +667,18 @@ static inline struct nlattr *nla_next(co
 }
 
 /**
+ * nla_find_nested - find attribute in a set of nested attributes
+ * @nla: attribute containing the nested attributes
+ * @attrtype: type of attribute to look for
+ *
+ * Returns the first attribute which matches the specified type.
+ */
+static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype)
+{
+	return nla_find(nla_data(nla), nla_len(nla), attrtype);
+}
+
+/**
  * nla_parse_nested - parse nested attributes
  * @tb: destination array with maxtype+1 elements
  * @maxtype: maximum attribute type to be expected
@@ -862,10 +910,7 @@ static inline int nla_nest_end(struct sk
  */
 static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
 {
-	if (start)
-		skb_trim(skb, (unsigned char *) start - skb->data);
-
-	return -1;
+	return nlmsg_trim(skb, start);
 }
 
 /**
@@ -880,4 +925,13 @@ static inline int nla_nest_cancel(struct
 	     nla_ok(pos, rem); \
 	     pos = nla_next(pos, &(rem)))
 
+/**
+ * nla_for_each_nested - iterate over nested attributes
+ * @pos: loop counter, set to current attribute
+ * @nla: attribute containing the nested attributes
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_nested(pos, nla, rem) \
+	nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
+
 #endif
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -75,7 +75,7 @@ static int prepare_reply(struct genl_inf
 	/*
 	 * If new attributes are added, please revisit this allocation
 	 */
-	skb = nlmsg_new(size);
+	skb = nlmsg_new(size, GFP_KERNEL);
 	if (!skb)
 		return -ENOMEM;
 
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -255,6 +255,26 @@ struct nlattr *__nla_reserve(struct sk_b
 }
 
 /**
+ * __nla_reserve_nohdr - reserve room for attribute without header
+ * @skb: socket buffer to reserve room on
+ * @attrlen: length of attribute payload
+ *
+ * Reserves room for attribute payload without a header.
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the payload.
+ */
+void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
+{
+	void *start;
+
+	start = skb_put(skb, NLA_ALIGN(attrlen));
+	memset(start, 0, NLA_ALIGN(attrlen));
+
+	return start;
+}
+
+/**
  * nla_reserve - reserve room for attribute on the skb
  * @skb: socket buffer to reserve room on
  * @attrtype: attribute type
@@ -275,6 +295,24 @@ struct nlattr *nla_reserve(struct sk_buf
 }
 
 /**
+ * nla_reserve - reserve room for attribute without header
+ * @skb: socket buffer to reserve room on
+ * @len: length of attribute payload
+ *
+ * Reserves room for attribute payload without a header.
+ *
+ * Returns NULL if the tailroom of the skb is insufficient to store
+ * the attribute payload.
+ */
+void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
+{
+	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
+		return NULL;
+
+	return __nla_reserve_nohdr(skb, attrlen);
+}
+
+/**
  * __nla_put - Add a netlink attribute to a socket buffer
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
@@ -293,6 +331,22 @@ void __nla_put(struct sk_buff *skb, int 
 	memcpy(nla_data(nla), data, attrlen);
 }
 
+/**
+ * __nla_put_nohdr - Add a netlink attribute without header
+ * @skb: socket buffer to add attribute to
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the attribute payload.
+ */
+void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
+{
+	void *start;
+
+	start = __nla_reserve_nohdr(skb, attrlen);
+	memcpy(start, data, attrlen);
+}
 
 /**
  * nla_put - Add a netlink attribute to a socket buffer
@@ -313,15 +367,36 @@ int nla_put(struct sk_buff *skb, int att
 	return 0;
 }
 
+/**
+ * nla_put_nohdr - Add a netlink attribute without header
+ * @skb: socket buffer to add attribute to
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * Returns -1 if the tailroom of the skb is insufficient to store
+ * the attribute payload.
+ */
+int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
+{
+	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
+		return -1;
+
+	__nla_put_nohdr(skb, attrlen, data);
+	return 0;
+}
 
 EXPORT_SYMBOL(nla_validate);
 EXPORT_SYMBOL(nla_parse);
 EXPORT_SYMBOL(nla_find);
 EXPORT_SYMBOL(nla_strlcpy);
 EXPORT_SYMBOL(__nla_reserve);
+EXPORT_SYMBOL(__nla_reserve_nohdr);
 EXPORT_SYMBOL(nla_reserve);
+EXPORT_SYMBOL(nla_reserve_nohdr);
 EXPORT_SYMBOL(__nla_put);
+EXPORT_SYMBOL(__nla_put_nohdr);
 EXPORT_SYMBOL(nla_put);
+EXPORT_SYMBOL(nla_put_nohdr);
 EXPORT_SYMBOL(nla_memcpy);
 EXPORT_SYMBOL(nla_memcmp);
 EXPORT_SYMBOL(nla_strcmp);
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -440,7 +440,7 @@ static struct sk_buff *ctrl_build_msg(st
 	struct sk_buff *skb;
 	int err;
 
-	skb = nlmsg_new(NLMSG_GOODSIZE);
+	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
 		return ERR_PTR(-ENOBUFS);
 

[NETLINK]: Improve string attribute validation

Introduces a new attribute type NLA_NUL_STRING to support NUL
terminated strings. Attributes of this kind require to carry
a terminating NUL within the maximum specified in the policy.

The `old' NLA_STRING which is not required to be NUL terminated
is extended to provide means to specify a maximum length of the
string.

Aims at easing the pain with using nla_strlcpy() on temporary
buffers.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---

--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -167,6 +167,7 @@ enum {
 	NLA_FLAG,
 	NLA_MSECS,
 	NLA_NESTED,
+	NLA_NUL_STRING,
 	__NLA_TYPE_MAX,
 };
 
@@ -175,21 +176,27 @@ enum {
 /**
  * struct nla_policy - attribute validation policy
  * @type: Type of attribute or NLA_UNSPEC
- * @minlen: Minimal length of payload required to be available
+ * @len: Type specific length of payload
  *
  * Policies are defined as arrays of this struct, the array must be
  * accessible by attribute type up to the highest identifier to be expected.
  *
+ * Meaning of `len' field:
+ *    NLA_STRING           Maximum length of string
+ *    NLA_NUL_STRING       Maximum length of string (excluding NUL)
+ *    NLA_FLAG             Unused
+ *    All other            Exact length of attribute payload
+ *
  * Example:
  * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = {
  * 	[ATTR_FOO] = { .type = NLA_U16 },
- *	[ATTR_BAR] = { .type = NLA_STRING },
- *	[ATTR_BAZ] = { .minlen = sizeof(struct mystruct) },
+ *	[ATTR_BAR] = { .type = NLA_STRING, len = BARSIZ },
+ *	[ATTR_BAZ] = { .len = sizeof(struct mystruct) },
  * };
  */
 struct nla_policy {
 	u16		type;
-	u16		minlen;
+	u16		len;
 };
 
 /**
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+
 	[NLA_U16]	= sizeof(u16),
 	[NLA_U32]	= sizeof(u32),
 	[NLA_U64]	= sizeof(u64),
-	[NLA_STRING]	= 1,
 	[NLA_NESTED]	= NLA_HDRLEN,
 };
 
@@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *n
 			struct nla_policy *policy)
 {
 	struct nla_policy *pt;
-	int minlen = 0;
+	int minlen = 0, attrlen = nla_len(nla);
 
 	if (nla->nla_type <= 0 || nla->nla_type > maxtype)
 		return 0;
@@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *n
 
 	BUG_ON(pt->type > NLA_TYPE_MAX);
 
-	if (pt->minlen)
-		minlen = pt->minlen;
-	else if (pt->type != NLA_UNSPEC)
-		minlen = nla_attr_minlen[pt->type];
+	switch (pt->type) {
+	case NLA_FLAG:
+		if (attrlen > 0)
+			return -ERANGE;
+		break;
+
+	case NLA_NUL_STRING:
+		if (pt->len)
+			minlen = min_t(int, attrlen, pt->len + 1);
+		else
+			minlen = attrlen;
+
+		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
+			return -EINVAL;
+		/* fall through */
+
+	case NLA_STRING:
+		if (attrlen < 1)
+			return -ERANGE;
 
-	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
-		return -ERANGE;
+		if (pt->len) {
+			char *buf = nla_data(nla);
 
-	if (nla_len(nla) < minlen)
-		return -ERANGE;
+			if (buf[attrlen - 1] == '\0')
+				attrlen--;
+
+			if (attrlen > pt->len)
+				return -ERANGE;
+		}
+		break;
+
+	default:
+		if (pt->len)
+			minlen = pt->len;
+		else if (pt->type != NLA_UNSPEC)
+			minlen = nla_attr_minlen[pt->type];
+
+		if (attrlen < minlen)
+			return -ERANGE;
+	}
 
 	return 0;
 }

Fix a problem where NetLabel would always set the value of 
sk_security_struct->peer_sid in selinux_netlbl_sock_graft() to the context of
the socket, causing problems when users would query the context of the
connection.  This patch fixes this so that the value in
sk_security_struct->peer_sid is only set when the connection is NetLabel based,
otherwise the value is untouched.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 include/net/cipso_ipv4.h       |    7 +++++
 include/net/netlabel.h         |    8 ++++++
 net/ipv4/cipso_ipv4.c          |   48 ++++++++++++++++++++++++++++-------------
 net/netlabel/netlabel_kapi.c   |   23 +++++++++++++++++++
 security/selinux/ss/services.c |   12 +++++++++-
 5 files changed, 82 insertions(+), 16 deletions(-)

Index: net-2.6.19/include/net/cipso_ipv4.h
===================================================================
--- net-2.6.19.orig/include/net/cipso_ipv4.h
+++ net-2.6.19/include/net/cipso_ipv4.h
@@ -205,6 +205,7 @@ void cipso_v4_error(struct sk_buff *skb,
 int cipso_v4_socket_setattr(const struct socket *sock,
 			    const struct cipso_v4_doi *doi_def,
 			    const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
 int cipso_v4_socket_getattr(const struct socket *sock,
 			    struct netlbl_lsm_secattr *secattr);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
@@ -225,6 +226,12 @@ static inline int cipso_v4_socket_setatt
 	return -ENOSYS;
 }
 
+static inline int cipso_v4_sock_getattr(struct sock *sk,
+					struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOSYS;
+}
+
 static inline int cipso_v4_socket_getattr(const struct socket *sock,
 					  struct netlbl_lsm_secattr *secattr)
 {
Index: net-2.6.19/include/net/netlabel.h
===================================================================
--- net-2.6.19.orig/include/net/netlabel.h
+++ net-2.6.19/include/net/netlabel.h
@@ -238,6 +238,8 @@ static inline void netlbl_secattr_free(s
 #ifdef CONFIG_NETLABEL
 int netlbl_socket_setattr(const struct socket *sock,
 			  const struct netlbl_lsm_secattr *secattr);
+int netlbl_sock_getattr(struct sock *sk,
+			struct netlbl_lsm_secattr *secattr);
 int netlbl_socket_getattr(const struct socket *sock,
 			  struct netlbl_lsm_secattr *secattr);
 int netlbl_skbuff_getattr(const struct sk_buff *skb,
@@ -250,6 +252,12 @@ static inline int netlbl_socket_setattr(
 	return -ENOSYS;
 }
 
+static inline int netlbl_sock_getattr(struct sock *sk,
+				      struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOSYS;
+}
+
 static inline int netlbl_socket_getattr(const struct socket *sock,
 					struct netlbl_lsm_secattr *secattr)
 {
Index: net-2.6.19/net/ipv4/cipso_ipv4.c
===================================================================
--- net-2.6.19.orig/net/ipv4/cipso_ipv4.c
+++ net-2.6.19/net/ipv4/cipso_ipv4.c
@@ -1486,43 +1486,40 @@ socket_setattr_failure:
 }
 
 /**
- * cipso_v4_socket_getattr - Get the security attributes from a socket
- * @sock: the socket
+ * cipso_v4_sock_getattr - Get the security attributes from a sock
+ * @sk: the sock
  * @secattr: the security attributes
  *
  * Description:
- * Query @sock to see if there is a CIPSO option attached to the socket and if
- * there is return the CIPSO security attributes in @secattr.  Returns zero on
- * success and negative values on failure.
+ * Query @sk to see if there is a CIPSO option attached to the sock and if
+ * there is return the CIPSO security attributes in @secattr.  This function
+ * requires that @sk be locked, or privately held, but it does not do any
+ * locking itself.  Returns zero on success and negative values on failure.
  *
  */
-int cipso_v4_socket_getattr(const struct socket *sock,
-			    struct netlbl_lsm_secattr *secattr)
+int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 {
 	int ret_val = -ENOMSG;
-	struct sock *sk;
 	struct inet_sock *sk_inet;
 	unsigned char *cipso_ptr;
 	u32 doi;
 	struct cipso_v4_doi *doi_def;
 
-	sk = sock->sk;
-	lock_sock(sk);
 	sk_inet = inet_sk(sk);
 	if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0)
-		goto socket_getattr_return;
+		return -ENOMSG;
 	cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
 		sizeof(struct iphdr);
 	ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr);
 	if (ret_val == 0)
-		goto socket_getattr_return;
+		return ret_val;
 
 	doi = ntohl(*(u32 *)&cipso_ptr[2]);
 	rcu_read_lock();
 	doi_def = cipso_v4_doi_getdef(doi);
 	if (doi_def == NULL) {
 		rcu_read_unlock();
-		goto socket_getattr_return;
+		return -ENOMSG;
 	}
 	switch (cipso_ptr[6]) {
 	case CIPSO_V4_TAG_RBITMAP:
@@ -1533,8 +1530,29 @@ int cipso_v4_socket_getattr(const struct
 	}
 	rcu_read_unlock();
 
-socket_getattr_return:
-	release_sock(sk);
+	return ret_val;
+}
+
+/**
+ * cipso_v4_socket_getattr - Get the security attributes from a socket
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Query @sock to see if there is a CIPSO option attached to the socket and if
+ * there is return the CIPSO security attributes in @secattr.  Returns zero on
+ * success and negative values on failure.
+ *
+ */
+int cipso_v4_socket_getattr(const struct socket *sock,
+			    struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+
+	lock_sock(sock->sk);
+	ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
+	release_sock(sock->sk);
+
 	return ret_val;
 }
 
Index: net-2.6.19/net/netlabel/netlabel_kapi.c
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_kapi.c
+++ net-2.6.19/net/netlabel/netlabel_kapi.c
@@ -85,6 +85,29 @@ socket_setattr_return:
 }
 
 /**
+ * netlbl_sock_getattr - Determine the security attributes of a sock
+ * @sk: the sock
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given sock to see any NetLabel style labeling has been
+ * applied to the sock, if so it parses the socket label and returns the
+ * security attributes in @secattr.  Returns zero on success, negative values
+ * on failure.
+ *
+ */
+int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+
+	ret_val = cipso_v4_sock_getattr(sk, secattr);
+	if (ret_val == 0)
+		return 0;
+
+	return netlbl_unlabel_getattr(secattr);
+}
+
+/**
  * netlbl_socket_getattr - Determine the security attributes of a socket
  * @sock: the socket
  * @secattr: the security attributes
Index: net-2.6.19/security/selinux/ss/services.c
===================================================================
--- net-2.6.19.orig/security/selinux/ss/services.c
+++ net-2.6.19/security/selinux/ss/services.c
@@ -2502,14 +2502,24 @@ void selinux_netlbl_sock_graft(struct so
 {
 	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
 	struct sk_security_struct *sksec = sk->sk_security;
+	struct netlbl_lsm_secattr secattr;
+	u32 nlbl_peer_sid;
 
 	sksec->sclass = isec->sclass;
 
 	if (sk->sk_family != PF_INET)
 		return;
 
+	netlbl_secattr_init(&secattr);
+	if (netlbl_sock_getattr(sk, &secattr) == 0 &&
+	    selinux_netlbl_secattr_to_sid(NULL,
+					  &secattr,
+					  sksec->sid,
+					  &nlbl_peer_sid) == 0)
+		sksec->peer_sid = nlbl_peer_sid;
+	netlbl_secattr_destroy(&secattr, 0);
+
 	sksec->nlbl_state = NLBL_REQUIRE;
-	sksec->peer_sid = sksec->sid;
 
 	/* Try to set the NetLabel on the socket to save time later, if we fail
 	 * here we will pick up the pieces in later calls to

The CIPSOv4 cache traversal routines are triggered both the userspace events
(cache invalidation due to DOI removal or updated SELinux policy) and network
packet processing events.  As a result there is a problem with the existing
CIPSOv4 cache spinlocks as they are not bottom-half/softirq safe.  This patch
converts the CIPSOv4 cache spin_[un]lock() calls into spin_[un]lock_bh() calls
to address this problem.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 net/ipv4/cipso_ipv4.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

Index: net-2.6.19/net/ipv4/cipso_ipv4.c
===================================================================
--- net-2.6.19.orig/net/ipv4/cipso_ipv4.c
+++ net-2.6.19/net/ipv4/cipso_ipv4.c
@@ -259,7 +259,7 @@ void cipso_v4_cache_invalidate(void)
 	u32 iter;
 
 	for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
-		spin_lock(&cipso_v4_cache[iter].lock);
+		spin_lock_bh(&cipso_v4_cache[iter].lock);
 		list_for_each_entry_safe(entry,
 					 tmp_entry,
 					 &cipso_v4_cache[iter].list, list) {
@@ -267,7 +267,7 @@ void cipso_v4_cache_invalidate(void)
 			cipso_v4_cache_entry_free(entry);
 		}
 		cipso_v4_cache[iter].size = 0;
-		spin_unlock(&cipso_v4_cache[iter].lock);
+		spin_unlock_bh(&cipso_v4_cache[iter].lock);
 	}
 
 	return;
@@ -309,7 +309,7 @@ static int cipso_v4_cache_check(const un
 
 	hash = cipso_v4_map_cache_hash(key, key_len);
 	bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
-	spin_lock(&cipso_v4_cache[bkt].lock);
+	spin_lock_bh(&cipso_v4_cache[bkt].lock);
 	list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
 		if (entry->hash == hash &&
 		    entry->key_len == key_len &&
@@ -318,7 +318,7 @@ static int cipso_v4_cache_check(const un
 			secattr->cache.free = entry->lsm_data.free;
 			secattr->cache.data = entry->lsm_data.data;
 			if (prev_entry == NULL) {
-				spin_unlock(&cipso_v4_cache[bkt].lock);
+				spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 				return 0;
 			}
 
@@ -333,12 +333,12 @@ static int cipso_v4_cache_check(const un
 					   &prev_entry->list);
 			}
 
-			spin_unlock(&cipso_v4_cache[bkt].lock);
+			spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 			return 0;
 		}
 		prev_entry = entry;
 	}
-	spin_unlock(&cipso_v4_cache[bkt].lock);
+	spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 
 	return -ENOENT;
 }
@@ -387,7 +387,7 @@ int cipso_v4_cache_add(const struct sk_b
 	entry->lsm_data.data = secattr->cache.data;
 
 	bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
-	spin_lock(&cipso_v4_cache[bkt].lock);
+	spin_lock_bh(&cipso_v4_cache[bkt].lock);
 	if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
 		list_add(&entry->list, &cipso_v4_cache[bkt].list);
 		cipso_v4_cache[bkt].size += 1;
@@ -398,7 +398,7 @@ int cipso_v4_cache_add(const struct sk_b
 		list_add(&entry->list, &cipso_v4_cache[bkt].list);
 		cipso_v4_cache_entry_free(old_entry);
 	}
-	spin_unlock(&cipso_v4_cache[bkt].lock);
+	spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 
 	return 0;
 

Change NetLabel to use the 'recvfrom' socket permission and the
SECINITSID_NETMSG SELinux SID as the NetLabel base SID for incoming packets.
This patch effectively makes the old, and currently unused, SELinux NETMSG
permissions NetLabel permissions.

Signed-of-by: Paul Moore <paul.moore@hp.com>
---
 security/selinux/ss/services.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

Index: net-2.6.19/security/selinux/ss/services.c
===================================================================
--- net-2.6.19.orig/security/selinux/ss/services.c
+++ net-2.6.19/security/selinux/ss/services.c
@@ -2611,7 +2611,7 @@ int selinux_netlbl_sock_rcv_skb(struct s
 	u32 netlbl_sid;
 	u32 recv_perm;
 
-	rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
+	rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid);
 	if (rc != 0)
 		return rc;
 
@@ -2620,13 +2620,13 @@ int selinux_netlbl_sock_rcv_skb(struct s
 
 	switch (sksec->sclass) {
 	case SECCLASS_UDP_SOCKET:
-		recv_perm = UDP_SOCKET__RECV_MSG;
+		recv_perm = UDP_SOCKET__RECVFROM;
 		break;
 	case SECCLASS_TCP_SOCKET:
-		recv_perm = TCP_SOCKET__RECV_MSG;
+		recv_perm = TCP_SOCKET__RECVFROM;
 		break;
 	default:
-		recv_perm = RAWIP_SOCKET__RECV_MSG;
+		recv_perm = RAWIP_SOCKET__RECVFROM;
 	}
 
 	rc = avc_has_perm(sksec->sid,

At the top of include/net/netlink.h is a list of Netlink interfaces, however,
the nla_for_each_nested() macro was not listed.  This patch adds this interface
to the list at the top of the header file.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 include/net/netlink.h |    1 +
 1 files changed, 1 insertion(+)

Index: net-2.6.19/include/net/netlink.h
===================================================================
--- net-2.6.19.orig/include/net/netlink.h
+++ net-2.6.19/include/net/netlink.h
@@ -151,6 +151,7 @@
  *   nla_parse()			parse and validate stream of attrs
  *   nla_parse_nested()			parse nested attribuets
  *   nla_for_each_attr()		loop over all attributes
+ *   nla_for_each_nested()		loop over the nested attributes
  *=========================================================================
  */
 

Add a new function, nla_validate_nested(), to validate nested Netlink
attributes.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 include/net/netlink.h |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+)

Index: net-2.6.19/include/net/netlink.h
===================================================================
--- net-2.6.19.orig/include/net/netlink.h
+++ net-2.6.19/include/net/netlink.h
@@ -146,6 +146,7 @@
  *   nla_ok(nla, remaining)		does nla fit into remaining bytes?
  *   nla_next(nla, remaining)		get next netlink attribute
  *   nla_validate()			validate a stream of attributes
+ *   nla_validate_nested()		validate a stream of nested attributes
  *   nla_find()				find attribute in stream of attributes
  *   nla_find_nested()			find attribute in nested attributes
  *   nla_parse()			parse and validate stream of attrs
@@ -951,6 +952,24 @@ static inline int nla_nest_cancel(struct
 }
 
 /**
+ * nla_validate_nested - Validate a stream of nested attributes
+ * @start: container attribute
+ * @maxtype: maximum attribute type to be expected
+ * @policy: validation policy
+ *
+ * Validates all attributes in the nested attribute stream against the
+ * specified policy. Attributes with a type exceeding maxtype will be
+ * ignored. See documenation of struct nla_policy for more details.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+static inline int nla_validate_nested(struct nlattr *start, int maxtype,
+				      struct nla_policy *policy)
+{
+	return nla_validate(nla_data(start), nla_len(start), maxtype, policy);
+}
+
+/**
  * nla_for_each_attr - iterate over a stream of attributes
  * @pos: loop counter, set to current attribute
  * @head: head of attribute stream

At the suggestion of Thomas Graf, rewrite NetLabel's use of Netlink attributes
to better follow the common Netlink attribute usage.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 include/net/cipso_ipv4.h           |   16 +-
 include/net/netlabel.h             |   49 --------
 net/ipv4/cipso_ipv4.c              |  203 ++++---------------------------------
 net/netlabel/netlabel_domainhash.c |  183 ++++++---------------------------
 net/netlabel/netlabel_domainhash.h |    6 -
 net/netlabel/netlabel_user.c       |   82 --------------
 net/netlabel/netlabel_user.h       |  141 -------------------------
 7 files changed, 76 insertions(+), 604 deletions(-)

Index: net-2.6.19/include/net/cipso_ipv4.h
===================================================================
--- net-2.6.19.orig/include/net/cipso_ipv4.h
+++ net-2.6.19/include/net/cipso_ipv4.h
@@ -130,8 +130,9 @@ extern int cipso_v4_rbm_strictvalid;
 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
 int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head));
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
-struct sk_buff *cipso_v4_doi_dump_all(size_t headroom);
-struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom);
+int cipso_v4_doi_walk(u32 *skip_cnt,
+		     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
+	             void *cb_arg);
 int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
 int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
 			       const char *domain);
@@ -152,14 +153,11 @@ static inline struct cipso_v4_doi *cipso
 	return NULL;
 }
 
-static inline struct sk_buff *cipso_v4_doi_dump_all(size_t headroom)
+static inline int cipso_v4_doi_walk(u32 *skip_cnt,
+		     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
+		     void *cb_arg)
 {
-	return NULL;
-}
-
-static inline struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom)
-{
-	return NULL;
+	return 0;
 }
 
 static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def,
Index: net-2.6.19/include/net/netlabel.h
===================================================================
--- net-2.6.19.orig/include/net/netlabel.h
+++ net-2.6.19/include/net/netlabel.h
@@ -57,9 +57,8 @@
  * The payload 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.  All of the fields in the NetLabel payload are NETLINK attributes, the
- * length of each field is the length of the NETLINK attribute payload, see
- * include/net/netlink.h for more information on NETLINK attributes.
+ * file.  All of the fields in the NetLabel payload are NETLINK attributes, see
+ * the include/net/netlink.h file for more information on NETLINK attributes.
  *
  */
 
@@ -82,50 +81,6 @@
 #define NETLBL_NLTYPE_UNLABELED         5
 #define NETLBL_NLTYPE_UNLABELED_NAME    "NLBL_UNLBL"
 
-/* NetLabel return codes */
-#define NETLBL_E_OK                     0
-
-/*
- * Helper functions
- */
-
-#define NETLBL_LEN_U8                   nla_total_size(sizeof(u8))
-#define NETLBL_LEN_U16                  nla_total_size(sizeof(u16))
-#define NETLBL_LEN_U32                  nla_total_size(sizeof(u32))
-
-/**
- * netlbl_netlink_alloc_skb - Allocate a NETLINK message buffer
- * @head: the amount of headroom in bytes
- * @body: the desired size (minus headroom) in bytes
- * @gfp_flags: the alloc flags to pass to alloc_skb()
- *
- * Description:
- * Allocate a NETLINK message buffer based on the sizes given in @head and
- * @body.  If @head is greater than zero skb_reserve() is called to reserve
- * @head bytes at the start of the buffer.  Returns a valid sk_buff pointer on
- * success, NULL on failure.
- *
- */
-static inline struct sk_buff *netlbl_netlink_alloc_skb(size_t head,
-						       size_t body,
-						       int gfp_flags)
-{
-	struct sk_buff *skb;
-
-	skb = alloc_skb(NLMSG_ALIGN(head + body), gfp_flags);
-	if (skb == NULL)
-		return NULL;
-	if (head > 0) {
-		skb_reserve(skb, head);
-		if (skb_tailroom(skb) < body) {
-			kfree_skb(skb);
-			return NULL;
-		}
-	}
-
-	return skb;
-}
-
 /*
  * NetLabel - Kernel API for accessing the network packet label mappings.
  *
Index: net-2.6.19/net/ipv4/cipso_ipv4.c
===================================================================
--- net-2.6.19.orig/net/ipv4/cipso_ipv4.c
+++ net-2.6.19/net/ipv4/cipso_ipv4.c
@@ -530,197 +530,42 @@ struct cipso_v4_doi *cipso_v4_doi_getdef
 }
 
 /**
- * cipso_v4_doi_dump_all - Dump all the CIPSO DOI definitions into a sk_buff
- * @headroom: the amount of headroom to allocate for the sk_buff
+ * cipso_v4_doi_walk - Iterate through the DOI definitions
+ * @skip_cnt: skip past this number of DOI definitions, updated
+ * @callback: callback for each DOI definition
+ * @cb_arg: argument for the callback function
  *
  * Description:
- * Dump a list of all the configured DOI values into a sk_buff.  The returned
- * sk_buff has room at the front of the sk_buff for @headroom bytes.  See
- * net/netlabel/netlabel_cipso_v4.h for the LISTALL message format.  This
- * function may fail if another process is changing the DOI list at the same
- * time.  Returns a pointer to a sk_buff on success, NULL on error.
+ * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
+ * For each entry call @callback, if @callback returns a negative value stop
+ * 'walking' through the list and return.  Updates the value in @skip_cnt upon
+ * return.  Returns zero on success, negative values on failure.
  *
  */
-struct sk_buff *cipso_v4_doi_dump_all(size_t headroom)
+int cipso_v4_doi_walk(u32 *skip_cnt,
+		     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
+		     void *cb_arg)
 {
-	struct sk_buff *skb = NULL;
-	struct cipso_v4_doi *iter;
+	int ret_val = -ENOENT;
 	u32 doi_cnt = 0;
-	ssize_t buf_len;
+	struct cipso_v4_doi *iter_doi;
 
-	buf_len = NETLBL_LEN_U32;
 	rcu_read_lock();
-	list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
-		if (iter->valid) {
-			doi_cnt += 1;
-			buf_len += 2 * NETLBL_LEN_U32;
-		}
-
-	skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
-	if (skb == NULL)
-		goto doi_dump_all_failure;
-
-	if (nla_put_u32(skb, NLA_U32, doi_cnt) != 0)
-		goto doi_dump_all_failure;
-	buf_len -= NETLBL_LEN_U32;
-	list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
-		if (iter->valid) {
-			if (buf_len < 2 * NETLBL_LEN_U32)
-				goto doi_dump_all_failure;
-			if (nla_put_u32(skb, NLA_U32, iter->doi) != 0)
-				goto doi_dump_all_failure;
-			if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
-				goto doi_dump_all_failure;
-			buf_len -= 2 * NETLBL_LEN_U32;
-		}
-	rcu_read_unlock();
-
-	return skb;
-
-doi_dump_all_failure:
-	rcu_read_unlock();
-	kfree(skb);
-	return NULL;
-}
-
-/**
- * cipso_v4_doi_dump - Dump a CIPSO DOI definition into a sk_buff
- * @doi: the DOI value
- * @headroom: the amount of headroom to allocate for the sk_buff
- *
- * Description:
- * Lookup the DOI definition matching @doi and dump it's contents into a
- * sk_buff.  The returned sk_buff has room at the front of the sk_buff for
- * @headroom bytes.  See net/netlabel/netlabel_cipso_v4.h for the LIST message
- * format.  This function may fail if another process is changing the DOI list
- * at the same time.  Returns a pointer to a sk_buff on success, NULL on error.
- *
- */
-struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom)
-{
-	struct sk_buff *skb = NULL;
-	struct cipso_v4_doi *iter;
-	u32 tag_cnt = 0;
-	u32 lvl_cnt = 0;
-	u32 cat_cnt = 0;
-	ssize_t buf_len;
-	ssize_t tmp;
-
-	rcu_read_lock();
-	iter = cipso_v4_doi_getdef(doi);
-	if (iter == NULL)
-		goto doi_dump_failure;
-	buf_len = NETLBL_LEN_U32;
-	switch (iter->type) {
-	case CIPSO_V4_MAP_PASS:
-		buf_len += NETLBL_LEN_U32;
-		while(tag_cnt < CIPSO_V4_TAG_MAXCNT &&
-		      iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
-			tag_cnt += 1;
-			buf_len += NETLBL_LEN_U8;
-		}
-		break;
-	case CIPSO_V4_MAP_STD:
-		buf_len += 3 * NETLBL_LEN_U32;
-		while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
-		       iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
-			tag_cnt += 1;
-			buf_len += NETLBL_LEN_U8;
-		}
-		for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
-			if (iter->map.std->lvl.local[tmp] !=
-			    CIPSO_V4_INV_LVL) {
-				lvl_cnt += 1;
-				buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U8;
+	list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
+		if (iter_doi->valid) {
+			if (doi_cnt++ < *skip_cnt)
+				continue;
+			ret_val = callback(iter_doi, cb_arg);
+			if (ret_val < 0) {
+				doi_cnt--;
+				goto doi_walk_return;
 			}
-		for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
-			if (iter->map.std->cat.local[tmp] !=
-			    CIPSO_V4_INV_CAT) {
-				cat_cnt += 1;
-				buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U16;
-			}
-		break;
-	}
-
-	skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
-	if (skb == NULL)
-		goto doi_dump_failure;
-
-	if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
-		goto doi_dump_failure;
-	buf_len -= NETLBL_LEN_U32;
-	if (iter != cipso_v4_doi_getdef(doi))
-		goto doi_dump_failure;
-	switch (iter->type) {
-	case CIPSO_V4_MAP_PASS:
-		if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
-			goto doi_dump_failure;
-		buf_len -= NETLBL_LEN_U32;
-		for (tmp = 0;
-		     tmp < CIPSO_V4_TAG_MAXCNT &&
-			     iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
-		     tmp++) {
-			if (buf_len < NETLBL_LEN_U8)
-				goto doi_dump_failure;
-			if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
-				goto doi_dump_failure;
-			buf_len -= NETLBL_LEN_U8;
-		}
-		break;
-	case CIPSO_V4_MAP_STD:
-		if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
-			goto doi_dump_failure;
-		if (nla_put_u32(skb, NLA_U32, lvl_cnt) != 0)
-			goto doi_dump_failure;
-		if (nla_put_u32(skb, NLA_U32, cat_cnt) != 0)
-			goto doi_dump_failure;
-		buf_len -= 3 * NETLBL_LEN_U32;
-		for (tmp = 0;
-		     tmp < CIPSO_V4_TAG_MAXCNT &&
-			     iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
-		     tmp++) {
-			if (buf_len < NETLBL_LEN_U8)
-				goto doi_dump_failure;
-			if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
-				goto doi_dump_failure;
-			buf_len -= NETLBL_LEN_U8;
 		}
-		for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
-			if (iter->map.std->lvl.local[tmp] !=
-			    CIPSO_V4_INV_LVL) {
-				if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U8)
-					goto doi_dump_failure;
-				if (nla_put_u32(skb, NLA_U32, tmp) != 0)
-					goto doi_dump_failure;
-				if (nla_put_u8(skb,
-					   NLA_U8,
-					   iter->map.std->lvl.local[tmp]) != 0)
-					goto doi_dump_failure;
-				buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U8;
-			}
-		for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
-			if (iter->map.std->cat.local[tmp] !=
-			    CIPSO_V4_INV_CAT) {
-				if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U16)
-					goto doi_dump_failure;
-				if (nla_put_u32(skb, NLA_U32, tmp) != 0)
-					goto doi_dump_failure;
-				if (nla_put_u16(skb,
-					   NLA_U16,
-					   iter->map.std->cat.local[tmp]) != 0)
-					goto doi_dump_failure;
-				buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U16;
-			}
-		break;
-	}
-	rcu_read_unlock();
 
-	return skb;
-
-doi_dump_failure:
+doi_walk_return:
 	rcu_read_unlock();
-	kfree(skb);
-	return NULL;
+	*skip_cnt = doi_cnt;
+	return ret_val;
 }
 
 /**
Index: net-2.6.19/net/netlabel/netlabel_domainhash.c
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_domainhash.c
+++ net-2.6.19/net/netlabel/netlabel_domainhash.c
@@ -354,160 +354,51 @@ struct netlbl_dom_map *netlbl_domhsh_get
 }
 
 /**
- * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff
+ * netlbl_domhsh_walk - Iterate through the domain mapping hash table
+ * @skip_bkt: the number of buckets to skip at the start
+ * @skip_chain: the number of entries to skip in the first iterated bucket
+ * @callback: callback for each entry
+ * @cb_arg: argument for the callback function
  *
  * 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
- * @headroom bytes.  See netlabel.h for the DOMAIN message format.  Returns a
- * pointer to a sk_buff on success, NULL on error.
+ * Interate over the domain mapping hash table, skipping the first @skip_bkt
+ * buckets and @skip_chain entries.  For each entry in the table call
+ * @callback, if @callback returns a negative value stop 'walking' through the
+ * table and return.  Updates the values in @skip_bkt and @skip_chain on
+ * return.  Returns zero on succcess, negative values on failure.
  *
  */
-struct sk_buff *netlbl_domhsh_dump(size_t headroom)
+int netlbl_domhsh_walk(u32 *skip_bkt,
+		     u32 *skip_chain,
+		     int (*callback) (struct netlbl_dom_map *entry, void *arg),
+		     void *cb_arg)
 {
-	struct sk_buff *skb = NULL;
-	ssize_t buf_len;
-	u32 bkt_iter;
-	u32 dom_cnt = 0;
-	struct netlbl_domhsh_tbl *hsh_tbl;
-	struct netlbl_dom_map *list_iter;
-	ssize_t tmp_len;
+	int ret_val = -ENOENT;
+	u32 iter_bkt;
+	struct netlbl_dom_map *iter_entry;
+	u32 chain_cnt = 0;
 
-	buf_len = NETLBL_LEN_U32;
 	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 += NETLBL_LEN_U32 +
-				nla_total_size(strlen(list_iter->domain) + 1);
-			switch (list_iter->type) {
-			case NETLBL_NLTYPE_UNLABELED:
-				break;
-			case NETLBL_NLTYPE_CIPSOV4:
-				buf_len += 2 * NETLBL_LEN_U32;
-				break;
+	for (iter_bkt = *skip_bkt;
+	     iter_bkt < rcu_dereference(netlbl_domhsh)->size;
+	     iter_bkt++, chain_cnt = 0) {
+		list_for_each_entry_rcu(iter_entry,
+					&netlbl_domhsh->tbl[iter_bkt],
+					list)
+			if (iter_entry->valid) {
+				if (chain_cnt++ < *skip_chain)
+					continue;
+				ret_val = callback(iter_entry, cb_arg);
+				if (ret_val < 0) {
+					chain_cnt--;
+					goto walk_return;
+				}
 			}
-			dom_cnt++;
-		}
+	}
 
-	skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
-	if (skb == NULL)
-		goto dump_failure;
-
-	if (nla_put_u32(skb, NLA_U32, dom_cnt) != 0)
-		goto dump_failure;
-	buf_len -= NETLBL_LEN_U32;
-	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 = nla_total_size(strlen(list_iter->domain) +
-						 1);
-			if (buf_len < NETLBL_LEN_U32 + tmp_len)
-				goto dump_failure;
-			if (nla_put_string(skb,
-					   NLA_STRING,
-					   list_iter->domain) != 0)
-				goto dump_failure;
-			if (nla_put_u32(skb, NLA_U32, list_iter->type) != 0)
-				goto dump_failure;
-			buf_len -= NETLBL_LEN_U32 + tmp_len;
-			switch (list_iter->type) {
-			case NETLBL_NLTYPE_UNLABELED:
-				break;
-			case NETLBL_NLTYPE_CIPSOV4:
-				if (buf_len < 2 * NETLBL_LEN_U32)
-					goto dump_failure;
-				if (nla_put_u32(skb,
-				       NLA_U32,
-				       list_iter->type_def.cipsov4->type) != 0)
-					goto dump_failure;
-				if (nla_put_u32(skb,
-				       NLA_U32,
-				       list_iter->type_def.cipsov4->doi) != 0)
-					goto dump_failure;
-				buf_len -= 2 * NETLBL_LEN_U32;
-				break;
-			}
-		}
-	rcu_read_unlock();
-
-	return skb;
-
-dump_failure:
-	rcu_read_unlock();
-	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 @headroom bytes.  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(size_t headroom)
-{
-	struct sk_buff *skb;
-	ssize_t buf_len;
-	struct netlbl_dom_map *entry;
-
-	buf_len = NETLBL_LEN_U32;
-	rcu_read_lock();
-	entry = rcu_dereference(netlbl_domhsh_def);
-	if (entry != NULL)
-		switch (entry->type) {
-		case NETLBL_NLTYPE_UNLABELED:
-			break;
-		case NETLBL_NLTYPE_CIPSOV4:
-			buf_len += 2 * NETLBL_LEN_U32;
-			break;
-		}
-
-	skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
-	if (skb == NULL)
-		goto dump_default_failure;
-
-	if (entry != rcu_dereference(netlbl_domhsh_def))
-		goto dump_default_failure;
-	if (entry != NULL) {
-		if (nla_put_u32(skb, NLA_U32, entry->type) != 0)
-			goto dump_default_failure;
-		buf_len -= NETLBL_LEN_U32;
-		switch (entry->type) {
-		case NETLBL_NLTYPE_UNLABELED:
-			break;
-		case NETLBL_NLTYPE_CIPSOV4:
-			if (buf_len < 2 * NETLBL_LEN_U32)
-				goto dump_default_failure;
-			if (nla_put_u32(skb,
-					NLA_U32,
-					entry->type_def.cipsov4->type) != 0)
-				goto dump_default_failure;
-			if (nla_put_u32(skb,
-					NLA_U32,
-					entry->type_def.cipsov4->doi) != 0)
-				goto dump_default_failure;
-			buf_len -= 2 * NETLBL_LEN_U32;
-			break;
-		}
-	} else
-		nla_put_u32(skb, NLA_U32, NETLBL_NLTYPE_NONE);
-	rcu_read_unlock();
-
-	return skb;
-
-dump_default_failure:
+walk_return:
 	rcu_read_unlock();
-	kfree_skb(skb);
-	return NULL;
+	*skip_bkt = iter_bkt;
+	*skip_chain = chain_cnt;
+	return ret_val;
 }
Index: net-2.6.19/net/netlabel/netlabel_domainhash.h
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_domainhash.h
+++ net-2.6.19/net/netlabel/netlabel_domainhash.h
@@ -61,7 +61,9 @@ int netlbl_domhsh_add(struct netlbl_dom_
 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(size_t headroom);
-struct sk_buff *netlbl_domhsh_dump_default(size_t headroom);
+int netlbl_domhsh_walk(u32 *skip_bkt,
+		     u32 *skip_chain,
+		     int (*callback) (struct netlbl_dom_map *entry, void *arg),
+		     void *cb_arg);
 
 #endif
Index: net-2.6.19/net/netlabel/netlabel_user.c
===================================================================
--- linux-2.6.18.i686/net/netlabel/netlabel_user.c.patch6	2006-09-27 14:12:40.000000000 -0400
+++ linux-2.6.18.i686/net/netlabel/netlabel_user.c	2006-09-27 14:13:24.000000000 -0400
@@ -74,85 +74,3 @@ int netlbl_netlink_init(void)
 
 	return 0;
 }
-
-/*
- * NetLabel Common Protocol Functions
- */
-
-/**
- * netlbl_netlink_send_ack - Send an ACK message
- * @info: the generic NETLINK information
- * @genl_family: the generic NETLINK family ID value
- * @ack_cmd: the generic NETLINK family ACK command value
- * @ret_code: return code to use
- *
- * Description:
- * This function sends an ACK message to the sender of the NETLINK message
- * specified by @info.
- *
- */
-void netlbl_netlink_send_ack(const struct genl_info *info,
-			     u32 genl_family,
-			     u8 ack_cmd,
-			     u32 ret_code)
-{
-	size_t data_size;
-	struct sk_buff *skb;
-
-	data_size = GENL_HDRLEN + 2 * NETLBL_LEN_U32;
-	skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL);
-	if (skb == NULL)
-		return;
-
-	if (netlbl_netlink_hdr_put(skb,
-				   info->snd_pid,
-				   0,
-				   genl_family,
-				   ack_cmd) == NULL)
-		goto send_ack_failure;
-
-	if (nla_put_u32(skb, NLA_U32, info->snd_seq) != 0)
-		goto send_ack_failure;
-	if (nla_put_u32(skb, NLA_U32, ret_code) != 0)
-		goto send_ack_failure;
-
-	netlbl_netlink_snd(skb, info->snd_pid);
-	return;
-
-send_ack_failure:
-	kfree_skb(skb);
-}
-
-/*
- * 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, u32 pid)
-{
-	return genlmsg_unicast(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, u32 pid, u32 group)
-{
-	return genlmsg_multicast(skb, pid, group);
-}
Index: net-2.6.19/net/netlabel/netlabel_user.h
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_user.h
+++ net-2.6.19/net/netlabel/netlabel_user.h
@@ -41,72 +41,6 @@
 /* NetLabel NETLINK helper functions */
 
 /**
- * netlbl_netlink_cap_check - Check the NETLINK msg capabilities
- * @skb: the NETLINK buffer
- * @req_cap: the required capability
- *
- * Description:
- * Check the NETLINK buffer's capabilities against the required capabilities.
- * Returns zero on success, negative values on failure.
- *
- */
-static inline int netlbl_netlink_cap_check(const struct sk_buff *skb,
-					   kernel_cap_t req_cap)
-{
-	if (cap_raised(NETLINK_CB(skb).eff_cap, req_cap))
-		return 0;
-	return -EPERM;
-}
-
-/**
- * netlbl_getinc_u8 - Read a u8 value from a nlattr stream and move on
- * @nla: the attribute
- * @rem_len: remaining length
- *
- * Description:
- * Return a u8 value pointed to by @nla and advance it to the next attribute.
- *
- */
-static inline u8 netlbl_getinc_u8(struct nlattr **nla, int *rem_len)
-{
-	u8 val = nla_get_u8(*nla);
-	*nla = nla_next(*nla, rem_len);
-	return val;
-}
-
-/**
- * netlbl_getinc_u16 - Read a u16 value from a nlattr stream and move on
- * @nla: the attribute
- * @rem_len: remaining length
- *
- * Description:
- * Return a u16 value pointed to by @nla and advance it to the next attribute.
- *
- */
-static inline u16 netlbl_getinc_u16(struct nlattr **nla, int *rem_len)
-{
-	u16 val = nla_get_u16(*nla);
-	*nla = nla_next(*nla, rem_len);
-	return val;
-}
-
-/**
- * netlbl_getinc_u32 - Read a u32 value from a nlattr stream and move on
- * @nla: the attribute
- * @rem_len: remaining length
- *
- * Description:
- * Return a u32 value pointed to by @nla and advance it to the next attribute.
- *
- */
-static inline u32 netlbl_getinc_u32(struct nlattr **nla, int *rem_len)
-{
-	u32 val = nla_get_u32(*nla);
-	*nla = nla_next(*nla, rem_len);
-	return val;
-}
-
-/**
  * netlbl_netlink_hdr_put - Write the NETLINK buffers into a sk_buff
  * @skb: the packet
  * @pid: the PID of the receipient
@@ -124,6 +58,7 @@ static inline void *netlbl_netlink_hdr_p
 					   u32 pid,
 					   u32 seq,
 					   int type,
+					   int flags,
 					   u8 cmd)
 {
 	return genlmsg_put(skb,
@@ -131,85 +66,13 @@ static inline void *netlbl_netlink_hdr_p
 			   seq,
 			   type,
 			   0,
-			   0,
+			   flags,
 			   cmd,
 			   NETLBL_PROTO_VERSION);
 }
 
-/**
- * netlbl_netlink_hdr_push - Write the NETLINK buffers into a sk_buff
- * @skb: the packet
- * @pid: the PID of the receipient
- * @seq: the sequence number
- * @type: the generic NETLINK message family type
- * @cmd: command
- *
- * Description:
- * Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr
- * struct to the packet.
- *
- */
-static inline void netlbl_netlink_hdr_push(struct sk_buff *skb,
-					   u32 pid,
-					   u32 seq,
-					   int type,
-					   u8 cmd)
-
-{
-	struct nlmsghdr *nlh;
-	struct genlmsghdr *hdr;
-
-	nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_SPACE(GENL_HDRLEN));
-	nlh->nlmsg_type = type;
-	nlh->nlmsg_len = skb->len;
-	nlh->nlmsg_flags = 0;
-	nlh->nlmsg_pid = pid;
-	nlh->nlmsg_seq = seq;
-
-	hdr = nlmsg_data(nlh);
-	hdr->cmd = cmd;
-	hdr->version = NETLBL_PROTO_VERSION;
-	hdr->reserved = 0;
-}
-
-/**
- * netlbl_netlink_payload_len - Return the length of the payload
- * @skb: the NETLINK buffer
- *
- * Description:
- * This function returns the length of the NetLabel payload.
- *
- */
-static inline u32 netlbl_netlink_payload_len(const struct sk_buff *skb)
-{
-	return nlmsg_len((struct nlmsghdr *)skb->data) - GENL_HDRLEN;
-}
-
-/**
- * netlbl_netlink_payload_data - Returns a pointer to the start of the payload
- * @skb: the NETLINK buffer
- *
- * Description:
- * This function returns a pointer to the start of the NetLabel payload.
- *
- */
-static inline void *netlbl_netlink_payload_data(const struct sk_buff *skb)
-{
-  return (unsigned char *)nlmsg_data((struct nlmsghdr *)skb->data) +
-	  GENL_HDRLEN;
-}
-
-/* NetLabel common protocol functions */
-
-void netlbl_netlink_send_ack(const struct genl_info *info,
-			     u32 genl_family,
-			     u8 ack_cmd,
-			     u32 ret_code);
-
 /* NetLabel NETLINK I/O functions */
 
 int netlbl_netlink_init(void);
-int netlbl_netlink_snd(struct sk_buff *skb, u32 pid);
-int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group);
 
 #endif

--
paul moore
linux security @ hp

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
At the suggestion of Thomas Graf, rewrite NetLabel's use of Netlink attributes
to better follow the common Netlink attribute usage.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 net/netlabel/netlabel_cipso_v4.c  |  630 ++++++++++++++++++++++++--------------
 net/netlabel/netlabel_cipso_v4.h  |  235 +++++---------
 net/netlabel/netlabel_mgmt.c      |  535 ++++++++++++++++----------------
 net/netlabel/netlabel_mgmt.h      |  213 ++++--------
 net/netlabel/netlabel_unlabeled.c |   79 ++--
 net/netlabel/netlabel_unlabeled.h |   41 --
 6 files changed, 899 insertions(+), 834 deletions(-)

Index: net-2.6.19/net/netlabel/netlabel_cipso_v4.c
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_cipso_v4.c
+++ net-2.6.19/net/netlabel/netlabel_cipso_v4.c
@@ -41,15 +41,37 @@
 #include "netlabel_user.h"
 #include "netlabel_cipso_v4.h"
 
+/* Argument struct for cipso_v4_doi_walk() */
+struct netlbl_cipsov4_doiwalk_arg {
+	struct netlink_callback *nl_cb;
+	struct sk_buff *skb;
+	u32 seq;
+};
+
 /* NetLabel Generic NETLINK CIPSOv4 family */
 static struct genl_family netlbl_cipsov4_gnl_family = {
 	.id = GENL_ID_GENERATE,
 	.hdrsize = 0,
 	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
 	.version = NETLBL_PROTO_VERSION,
-	.maxattr = 0,
+	.maxattr = NLBL_CIPSOV4_A_MAX,
 };
 
+/* NetLabel Netlink attribute policy */
+static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
+	[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
+	[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
+	[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
+	[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
+	[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
+	[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
+	[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
+};
 
 /*
  * Helper Functions
@@ -81,6 +103,41 @@ static void netlbl_cipsov4_doi_free(stru
 	kfree(ptr);
 }
 
+/**
+ * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
+ * @info: the Generic NETLINK info block
+ * @doi_def: the CIPSO V4 DOI definition
+ *
+ * Description:
+ * Parse the common sections of a ADD message and fill in the related values
+ * in @doi_def.  Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_cipsov4_add_common(struct genl_info *info,
+				     struct cipso_v4_doi *doi_def)
+{
+	struct nlattr *nla;
+	int nla_rem;
+	u32 iter = 0;
+
+	doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
+
+	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
+				NLBL_CIPSOV4_A_MAX,
+				netlbl_cipsov4_genl_policy) != 0)
+		return -EINVAL;
+
+	nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
+		if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
+			if (iter > CIPSO_V4_TAG_MAXCNT)
+				return -EINVAL;
+			doi_def->tags[iter++] = nla_get_u8(nla);
+		}
+	if (iter < CIPSO_V4_TAG_MAXCNT)
+		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
+
+	return 0;
+}
 
 /*
  * NetLabel Command Handlers
@@ -88,9 +145,7 @@ static void netlbl_cipsov4_doi_free(stru
 
 /**
  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
- * @doi: the DOI value
- * @msg: the ADD message data
- * @msg_size: the size of the ADD message buffer
+ * @info: the Generic NETLINK info block
  *
  * Description:
  * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
@@ -98,29 +153,28 @@ static void netlbl_cipsov4_doi_free(stru
  * error.
  *
  */
-static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
+static int netlbl_cipsov4_add_std(struct genl_info *info)
 {
 	int ret_val = -EINVAL;
-	int msg_len = msg_size;
-	u32 num_tags;
-	u32 num_lvls;
-	u32 num_cats;
 	struct cipso_v4_doi *doi_def = NULL;
-	u32 iter;
-	u32 tmp_val_a;
-	u32 tmp_val_b;
-
-	if (msg_len < NETLBL_LEN_U32)
-		goto add_std_failure;
-	num_tags = netlbl_getinc_u32(&msg, &msg_len);
-	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
-		goto add_std_failure;
+	struct nlattr *nla_a;
+	struct nlattr *nla_b;
+	int nla_a_rem;
+	int nla_b_rem;
+
+	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
+	    !info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
+	    !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
+		return -EINVAL;
+
+	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
+				NLBL_CIPSOV4_A_MAX,
+				netlbl_cipsov4_genl_policy) != 0)
+		return -EINVAL;
 
 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
-	if (doi_def == NULL) {
-		ret_val = -ENOMEM;
-		goto add_std_failure;
-	}
+	if (doi_def == NULL)
+		return -ENOMEM;
 	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
 	if (doi_def->map.std == NULL) {
 		ret_val = -ENOMEM;
@@ -128,28 +182,32 @@ static int netlbl_cipsov4_add_std(u32 do
 	}
 	doi_def->type = CIPSO_V4_MAP_STD;
 
-	for (iter = 0; iter < num_tags; iter++) {
-		if (msg_len < NETLBL_LEN_U8)
-			goto add_std_failure;
-		doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
-		switch (doi_def->tags[iter]) {
-		case CIPSO_V4_TAG_RBITMAP:
-			break;
-		default:
-			goto add_std_failure;
-		}
-	}
-	if (iter < CIPSO_V4_TAG_MAXCNT)
-		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
-
-	if (msg_len < 6 * NETLBL_LEN_U32)
+	ret_val = netlbl_cipsov4_add_common(info, doi_def);
+	if (ret_val != 0)
 		goto add_std_failure;
 
-	num_lvls = netlbl_getinc_u32(&msg, &msg_len);
-	if (num_lvls == 0)
-		goto add_std_failure;
-	doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len);
-	if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS)
+	nla_for_each_nested(nla_a,
+			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
+			    nla_a_rem)
+		if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
+			nla_for_each_nested(nla_b, nla_a, nla_b_rem)
+				switch (nla_b->nla_type) {
+				case NLBL_CIPSOV4_A_MLSLVLLOC:
+					if (nla_get_u32(nla_b) >=
+					    doi_def->map.std->lvl.local_size)
+					     doi_def->map.std->lvl.local_size =
+						     nla_get_u32(nla_b) + 1;
+					break;
+				case NLBL_CIPSOV4_A_MLSLVLREM:
+					if (nla_get_u32(nla_b) >=
+					    doi_def->map.std->lvl.cipso_size)
+					     doi_def->map.std->lvl.cipso_size =
+						     nla_get_u32(nla_b) + 1;
+					break;
+				}
+		}
+	if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
+	    doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
 		goto add_std_failure;
 	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
 					      sizeof(u32),
@@ -158,9 +216,6 @@ static int netlbl_cipsov4_add_std(u32 do
 		ret_val = -ENOMEM;
 		goto add_std_failure;
 	}
-	doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len);
-	if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
-		goto add_std_failure;
 	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
 					      sizeof(u32),
 					      GFP_KERNEL);
@@ -168,68 +223,101 @@ static int netlbl_cipsov4_add_std(u32 do
 		ret_val = -ENOMEM;
 		goto add_std_failure;
 	}
+	nla_for_each_nested(nla_a,
+			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
+			    nla_a_rem)
+		if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
+			struct nlattr *lvl_loc;
+			struct nlattr *lvl_rem;
+
+			if (nla_validate_nested(nla_a,
+					      NLBL_CIPSOV4_A_MAX,
+					      netlbl_cipsov4_genl_policy) != 0)
+				goto add_std_failure;
+
+			lvl_loc = nla_find_nested(nla_a,
+						  NLBL_CIPSOV4_A_MLSLVLLOC);
+			lvl_rem = nla_find_nested(nla_a,
+						  NLBL_CIPSOV4_A_MLSLVLREM);
+			if (lvl_loc == NULL || lvl_rem == NULL)
+				goto add_std_failure;
+			doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
+				nla_get_u32(lvl_rem);
+			doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
+				nla_get_u32(lvl_loc);
+		}
 
-	num_cats = netlbl_getinc_u32(&msg, &msg_len);
-	doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len);
-	if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS)
-		goto add_std_failure;
-	doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size,
+	if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
+		if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
+					NLBL_CIPSOV4_A_MAX,
+					netlbl_cipsov4_genl_policy) != 0)
+			goto add_std_failure;
+
+		nla_for_each_nested(nla_a,
+				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
+				    nla_a_rem)
+			if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
+				if (nla_validate_nested(nla_a,
+					      NLBL_CIPSOV4_A_MAX,
+					      netlbl_cipsov4_genl_policy) != 0)
+					goto add_std_failure;
+				nla_for_each_nested(nla_b, nla_a, nla_b_rem)
+					switch (nla_b->nla_type) {
+					case NLBL_CIPSOV4_A_MLSCATLOC:
+						if (nla_get_u32(nla_b) >=
+					      doi_def->map.std->cat.local_size)
+					     doi_def->map.std->cat.local_size =
+						     nla_get_u32(nla_b) + 1;
+						break;
+					case NLBL_CIPSOV4_A_MLSCATREM:
+						if (nla_get_u32(nla_b) >=
+					      doi_def->map.std->cat.cipso_size)
+					     doi_def->map.std->cat.cipso_size =
+						     nla_get_u32(nla_b) + 1;
+						break;
+					}
+			}
+		if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
+		    doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
+			goto add_std_failure;
+		doi_def->map.std->cat.local = kcalloc(
+			                      doi_def->map.std->cat.local_size,
 					      sizeof(u32),
 					      GFP_KERNEL);
-	if (doi_def->map.std->cat.local == NULL) {
-		ret_val = -ENOMEM;
-		goto add_std_failure;
-	}
-	doi_def->map.std->cat.cipso_size = netlbl_getinc_u16(&msg, &msg_len);
-	if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
-		goto add_std_failure;
-	doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size,
+		if (doi_def->map.std->cat.local == NULL) {
+			ret_val = -ENOMEM;
+			goto add_std_failure;
+		}
+		doi_def->map.std->cat.cipso = kcalloc(
+			                      doi_def->map.std->cat.cipso_size,
 					      sizeof(u32),
 					      GFP_KERNEL);
-	if (doi_def->map.std->cat.cipso == NULL) {
-		ret_val = -ENOMEM;
-		goto add_std_failure;
-	}
-
-	if (msg_len <
-	    num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) +
-	    num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16))
-		goto add_std_failure;
-
-	for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
-		doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
-	for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
-		doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
-	for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
-		doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
-	for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
-		doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
-
-	for (iter = 0; iter < num_lvls; iter++) {
-		tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
-		tmp_val_b = netlbl_getinc_u8(&msg, &msg_len);
-
-		if (tmp_val_a >= doi_def->map.std->lvl.local_size ||
-		    tmp_val_b >= doi_def->map.std->lvl.cipso_size)
-			goto add_std_failure;
-
-		doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a;
-		doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b;
-	}
-
-	for (iter = 0; iter < num_cats; iter++) {
-		tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
-		tmp_val_b = netlbl_getinc_u16(&msg, &msg_len);
-
-		if (tmp_val_a >= doi_def->map.std->cat.local_size ||
-		    tmp_val_b >= doi_def->map.std->cat.cipso_size)
+		if (doi_def->map.std->cat.cipso == NULL) {
+			ret_val = -ENOMEM;
 			goto add_std_failure;
-
-		doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a;
-		doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b;
+		}
+		nla_for_each_nested(nla_a,
+				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
+				    nla_a_rem)
+			if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
+				struct nlattr *cat_loc;
+				struct nlattr *cat_rem;
+
+				cat_loc = nla_find_nested(nla_a,
+						     NLBL_CIPSOV4_A_MLSCATLOC);
+				cat_rem = nla_find_nested(nla_a,
+						     NLBL_CIPSOV4_A_MLSCATREM);
+				if (cat_loc == NULL || cat_rem == NULL)
+					goto add_std_failure;
+				doi_def->map.std->cat.local[
+				                        nla_get_u32(cat_loc)] =
+					nla_get_u32(cat_rem);
+				doi_def->map.std->cat.cipso[
+					                nla_get_u32(cat_rem)] =
+					nla_get_u32(cat_loc);
+			}
 	}
 
-	doi_def->doi = doi;
 	ret_val = cipso_v4_doi_add(doi_def);
 	if (ret_val != 0)
 		goto add_std_failure;
@@ -243,9 +331,7 @@ add_std_failure:
 
 /**
  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
- * @doi: the DOI value
- * @msg: the ADD message data
- * @msg_size: the size of the ADD message buffer
+ * @info: the Generic NETLINK info block
  *
  * Description:
  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
@@ -253,52 +339,31 @@ add_std_failure:
  * error.
  *
  */
-static int netlbl_cipsov4_add_pass(u32 doi,
-				   struct nlattr *msg,
-				   size_t msg_size)
+static int netlbl_cipsov4_add_pass(struct genl_info *info)
 {
-	int ret_val = -EINVAL;
-	int msg_len = msg_size;
-	u32 num_tags;
+	int ret_val;
 	struct cipso_v4_doi *doi_def = NULL;
-	u32 iter;
 
-	if (msg_len < NETLBL_LEN_U32)
-		goto add_pass_failure;
-	num_tags = netlbl_getinc_u32(&msg, &msg_len);
-	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
-		goto add_pass_failure;
+	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
+	    !info->attrs[NLBL_CIPSOV4_A_TAGLST])
+		return -EINVAL;
 
 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
-	if (doi_def == NULL) {
-		ret_val = -ENOMEM;
-		goto add_pass_failure;
-	}
+	if (doi_def == NULL)
+		return -ENOMEM;
 	doi_def->type = CIPSO_V4_MAP_PASS;
 
-	for (iter = 0; iter < num_tags; iter++) {
-		if (msg_len < NETLBL_LEN_U8)
-			goto add_pass_failure;
-		doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
-		switch (doi_def->tags[iter]) {
-		case CIPSO_V4_TAG_RBITMAP:
-			break;
-		default:
-			goto add_pass_failure;
-		}
-	}
-	if (iter < CIPSO_V4_TAG_MAXCNT)
-		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
+	ret_val = netlbl_cipsov4_add_common(info, doi_def);
+	if (ret_val != 0)
+		goto add_pass_failure;
 
-	doi_def->doi = doi;
 	ret_val = cipso_v4_doi_add(doi_def);
 	if (ret_val != 0)
 		goto add_pass_failure;
 	return 0;
 
 add_pass_failure:
-	if (doi_def)
-		netlbl_cipsov4_doi_free(&doi_def->rcu);
+	netlbl_cipsov4_doi_free(&doi_def->rcu);
 	return ret_val;
 }
 
@@ -316,34 +381,21 @@ static int netlbl_cipsov4_add(struct sk_
 
 {
 	int ret_val = -EINVAL;
-	u32 doi;
 	u32 map_type;
-	int msg_len = netlbl_netlink_payload_len(skb);
-	struct nlattr *msg = netlbl_netlink_payload_data(skb);
-
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		goto add_return;
 
-	if (msg_len < 2 * NETLBL_LEN_U32)
-		goto add_return;
+	if (!info->attrs[NLBL_CIPSOV4_A_MTYPE])
+		return -EINVAL;
 
-	doi = netlbl_getinc_u32(&msg, &msg_len);
-	map_type = netlbl_getinc_u32(&msg, &msg_len);
+	map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
 	switch (map_type) {
 	case CIPSO_V4_MAP_STD:
-		ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len);
+		ret_val = netlbl_cipsov4_add_std(info);
 		break;
 	case CIPSO_V4_MAP_PASS:
-		ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len);
+		ret_val = netlbl_cipsov4_add_pass(info);
 		break;
 	}
 
-add_return:
-	netlbl_netlink_send_ack(info,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_ACK,
-				-ret_val);
 	return ret_val;
 }
 
@@ -353,84 +405,239 @@ add_return:
  * @info: the Generic NETLINK info block
  *
  * Description:
- * Process a user generated LIST message and respond accordingly.  Returns
- * zero on success and negative values on error.
+ * Process a user generated LIST message and respond accordingly.  While the
+ * response message generated by the kernel is straightforward, determining
+ * before hand the size of the buffer to allocate is not (we have to generate
+ * the message to know the size).  In order to keep this function sane what we
+ * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
+ * that size, if we fail then we restart with a larger buffer and try again.
+ * We continue in this manner until we hit a limit of failed attempts then we
+ * give up and just send an error message.  Returns zero on success and
+ * negative values on error.
  *
  */
 static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val = -EINVAL;
+	int ret_val;
+	struct sk_buff *ans_skb = NULL;
+	u32 nlsze_mult = 1;
+	void *data;
 	u32 doi;
-	struct nlattr *msg = netlbl_netlink_payload_data(skb);
-	struct sk_buff *ans_skb;
+	struct nlattr *nla_a;
+	struct nlattr *nla_b;
+	struct cipso_v4_doi *doi_def;
+	u32 iter;
 
-	if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32)
+	if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
+		ret_val = -EINVAL;
 		goto list_failure;
+	}
 
-	doi = nla_get_u32(msg);
-	ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN));
+list_start:
+	ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL);
 	if (ans_skb == NULL) {
 		ret_val = -ENOMEM;
 		goto list_failure;
 	}
-	netlbl_netlink_hdr_push(ans_skb,
-				info->snd_pid,
-				0,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_LIST);
+	data = netlbl_netlink_hdr_put(ans_skb,
+				      info->snd_pid,
+				      info->snd_seq,
+				      netlbl_cipsov4_gnl_family.id,
+				      0,
+				      NLBL_CIPSOV4_C_LIST);
+	if (data == NULL) {
+		ret_val = -ENOMEM;
+		goto list_failure;
+	}
+
+	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
+
+	rcu_read_lock();
+	doi_def = cipso_v4_doi_getdef(doi);
+	if (doi_def == NULL) {
+		ret_val = -EINVAL;
+		goto list_failure;
+	}
+
+	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
+	if (ret_val != 0)
+		goto list_failure_lock;
+
+	nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
+	if (nla_a == NULL) {
+		ret_val = -ENOMEM;
+		goto list_failure_lock;
+	}
+	for (iter = 0;
+	     iter < CIPSO_V4_TAG_MAXCNT &&
+	       doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
+	     iter++) {
+		ret_val = nla_put_u8(ans_skb,
+				     NLBL_CIPSOV4_A_TAG,
+				     doi_def->tags[iter]);
+		if (ret_val != 0)
+			goto list_failure_lock;
+	}
+	nla_nest_end(ans_skb, nla_a);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
+		if (nla_a == NULL) {
+			ret_val = -ENOMEM;
+			goto list_failure_lock;
+		}
+		for (iter = 0;
+		     iter < doi_def->map.std->lvl.local_size;
+		     iter++) {
+			if (doi_def->map.std->lvl.local[iter] ==
+			    CIPSO_V4_INV_LVL)
+				continue;
+
+			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
+			if (nla_b == NULL) {
+				ret_val = -ENOMEM;
+				goto list_retry;
+			}
+			ret_val = nla_put_u32(ans_skb,
+					      NLBL_CIPSOV4_A_MLSLVLLOC,
+					      iter);
+			if (ret_val != 0)
+				goto list_retry;
+			ret_val = nla_put_u32(ans_skb,
+					    NLBL_CIPSOV4_A_MLSLVLREM,
+					    doi_def->map.std->lvl.local[iter]);
+			if (ret_val != 0)
+				goto list_retry;
+			nla_nest_end(ans_skb, nla_b);
+		}
+		nla_nest_end(ans_skb, nla_a);
+
+		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
+		if (nla_a == NULL) {
+			ret_val = -ENOMEM;
+			goto list_retry;
+		}
+		for (iter = 0;
+		     iter < doi_def->map.std->cat.local_size;
+		     iter++) {
+			if (doi_def->map.std->cat.local[iter] ==
+			    CIPSO_V4_INV_CAT)
+				continue;
+
+			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
+			if (nla_b == NULL) {
+				ret_val = -ENOMEM;
+				goto list_retry;
+			}
+			ret_val = nla_put_u32(ans_skb,
+					      NLBL_CIPSOV4_A_MLSCATLOC,
+					      iter);
+			if (ret_val != 0)
+				goto list_retry;
+			ret_val = nla_put_u32(ans_skb,
+					    NLBL_CIPSOV4_A_MLSCATREM,
+					    doi_def->map.std->cat.local[iter]);
+			if (ret_val != 0)
+				goto list_retry;
+			nla_nest_end(ans_skb, nla_b);
+		}
+		nla_nest_end(ans_skb, nla_a);
+
+		break;
+	}
+	rcu_read_unlock();
+
+	genlmsg_end(ans_skb, data);
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
+	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
 	if (ret_val != 0)
 		goto list_failure;
 
 	return 0;
 
+list_retry:
+	/* XXX - this limit is a guesstimate */
+	if (nlsze_mult < 4) {
+		rcu_read_unlock();
+		kfree_skb(ans_skb);
+		nlsze_mult++;
+		goto list_start;
+	}
+list_failure_lock:
+	rcu_read_unlock();
 list_failure:
-	netlbl_netlink_send_ack(info,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_ACK,
-				-ret_val);
+	kfree_skb(ans_skb);
+	return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
+ * @doi_def: the CIPSOv4 DOI definition
+ * @arg: the netlbl_cipsov4_doiwalk_arg structure
+ *
+ * Description:
+ * This function is designed to be used as a callback to the
+ * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
+ * message.  Returns the size of the message on success, negative values on
+ * failure.
+ *
+ */
+static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
+{
+	int ret_val = -ENOMEM;
+	struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
+	void *data;
+
+	data = netlbl_netlink_hdr_put(cb_arg->skb,
+				      NETLINK_CB(cb_arg->nl_cb->skb).pid,
+				      cb_arg->seq,
+				      netlbl_cipsov4_gnl_family.id,
+				      NLM_F_MULTI,
+				      NLBL_CIPSOV4_C_LISTALL);
+	if (data == NULL)
+		goto listall_cb_failure;
+
+	ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
+	if (ret_val != 0)
+		goto listall_cb_failure;
+	ret_val = nla_put_u32(cb_arg->skb,
+			      NLBL_CIPSOV4_A_MTYPE,
+			      doi_def->type);
+	if (ret_val != 0)
+		goto listall_cb_failure;
+
+	return genlmsg_end(cb_arg->skb, data);
+
+listall_cb_failure:
+	genlmsg_cancel(cb_arg->skb, data);
 	return ret_val;
 }
 
 /**
  * netlbl_cipsov4_listall - Handle a LISTALL message
  * @skb: the NETLINK buffer
- * @info: the Generic NETLINK info block
+ * @cb: the NETLINK callback
  *
  * Description:
  * Process a user generated LISTALL message and respond accordingly.  Returns
  * zero on success and negative values on error.
  *
  */
-static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_cipsov4_listall(struct sk_buff *skb,
+				  struct netlink_callback *cb)
 {
-	int ret_val = -EINVAL;
-	struct sk_buff *ans_skb;
+	struct netlbl_cipsov4_doiwalk_arg cb_arg;
+	int doi_skip = cb->args[0];
 
-	ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN));
-	if (ans_skb == NULL) {
-		ret_val = -ENOMEM;
-		goto listall_failure;
-	}
-	netlbl_netlink_hdr_push(ans_skb,
-				info->snd_pid,
-				0,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_LISTALL);
+	cb_arg.nl_cb = cb;
+	cb_arg.skb = skb;
+	cb_arg.seq = cb->nlh->nlmsg_seq;
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
-	if (ret_val != 0)
-		goto listall_failure;
-
-	return 0;
+	cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
 
-listall_failure:
-	netlbl_netlink_send_ack(info,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_ACK,
-				-ret_val);
-	return ret_val;
+	cb->args[0] = doi_skip;
+	return skb->len;
 }
 
 /**
@@ -445,27 +652,14 @@ listall_failure:
  */
 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val;
+	int ret_val = -EINVAL;
 	u32 doi;
-	struct nlattr *msg = netlbl_netlink_payload_data(skb);
 
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		goto remove_return;
-
-	if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) {
-		ret_val = -EINVAL;
-		goto remove_return;
+	if (info->attrs[NLBL_CIPSOV4_A_DOI]) {
+		doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
+		ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
 	}
 
-	doi = nla_get_u32(msg);
-	ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
-
-remove_return:
-	netlbl_netlink_send_ack(info,
-				netlbl_cipsov4_gnl_family.id,
-				NLBL_CIPSOV4_C_ACK,
-				-ret_val);
 	return ret_val;
 }
 
@@ -475,14 +669,16 @@ remove_return:
 
 static struct genl_ops netlbl_cipsov4_genl_c_add = {
 	.cmd = NLBL_CIPSOV4_C_ADD,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_cipsov4_genl_policy,
 	.doit = netlbl_cipsov4_add,
 	.dumpit = NULL,
 };
 
 static struct genl_ops netlbl_cipsov4_genl_c_remove = {
 	.cmd = NLBL_CIPSOV4_C_REMOVE,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_cipsov4_genl_policy,
 	.doit = netlbl_cipsov4_remove,
 	.dumpit = NULL,
 };
@@ -490,6 +686,7 @@ static struct genl_ops netlbl_cipsov4_ge
 static struct genl_ops netlbl_cipsov4_genl_c_list = {
 	.cmd = NLBL_CIPSOV4_C_LIST,
 	.flags = 0,
+	.policy = netlbl_cipsov4_genl_policy,
 	.doit = netlbl_cipsov4_list,
 	.dumpit = NULL,
 };
@@ -497,8 +694,9 @@ static struct genl_ops netlbl_cipsov4_ge
 static struct genl_ops netlbl_cipsov4_genl_c_listall = {
 	.cmd = NLBL_CIPSOV4_C_LISTALL,
 	.flags = 0,
-	.doit = netlbl_cipsov4_listall,
-	.dumpit = NULL,
+	.policy = netlbl_cipsov4_genl_policy,
+	.doit = NULL,
+	.dumpit = netlbl_cipsov4_listall,
 };
 
 /*
Index: net-2.6.19/net/netlabel/netlabel_cipso_v4.h
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_cipso_v4.h
+++ net-2.6.19/net/netlabel/netlabel_cipso_v4.h
@@ -34,175 +34,71 @@
 #include <net/netlabel.h>
 
 /*
- * The following NetLabel payloads are supported by the CIPSO 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: return value, based on errno values
+ * The following NetLabel payloads are supported by the CIPSO subsystem.
  *
  * o ADD:
- *   Sent by an application to add a new DOI mapping table, after completion
- *   of the task the kernel should ACK this message.
+ *   Sent by an application to add a new DOI mapping table.
+ *
+ *   Required attributes:
+ *
+ *     NLBL_CIPSOV4_A_DOI
+ *     NLBL_CIPSOV4_A_MTYPE
+ *     NLBL_CIPSOV4_A_TAGLST
  *
- *   +---------------+--------------------+---------------------+
- *   | DOI (32 bits) | map type (32 bits) | tag count (32 bits) | ...
- *   +---------------+--------------------+---------------------+
- *
- *   +-----------------+
- *   | tag #X (8 bits) | ... repeated
- *   +-----------------+
- *
- *   +-------------- ---- --- -- -
- *   | mapping data
- *   +-------------- ---- --- -- -
- *
- *     DOI:          the DOI value
- *     map type:     the mapping table type (defined in the cipso_ipv4.h header
- *                   as CIPSO_V4_MAP_*)
- *     tag count:    the number of tags, must be greater than zero
- *     tag:          the CIPSO tag for the DOI, tags listed first are given
- *                   higher priorirty when sending packets
- *     mapping data: specific to the map type (see below)
- *
- *   CIPSO_V4_MAP_STD
- *
- *   +------------------+-----------------------+----------------------+
- *   | levels (32 bits) | max l level (32 bits) | max r level (8 bits) | ...
- *   +------------------+-----------------------+----------------------+
- *
- *   +----------------------+---------------------+---------------------+
- *   | categories (32 bits) | max l cat (32 bits) | max r cat (16 bits) | ...
- *   +----------------------+---------------------+---------------------+
- *
- *   +--------------------------+-------------------------+
- *   | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated
- *   +--------------------------+-------------------------+
- *
- *   +-----------------------------+-----------------------------+
- *   | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated
- *   +-----------------------------+-----------------------------+
- *
- *     levels:         the number of level mappings
- *     max l level:    the highest local level
- *     max r level:    the highest remote/CIPSO level
- *     categories:     the number of category mappings
- *     max l cat:      the highest local category
- *     max r cat:      the highest remote/CIPSO category
- *     local level:    the local part of a level mapping
- *     CIPSO level:    the remote/CIPSO part of a level mapping
- *     local category: the local part of a category mapping
- *     CIPSO category: the remote/CIPSO part of a category mapping
+ *   If using CIPSO_V4_MAP_STD the following attributes are required:
  *
- *   CIPSO_V4_MAP_PASS
+ *     NLBL_CIPSOV4_A_MLSLVLLST
+ *     NLBL_CIPSOV4_A_MLSCATLST
  *
- *   No mapping data is needed for this map type.
+ *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
  *
  * o REMOVE:
  *   Sent by an application to remove a specific DOI mapping table from the
- *   CIPSO V4 system.  The kernel should ACK this message.
+ *   CIPSO V4 system.
  *
- *   +---------------+
- *   | DOI (32 bits) |
- *   +---------------+
+ *   Required attributes:
  *
- *     DOI:          the DOI value
+ *     NLBL_CIPSOV4_A_DOI
  *
  * o LIST:
- *   Sent by an application to list the details of a DOI definition.  The
- *   kernel should send an ACK on error or a response as indicated below.  The
- *   application generated message format is shown below.
- *
- *   +---------------+
- *   | DOI (32 bits) |
- *   +---------------+
+ *   Sent by an application to list the details of a DOI definition.  On
+ *   success the kernel should send a response using the following format.
  *
- *     DOI:          the DOI value
+ *   Required attributes:
+ *
+ *     NLBL_CIPSOV4_A_DOI
  *
  *   The valid response message format depends on the type of the DOI mapping,
- *   the known formats are shown below.
+ *   the defined formats are shown below.
+ *
+ *   Required attributes:
+ *
+ *     NLBL_CIPSOV4_A_MTYPE
+ *     NLBL_CIPSOV4_A_TAGLST
  *
- *   +--------------------+
- *   | map type (32 bits) | ...
- *   +--------------------+
- *
- *     map type:       the DOI mapping table type (defined in the cipso_ipv4.h
- *                     header as CIPSO_V4_MAP_*)
- *
- *   (map type == CIPSO_V4_MAP_STD)
- *
- *   +----------------+------------------+----------------------+
- *   | tags (32 bits) | levels (32 bits) | categories (32 bits) | ...
- *   +----------------+------------------+----------------------+
- *
- *   +-----------------+
- *   | tag #X (8 bits) | ... repeated
- *   +-----------------+
- *
- *   +--------------------------+-------------------------+
- *   | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated
- *   +--------------------------+-------------------------+
- *
- *   +-----------------------------+-----------------------------+
- *   | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated
- *   +-----------------------------+-----------------------------+
- *
- *     tags:           the number of CIPSO tag types
- *     levels:         the number of level mappings
- *     categories:     the number of category mappings
- *     tag:            the tag number, tags listed first are given higher
- *                     priority when sending packets
- *     local level:    the local part of a level mapping
- *     CIPSO level:    the remote/CIPSO part of a level mapping
- *     local category: the local part of a category mapping
- *     CIPSO category: the remote/CIPSO part of a category mapping
- *
- *   (map type == CIPSO_V4_MAP_PASS)
- *
- *   +----------------+
- *   | tags (32 bits) | ...
- *   +----------------+
- *
- *   +-----------------+
- *   | tag #X (8 bits) | ... repeated
- *   +-----------------+
- *
- *     tags:           the number of CIPSO tag types
- *     tag:            the tag number, tags listed first are given higher
- *                     priority when sending packets
+ *   If using CIPSO_V4_MAP_STD the following attributes are required:
+ *
+ *     NLBL_CIPSOV4_A_MLSLVLLST
+ *     NLBL_CIPSOV4_A_MLSCATLST
+ *
+ *   If using CIPSO_V4_MAP_PASS no additional attributes are required.
  *
  * o LISTALL:
  *   This message is sent by an application to list the valid DOIs on the
- *   system.  There is no payload and the kernel should respond with an ACK
- *   or the following message.
+ *   system.  When sent by an application there is no payload and the
+ *   NLM_F_DUMP flag should be set.  The kernel should respond with a series of
+ *   the following messages.
+ *
+ *   Required attributes:
  *
- *   +---------------------+------------------+-----------------------+
- *   | DOI count (32 bits) | DOI #X (32 bits) | map type #X (32 bits) |
- *   +---------------------+------------------+-----------------------+
- *
- *   +-----------------------+
- *   | map type #X (32 bits) | ...
- *   +-----------------------+
- *
- *     DOI count:      the number of DOIs
- *     DOI:            the DOI value
- *     map type:       the DOI mapping table type (defined in the cipso_ipv4.h
- *                     header as CIPSO_V4_MAP_*)
+ *    NLBL_CIPSOV4_A_DOI
+ *    NLBL_CIPSOV4_A_MTYPE
  *
  */
 
 /* NetLabel CIPSOv4 commands */
 enum {
 	NLBL_CIPSOV4_C_UNSPEC,
-	NLBL_CIPSOV4_C_ACK,
 	NLBL_CIPSOV4_C_ADD,
 	NLBL_CIPSOV4_C_REMOVE,
 	NLBL_CIPSOV4_C_LIST,
@@ -211,6 +107,59 @@ enum {
 };
 #define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1)
 
+/* NetLabel CIPSOv4 attributes */
+enum {
+	NLBL_CIPSOV4_A_UNSPEC,
+	NLBL_CIPSOV4_A_DOI,
+	/* (NLA_U32)
+	 * the DOI value */
+	NLBL_CIPSOV4_A_MTYPE,
+	/* (NLA_U32)
+	 * the mapping table type (defined in the cipso_ipv4.h header as
+	 * CIPSO_V4_MAP_*) */
+	NLBL_CIPSOV4_A_TAG,
+	/* (NLA_U8)
+	 * a CIPSO tag type, meant to be used within a NLBL_CIPSOV4_A_TAGLST
+	 * attribute */
+	NLBL_CIPSOV4_A_TAGLST,
+	/* (NLA_NESTED)
+	 * the CIPSO tag list for the DOI, there must be at least one
+	 * NLBL_CIPSOV4_A_TAG attribute, tags listed first are given higher
+	 * priorirty when sending packets */
+	NLBL_CIPSOV4_A_MLSLVLLOC,
+	/* (NLA_U32)
+	 * the local MLS sensitivity level */
+	NLBL_CIPSOV4_A_MLSLVLREM,
+	/* (NLA_U32)
+	 * the remote MLS sensitivity level */
+	NLBL_CIPSOV4_A_MLSLVL,
+	/* (NLA_NESTED)
+	 * a MLS sensitivity level mapping, must contain only one attribute of
+	 * each of the following types: NLBL_CIPSOV4_A_MLSLVLLOC and
+	 * NLBL_CIPSOV4_A_MLSLVLREM */
+	NLBL_CIPSOV4_A_MLSLVLLST,
+	/* (NLA_NESTED)
+	 * the CIPSO level mappings, there must be at least one
+	 * NLBL_CIPSOV4_A_MLSLVL attribute */
+	NLBL_CIPSOV4_A_MLSCATLOC,
+	/* (NLA_U32)
+	 * the local MLS category */
+	NLBL_CIPSOV4_A_MLSCATREM,
+	/* (NLA_U32)
+	 * the remote MLS category */
+	NLBL_CIPSOV4_A_MLSCAT,
+	/* (NLA_NESTED)
+	 * a MLS category mapping, must contain only one attribute of each of
+	 * the following types: NLBL_CIPSOV4_A_MLSCATLOC and
+	 * NLBL_CIPSOV4_A_MLSCATREM */
+	NLBL_CIPSOV4_A_MLSCATLST,
+	/* (NLA_NESTED)
+	 * the CIPSO category mappings, there must be at least one
+	 * NLBL_CIPSOV4_A_MLSCAT attribute */
+	__NLBL_CIPSOV4_A_MAX,
+};
+#define NLBL_CIPSOV4_A_MAX (__NLBL_CIPSOV4_A_MAX - 1)
+
 /* NetLabel protocol functions */
 int netlbl_cipsov4_genl_init(void);
 
Index: net-2.6.19/net/netlabel/netlabel_mgmt.c
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_mgmt.c
+++ net-2.6.19/net/netlabel/netlabel_mgmt.c
@@ -42,15 +42,29 @@
 #include "netlabel_user.h"
 #include "netlabel_mgmt.h"
 
+/* Argument struct for netlbl_domhsh_walk() */
+struct netlbl_domhsh_walk_arg {
+	struct netlink_callback *nl_cb;
+	struct sk_buff *skb;
+	u32 seq;
+};
+
 /* NetLabel Generic NETLINK CIPSOv4 family */
 static struct genl_family netlbl_mgmt_gnl_family = {
 	.id = GENL_ID_GENERATE,
 	.hdrsize = 0,
 	.name = NETLBL_NLTYPE_MGMT_NAME,
 	.version = NETLBL_PROTO_VERSION,
-	.maxattr = 0,
+	.maxattr = NLBL_MGMT_A_MAX,
 };
 
+/* NetLabel Netlink attribute policy */
+static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
+	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
+	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
+	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
+	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
+};
 
 /*
  * NetLabel Command Handlers
@@ -70,97 +84,62 @@ static struct genl_family netlbl_mgmt_gn
 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
 {
 	int ret_val = -EINVAL;
-	struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
-	int msg_len = netlbl_netlink_payload_len(skb);
-	u32 count;
 	struct netlbl_dom_map *entry = NULL;
-	u32 iter;
+	size_t tmp_size;
 	u32 tmp_val;
-	int tmp_size;
 
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
+	if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
+	    !info->attrs[NLBL_MGMT_A_PROTOCOL])
 		goto add_failure;
 
-	if (msg_len < NETLBL_LEN_U32)
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL) {
+		ret_val = -ENOMEM;
 		goto add_failure;
-	count = netlbl_getinc_u32(&msg_ptr, &msg_len);
+	}
+	tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
+	entry->domain = kmalloc(tmp_size, GFP_KERNEL);
+	if (entry->domain == NULL) {
+		ret_val = -ENOMEM;
+		goto add_failure;
+	}
+	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
+	nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
 
-	for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) {
-		if (msg_len <= 0) {
-			ret_val = -EINVAL;
-			goto add_failure;
-		}
-		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-		if (entry == NULL) {
-			ret_val = -ENOMEM;
-			goto add_failure;
-		}
-		tmp_size = nla_len(msg_ptr);
-		if (tmp_size <= 0 || tmp_size > msg_len) {
-			ret_val = -EINVAL;
-			goto add_failure;
-		}
-		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
-		if (entry->domain == NULL) {
-			ret_val = -ENOMEM;
+	switch (entry->type) {
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = netlbl_domhsh_add(entry);
+		break;
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
 			goto add_failure;
-		}
-		nla_strlcpy(entry->domain, msg_ptr, tmp_size);
-		entry->domain[tmp_size - 1] = '\0';
-		msg_ptr = nla_next(msg_ptr, &msg_len);
 
-		if (msg_len < NETLBL_LEN_U32) {
-			ret_val = -EINVAL;
-			goto add_failure;
-		}
-		tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
-		entry->type = tmp_val;
-		switch (tmp_val) {
-		case NETLBL_NLTYPE_UNLABELED:
-			ret_val = netlbl_domhsh_add(entry);
-			break;
-		case NETLBL_NLTYPE_CIPSOV4:
-			if (msg_len < NETLBL_LEN_U32) {
-				ret_val = -EINVAL;
-				goto add_failure;
-			}
-			tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
-			/* 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();
-				ret_val = -EINVAL;
-				goto add_failure;
-			}
-			ret_val = netlbl_domhsh_add(entry);
+		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
+		/* 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();
-			break;
-		default:
-			ret_val = -EINVAL;
-		}
-		if (ret_val != 0)
 			goto add_failure;
+		}
+		ret_val = netlbl_domhsh_add(entry);
+		rcu_read_unlock();
+		break;
+	default:
+		goto add_failure;
 	}
+	if (ret_val != 0)
+		goto add_failure;
 
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				NETLBL_E_OK);
 	return 0;
 
 add_failure:
 	if (entry)
 		kfree(entry->domain);
 	kfree(entry);
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
 	return ret_val;
 }
 
@@ -176,90 +155,101 @@ add_failure:
  */
 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val = -EINVAL;
-	struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
-	int msg_len = netlbl_netlink_payload_len(skb);
-	u32 count;
-	u32 iter;
-	int tmp_size;
-	unsigned char *domain;
-
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		goto remove_return;
-
-	if (msg_len < NETLBL_LEN_U32)
-		goto remove_return;
-	count = netlbl_getinc_u32(&msg_ptr, &msg_len);
-
-	for (iter = 0; iter < count && msg_len > 0; iter++) {
-		if (msg_len <= 0) {
-			ret_val = -EINVAL;
-			goto remove_return;
-		}
-		tmp_size = nla_len(msg_ptr);
-		domain = nla_data(msg_ptr);
-		if (tmp_size <= 0 || tmp_size > msg_len ||
-		    domain[tmp_size - 1] != '\0') {
-			ret_val = -EINVAL;
-			goto remove_return;
-		}
-		ret_val = netlbl_domhsh_remove(domain);
-		if (ret_val != 0)
-			goto remove_return;
-		msg_ptr = nla_next(msg_ptr, &msg_len);
-	}
+	char *domain;
 
-	ret_val = 0;
+	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
+		return -EINVAL;
 
-remove_return:
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
-	return ret_val;
+	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
+	return netlbl_domhsh_remove(domain);
 }
 
 /**
- * netlbl_mgmt_list - Handle a LIST message
- * @skb: the NETLINK buffer
- * @info: the Generic NETLINK info block
+ * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
+ * @entry: the domain mapping hash table entry
+ * @arg: the netlbl_domhsh_walk_arg structure
  *
  * 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, negative values on failure.
+ * This function is designed to be used as a callback to the
+ * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
+ * message.  Returns the size of the message on success, negative values on
+ * failure.
  *
  */
-static int netlbl_mgmt_list(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
 {
 	int ret_val = -ENOMEM;
-	struct sk_buff *ans_skb;
-
-	ans_skb = netlbl_domhsh_dump(NLMSG_SPACE(GENL_HDRLEN));
-	if (ans_skb == NULL)
-		goto list_failure;
-	netlbl_netlink_hdr_push(ans_skb,
-				info->snd_pid,
-				0,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_LIST);
+	struct netlbl_domhsh_walk_arg *cb_arg = arg;
+	void *data;
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
+	data = netlbl_netlink_hdr_put(cb_arg->skb,
+				      NETLINK_CB(cb_arg->nl_cb->skb).pid,
+				      cb_arg->seq,
+				      netlbl_mgmt_gnl_family.id,
+				      NLM_F_MULTI,
+				      NLBL_MGMT_C_LISTALL);
+	if (data == NULL)
+		goto listall_cb_failure;
+
+	ret_val = nla_put_string(cb_arg->skb,
+				 NLBL_MGMT_A_DOMAIN,
+				 entry->domain);
+	if (ret_val != 0)
+		goto listall_cb_failure;
+	ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
 	if (ret_val != 0)
-		goto list_failure;
+		goto listall_cb_failure;
+	switch (entry->type) {
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = nla_put_u32(cb_arg->skb,
+				      NLBL_MGMT_A_CV4DOI,
+				      entry->type_def.cipsov4->doi);
+		if (ret_val != 0)
+			goto listall_cb_failure;
+		break;
+	}
 
-	return 0;
+	cb_arg->seq++;
+	return genlmsg_end(cb_arg->skb, data);
 
-list_failure:
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
+listall_cb_failure:
+	genlmsg_cancel(cb_arg->skb, data);
 	return ret_val;
 }
 
 /**
+ * netlbl_mgmt_listall - Handle a LISTALL message
+ * @skb: the NETLINK buffer
+ * @cb: the NETLINK callback
+ *
+ * Description:
+ * Process a user generated LISTALL message and dumps the domain hash table in
+ * a form suitable for use in a kernel generated LISTALL message.  Returns zero
+ * on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_listall(struct sk_buff *skb,
+			       struct netlink_callback *cb)
+{
+	struct netlbl_domhsh_walk_arg cb_arg;
+	u32 skip_bkt = cb->args[0];
+	u32 skip_chain = cb->args[1];
+
+	cb_arg.nl_cb = cb;
+	cb_arg.skb = skb;
+	cb_arg.seq = cb->nlh->nlmsg_seq;
+
+	netlbl_domhsh_walk(&skip_bkt,
+			   &skip_chain,
+			   netlbl_mgmt_listall_cb,
+			   &cb_arg);
+
+	cb->args[0] = skip_bkt;
+	cb->args[1] = skip_chain;
+	return skb->len;
+}
+
+/**
  * netlbl_mgmt_adddef - Handle an ADDDEF message
  * @skb: the NETLINK buffer
  * @info: the Generic NETLINK info block
@@ -272,68 +262,51 @@ list_failure:
 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
 {
 	int ret_val = -EINVAL;
-	struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
-	int msg_len = netlbl_netlink_payload_len(skb);
 	struct netlbl_dom_map *entry = NULL;
 	u32 tmp_val;
 
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		goto adddef_failure;
-
-	if (msg_len < NETLBL_LEN_U32)
+	if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
 		goto adddef_failure;
-	tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
 
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (entry == NULL) {
 		ret_val = -ENOMEM;
 		goto adddef_failure;
 	}
+	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
 
-	entry->type = tmp_val;
 	switch (entry->type) {
 	case NETLBL_NLTYPE_UNLABELED:
 		ret_val = netlbl_domhsh_add_default(entry);
 		break;
 	case NETLBL_NLTYPE_CIPSOV4:
-		if (msg_len < NETLBL_LEN_U32) {
-			ret_val = -EINVAL;
+		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
 			goto adddef_failure;
-		}
-		tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
-		/* 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. */
+
+		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
+		/* 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();
-			ret_val = -EINVAL;
 			goto adddef_failure;
 		}
 		ret_val = netlbl_domhsh_add_default(entry);
 		rcu_read_unlock();
 		break;
 	default:
-		ret_val = -EINVAL;
+		goto adddef_failure;
 	}
 	if (ret_val != 0)
 		goto adddef_failure;
 
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				NETLBL_E_OK);
 	return 0;
 
 adddef_failure:
 	kfree(entry);
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
 	return ret_val;
 }
 
@@ -349,20 +322,7 @@ adddef_failure:
  */
 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val;
-
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		goto removedef_return;
-
-	ret_val = netlbl_domhsh_remove_default();
-
-removedef_return:
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
-	return ret_val;
+	return netlbl_domhsh_remove_default();
 }
 
 /**
@@ -379,85 +339,128 @@ removedef_return:
 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
 {
 	int ret_val = -ENOMEM;
-	struct sk_buff *ans_skb;
+	struct sk_buff *ans_skb = NULL;
+	void *data;
+	struct netlbl_dom_map *entry;
 
-	ans_skb = netlbl_domhsh_dump_default(NLMSG_SPACE(GENL_HDRLEN));
+	ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (ans_skb == NULL)
+		return -ENOMEM;
+	data = netlbl_netlink_hdr_put(ans_skb,
+				      info->snd_pid,
+				      info->snd_seq,
+				      netlbl_mgmt_gnl_family.id,
+				      0,
+				      NLBL_MGMT_C_LISTDEF);
+	if (data == NULL)
 		goto listdef_failure;
-	netlbl_netlink_hdr_push(ans_skb,
-				info->snd_pid,
-				0,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_LISTDEF);
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
+	rcu_read_lock();
+	entry = netlbl_domhsh_getentry(NULL);
+	if (entry == NULL) {
+		ret_val = -ENOENT;
+		goto listdef_failure_lock;
+	}
+	ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
 	if (ret_val != 0)
-		goto listdef_failure;
+		goto listdef_failure_lock;
+	switch (entry->type) {
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = nla_put_u32(ans_skb,
+				      NLBL_MGMT_A_CV4DOI,
+				      entry->type_def.cipsov4->doi);
+		if (ret_val != 0)
+			goto listdef_failure_lock;
+		break;
+	}
+	rcu_read_unlock();
 
+	genlmsg_end(ans_skb, data);
+
+	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
+	if (ret_val != 0)
+		goto listdef_failure;
 	return 0;
 
+listdef_failure_lock:
+	rcu_read_unlock();
 listdef_failure:
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
+	kfree_skb(ans_skb);
 	return ret_val;
 }
 
 /**
- * netlbl_mgmt_modules - Handle a MODULES message
- * @skb: the NETLINK buffer
- * @info: the Generic NETLINK info block
+ * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
+ * @skb: the skb to write to
+ * @seq: the NETLINK sequence number
+ * @cb: the NETLINK callback
+ * @protocol: the NetLabel protocol to use in the message
  *
  * Description:
- * Process a user generated MODULES message and respond accordingly.
+ * This function is to be used in conjunction with netlbl_mgmt_protocols() to
+ * answer a application's PROTOCOLS message.  Returns the size of the message
+ * on success, negative values on failure.
  *
  */
-static int netlbl_mgmt_modules(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
+				    struct netlink_callback *cb,
+				    u32 protocol)
 {
 	int ret_val = -ENOMEM;
-	size_t data_size;
-	u32 mod_count;
-	struct sk_buff *ans_skb = NULL;
+	void *data;
 
-	/* unlabeled + cipsov4 */
-	mod_count = 2;
+	data = netlbl_netlink_hdr_put(skb,
+				      NETLINK_CB(cb->skb).pid,
+				      cb->nlh->nlmsg_seq,
+				      netlbl_mgmt_gnl_family.id,
+				      NLM_F_MULTI,
+				      NLBL_MGMT_C_PROTOCOLS);
+	if (data == NULL)
+		goto protocols_cb_failure;
 
-	data_size = GENL_HDRLEN + NETLBL_LEN_U32 + mod_count * NETLBL_LEN_U32;
-	ans_skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL);
-	if (ans_skb == NULL)
-		goto modules_failure;
+	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
+	if (ret_val != 0)
+		goto protocols_cb_failure;
 
-	if (netlbl_netlink_hdr_put(ans_skb,
-				   info->snd_pid,
-				   0,
-				   netlbl_mgmt_gnl_family.id,
-				   NLBL_MGMT_C_MODULES) == NULL)
-		goto modules_failure;
+	return genlmsg_end(skb, data);
 
-	ret_val = nla_put_u32(ans_skb, NLA_U32, mod_count);
-	if (ret_val != 0)
-		goto modules_failure;
-	ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_UNLABELED);
-	if (ret_val != 0)
-		goto modules_failure;
-	ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_CIPSOV4);
-	if (ret_val != 0)
-		goto modules_failure;
+protocols_cb_failure:
+	genlmsg_cancel(skb, data);
+	return ret_val;
+}
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
-	if (ret_val != 0)
-		goto modules_failure;
+/**
+ * netlbl_mgmt_protocols - Handle a PROTOCOLS message
+ * @skb: the NETLINK buffer
+ * @cb: the NETLINK callback
+ *
+ * Description:
+ * Process a user generated PROTOCOLS message and respond accordingly.
+ *
+ */
+static int netlbl_mgmt_protocols(struct sk_buff *skb,
+				 struct netlink_callback *cb)
+{
+	u32 protos_sent = cb->args[0];
 
-	return 0;
+	if (protos_sent == 0) {
+		if (netlbl_mgmt_protocols_cb(skb,
+					     cb,
+					     NETLBL_NLTYPE_UNLABELED) < 0)
+			goto protocols_return;
+		protos_sent++;
+	}
+	if (protos_sent == 1) {
+		if (netlbl_mgmt_protocols_cb(skb,
+					     cb,
+					     NETLBL_NLTYPE_CIPSOV4) < 0)
+			goto protocols_return;
+		protos_sent++;
+	}
 
-modules_failure:
-	kfree_skb(ans_skb);
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
-	return ret_val;
+protocols_return:
+	cb->args[0] = protos_sent;
+	return skb->len;
 }
 
 /**
@@ -474,35 +477,35 @@ static int netlbl_mgmt_version(struct sk
 {
 	int ret_val = -ENOMEM;
 	struct sk_buff *ans_skb = NULL;
+	void *data;
 
-	ans_skb = netlbl_netlink_alloc_skb(0,
-					   GENL_HDRLEN + NETLBL_LEN_U32,
-					   GFP_KERNEL);
+	ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (ans_skb == NULL)
-		goto version_failure;
-	if (netlbl_netlink_hdr_put(ans_skb,
-				   info->snd_pid,
-				   0,
-				   netlbl_mgmt_gnl_family.id,
-				   NLBL_MGMT_C_VERSION) == NULL)
+		return -ENOMEM;
+	data = netlbl_netlink_hdr_put(ans_skb,
+				      info->snd_pid,
+				      info->snd_seq,
+				      netlbl_mgmt_gnl_family.id,
+				      0,
+				      NLBL_MGMT_C_VERSION);
+	if (data == NULL)
 		goto version_failure;
 
-	ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_PROTO_VERSION);
+	ret_val = nla_put_u32(ans_skb,
+			      NLBL_MGMT_A_VERSION,
+			      NETLBL_PROTO_VERSION);
 	if (ret_val != 0)
 		goto version_failure;
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
+	genlmsg_end(ans_skb, data);
+
+	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
 	if (ret_val != 0)
 		goto version_failure;
-
 	return 0;
 
 version_failure:
 	kfree_skb(ans_skb);
-	netlbl_netlink_send_ack(info,
-				netlbl_mgmt_gnl_family.id,
-				NLBL_MGMT_C_ACK,
-				-ret_val);
 	return ret_val;
 }
 
@@ -513,35 +516,40 @@ version_failure:
 
 static struct genl_ops netlbl_mgmt_genl_c_add = {
 	.cmd = NLBL_MGMT_C_ADD,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_add,
 	.dumpit = NULL,
 };
 
 static struct genl_ops netlbl_mgmt_genl_c_remove = {
 	.cmd = NLBL_MGMT_C_REMOVE,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_remove,
 	.dumpit = NULL,
 };
 
-static struct genl_ops netlbl_mgmt_genl_c_list = {
-	.cmd = NLBL_MGMT_C_LIST,
+static struct genl_ops netlbl_mgmt_genl_c_listall = {
+	.cmd = NLBL_MGMT_C_LISTALL,
 	.flags = 0,
-	.doit = netlbl_mgmt_list,
-	.dumpit = NULL,
+	.policy = netlbl_mgmt_genl_policy,
+	.doit = NULL,
+	.dumpit = netlbl_mgmt_listall,
 };
 
 static struct genl_ops netlbl_mgmt_genl_c_adddef = {
 	.cmd = NLBL_MGMT_C_ADDDEF,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_adddef,
 	.dumpit = NULL,
 };
 
 static struct genl_ops netlbl_mgmt_genl_c_removedef = {
 	.cmd = NLBL_MGMT_C_REMOVEDEF,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_removedef,
 	.dumpit = NULL,
 };
@@ -549,20 +557,23 @@ static struct genl_ops netlbl_mgmt_genl_
 static struct genl_ops netlbl_mgmt_genl_c_listdef = {
 	.cmd = NLBL_MGMT_C_LISTDEF,
 	.flags = 0,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_listdef,
 	.dumpit = NULL,
 };
 
-static struct genl_ops netlbl_mgmt_genl_c_modules = {
-	.cmd = NLBL_MGMT_C_MODULES,
+static struct genl_ops netlbl_mgmt_genl_c_protocols = {
+	.cmd = NLBL_MGMT_C_PROTOCOLS,
 	.flags = 0,
-	.doit = netlbl_mgmt_modules,
-	.dumpit = NULL,
+	.policy = netlbl_mgmt_genl_policy,
+	.doit = NULL,
+	.dumpit = netlbl_mgmt_protocols,
 };
 
 static struct genl_ops netlbl_mgmt_genl_c_version = {
 	.cmd = NLBL_MGMT_C_VERSION,
 	.flags = 0,
+	.policy = netlbl_mgmt_genl_policy,
 	.doit = netlbl_mgmt_version,
 	.dumpit = NULL,
 };
@@ -596,7 +607,7 @@ int netlbl_mgmt_genl_init(void)
 	if (ret_val != 0)
 		return ret_val;
 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
-				    &netlbl_mgmt_genl_c_list);
+				    &netlbl_mgmt_genl_c_listall);
 	if (ret_val != 0)
 		return ret_val;
 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
@@ -612,7 +623,7 @@ int netlbl_mgmt_genl_init(void)
 	if (ret_val != 0)
 		return ret_val;
 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
-				    &netlbl_mgmt_genl_c_modules);
+				    &netlbl_mgmt_genl_c_protocols);
 	if (ret_val != 0)
 		return ret_val;
 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
Index: net-2.6.19/net/netlabel/netlabel_mgmt.h
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_mgmt.h
+++ net-2.6.19/net/netlabel/netlabel_mgmt.h
@@ -34,212 +34,137 @@
 #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: return value, based on errno values
+ * The following NetLabel payloads are supported by the management interface.
  *
  * 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 string (variable) | protocol type (32 bits) | ...
- *   +--------------------------+-------------------------+
- *
- *   +-------------- ---- --- -- -
- *   | mapping data                ... repeated
- *   +-------------- ---- --- -- -
- *
- *     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
+ *   Required attributes:
  *
- *     No mapping data for this protocol type.
+ *     NLBL_MGMT_A_DOMAIN
+ *     NLBL_MGMT_A_PROTOCOL
  *
- *   NETLBL_NLTYPE_CIPSOV4
+ *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
- *   +---------------+
- *   | doi (32 bits) |
- *   +---------------+
+ *     NLBL_MGMT_A_CV4DOI
  *
- *     doi:  the CIPSO DOI value
+ *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
  *
  * o REMOVE:
  *   Sent by an application to remove a domain mapping from the NetLabel
- *   system.  The kernel should ACK this message.
+ *   system.
  *
- *   +-------------------+
- *   | domains (32 bits) | ...
- *   +-------------------+
+ *   Required attributes:
  *
- *     domains: the number of domains in the message
+ *     NLBL_MGMT_A_DOMAIN
  *
- *   +--------------------------+
- *   | domain string (variable) | ...
- *   +--------------------------+
- *
- *     domain string: the domain string, NULL terminated
- *
- * o LIST:
+ * o LISTALL:
  *   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 string (variable) | ...
- *   +--------------------------+
- *
- *   +-------------------------+-------------- ---- --- -- -
- *   | protocol type (32 bits) | mapping data                ... repeated
- *   +-------------------------+-------------- ---- --- -- -
+ *   response to an application generated LISTALL message.  When sent by an
+ *   application there is no payload and the NLM_F_DUMP flag should be set.
+ *   The kernel should respond with a series of the following messages.
  *
- *     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)
+ *   Required attributes:
  *
- *   NETLBL_NLTYPE_UNLABELED
+ *     NLBL_MGMT_A_DOMAIN
+ *     NLBL_MGMT_A_PROTOCOL
  *
- *     No mapping data for this protocol type.
+ *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
- *   NETLBL_NLTYPE_CIPSOV4
+ *     NLBL_MGMT_A_CV4DOI
  *
- *   +----------------+---------------+
- *   | 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
+ *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
  *
  * 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)
+ *   system.
  *
- *   NETLBL_NLTYPE_UNLABELED
+ *   Required attributes:
  *
- *     No mapping data for this protocol type.
+ *     NLBL_MGMT_A_PROTOCOL
  *
- *   NETLBL_NLTYPE_CIPSOV4
+ *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
- *   +---------------+
- *   | doi (32 bits) |
- *   +---------------+
+ *     NLBL_MGMT_A_CV4DOI
  *
- *     doi:  the CIPSO DOI value
+ *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
  *
  * 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.
+ *   NetLabel system, there is no payload.
  *
  * 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
+ *   application there is no payload.  On success the kernel should send a
+ *   response using the following format.
  *
- *     No mapping data for this protocol type.
+ *   Required attributes:
  *
- *   NETLBL_NLTYPE_CIPSOV4
+ *     NLBL_MGMT_A_PROTOCOL
  *
- *   +----------------+---------------+
- *   | type (32 bits) | doi (32 bits) |
- *   +----------------+---------------+
+ *   If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
  *
- *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
- *           as CIPSO_V4_MAP_*)
- *     doi:  the CIPSO DOI value
+ *     NLBL_MGMT_A_CV4DOI
  *
- * o MODULES:
- *   Sent by an application to request a list of configured NetLabel modules
- *   in the kernel.  When sent by an application there is no payload.
+ *   If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
  *
- *   +-------------------+
- *   | modules (32 bits) | ...
- *   +-------------------+
+ * o PROTOCOLS:
+ *   Sent by an application to request a list of configured NetLabel protocols
+ *   in the kernel.  When sent by an application there is no payload and the
+ *   NLM_F_DUMP flag should be set.  The kernel should respond with a series of
+ *   the following messages.
  *
- *     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
+ *   Required attributes:
  *
- *   +------------------+
- *   | module (32 bits) | ... repeated
- *   +------------------+
- *
- *     module: the module number as defined by NETLBL_NLTYPE_*
+ *     NLBL_MGMT_A_PROTOCOL
  *
  * o VERSION:
- *   Sent by an application to request the NetLabel version string.  When sent
- *   by an application there is no payload.  This message type is also used by
- *   the kernel to respond to an VERSION request.
- *
- *   +-------------------+
- *   | version (32 bits) |
- *   +-------------------+
+ *   Sent by an application to request the NetLabel version.  When sent by an
+ *   application there is no payload.  This message type is also used by the
+ *   kernel to respond to an VERSION request.
+ *
+ *   Required attributes:
  *
- *     version: the protocol version number
+ *     NLBL_MGMT_A_VERSION
  *
  */
 
 /* NetLabel Management commands */
 enum {
 	NLBL_MGMT_C_UNSPEC,
-	NLBL_MGMT_C_ACK,
 	NLBL_MGMT_C_ADD,
 	NLBL_MGMT_C_REMOVE,
-	NLBL_MGMT_C_LIST,
+	NLBL_MGMT_C_LISTALL,
 	NLBL_MGMT_C_ADDDEF,
 	NLBL_MGMT_C_REMOVEDEF,
 	NLBL_MGMT_C_LISTDEF,
-	NLBL_MGMT_C_MODULES,
+	NLBL_MGMT_C_PROTOCOLS,
 	NLBL_MGMT_C_VERSION,
 	__NLBL_MGMT_C_MAX,
 };
 #define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1)
 
+/* NetLabel Management attributes */
+enum {
+	NLBL_MGMT_A_UNSPEC,
+	NLBL_MGMT_A_DOMAIN,
+	/* (NLA_NUL_STRING)
+	 * the NULL terminated LSM domain string */
+	NLBL_MGMT_A_PROTOCOL,
+	/* (NLA_U32)
+	 * the NetLabel protocol type (defined by NETLBL_NLTYPE_*) */
+	NLBL_MGMT_A_VERSION,
+	/* (NLA_U32)
+	 * the NetLabel protocol version number (defined by
+	 * NETLBL_PROTO_VERSION) */
+	NLBL_MGMT_A_CV4DOI,
+	/* (NLA_U32)
+	 * the CIPSOv4 DOI value */
+	__NLBL_MGMT_A_MAX,
+};
+#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
+
 /* NetLabel protocol functions */
 int netlbl_mgmt_genl_init(void);
 
Index: net-2.6.19/net/netlabel/netlabel_unlabeled.c
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_unlabeled.c
+++ net-2.6.19/net/netlabel/netlabel_unlabeled.c
@@ -55,9 +55,13 @@ static struct genl_family netlbl_unlabel
 	.hdrsize = 0,
 	.name = NETLBL_NLTYPE_UNLABELED_NAME,
 	.version = NETLBL_PROTO_VERSION,
-	.maxattr = 0,
+	.maxattr = NLBL_UNLABEL_A_MAX,
 };
 
+/* NetLabel Netlink attribute policy */
+static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
+	[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
+};
 
 /*
  * NetLabel Command Handlers
@@ -75,31 +79,18 @@ static struct genl_family netlbl_unlabel
  */
 static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val;
-	struct nlattr *data = netlbl_netlink_payload_data(skb);
-	u32 value;
-
-	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
-	if (ret_val != 0)
-		return ret_val;
+	int ret_val = -EINVAL;
+	u8 value;
 
-	if (netlbl_netlink_payload_len(skb) == NETLBL_LEN_U32) {
-		value = nla_get_u32(data);
+	if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
+		value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
 		if (value == 1 || value == 0) {
 			atomic_set(&netlabel_unlabel_accept_flg, value);
-			netlbl_netlink_send_ack(info,
-						netlbl_unlabel_gnl_family.id,
-						NLBL_UNLABEL_C_ACK,
-						NETLBL_E_OK);
-			return 0;
+			ret_val = 0;
 		}
 	}
 
-	netlbl_netlink_send_ack(info,
-				netlbl_unlabel_gnl_family.id,
-				NLBL_UNLABEL_C_ACK,
-				EINVAL);
-	return -EINVAL;
+	return ret_val;
 }
 
 /**
@@ -114,39 +105,39 @@ static int netlbl_unlabel_accept(struct 
  */
 static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
 {
-	int ret_val = -ENOMEM;
+	int ret_val = -EINVAL;
 	struct sk_buff *ans_skb;
+	void *data;
 
-	ans_skb = netlbl_netlink_alloc_skb(0,
-					   GENL_HDRLEN + NETLBL_LEN_U32,
-					   GFP_KERNEL);
+	ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (ans_skb == NULL)
 		goto list_failure;
-
-	if (netlbl_netlink_hdr_put(ans_skb,
-				   info->snd_pid,
-				   0,
-				   netlbl_unlabel_gnl_family.id,
-				   NLBL_UNLABEL_C_LIST) == NULL)
+	data = netlbl_netlink_hdr_put(ans_skb,
+				      info->snd_pid,
+				      info->snd_seq,
+				      netlbl_unlabel_gnl_family.id,
+				      0,
+				      NLBL_UNLABEL_C_LIST);
+	if (data == NULL) {
+		ret_val = -ENOMEM;
 		goto list_failure;
+	}
 
-	ret_val = nla_put_u32(ans_skb,
-			      NLA_U32,
-			      atomic_read(&netlabel_unlabel_accept_flg));
+	ret_val = nla_put_u8(ans_skb,
+			     NLBL_UNLABEL_A_ACPTFLG,
+			     atomic_read(&netlabel_unlabel_accept_flg));
 	if (ret_val != 0)
 		goto list_failure;
 
-	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
+	genlmsg_end(ans_skb, data);
+
+	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
 	if (ret_val != 0)
 		goto list_failure;
-
 	return 0;
 
 list_failure:
-	netlbl_netlink_send_ack(info,
-				netlbl_unlabel_gnl_family.id,
-				NLBL_UNLABEL_C_ACK,
-				-ret_val);
+	kfree(ans_skb);
 	return ret_val;
 }
 
@@ -157,7 +148,8 @@ list_failure:
 
 static struct genl_ops netlbl_unlabel_genl_c_accept = {
 	.cmd = NLBL_UNLABEL_C_ACCEPT,
-	.flags = 0,
+	.flags = GENL_ADMIN_PERM,
+	.policy = netlbl_unlabel_genl_policy,
 	.doit = netlbl_unlabel_accept,
 	.dumpit = NULL,
 };
@@ -165,6 +157,7 @@ static struct genl_ops netlbl_unlabel_ge
 static struct genl_ops netlbl_unlabel_genl_c_list = {
 	.cmd = NLBL_UNLABEL_C_LIST,
 	.flags = 0,
+	.policy = netlbl_unlabel_genl_policy,
 	.doit = netlbl_unlabel_list,
 	.dumpit = NULL,
 };
@@ -218,10 +211,8 @@ int netlbl_unlabel_genl_init(void)
  */
 int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
 {
-	if (atomic_read(&netlabel_unlabel_accept_flg) == 1) {
-		memset(secattr, 0, sizeof(*secattr));
-		return 0;
-	}
+	if (atomic_read(&netlabel_unlabel_accept_flg) == 1)
+		return netlbl_secattr_init(secattr);
 
 	return -ENOMSG;
 }
Index: net-2.6.19/net/netlabel/netlabel_unlabeled.h
===================================================================
--- net-2.6.19.orig/net/netlabel/netlabel_unlabeled.h
+++ net-2.6.19/net/netlabel/netlabel_unlabeled.h
@@ -36,56 +36,47 @@
 /*
  * The following NetLabel payloads are supported by the Unlabeled subsystem.
  *
- * 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: return value, based on errno values
- *
  * 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) |
- *   +-----------------+
+ *   Required attributes:
  *
- *     allow: if true (1) then allow the packets to pass, if false (0) then
- *            reject the packets
+ *     NLBL_UNLABEL_A_ACPTFLG
  *
  * 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.
+ *   message with a LIST message on success.
  *
- *   +-----------------------+
- *   | accept flag (32 bits) |
- *   +-----------------------+
+ *   Required attributes:
  *
- *     accept flag: if true (1) then unlabeled packets are allowed to pass,
- *                  if false (0) then unlabeled packets are rejected
+ *     NLBL_UNLABEL_A_ACPTFLG
  *
  */
 
 /* NetLabel Unlabeled commands */
 enum {
 	NLBL_UNLABEL_C_UNSPEC,
-	NLBL_UNLABEL_C_ACK,
 	NLBL_UNLABEL_C_ACCEPT,
 	NLBL_UNLABEL_C_LIST,
 	__NLBL_UNLABEL_C_MAX,
 };
 #define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
 
+/* NetLabel Unlabeled attributes */
+enum {
+	NLBL_UNLABEL_A_UNSPEC,
+	NLBL_UNLABEL_A_ACPTFLG,
+	/* (NLA_U8)
+	 * if true then unlabeled packets are allowed to pass, else unlabeled
+	 * packets are rejected */
+	__NLBL_UNLABEL_A_MAX,
+};
+#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
+
 /* NetLabel protocol functions */
 int netlbl_unlabel_genl_init(void);
 

Now that all of the supporting pieces of NetLabel have a home at SourceForge
update the Kconfig help text and add an entry to the MAINTAINERS file.

Signed-off-by: Paul Moore <paul.moore@hp.com>
---
 MAINTAINERS          |    7 +++++++
 net/netlabel/Kconfig |    5 ++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

Index: net-2.6.19/MAINTAINERS
===================================================================
--- net-2.6.19.orig/MAINTAINERS
+++ net-2.6.19/MAINTAINERS
@@ -2008,6 +2008,13 @@ L:	netfilter@lists.netfilter.org
 L:	netfilter-devel@lists.netfilter.org
 S:	Supported
 
+NETLABEL
+P:	Paul Moore
+M:	paul.moore@hp.com
+W:	http://netlabel.sf.net
+L:	netdev@vger.kernel.org
+S:	Supported
+
 NETROM NETWORK LAYER
 P:	Ralf Baechle
 M:	ralf@linux-mips.org
Index: net-2.6.19/net/netlabel/Kconfig
===================================================================
--- net-2.6.19.orig/net/netlabel/Kconfig
+++ net-2.6.19/net/netlabel/Kconfig
@@ -9,6 +9,9 @@ config NETLABEL
 	---help---
 	  NetLabel provides support for explicit network packet labeling
 	  protocols such as CIPSO and RIPSO.  For more information see
-	  Documentation/netlabel.
+	  Documentation/netlabel as well as the NetLabel SourceForge project
+	  for configuration tools and additional documentation.
+
+	   * http://netlabel.sf.net
 
 	  If you are unsure, say N.