[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[redhat-lspp] Updated NetLabel patch



Attached is an updated NetLabel patch from June 13th (today) against the
lspp.35 sources.  As before it has been quickly tested on x86, x86_64,
targeted/enforcing, and mls/permissive although not all hw/policy
combinations have been tested.  If you wish to configure NetLabel to use
CIPSO please grab the June 13th release of netlabel_tools which can be
found here:

 * http://free.linux.hp.com/~pmoore/projects/linux_cipso

The big changes since the last posting on June 6th are:

 * Demonstrated interop between TSOL v 8 (big thanks to Ted)
 * Relabeling of sockets on accept()
 * The addition of the "pass through" CIPSO mapping
 * Better NetLabel netlink error reporting to userspace
 * Verified CIPSO option is recognized as immutable by AH
   (not yet tested)

The patch stats:

 CREDITS                                                   |    7
 Documentation/00-INDEX                                    |    2
 Documentation/netlabel/00-INDEX                           |   10
 Documentation/netlabel/cipso_ipv4.txt                     |   48
 Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt |  791 ++++
 Documentation/netlabel/introduction.txt                   |   44
 Documentation/netlabel/lsm_interface.txt                  |   47
 include/linux/ip.h                                        |    1
 include/linux/netlink.h                                   |    1
 include/net/cipso_ipv4.h                                  |  159
 include/net/inet_sock.h                                   |    2
 include/net/netlabel.h                                    |  354 ++
 net/Kconfig                                               |    2
 net/Makefile                                              |    1
 net/ipv4/Makefile                                         |    1
 net/ipv4/ah4.c                                            |    2
 net/ipv4/cipso_ipv4.c                                     | 1749 ++++++
 net/ipv4/ip_options.c                                     |   19
 net/netlabel/Kconfig                                      |   47
 net/netlabel/Makefile                                     |   15
 net/netlabel/netlabel_cipso_v4.c                          |  580 +++
 net/netlabel/netlabel_cipso_v4.h                          |  201 +
 net/netlabel/netlabel_domainhash.c                        |  629 +++
 net/netlabel/netlabel_domainhash.h                        |   64
 net/netlabel/netlabel_kapi.c                              |  420 ++
 net/netlabel/netlabel_mgmt.c                              |  677 +++
 net/netlabel/netlabel_mgmt.h                              |  248 +
 net/netlabel/netlabel_unlabeled.c                         |  285 +
 net/netlabel/netlabel_unlabeled.h                         |   83
 net/netlabel/netlabel_user.c                              |  174
 net/netlabel/netlabel_user.h                              |   42
 security/selinux/hooks.c                                  |   81
 security/selinux/include/av_inherit.h                     |    1
 security/selinux/include/av_perm_to_string.h              |    2
 security/selinux/include/av_permissions.h                 |    1
 security/selinux/include/flask.h                          |    1
 security/selinux/include/security.h                       |    9
 security/selinux/nlmsgtab.c                               |  159
 security/selinux/ss/ebitmap.c                             |  155
 security/selinux/ss/ebitmap.h                             |    6
 security/selinux/ss/mls.c                                 |  160
 security/selinux/ss/mls.h                                 |   25
 security/selinux/ss/services.c                            |  415 ++
 security/selinux/xfrm.c                                   |   22
 44 files changed, 7652 insertions(+), 90 deletions(-)

I'll be posting a more "reviewer friendly" patchset in a week or so once
this has been out for a few days and I have had a chance to work on the
patch a bit more (discussed on Monday's concall).

-- 
paul moore
linux security @ hp
diff -purN linux-2.6.16.i686/CREDITS linux-2.6.16.i686-netlabel_06132006/CREDITS
--- linux-2.6.16.i686/CREDITS	2006-06-13 10:47:07.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/CREDITS	2006-06-13 11:19:58.000000000 -0400
@@ -2383,6 +2383,13 @@ N: Thomas Molina
 E: tmolina cablespeed com
 D: bug fixes, documentation, minor hackery
 
+N: Paul Moore
+E: paul moore hp com
+D: NetLabel author
+S: Hewlett-Packard
+S: 110 Spit Brook Road
+S: Nashua, NH 03062
+
 N: James Morris
 E: jmorris namei org
 W: http://namei.org/
diff -purN linux-2.6.16.i686/Documentation/00-INDEX linux-2.6.16.i686-netlabel_06132006/Documentation/00-INDEX
--- linux-2.6.16.i686/Documentation/00-INDEX	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/00-INDEX	2006-06-13 11:19:58.000000000 -0400
@@ -184,6 +184,8 @@ mtrr.txt
 	- how to use PPro Memory Type Range Registers to increase performance.
 nbd.txt
 	- info on a TCP implementation of a network block device.
+netlabel/
+	- directory with information on the NetLabel subsystem.
 networking/
 	- directory with info on various aspects of networking with Linux.
 nfsroot.txt
diff -purN linux-2.6.16.i686/Documentation/netlabel/00-INDEX linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/00-INDEX
--- linux-2.6.16.i686/Documentation/netlabel/00-INDEX	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/00-INDEX	2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,10 @@
+00-INDEX
+	- this file.
+cipso_ipv4.txt
+	- documentation on the IPv4 CIPSO protocol engine.
+draft-ietf-cipso-ipsecurity-01.txt
+	- IETF draft of the CIPSO protocol, dated 16 July 1992.
+introduction.txt
+	- NetLabel introduction, READ THIS FIRST.
+lsm_interface.txt
+	- documentation on the NetLabel kernel security module API.
diff -purN linux-2.6.16.i686/Documentation/netlabel/cipso_ipv4.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/cipso_ipv4.txt
--- linux-2.6.16.i686/Documentation/netlabel/cipso_ipv4.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/cipso_ipv4.txt	2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,48 @@
+NetLabel CIPSO/IPv4 Protocol Engine
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial IP
+Security Option (CIPSO) draft from July 16, 1992.  A copy of this draft can be
+found in this directory, consult '00-INDEX' for the filename.  While the IETF
+draft never made it to an RFC standard it has become a de-facto standard for
+labeled networking and is used in many trusted operating systems.
+
+ * Outbound Packet Processing
+
+The CIPSO/IPv4 protocol engine applies the CIPSO IP option to packets by
+adding the CIPSO label to the socket.  This causes all packets leaving the
+system through the socket to have the CIPSO IP option applied.  The socket's
+CIPSO label can be changed at any point in time, however, it is recommended
+that it is set upon the socket's creation.  The LSM can set the socket's CIPSO
+label by using the NetLabel security module API; if the NetLabel "domain" is
+configured to use CIPSO for packet labeling then a CIPSO IP option will be
+generated and attached to the socket.
+
+ * Inbound Packet Processing
+
+The CIPSO/IPv4 protocol engine validates every CIPSO IP option it finds at the
+IP layer without any special handling required by the LSM.  However, in order
+to decode and translate the CIPSO label on the packet the LSM must use the
+NetLabel security module API to extract the security attributes of the packet.
+This is typically done at the socket layer using the 'socket_sock_rcv_skb()'
+LSM hook.
+
+ * Label Translation
+
+The CIPSO/IPv4 protocol engine contains a mechanism to translate CIPSO security
+attributes such as sensitivity level and category to values which are
+appropriate for the host.  These mappings are defined as part of a CIPSO
+Domain Of Interpretation (DOI) definition and are configured through the
+NetLabel user space communication layer.  Each DOI definition can have a
+different security attribute mapping table.
+
+ * Label Translation Cache
+
+The NetLabel system provides a framework for caching security attribute
+mappings from the network labels to the corresponding LSM identifiers.  The 
+CIPSO/IPv4 protocol engine supports this caching mechanism.
diff -purN linux-2.6.16.i686/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt
--- linux-2.6.16.i686/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt	2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,791 @@
+IETF CIPSO Working Group
+16 July, 1992                                                                
+
+
+
+                 COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)                    
+
+
+
+1.    Status                                                                 
+
+This Internet Draft provides the high level specification for a Commercial   
+IP Security Option (CIPSO).  This draft reflects the version as approved by  
+the CIPSO IETF Working Group.  Distribution of this memo is unlimited.       
+
+This document is an Internet Draft.  Internet Drafts are working documents   
+of the Internet Engineering Task Force (IETF), its Areas, and its Working    
+Groups. Note that other groups may also distribute working documents as      
+Internet Drafts.                                                             
+
+Internet Drafts are draft documents valid for a maximum of six months.       
+Internet Drafts may be updated, replaced, or obsoleted by other documents    
+at any time.  It is not appropriate to use Internet Drafts as reference      
+material or to cite them other than as a "working draft" or "work in         
+progress."                                                                   
+
+Please check the I-D abstract listing contained in each Internet Draft       
+directory to learn the current status of this or any other Internet Draft.   
+
+
+
+
+2.    Background                                                             
+
+Currently the Internet Protocol includes two security options.  One of 
+these options is the DoD Basic Security Option (BSO) (Type 130) which allows 
+IP datagrams to be labeled with security classifications.  This option 
+provides sixteen security classifications and a variable number of handling 
+restrictions.  To handle additional security information, such as security 
+categories or compartments, another security option (Type 133) exists and 
+is referred to as the DoD Extended Security Option (ESO).  The values for 
+the fixed fields within these two options are administered by the Defense 
+Information Systems Agency (DISA).
+
+Computer vendors are now building commercial operating systems with 
+mandatory access controls and multi-level security.  These systems are
+no longer built specifically for a particular group in the defense or
+intelligence communities.  They are generally available commercial systems
+for use in a variety of government and civil sector environments. 
+
+The small number of ESO format codes can not support all the possible 
+applications of a commercial security option.  The BSO and ESO were 
+designed to only support the United States DoD.  CIPSO has been designed 
+to support multiple security policies.  This Internet Draft provides the 
+format and procedures required to support a Mandatory Access Control       
+security policy.  Support for additional security policies shall be          
+defined in future RFCs.
+
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 1]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+
+3.    CIPSO Format                                                           
+
+Option type: 134 (Class 0, Number 6, Copy on Fragmentation)
+Option length: Variable
+
+This option permits security related information to be passed between
+systems within a single Domain of Interpretation (DOI).  A DOI is a
+collection of systems which agree on the meaning of particular values
+in the security option.  An authority that has been assigned a DOI           
+identifier will define a mapping between appropriate CIPSO field values      
+and their human readable equivalent.  This authority will distribute that    
+mapping to hosts within the authority's domain.  These mappings may be       
+sensitive, therefore a DOI authority is not required to make these 
+mappings available to anyone other than the systems that are included in 
+the DOI.  
+
+This option MUST be copied on fragmentation.  This option appears at most 
+once in a datagram.  All multi-octet fields in the option are defined to be 
+transmitted in network byte order.  The format of this option is as follows:
+
++----------+----------+------//------+-----------//---------+
+| 10000110 | LLLLLLLL | DDDDDDDDDDDD | TTTTTTTTTTTTTTTTTTTT |
++----------+----------+------//------+-----------//---------+
+
+  TYPE=134    OPTION    DOMAIN OF               TAGS
+              LENGTH    INTERPRETATION
+
+
+                Figure 1. CIPSO Format
+
+
+3.1    Type
+
+This field is 1 octet in length.  Its value is 134.
+
+
+3.2    Length
+
+This field is 1 octet in length.  It is the total length of the option
+including the type and length fields.  With the current IP header length
+restriction of 40 octets the value of this field MUST not exceed 40.         
+
+
+3.3    Domain of Interpretation Identifier
+
+This field is an unsigned 32 bit integer.  The value 0 is reserved and MUST  
+not appear as the DOI identifier in any CIPSO option.  Implementations        
+should assume that the DOI identifier field is not aligned on any particular 
+byte boundary.
+
+To conserve space in the protocol, security levels and categories are 
+represented by numbers rather than their ASCII equivalent.  This requires
+a mapping table within CIPSO hosts to map these numbers to their 
+corresponding ASCII representations.  Non-related groups of systems may      
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 2]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+have their own unique mappings.  For example, one group of systems may 
+use the number 5 to represent Unclassified while another group may use the 
+number 1 to represent that same security level.  The DOI identifier is used 
+to identify which mapping was used for the values within the option.
+
+
+3.4    Tag Types
+
+A common format for passing security related information is necessary
+for interoperability.  CIPSO uses sets of "tags" to contain the security     
+information relevant to the data in the IP packet.  Each tag begins with     
+a tag type identifier followed by the length of the tag and ends with the 
+actual security information to be passed.  All multi-octet fields in a tag 
+are defined to be transmitted in network byte order.  Like the DOI 
+identifier field in the CIPSO header, implementations should assume that 
+all tags, as well as fields within a tag, are not aligned on any particular 
+octet boundary.   The tag types defined in this document contain alignment   
+bytes to assist alignment of some information, however alignment can not    
+be guaranteed if CIPSO is not the first IP option.                           
+
+CIPSO tag types 0 through 127 are reserved for defining standard tag
+formats.  Their definitions will be published in RFCs.  Tag types whose      
+identifiers are greater than 127 are defined by the DOI authority and may 
+only be meaningful in certain Domains of Interpretation.  For these tag 
+types, implementations will require the DOI identifier as well as the tag 
+number to determine the security policy and the format associated with the 
+tag.  Use of tag types above 127 are restricted to closed networks where 
+interoperability with other networks will not be an issue.  Implementations  
+that support a tag type greater than 127 MUST support at least one DOI that  
+requires only tag types 1 to 127.                                            
+
+Tag type 0 is reserved. Tag types 1, 2, and 5 are defined in this 
+Internet Draft.  Types 3 and 4 are reserved for work in progress.
+The standard format for all current and future CIPSO tags is shown below:
+
++----------+----------+--------//--------+
+| TTTTTTTT | LLLLLLLL | IIIIIIIIIIIIIIII |
++----------+----------+--------//--------+
+    TAG       TAG         TAG
+    TYPE      LENGTH      INFORMATION
+
+    Figure 2:  Standard Tag Format
+
+In the three tag types described in this document, the length and count
+restrictions are based on the current IP limitation of 40 octets for all
+IP options.  If the IP header is later expanded, then the length and count   
+restrictions specified in this document may increase to use the full area 
+provided for IP options.
+
+
+3.4.1    Tag Type Classes
+
+Tag classes consist of tag types that have common processing requirements 
+and support the same security policy.  The three tags defined in this 
+Internet Draft belong to the Mandatory Access Control (MAC) Sensitivity 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 3]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+class and support the MAC Sensitivity security policy.
+
+
+3.4.2    Tag Type 1
+
+This is referred to as the "bit-mapped" tag type.  Tag type 1 is included
+in the MAC Sensitivity tag type class.  The format of this tag type is as 
+follows:
+
++----------+----------+----------+----------+--------//---------+
+| 00000001 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCC |
++----------+----------+----------+----------+--------//---------+
+
+    TAG       TAG      ALIGNMENT  SENSITIVITY    BIT MAP OF
+    TYPE      LENGTH   OCTET      LEVEL          CATEGORIES
+
+            Figure 3. Tag Type 1 Format
+
+
+3.4.2.1    Tag Type
+
+This field is 1 octet in length and has a value of 1.
+
+
+3.4.2.2    Tag Length
+
+This field is 1 octet in length.  It is the total length of the tag type
+including the type and length fields.  With the current IP header length
+restriction of 40 bytes the value within this field is between 4 and 34.     
+
+
+3.4.2.3    Alignment Octet
+
+This field is 1 octet in length and always has the value of 0.  Its purpose
+is to align the category bitmap field on an even octet boundary.  This will
+speed many implementations including router implementations.
+
+
+3.4.2.4    Sensitivity Level
+
+This field is 1 octet in length.  Its value is from 0 to 255.  The values    
+are ordered with 0 being the minimum value and 255 representing the maximum 
+value.
+
+
+3.4.2.5    Bit Map of Categories
+
+The length of this field is variable and ranges from 0 to 30 octets.  This
+provides representation of categories 0 to 239.  The ordering of the bits
+is left to right or MSB to LSB.  For example category 0 is represented by 
+the most significant bit of the first byte and category 15 is represented 
+by the least significant bit of the second byte.  Figure 4 graphically 
+shows this ordering.  Bit N is binary 1 if category N is part of the label 
+for the datagram, and bit N is binary 0 if category N is not part of the 
+label.  Except for the optimized tag 1 format described in the next section, 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 4]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+minimal encoding SHOULD be used resulting in no trailing zero octets in the 
+category bitmap.
+
+        octet 0  octet 1  octet 2  octet 3  octet 4  octet 5 
+        XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX . . . 
+bit     01234567 89111111 11112222 22222233 33333333 44444444
+number             012345 67890123 45678901 23456789 01234567
+
+            Figure 4. Ordering of Bits in Tag 1 Bit Map
+
+
+3.4.2.6    Optimized Tag 1 Format
+
+Routers work most efficiently when processing fixed length fields.  To
+support these routers there is an optimized form of tag type 1.  The format  
+does not change.  The only change is to the category bitmap which is set to 
+a constant length of 10 octets.  Trailing octets required to fill out the 10 
+octets are zero filled.  Ten octets, allowing for 80 categories, was chosen 
+because it makes the total length of the CIPSO option 20 octets.  If CIPSO 
+is the only option then the option will be full word aligned and additional  
+filler octets will not be required.                                          
+ 
+
+3.4.3    Tag Type 2
+
+This is referred to as the "enumerated" tag type.  It is used to describe 
+large but sparsely populated sets of categories.  Tag type 2 is in the MAC
+Sensitivity tag type class.  The format of this tag type is as follows:
+
++----------+----------+----------+----------+-------------//-------------+
+| 00000010 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCCCCCCCCCCC |
++----------+----------+----------+----------+-------------//-------------+
+
+    TAG       TAG      ALIGNMENT  SENSITIVITY         ENUMERATED
+    TYPE      LENGTH   OCTET      LEVEL               CATEGORIES
+
+                Figure 5. Tag Type 2 Format
+
+
+3.4.3.1     Tag Type
+
+This field is one octet in length and has a value of 2.
+
+
+3.4.3.2    Tag Length
+
+This field is 1 octet in length. It is the total length of the tag type
+including the type and length fields.  With the current IP header length        
+restriction of 40 bytes the value within this field is between 4 and 34.     
+
+
+3.4.3.3    Alignment Octet
+
+This field is 1 octet in length and always has the value of 0.  Its purpose
+is to align the category field on an even octet boundary.  This will
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 5]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+speed many implementations including router implementations.
+
+
+3.4.3.4    Sensitivity Level
+
+This field is 1 octet in length. Its value is from 0 to 255.  The values 
+are ordered with 0 being the minimum value and 255 representing the          
+maximum value.
+
+
+3.4.3.5    Enumerated Categories
+
+In this tag, categories are represented by their actual value rather than
+by their position within a bit field.  The length of each category is 2 
+octets.  Up to 15 categories may be represented by this tag.  Valid values 
+for categories are 0 to 65534.  Category 65535 is not a valid category       
+value.  The categories MUST be listed in ascending order within the tag.     
+
+
+3.4.4    Tag Type 5
+
+This is referred to as the "range" tag type.  It is used to represent
+labels where all categories in a range, or set of ranges, are included
+in the sensitivity label.  Tag type 5 is in the MAC Sensitivity tag type 
+class.  The format of this tag type is as follows:
+
++----------+----------+----------+----------+------------//-------------+
+| 00000101 | LLLLLLLL | 00000000 | LLLLLLLL |  Top/Bottom | Top/Bottom  |
++----------+----------+----------+----------+------------//-------------+
+
+    TAG       TAG      ALIGNMENT  SENSITIVITY        CATEGORY RANGES
+    TYPE      LENGTH   OCTET      LEVEL                 
+
+                     Figure 6. Tag Type 5 Format
+
+
+3.4.4.1     Tag Type
+
+This field is one octet in length and has a value of 5.
+
+
+3.4.4.2    Tag Length
+
+This field is 1 octet in length. It is the total length of the tag type
+including the type and length fields.  With the current IP header length
+restriction of 40 bytes the value within this field is between 4 and 34.     
+
+
+3.4.4.3    Alignment Octet
+
+This field is 1 octet in length and always has the value of 0.  Its purpose
+is to align the category range field on an even octet boundary.  This will
+speed many implementations including router implementations.
+
+
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 6]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+3.4.4.4    Sensitivity Level
+
+This field is 1 octet in length. Its value is from 0 to 255.  The values     
+are ordered with 0 being the minimum value and 255 representing the maximum 
+value.
+
+
+3.4.4.5    Category Ranges
+
+A category range is a 4 octet field comprised of the 2 octet index of the    
+highest numbered category followed by the 2 octet index of the lowest        
+numbered category.  These range endpoints are inclusive within the range of  
+categories.  All categories within a range are included in the sensitivity 
+label.  This tag may contain a maximum of 7 category pairs.  The bottom 
+category endpoint for the last pair in the tag MAY be omitted and SHOULD be  
+assumed to be 0.  The ranges MUST be non-overlapping and be listed in        
+descending order.  Valid values for categories are 0 to 65534.  Category     
+65535 is not a valid category value.    
+
+
+3.4.5     Minimum Requirements 
+
+A CIPSO implementation MUST be capable of generating at least tag type 1 in
+the non-optimized form.  In addition, a CIPSO implementation MUST be able
+to receive any valid tag type 1 even those using the optimized tag type 1
+format.
+
+
+4.    Configuration Parameters                                               
+
+The configuration parameters defined below are required for all CIPSO hosts,
+gateways, and routers that support multiple sensitivity labels.  A CIPSO 
+host is defined to be the origination or destination system for an IP 
+datagram.  A CIPSO gateway provides IP routing services between two or more 
+IP networks and may be required to perform label translations between
+networks.  A CIPSO gateway may be an enhanced CIPSO host or it may just
+provide gateway services with no end system CIPSO capabilities.  A CIPSO 
+router is a dedicated IP router that routes IP datagrams between two or more 
+IP networks.  
+
+An implementation of CIPSO on a host MUST have the capability to reject a    
+datagram for reasons that the information contained can not be adequately 
+protected by the receiving host or if acceptance may result in violation of 
+the host or network security policy.  In addition, a CIPSO gateway or router
+MUST be able to reject datagrams going to networks that can not provide      
+adequate protection or may violate the network's security policy.  To 
+provide this capability the following minimal set of configuration 
+parameters are required for CIPSO implementations:
+
+HOST_LABEL_MAX - This parameter contains the maximum sensitivity label that
+a CIPSO host is authorized to handle.  All datagrams that have a label 
+greater than this maximum MUST be rejected by the CIPSO host.  This          
+parameter does not apply to CIPSO gateways or routers.  This parameter need 
+not be defined explicitly as it can be implicitly derived from the 
+PORT_LABEL_MAX parameters for the associated interfaces.
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 7]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+
+HOST_LABEL_MIN - This parameter contains the minimum sensitivity label that
+a CIPSO host is authorized to handle.  All datagrams that have a label less
+than this minimum MUST be rejected by the CIPSO host.  This parameter does   
+not apply to CIPSO gateways or routers.  This parameter need not be defined
+explicitly as it can be implicitly derived from the PORT_LABEL_MIN 
+parameters for the associated interfaces.
+
+PORT_LABEL_MAX - This parameter contains the maximum sensitivity label for
+all datagrams that may exit a particular network interface port.  All 
+outgoing datagrams that have a label greater than this maximum MUST be       
+rejected by the CIPSO system.  The label within this parameter MUST be       
+less than or equal to the label within the HOST_LABEL_MAX parameter.  This 
+parameter does not apply to CIPSO hosts that support only one network port.
+
+PORT_LABEL_MIN - This parameter contains the minimum sensitivity label for
+all datagrams that may exit a particular network interface port.  All 
+outgoing datagrams that have a label less than this minimum MUST be          
+rejected by the CIPSO system.  The label within this parameter MUST be       
+greater than or equal to the label within the HOST_LABEL_MIN parameter.  
+This parameter does not apply to CIPSO hosts that support only one network 
+port.
+
+PORT_DOI - This parameter is used to assign a DOI identifier value to a 
+particular network interface port.  All CIPSO labels within datagrams 
+going out this port MUST use the specified DOI identifier.  All CIPSO        
+hosts and gateways MUST support either this parameter, the NET_DOI           
+parameter, or the HOST_DOI parameter.  
+
+NET_DOI - This parameter is used to assign a DOI identifier value to a 
+particular IP network address.  All CIPSO labels within datagrams destined 
+for the particular IP network MUST use the specified DOI identifier.  All    
+CIPSO hosts and gateways MUST support either this parameter, the PORT_DOI    
+parameter, or the HOST_DOI parameter.  
+
+HOST_DOI - This parameter is used to assign a DOI identifier value to a 
+particular IP host address.  All CIPSO labels within datagrams destined for 
+the particular IP host will use the specified DOI identifier.  All CIPSO     
+hosts and gateways MUST support either this parameter, the PORT_DOI          
+parameter, or the NET_DOI parameter.  
+
+This list represents the minimal set of configuration parameters required 
+to be compliant.  Implementors are encouraged to add to this list to 
+provide enhanced functionality and control.  For example, many security 
+policies may require both incoming and outgoing datagrams be checked against
+the port and host label ranges.
+
+
+4.1    Port Range Parameters
+
+The labels represented by the PORT_LABEL_MAX and PORT_LABEL_MIN parameters
+MAY be in CIPSO or local format.  Some CIPSO systems, such as routers, may   
+want to have the range parameters expressed in CIPSO format so that incoming
+labels do not have to be converted to a local format before being compared
+against the range.  If multiple DOIs are supported by one of these CIPSO 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 8]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+systems then multiple port range parameters would be needed, one set for 
+each DOI supported on a particular port.  
+
+The port range will usually represent the total set of labels that may 
+exist on the logical network accessed through the corresponding network 
+interface.  It may, however, represent a subset of these labels that are 
+allowed to enter the CIPSO system.  
+
+
+4.2    Single Label CIPSO Hosts
+
+CIPSO implementations that support only one label are not required to 
+support the parameters described above.  These limited implementations are
+only required to support a NET_LABEL parameter.  This parameter contains
+the CIPSO label that may be inserted in datagrams that exit the host.  In
+addition, the host MUST reject any incoming datagram that has a label which  
+is not equivalent to the NET_LABEL parameter.  
+
+
+5.    Handling Procedures                                                    
+
+This section describes the processing requirements for incoming and 
+outgoing IP datagrams.  Just providing the correct CIPSO label format
+is not enough.  Assumptions will be made by one system on how a 
+receiving system will handle the CIPSO label.  Wrong assumptions may 
+lead to non-interoperability or even a security incident.  The 
+requirements described below represent the minimal set needed for 
+interoperability and that provide users some level of confidence.
+Many other requirements could be added to increase user confidence,
+however at the risk of restricting creativity and limiting vendor
+participation.
+
+
+5.1    Input Procedures
+
+All datagrams received through a network port MUST have a security label    
+associated with them, either contained in the datagram or assigned to the    
+receiving port.  Without this label the host, gateway, or router will not    
+have the information it needs to make security decisions.  This security 
+label will be obtained from the CIPSO if the option is present in the 
+datagram.  See section 4.1.2 for handling procedures for unlabeled 
+datagrams.  This label will be compared against the PORT (if appropriate) 
+and HOST configuration parameters defined in section 3.  
+
+If any field within the CIPSO option, such as the DOI identifier, is not 
+recognized the IP datagram is discarded and an ICMP "parameter problem" 
+(type 12) is generated and returned.  The ICMP code field is set to "bad 
+parameter" (code 0) and the pointer is set to the start of the CIPSO field 
+that is unrecognized.
+
+If the contents of the CIPSO are valid but the security label is
+outside of the configured host or port label range, the datagram is 
+discarded and an ICMP "destination unreachable" (type 3) is generated 
+and returned.  The code field of the ICMP is set to "communication with 
+destination network administratively prohibited" (code 9) or to 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 9]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+"communication with destination host administratively prohibited" 
+(code 10).  The value of the code field used is dependent upon whether
+the originator of the ICMP message is acting as a CIPSO host or a CIPSO
+gateway.  The recipient of the ICMP message MUST be able to handle either    
+value.  The same procedure is performed if a CIPSO can not be added to an    
+IP packet because it is too large to fit in the IP options area.             
+
+If the error is triggered by receipt of an ICMP message, the message 
+is discarded and no response is permitted (consistent with general ICMP 
+processing rules).
+
+
+5.1.1    Unrecognized tag types
+    
+The default condition for any CIPSO implementation is that an 
+unrecognized tag type MUST be treated as a "parameter problem" and          
+handled as described in section 4.1.  A CIPSO implementation MAY allow     
+the system administrator to identify tag types that may safely be 
+ignored.  This capability is an allowable enhancement, not a 
+requirement.
+
+
+5.1.2    Unlabeled Packets
+
+A network port may be configured to not require a CIPSO label for all
+incoming  datagrams.  For this configuration a CIPSO label must be 
+assigned to that network port and associated with all unlabeled IP 
+datagrams.  This capability might be used for single level networks or
+networks that have CIPSO and non-CIPSO hosts and the non-CIPSO hosts 
+all operate at the same label.
+
+If a CIPSO option is required and none is found, the datagram is 
+discarded and an ICMP "parameter problem" (type 12) is generated and 
+returned to the originator of the datagram.  The code field of the ICMP 
+is set to "option missing" (code 1) and the ICMP pointer is set to 134 
+(the value of the option type for the missing CIPSO option).
+
+
+5.2    Output Procedures
+
+A CIPSO option MUST appear only once in a datagram.  Only one tag type       
+from the MAC Sensitivity class MAY be included in a CIPSO option.  Given     
+the current set of defined tag types, this means that CIPSO labels at 
+first will contain only one tag.                                             
+
+All datagrams leaving a CIPSO system MUST meet the following condition:
+
+        PORT_LABEL_MIN <= CIPSO label <= PORT_LABEL_MAX   
+
+If this condition is not satisfied the datagram MUST be discarded.
+If the CIPSO system only supports one port, the HOST_LABEL_MIN and the
+HOST_LABEL_MAX parameters MAY be substituted for the PORT parameters in      
+the above condition.
+
+The DOI identifier to be used for all outgoing datagrams is configured by 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 10]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+the administrator.  If port level DOI identifier assignment is used, then 
+the PORT_DOI configuration parameter MUST contain the DOI identifier to 
+use.  If network level DOI assignment is used, then the NET_DOI parameter 
+MUST contain the DOI identifier to use.  And if host level DOI assignment    
+is employed, then the HOST_DOI parameter MUST contain the DOI identifier     
+to use.  A CIPSO implementation need only support one level of DOI 
+assignment.
+
+
+5.3    DOI Processing Requirements
+
+A CIPSO implementation MUST support at least one DOI and SHOULD support
+multiple DOIs.  System and network administrators are cautioned to
+ensure that at least one DOI is common within an IP network to allow for
+broadcasting of IP datagrams.  
+
+CIPSO gateways MUST be capable of translating a CIPSO option from one 
+DOI to another when forwarding datagrams between networks.  For 
+efficiency purposes this capability is only a desired feature for CIPSO 
+routers.
+
+
+5.4    Label of ICMP Messages
+
+The CIPSO label to be used on all outgoing ICMP messages MUST be equivalent  
+to the label of the datagram that caused the ICMP message.  If the ICMP was 
+generated due to a problem associated with the original CIPSO label then the 
+following responses are allowed:
+
+  a.  Use the CIPSO label of the original IP datagram
+  b.  Drop the original datagram with no return message generated
+
+In most cases these options will have the same effect.  If you can not 
+interpret the label or if it is outside the label range of your host or 
+interface then an ICMP message with the same label will probably not be 
+able to exit the system. 
+
+
+6.    Assignment of DOI Identifier Numbers                                   =
+
+Requests for assignment of a DOI identifier number should be addressed to 
+the Internet Assigned Numbers Authority (IANA).  
+
+
+7.    Acknowledgements                                                       
+
+Much of the material in this RFC is based on (and copied from) work
+done by Gary Winiger of Sun Microsystems and published as Commercial
+IP Security Option at the INTEROP 89, Commercial IPSO Workshop.
+
+
+8.    Author's Address                                                       
+
+To submit mail for distribution to members of the IETF CIPSO Working
+Group, send mail to: cipso wdl1 wdl loral com 
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 11]
+
+
+
+CIPSO INTERNET DRAFT                                         16 July, 1992
+
+
+
+
+To be added to or deleted from this distribution, send mail to:
+cipso-request wdl1 wdl loral com 
+
+
+9.    References                                                             
+
+RFC 1038, "Draft Revised IP Security Option", M. St. Johns, IETF, January
+1988.
+
+RFC 1108, "U.S. Department of Defense Security Options 
+for the Internet Protocol", Stephen Kent, IAB, 1 March, 1991.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Internet Draft, Expires 15 Jan 93                                 [PAGE 12]
+
+
+
diff -purN linux-2.6.16.i686/Documentation/netlabel/introduction.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/introduction.txt
--- linux-2.6.16.i686/Documentation/netlabel/introduction.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/introduction.txt	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,44 @@
+NetLabel Introduction
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+NetLabel is a mechanism which can be used by kernel security modules to attach
+security attributes to outgoing network packets and read security attributes
+from incoming network packets.  It is composed of three main components, the
+protocol engines, the communication layer, and the kernel security module API.
+
+ * Protocol Engines
+
+The protocol engines are responsible for both applying and retrieving the
+network packet's security attributes.  If any translation between the network
+security attributes and those on the host are required then the protocol
+engine will handle those tasks as well.  Other kernel subsystems should
+refrain from calling the protocol engines directly, instead they should use
+the NetLabel kernel security module API described below.
+
+Detailed information about each NetLabel protocol engine can be found in this
+directory, consult '00-INDEX' for filenames.
+
+ * Communication Layer
+
+The communication layer exists to allow NetLabel configuration and monitoring
+from user space.  The NetLabel communication layer uses a message based
+protocol built on top of the NETLINK transport mechanism.  The exact formatting
+of these NetLabel messages can be found in the the 'net/netlabel/' directory as
+comments in the header files.
+
+ * Security Module API
+
+The purpose of the NetLabel security module API is to provide a protocol
+independent interface to the underlying NetLabel protocol engines.  In addition
+to protocol independence, the security module API is designed to be completely
+LSM independent which should allow multiple LSMs to leverage the same code
+base.
+
+Detailed information about the NetLabel security module API can be found in the
+'include/net/netlabel.h' header file as well as the 'lsm_interface.txt' file
+found in this directory.
diff -purN linux-2.6.16.i686/Documentation/netlabel/lsm_interface.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/lsm_interface.txt
--- linux-2.6.16.i686/Documentation/netlabel/lsm_interface.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/lsm_interface.txt	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,47 @@
+NetLabel Linux Security Module Interface
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+NetLabel is a mechanism which can set and retrieve security attributes from
+network packets.  It is intended to be used by LSM developers who want to make
+use of a common code base for several different packet labeling protocols.
+The NetLabel security module API is defined in 'include/net/netlabel.h' but a
+brief overview is given below.
+
+ * NetLabel Security Attributes
+
+Since NetLabel supports multiple different packet labeling protocols and LSMs
+it uses the concept of security attributes to refer to the packet's security
+labels.  The NetLabel security attributes are defined by the 
+'netlbl_lsm_secattr' structure in the NetLabel header file.  Internally the
+NetLabel subsystem converts the security attributes to and from the correct
+low-level packet label depending on the NetLabel build time and run time
+configuration.  It is up to the LSM developer to translate the NetLabel
+security attributes into whatever security identifiers are in use for their
+particular LSM.
+
+ * NetLabel LSM Protocol Operations
+
+These are the functions which allow the LSM developer to manipulate the labels
+on outgoing packets as well as read the labels on incoming packets.  Functions
+exist to operate both on sockets as well as the sk_buffs directly.  These high
+level functions are translated into low level protocol operations based on how
+the administrator has configured the NetLabel subsystem.
+
+ * NetLabel Label Mapping Cache Operations
+
+Depending on the exact configuration, translation between the network packet
+label and the internal LSM security identifier can be time consuming.  The
+NetLabel label mapping cache is a caching mechanism which can be used to
+sidestep much of this overhead once a mapping has been established.  Once the
+LSM has received a packet, used NetLabel to decode it's security attributes,
+and translated the security attributes into a LSM internal identifier the LSM
+can use the NetLabel caching functions to associate the LSM internal
+identifier with the network packet's label.  This means that in the future
+when a incoming packet matches a cached value not only are the internal
+NetLabel translation mechanisms bypassed but the LSM translation mechanisms are
+bypassed as well which should result in a significant reduction in overhead.
diff -purN linux-2.6.16.i686/include/linux/ip.h linux-2.6.16.i686-netlabel_06132006/include/linux/ip.h
--- linux-2.6.16.i686/include/linux/ip.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/linux/ip.h	2006-06-13 11:19:59.000000000 -0400
@@ -57,6 +57,7 @@
 #define IPOPT_SEC	(2 |IPOPT_CONTROL|IPOPT_COPY)
 #define IPOPT_LSRR	(3 |IPOPT_CONTROL|IPOPT_COPY)
 #define IPOPT_TIMESTAMP	(4 |IPOPT_MEASUREMENT)
+#define IPOPT_CIPSO	(6 |IPOPT_CONTROL|IPOPT_COPY)
 #define IPOPT_RR	(7 |IPOPT_CONTROL)
 #define IPOPT_SID	(8 |IPOPT_CONTROL|IPOPT_COPY)
 #define IPOPT_SSRR	(9 |IPOPT_CONTROL|IPOPT_COPY)
diff -purN linux-2.6.16.i686/include/linux/netlink.h linux-2.6.16.i686-netlabel_06132006/include/linux/netlink.h
--- linux-2.6.16.i686/include/linux/netlink.h	2006-06-13 10:46:57.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/include/linux/netlink.h	2006-06-13 11:19:59.000000000 -0400
@@ -21,6 +21,7 @@
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
 #define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
 #define NETLINK_GENERIC		16
+#define NETLINK_NETLABEL	17	/* Network packet labeling */
 
 #define MAX_LINKS 32		
 
diff -purN linux-2.6.16.i686/include/net/cipso_ipv4.h linux-2.6.16.i686-netlabel_06132006/include/net/cipso_ipv4.h
--- linux-2.6.16.i686/include/net/cipso_ipv4.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/cipso_ipv4.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,159 @@
+/*
+ * CIPSO - Commercial IP Security Option
+ *
+ * This is an implementation of the CIPSO 2.2 protocol as specified in
+ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
+ * FIPS-188, copies of both documents can be found in the Documentation
+ * directory.  While CIPSO never became a full IETF RFC standard many vendors
+ * have chosen to adopt the protocol and over the years it has become a
+ * de-facto standard for labeled networking.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _CIPSO_IPV4_H
+#define _CIPSO_IPV4_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <net/netlabel.h>
+
+/* known doi values */
+#define CIPSO_V4_DOI_UNKNOWN          0x00000000
+
+/* tag types */
+#define CIPSO_V4_TAG_INVALID          0
+#define CIPSO_V4_TAG_RBITMAP          1
+#define CIPSO_V4_TAG_ENUM             2
+#define CIPSO_V4_TAG_RANGE            5
+#define CIPSO_V4_TAG_PBITMAP          6
+#define CIPSO_V4_TAG_FREEFORM         7
+
+/* doi mapping types */
+#define CIPSO_V4_MAP_UNKNOWN          0
+#define CIPSO_V4_MAP_STD              1
+#define CIPSO_V4_MAP_PASS             2
+
+/* limits */
+#define CIPSO_V4_MAX_REM_LVLS         256
+#define CIPSO_V4_INV_LVL              0x80000000
+#define CIPSO_V4_MAX_LOC_LVLS         (CIPSO_V4_INV_LVL - 1)
+#define CIPSO_V4_MAX_REM_CATS         65536
+#define CIPSO_V4_INV_CAT              0x80000000
+#define CIPSO_V4_MAX_LOC_CATS         (CIPSO_V4_INV_CAT - 1)
+
+/* 
+ * CIPSO DOI definitions
+ */
+
+/* DOI definition struct */
+#define CIPSO_V4_TAG_MAXCNT           5
+struct cipso_v4_doi {
+	u32 doi;
+	u32 type;
+	union {
+		struct cipso_v4_std_map_tbl *std;
+	} map;
+	u8 tags[CIPSO_V4_TAG_MAXCNT];
+
+	u32 valid;
+	struct list_head list;
+	struct rcu_head rcu;
+	struct list_head dom_list;
+};
+
+/* Standard CIPSO mapping table */
+/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the
+ *       bit is set then consider that value as unspecified, meaning the
+ *       mapping for that particular level/category is invalid */
+struct cipso_v4_std_map_tbl {
+	struct {
+		u32 *cipso;
+		u32 *local;
+		u32 cipso_size;
+		u32 local_size;
+	} lvl;
+	struct {
+		u32 *cipso;
+		u32 *local;
+		u32 cipso_size;
+		u32 local_size;
+	} cat;
+};
+
+/*
+ * Helper Functions
+ */
+
+#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
+#define CIPSO_V4_OPTPTR(x) ((x)->nh.raw + IPCB(x)->opt.cipso)
+
+/*
+ * DOI List Functions
+ */
+
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(const u32 doi,
+			void (*callback) (struct rcu_head * head));
+struct cipso_v4_doi *cipso_v4_doi_getdef(const u32 doi);
+
+struct sk_buff *cipso_v4_doi_dump(const u32 doi, const u32 headroom);
+
+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);
+
+/*
+ * Label Mapping Cache Functions
+ */
+
+int cipso_v4_cache_invalidate(void);
+int cipso_v4_cache_add(const struct sk_buff *skb, 
+		       const struct netlbl_lsm_secattr *secattr);
+
+/*
+ * Protocol Handling Functions
+ */
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+int cipso_v4_validate(unsigned char **option);
+#else
+static inline int cipso_v4_validate(unsigned char **option)
+{
+	return *option;
+}
+#endif /* CONFIG_NETLABEL_CIPSOV4 */
+
+int cipso_v4_error(struct sk_buff *skb,
+		   const int error,
+		   const u32 gateway);
+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_socket_getattr(const struct socket *sock,
+			    struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
+			    struct netlbl_lsm_secattr *secattr);
+
+#endif /* _CIPSO_IPV4_H */
diff -purN linux-2.6.16.i686/include/net/inet_sock.h linux-2.6.16.i686-netlabel_06132006/include/net/inet_sock.h
--- linux-2.6.16.i686/include/net/inet_sock.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/inet_sock.h	2006-06-13 11:19:59.000000000 -0400
@@ -52,7 +52,7 @@ struct ip_options {
 			ts_needtime:1,
 			ts_needaddr:1;
 	unsigned char	router_alert;
-	unsigned char	__pad1;
+	unsigned char	cipso;
 	unsigned char	__pad2;
 	unsigned char	__data[0];
 };
diff -purN linux-2.6.16.i686/include/net/netlabel.h linux-2.6.16.i686-netlabel_06132006/include/net/netlabel.h
--- linux-2.6.16.i686/include/net/netlabel.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/netlabel.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,354 @@
+/*
+ * NetLabel System
+ *
+ * The NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_H
+#define _NETLABEL_H
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+
+/*
+ * NetLabel - A management interface for maintaining network packet label
+ *            mapping tables for explicit packet labling protocols.
+ *
+ * Network protocols such as CIPSO and RIPSO require a label translation layer
+ * to convert the label on the packet into something meaningful on the host
+ * machine.  In the current Linux implementation these mapping tables live
+ * inside the kernel; NetLabel provides a mechanism for user space applications
+ * to manage these mapping tables.
+ *
+ * NetLabel makes use of NETLINK as a transport layer to send messages between
+ * kernel and user space.  The general format of a NetLabel message is shown
+ * below:
+ *
+ *  +----------+------------------+--------- --- -- -
+ *  | nlmsghdr | subsystem header | payload
+ *  +----------+------------------+--------- --- -- -
+ *
+ * The 'nlmsghdr' struct should be dealt with like any other NETLINK 'nlmsghdr'
+ * struct.  The subsystem header structure is dependent on the subsystem
+ * specified in the 'nlmsghdr->nlmsg_type' and should be defined below,
+ * supporting functions should be defined in the corresponding
+ * net/netlabel/netlabel_<subsys>.h|c file.
+ *
+ */
+
+/*
+ * NetLabel NETLINK protocol
+ */
+
+#define NETLBL_PROTO_VERSION        1
+
+/* NetLabel NETLINK groups */
+#define NETLBL_NLGRP_NONE           0x00000000
+#define NETLBL_NLGRP_MAX            0x00000000
+
+/* NetLabel NETLINK types */
+#define NETLBL_NLTYPE_NONE          0
+#define NETLBL_NLTYPE_MGMT          1
+#define NETLBL_NLTYPE_RIPSO         2
+#define NETLBL_NLTYPE_CIPSOV4       3
+#define NETLBL_NLTYPE_CIPSOV6       4
+#define NETLBL_NLTYPE_UNLABELED     5
+
+/* NetLabel return codes */
+#define NETLBL_E_OK                 0
+
+/*
+ * Helper functions
+ */
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u8(unsigned char *buffer, const u8 val)
+{
+	*(u8 *)buffer = val;
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u32(unsigned char *buffer, const u32 val)
+{
+	*(u32 *)buffer = val;
+}
+
+/**
+ * netlbl_put_str - Write a string into a buffer
+ * @buffer: the buffer
+ * @val: the string
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_str(unsigned char *buffer, const char *val)
+{
+	strcpy((char *)buffer, val);
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer.
+ *
+ */
+static inline void netlbl_put_hdr(unsigned char *buffer,
+				  const u32 msg_type,
+				  const u16 msg_len,
+				  const u16 msg_flags, 
+				  const u32 msg_pid, 
+				  const u32 msg_seq)
+{
+	struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+	hdr->nlmsg_len = msg_len;
+	hdr->nlmsg_type = msg_type;
+	hdr->nlmsg_flags = msg_flags;
+	hdr->nlmsg_seq = msg_seq;
+	hdr->nlmsg_pid = msg_pid;
+}
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u8(unsigned char **buffer, const u8 val)
+{
+	netlbl_put_u8(*buffer, val);
+	*buffer += sizeof(u8);
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u32(unsigned char **buffer, const u32 val)
+{
+	netlbl_put_u32(*buffer, val);
+	*buffer += sizeof(u32);
+}
+
+/**
+ * netlbl_put_u8 - Write a string into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_str(unsigned char **buffer, const char *val)
+{
+	netlbl_put_str(*buffer, val);
+	*buffer += strlen(val) + 1;
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer and increment the ptr
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer and
+ * then increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_putinc_hdr(unsigned char **buffer,
+				     const u32 msg_type,
+				     const u16 msg_len,
+				     const u16 msg_flags, 
+				     const u32 msg_pid, 
+				     const u32 msg_seq)
+{
+	netlbl_put_hdr(*buffer, 
+		       msg_type, 
+		       msg_len, 
+		       msg_flags, 
+		       msg_pid, 
+		       msg_seq);
+	*buffer += NLMSG_HDRLEN;
+}
+
+/**
+ * netlbl_get_u8 - Read a u8 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u8 netlbl_get_u8(const unsigned char *buffer)
+{
+	return *(u8 *)buffer;
+}
+
+/**
+ * netlbl_get_u32 - Read a u32 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u32 netlbl_get_u32(const unsigned char *buffer)
+{
+	return *(u32 *)buffer;
+}
+
+/**
+ * netlbl_getinc_u8 - Read a u8 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u8 netlbl_getinc_u8(unsigned char **buffer)
+{
+	u8 val = netlbl_get_u8(*buffer);
+	*buffer += sizeof(u8);
+	return val;
+}
+
+/**
+ * netlbl_getinc_u32 - Read a u32 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u32 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u32 netlbl_getinc_u32(unsigned char **buffer)
+{
+	u32 val = netlbl_get_u32(*buffer);
+	*buffer += sizeof(u32);
+	return val;
+}
+
+/*
+ * NetLabel - Kernel API for accessing the network packet label mappings.
+ *
+ * The following functions are provided for use by other kernel modules,
+ * specifically kernel LSM modules, to provide a consistent, transparent API
+ * for dealing with explicit packet labeling protocols such as CIPSO and
+ * RIPSO.  The functions defined here are implemented in the 
+ * net/netlabel/netlabel_kapi.c file.
+ *
+ */
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map;
+
+/* Domain mapping operations */
+int netlbl_domhsh_remove(const char *domain);
+
+/* LSM security attributes */
+struct netlbl_lsm_cache {
+	void (*free) (const void *data);
+	void *data;
+};
+struct netlbl_lsm_secattr {
+	char *domain;
+
+	u32 mls_lvl;
+	unsigned char *mls_cat;
+	u32 mls_cat_len;
+
+	struct netlbl_lsm_cache cache;
+
+	u32 set_domain:1, 
+	    set_mls_lvl:1,
+	    set_mls_cat:1,
+	    set_cache:1,
+	    unused:28;
+};
+
+/* LSM security attribute operations */
+struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags);
+void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr);
+int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr);
+void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr);
+
+/* LSM protocol operations */
+int netlbl_socket_setattr(const struct socket *sock,
+			  const struct netlbl_lsm_secattr *secattr);
+int netlbl_socket_peekattr(const struct socket *sock, 
+			   struct netlbl_lsm_secattr *secattr);
+int netlbl_socket_getattr(const struct socket *sock, 
+			  struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_getattr(const struct sk_buff *skb, 
+			  struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_err(struct sk_buff *skb, int error);
+
+/* LSM label mapping cache operations */
+int netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb, 
+		     const struct netlbl_lsm_secattr *secattr);
+
+#endif /* _NETLABEL_H */
diff -purN linux-2.6.16.i686/net/ipv4/ah4.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/ah4.c
--- linux-2.6.16.i686/net/ipv4/ah4.c	2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/ah4.c	2006-06-13 11:19:59.000000000 -0400
@@ -35,7 +35,7 @@ static int ip_clear_mutable_options(stru
 		switch (*optptr) {
 		case IPOPT_SEC:
 		case 0x85:	/* Some "Extended Security" crap. */
-		case 0x86:	/* Another "Commercial Security" crap. */
+		case IPOPT_CIPSO:
 		case IPOPT_RA:
 		case 0x80|21:	/* RFC1770 */
 			break;
diff -purN linux-2.6.16.i686/net/ipv4/cipso_ipv4.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/cipso_ipv4.c
--- linux-2.6.16.i686/net/ipv4/cipso_ipv4.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/cipso_ipv4.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,1749 @@
+/*
+ * CIPSO - Commercial IP Security Option
+ *
+ * This is an implementation of the CIPSO 2.2 protocol as specified in
+ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
+ * FIPS-188, copies of both documents can be found in the Documentation
+ * directory.  While CIPSO never became a full IETF RFC standard many vendors
+ * have chosen to adopt the protocol and over the years it has become a
+ * de-facto standard for labeled networking.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+struct cipso_v4_domhsh_entry {
+	char *domain;
+	u32 valid;
+	struct list_head list;
+	struct rcu_head rcu;
+};
+
+/* List of available DOI definitions */
+/* XXX - Updates should be minimal so having a single lock for the
+   cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
+   okay. */
+/* XXX - This currently assumes a minimal number of different DOIs in use,
+   if in practice there are a lot of different DOIs this list should
+   probably be turned into a hash table or something similar so we
+   can do quick lookups. */
+DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
+static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);
+
+/* Label mapping cache */
+#define CIPSO_V4_CACHE_BUCKETBITS     7
+#define CIPSO_V4_CACHE_BUCKETS        (1 << CIPSO_V4_CACHE_BUCKETBITS)
+#define CIPSO_V4_CACHE_BUCKETSIZE     10
+#define CIPSO_V4_CACHE_REORDERLIMIT   10
+/* PM - the number of cache buckets should probably be a compile time option */
+struct cipso_v4_map_cache_bkt {
+	spinlock_t lock;
+	u32 size;
+	struct list_head list;
+};
+struct cipso_v4_map_cache_entry {
+	u32 hash;
+	unsigned char *key;
+	u32 key_len;
+
+	struct netlbl_lsm_cache lsm_data;
+
+	u32 activity;
+	struct list_head list;
+};
+static u32 cipso_v4_cache_size = 0;
+static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
+#define CIPSO_V4_CACHE_ENABLED (cipso_v4_cache_size > 0)
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
+ * @bitmap: the bitmap
+ * @bitmap_len: length in bits
+ * @offset: starting offset
+ * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
+ *
+ * Description:
+ * Starting at @offset, walk the bitmap from left to right until either the
+ * desired bit is found or we reach the end.  Return the bit offset, -1 if
+ * not found, or -2 if error.
+ */
+static inline int cipso_v4_bitmap_walk(const unsigned char *bitmap,
+				       const u32 bitmap_len,
+				       const u32 offset,
+				       const u8 state)
+{
+	u32 byte_spot;
+	u32 byte_spot_rem;
+	unsigned char bitmask;
+
+	/* gcc always rounds to zero when doing integer division */
+	byte_spot = offset / 8;
+	byte_spot_rem = offset % 8;
+	bitmask = 0x80 >> byte_spot_rem;
+
+	/* XXX - probably should use include/asm/bitops.h if we can */
+	while ((byte_spot * 8 + byte_spot_rem) < bitmap_len) {
+		if ((state && (bitmap[byte_spot] & bitmask) == bitmask) ||
+		    (state == 0 && (bitmap[byte_spot] & bitmask) == 0))
+			return byte_spot * 8 + byte_spot_rem;
+
+		if (++byte_spot_rem == 8) {
+			byte_spot++;
+			byte_spot_rem = 0;
+			bitmask = 0x80;
+		} else
+			bitmask = bitmask >> 1;
+	}
+
+	return -1;
+}
+
+/**
+ * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
+ * @bitmap: the bitmap
+ * @bit: the bit
+ * @state: if non-zero, set the bit (1) else clear the bit (0)
+ *
+ * Description:
+ * Set a single bit in the bitmask.  Returns zero on success, negative values
+ * on error.
+ */
+static inline int cipso_v4_bitmap_setbit(unsigned char *bitmap,
+					 const u32 bit,
+					 const u8 state)
+{
+	u32 byte_spot;
+	u8 bitmask;
+
+	/* gcc always rounds to zero when doing integer division */
+	byte_spot = bit / 8;
+	bitmask = 0x80 >> bit % 8;
+	if (state)
+		bitmap[byte_spot] |= bitmask;
+	else
+		bitmap[byte_spot] &= ~bitmask;
+
+	return 0;
+}
+
+/**
+ * cipso_v4_doi_domhsh_free - Frees a domain list entry
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to a domain list entry can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
+{
+	struct cipso_v4_domhsh_entry *ptr;
+
+	ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
+	if (ptr->domain)
+		kfree(ptr->domain);
+	kfree(ptr);
+}
+
+/**
+ * cipso_v4_cache_entry_free - Frees a cache entry
+ * @entry: the entry to free
+ *
+ * Description:
+ * This function frees the memory associated with a cache entry.
+ *
+ */
+static inline void cipso_v4_cache_entry_free(
+	struct cipso_v4_map_cache_entry *entry)
+{
+	BUG_ON(entry == NULL);
+
+	if (entry->lsm_data.free)
+		entry->lsm_data.free(entry->lsm_data.data);
+	if (entry->key)
+		kfree(entry->key);
+	kfree(entry);
+}
+
+/**
+ * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
+ * @key: the hash key
+ * @key_len: the length of the key in bytes
+ *
+ * Description:
+ * The CIPSO tag hashing function.  Returns a 32-bit hash value.
+ *
+ */
+static inline u32 cipso_v4_map_cache_hash(const unsigned char *key,
+					  const u32 key_len)
+{
+	unsigned char *p;
+	unsigned char *keyp = (char *)key;
+	u32 val = 0;
+
+	/* This is taken (with slight modification) from 
+	   security/selinux/ss/symtab.c:symhash(), we probably need to find
+	   a better hash for dealing with bitmaps */
+
+	for (p = keyp; (p - keyp) < key_len; p++)
+		val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ (*p);
+	return val;
+}
+
+/*
+ * Label Mapping Cache Functions
+ */
+
+/**
+ * cipso_v4_cache_init - Initialize the CIPSO cache
+ * @bkt_size: the number of cache buckets
+ *
+ * Description:
+ * Initializes the CIPSO label mapping cache, this function should be called
+ * before any of the other functions defined in this file.  Returns zero on
+ * success, negative values on error.
+ *
+ */
+static int cipso_v4_cache_init(const u32 bkt_size)
+{
+	struct cipso_v4_map_cache_bkt *cache;
+	u32 iter;
+
+	BUG_ON(cipso_v4_cache != NULL);
+
+	if (bkt_size == 0)
+		return -EINVAL;
+
+	cache = kcalloc(bkt_size,
+			sizeof(struct cipso_v4_map_cache_bkt), GFP_KERNEL);
+	if (cache == NULL)
+		return -ENOMEM;
+
+	for (iter = 0; iter < bkt_size; iter++) {
+		cache[iter].lock = SPIN_LOCK_UNLOCKED;
+		cache[iter].size = 0;
+		INIT_LIST_HEAD(&cache[iter].list);
+	}
+	cipso_v4_cache = cache;
+	cipso_v4_cache_size = bkt_size;
+
+	return 0;
+}
+
+/**
+ * cipso_v4_cache_destroy - Destroy the CIPSO cache
+ *
+ * Description:
+ * Clears the CIPSO cache and frees all the memory.  This function does not
+ * hold any locks and should only be called when the module is being unloaded.
+ *
+ */
+static int cipso_v4_cache_destroy(void)
+{
+	struct cipso_v4_map_cache_bkt *cache;
+	struct cipso_v4_map_cache_entry *entry;
+	u32 cache_size;
+	u32 iter;
+
+	BUG_ON(cipso_v4_cache == NULL);
+
+	cache = cipso_v4_cache;
+	cache_size = cipso_v4_cache_size;
+	cipso_v4_cache_size = 0;
+	cipso_v4_cache = NULL;
+
+	for (iter = 0; iter < cache_size; iter++)
+		list_for_each_entry(entry, &cache[iter].list, list) {
+			list_del(&entry->list);
+			cipso_v4_cache_entry_free(entry);
+		}
+
+	return 0;
+}
+
+/**
+ * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
+ *
+ * Description:
+ * Invalidates and frees any entries in the CIPSO cache.  Returns zero on
+ * success and negative values on failure.
+ * 
+ */
+int cipso_v4_cache_invalidate(void)
+{
+	struct cipso_v4_map_cache_entry *entry, *tmp_entry;
+	u32 iter;
+
+	if (!CIPSO_V4_CACHE_ENABLED)
+		return 0;
+
+	for (iter = 0; iter < cipso_v4_cache_size; iter++) {
+		spin_lock(&cipso_v4_cache[iter].lock);
+		list_for_each_entry_safe(entry,
+					 tmp_entry,
+					 &cipso_v4_cache[iter].list, list) {
+			list_del(&entry->list);
+			cipso_v4_cache_entry_free(entry);
+		}
+		cipso_v4_cache[iter].size = 0;
+		spin_unlock(&cipso_v4_cache[iter].lock);
+	}
+
+	return 0;
+}
+
+/**
+ * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
+ * @skb: the packet
+ * @secattr: the security attribute struct to use
+ *
+ * Description:
+ * This function checks the cache to see if a label mapping already exists for
+ * the CIPSO tags in the packet.  If there is a match then the cache is
+ * adjusted and the @secattr struct is populated with the correct LSM security
+ * attributes.  The cache is adjusted in the following manner if the entry is
+ * not already the first in the cache bucket:
+ * 
+ *  1. The cache entry's activity counter is incremented
+ *  2. The previous (higher ranking) entry's activity counter is decremented
+ *  3. If the difference between the two activity counters is geater than
+ *     CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
+ *
+ * Returns zero on success, -ENOENT for a cache miss, and other negative values
+ * on error.
+ *
+ */
+static int cipso_v4_cache_check(const struct sk_buff *skb,
+				struct netlbl_lsm_secattr *secattr)
+{
+	u32 bkt;
+	struct cipso_v4_map_cache_entry *entry;
+	struct cipso_v4_map_cache_entry *prev_entry = NULL;
+	unsigned char *cipso_ptr;
+	u32 cipso_ptr_len;
+	u32 hash;
+
+	if (!CIPSO_V4_CACHE_ENABLED)
+		return -ENOENT;
+
+	cipso_ptr = CIPSO_V4_OPTPTR(skb);
+	cipso_ptr_len = cipso_ptr[1];
+	hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
+
+	bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+	spin_lock(&cipso_v4_cache[bkt].lock);
+	list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
+		if (entry->hash == hash &&
+		    entry->key_len == cipso_ptr_len &&
+		    memcmp(entry->key, cipso_ptr, cipso_ptr_len) == 0) {
+			entry->activity += 1;
+			if (prev_entry != NULL) {
+				if (prev_entry->activity > 0)
+					prev_entry->activity -= 1;
+				if (entry->activity > prev_entry->activity &&
+				    entry->activity - prev_entry->activity >
+				    CIPSO_V4_CACHE_REORDERLIMIT) {
+					__list_del(entry->list.prev,
+						   entry->list.next);
+					__list_add(&entry->list,
+						   prev_entry->list.prev,
+						   &prev_entry->list);
+				}
+			}
+			secattr->cache.free = entry->lsm_data.free;
+			secattr->cache.data = entry->lsm_data.data;
+			spin_unlock(&cipso_v4_cache[bkt].lock);
+			secattr->set_cache = 1;
+			return 0;
+		}
+		prev_entry = entry;
+	}
+	spin_unlock(&cipso_v4_cache[bkt].lock);
+
+	return -ENOENT;
+}
+
+/**
+ * cipso_v4_cache_add - Add an entry to the CIPSO cache
+ * @skb: the packet
+ * @secattr: the packet's security attributes
+ *
+ * Description:
+ * Add a new entry into the CIPSO label mapping cache.  Add the new entry to
+ * head of the cache bucket's list, if the cache bucket is out of room remove
+ * the last entry in the list first.  It is important to note that there is
+ * currently no checking for duplicate keys.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int cipso_v4_cache_add(const struct sk_buff *skb, 
+		       const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -EPERM;
+	u32 bkt;
+	struct cipso_v4_map_cache_entry *entry = NULL;
+	struct cipso_v4_map_cache_entry *old_entry = NULL;
+	unsigned char *cipso_ptr;
+	u32 cipso_ptr_len;
+
+	BUG_ON(skb == NULL || secattr == NULL);
+
+	if (!CIPSO_V4_CACHE_ENABLED)
+		return 0;
+
+	cipso_ptr = CIPSO_V4_OPTPTR(skb);
+	BUG_ON(cipso_ptr == NULL);
+	cipso_ptr_len = cipso_ptr[1];
+
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+	if (entry == NULL)
+		return -ENOMEM;
+	entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC);
+	if (entry->key == NULL) {
+		ret_val = -ENOMEM;
+		goto cache_add_failure;
+	}
+
+	entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
+	memcpy(entry->key, cipso_ptr, cipso_ptr_len);
+	entry->key_len = cipso_ptr_len;
+	entry->lsm_data.free = secattr->cache.free;
+	entry->lsm_data.data = secattr->cache.data;
+
+	bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+	spin_lock(&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;
+	} else {
+		old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
+				       struct cipso_v4_map_cache_entry, list);
+		list_del(&old_entry->list);
+		list_add(&entry->list, &cipso_v4_cache[bkt].list);
+	}
+	spin_unlock(&cipso_v4_cache[bkt].lock);
+
+	if (old_entry)
+		cipso_v4_cache_entry_free(old_entry);
+
+	return 0;
+
+cache_add_failure:
+	if (entry)
+		cipso_v4_cache_entry_free(entry);
+	return ret_val;
+}
+
+/*
+ * DOI List Functions
+ */
+
+/**
+ * cipso_v4_doi_search - Searches for a DOI definition
+ * @doi: the DOI to search for
+ *
+ * Description:
+ * Search the DOI definition list for a DOI definition with a DOI value that
+ * matches @doi.  The caller is responsibile for calling rcu_read_[un]lock().
+ * Returns a pointer to the DOI definition on success and NULL on failure.
+ */
+static struct cipso_v4_doi *cipso_v4_doi_search(const u32 doi)
+{
+	struct cipso_v4_doi *iter;
+
+	list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+		if (iter->doi == doi && iter->valid)
+			return iter;
+	return NULL;
+}
+
+/**
+ * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
+ * @doi_def: the DOI structure
+ *
+ * Description:
+ * The caller defines a new DOI for use by the CIPSO engine and calls this
+ * function to add it to the list of acceptable domains.  The caller must
+ * ensure that the mapping table specified in @doi_def->map meets all of the
+ * requirements of the mapping type (see cipso_ipv4.h for details).  Returns
+ * zero on success and non-zero on failure.
+ *
+ */
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
+{
+	if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
+		return -EINVAL;
+
+	doi_def->valid = 1;
+	INIT_RCU_HEAD(&doi_def->rcu);
+	INIT_LIST_HEAD(&doi_def->dom_list);
+
+	rcu_read_lock();
+	if (cipso_v4_doi_search(doi_def->doi) != NULL) {
+		rcu_read_unlock();
+		return -EEXIST;
+	}
+	spin_lock(&cipso_v4_doi_list_lock);
+	list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
+	spin_unlock(&cipso_v4_doi_list_lock);
+	rcu_read_unlock();
+
+	return 0;
+}
+
+/**
+ * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
+ * @doi: the DOI value
+ * @callback: the DOI cleanup/free callback
+ *
+ * Description:
+ * Removes a DOI definition from the CIPSO engine, @callback is called to
+ * free any memory.  The NetLabel routines will be called to release their own
+ * LSM domain mappings as well as our own domain list.  Returns zero on
+ * success and negative values on failure.
+ *
+ */
+int cipso_v4_doi_remove(const u32 doi,
+			void (*callback) (struct rcu_head * head))
+{
+	struct cipso_v4_doi *doi_def;
+	struct cipso_v4_domhsh_entry *dom_iter;
+
+	if (doi == CIPSO_V4_DOI_UNKNOWN || callback == NULL)
+		return -EINVAL;
+
+	rcu_read_lock();
+	doi_def = cipso_v4_doi_search(doi);
+	if (doi_def != NULL) {
+		spin_lock(&cipso_v4_doi_list_lock);
+		doi_def->valid = 0;
+		list_del_rcu(&doi_def->list);
+		spin_unlock(&cipso_v4_doi_list_lock);
+		list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
+			if (dom_iter->valid)
+				netlbl_domhsh_remove(dom_iter->domain);
+		rcu_read_unlock();
+		/* PM - should we invalidate the cache before we drop the
+		        lock? */
+		cipso_v4_cache_invalidate();
+
+		call_rcu(&doi_def->rcu, callback);
+		return 0;
+	}
+	rcu_read_unlock();
+
+	return -ENOENT;
+}
+
+/**
+ * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * @doi: the DOI value
+ *
+ * Description:
+ * Searches for a valid DOI definition and if one is found it is returned to
+ * the caller.  Otherwise NULL is returned.  The caller must ensure that
+ * rcu_read_lock() is held while accessing the returned definition.
+ *
+ */
+struct cipso_v4_doi *cipso_v4_doi_getdef(const u32 doi)
+{
+	struct cipso_v4_doi *doi_def;
+
+	if (doi == CIPSO_V4_DOI_UNKNOWN)
+		return NULL;
+
+	doi_def = cipso_v4_doi_search(doi);
+
+	return doi_def;
+}
+
+/**
+ * cipso_v4_doi_dump - Dump the CIPSO DOI definitions into a sk_buff
+ * @doi: the DOI value
+ * @headroom: the amount of headroom to allocate for the sk_buff 
+ *
+ * Description:
+ * If the @doi value is zero then dump a list of all the configured DOI values
+ * into a sk_buff.  If the @doi value is non-zero, lookup the match DOI
+ * definition and dump it's contents into a sk_buff.  The returned sk_buff has
+ * room at the front of the sk_buff for a nlmsghdr struct and a @headroom
+ * bytes.  See 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(const u32 doi, const u32 headroom)
+{
+	struct sk_buff *skb;
+	unsigned char *buf;
+	struct cipso_v4_doi *iter;
+	u32 doi_cnt = 0;
+	u32 tag_cnt = 0;
+	u32 lvl_cnt = 0;
+	u32 cat_cnt = 0;
+	u32 buf_len;
+	u32 tmp_len;
+
+	/* XXX - In both cases, this is kinda ugly as we have to go through
+	   the list once to determine how large of a buffer we need,
+	   drop the locks, allocate the buffer, grab the locks, and
+	   finally fill the buffer.  The problem is that there is that
+	   open window where the table could grow and we will end up
+	   short on space. */
+
+	if (doi == 0) {
+		buf_len = 4;
+		rcu_read_lock();
+		list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+			if (iter->valid) {
+				doi_cnt += 1;
+				buf_len += 8;
+			}
+		rcu_read_unlock();
+
+		skb = alloc_skb(NLMSG_SPACE(headroom + buf_len), GFP_KERNEL);
+		if (skb == NULL)
+			return NULL;
+		skb_reserve(skb, NLMSG_SPACE(headroom));
+		tmp_len = skb_tailroom(skb);
+		if (tmp_len < buf_len)
+			goto doi_dump_failure;
+		buf = skb_put(skb, buf_len);
+		buf_len -= 4;
+		netlbl_putinc_u32(&buf, doi_cnt);
+
+		rcu_read_lock();
+		list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+			if (iter->valid) {
+				if (buf_len < 8) {
+					rcu_read_unlock();
+					goto doi_dump_failure;
+				}
+				buf_len -= 8;
+				netlbl_putinc_u32(&buf, iter->doi);
+				netlbl_putinc_u32(&buf, iter->type);
+			}
+		rcu_read_unlock();
+	} else {
+		rcu_read_lock();
+		iter = cipso_v4_doi_getdef(doi);
+		if (iter == NULL) {
+			rcu_read_unlock();
+			return NULL;
+		}
+		buf_len = 4;
+		switch (iter->type) {
+		case CIPSO_V4_MAP_STD:
+			buf_len += 12;
+			while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
+			       iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
+				tag_cnt += 1;
+				buf_len += 1;
+			}
+			tmp_len = 0;
+			while (tmp_len < iter->map.std->lvl.local_size)
+				if (iter->map.std->lvl.local[tmp_len++] !=
+				    CIPSO_V4_INV_LVL) {
+					lvl_cnt += 1;
+					buf_len += 8;
+				}
+			tmp_len = 0;
+			while (tmp_len < iter->map.std->cat.local_size)
+				if (iter->map.std->cat.local[tmp_len++] !=
+				    CIPSO_V4_INV_CAT) {
+					cat_cnt += 1;
+					buf_len += 8;
+				}
+			break;
+		case CIPSO_V4_MAP_PASS:
+			buf_len += 4;
+			while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
+			       iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
+				tag_cnt += 1;
+				buf_len += 1;
+			}
+			break;
+		default:
+			rcu_read_unlock();
+			return NULL;
+		}
+		rcu_read_unlock();
+
+		skb = alloc_skb(NLMSG_SPACE(sizeof(headroom) + buf_len),
+				GFP_KERNEL);
+		if (skb == NULL)
+			return NULL;
+		skb_reserve(skb, NLMSG_SPACE(headroom));
+		tmp_len = skb_tailroom(skb);
+		if (tmp_len < buf_len)
+			goto doi_dump_failure;
+		buf = skb_put(skb, buf_len);
+		buf_len -= 4;
+		netlbl_putinc_u32(&buf, iter->type);
+
+		rcu_read_lock();
+		if (iter != cipso_v4_doi_getdef(doi)) {
+			rcu_read_unlock();
+			goto doi_dump_failure;
+		}
+		switch (iter->type) {
+		case CIPSO_V4_MAP_STD:
+			buf_len -= 12;
+			netlbl_putinc_u32(&buf, tag_cnt);
+			netlbl_putinc_u32(&buf, lvl_cnt);
+			netlbl_putinc_u32(&buf, cat_cnt);
+			tmp_len = 0;
+			while (tmp_len < CIPSO_V4_TAG_MAXCNT &&
+			       iter->tags[tmp_len] != CIPSO_V4_TAG_INVALID) {
+				if (buf_len < 1) {
+					rcu_read_unlock();
+					goto doi_dump_failure;
+				}
+				buf_len -= 1;
+				netlbl_putinc_u8(&buf, iter->tags[tmp_len++]);
+			}
+			tmp_len = 0;
+			while (tmp_len < iter->map.std->lvl.local_size) {
+				if (iter->map.std->lvl.local[tmp_len] !=
+				    CIPSO_V4_INV_LVL) {
+					if (buf_len < 8) {
+						rcu_read_unlock();
+						goto doi_dump_failure;
+					}
+					buf_len -= 8;
+					netlbl_putinc_u32(&buf, tmp_len);
+					netlbl_putinc_u32(&buf,
+							  iter->map.std->lvl.
+							  local[tmp_len]);
+				}
+				tmp_len += 1;
+			}
+			tmp_len = 0;
+			while (tmp_len < iter->map.std->cat.local_size) {
+				if (iter->map.std->cat.local[tmp_len] !=
+				    CIPSO_V4_INV_CAT) {
+					if (buf_len < 8) {
+						rcu_read_unlock();
+						goto doi_dump_failure;
+					}
+					buf_len -= 8;
+					netlbl_putinc_u32(&buf, tmp_len);
+					netlbl_putinc_u32(&buf,
+							  iter->map.std->cat.
+							  local[tmp_len]);
+				}
+				tmp_len += 1;
+			}
+			break;
+		case CIPSO_V4_MAP_PASS:
+			netlbl_putinc_u32(&buf, tag_cnt);
+			tmp_len = 0;
+			while (tmp_len < CIPSO_V4_TAG_MAXCNT &&
+			       iter->tags[tmp_len] != CIPSO_V4_TAG_INVALID) {
+				if (buf_len < 1) {
+					rcu_read_unlock();
+					goto doi_dump_failure;
+				}
+				buf_len -= 1;
+				netlbl_putinc_u8(&buf, iter->tags[tmp_len++]);
+			}
+			break;
+		}
+		rcu_read_unlock();
+	}
+
+	return skb;
+
+doi_dump_failure:
+	kfree(skb);
+	return NULL;
+}
+
+/**
+ * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
+ * @doi_def: the DOI definition
+ * @domain: the domain to add
+ *
+ * Description:
+ * Adds the @domain to the the DOI specified by @doi_def, this function
+ * should only be called by external functions (i.e. NetLabel).  This function
+ * does allocate memory.  Returns zero on success, negative values on failure.
+ *
+ */
+int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
+{
+	struct cipso_v4_domhsh_entry *iter;
+	struct cipso_v4_domhsh_entry *new_dom;
+
+	BUG_ON(doi_def == NULL);
+
+	new_dom = kmalloc(sizeof(*new_dom), GFP_KERNEL);
+	if (new_dom == NULL)
+		return -ENOMEM;
+	if (domain) {
+		new_dom->domain = kstrdup(domain, GFP_KERNEL);
+		if (new_dom->domain == NULL) {
+			kfree(new_dom);
+			return -ENOMEM;
+		}
+	} else
+		new_dom->domain = NULL;
+	new_dom->valid = 1;
+	INIT_RCU_HEAD(&new_dom->rcu);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
+		if (iter->valid &&
+		    ((domain != NULL && strcmp(iter->domain, domain) == 0) ||
+		     (domain == NULL && iter->domain == NULL))) {
+			rcu_read_unlock();
+			if (new_dom->domain != NULL)
+				kfree(new_dom->domain);
+			kfree(new_dom);
+			return -EEXIST;
+		}
+	spin_lock(&cipso_v4_doi_list_lock);
+	list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
+	spin_unlock(&cipso_v4_doi_list_lock);
+	rcu_read_unlock();
+	return 0;
+}
+
+/**
+ * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
+ * @doi_def: the DOI definition
+ * @domain: the domain to remove
+ *
+ * Description:
+ * Removes the @domain from the DOI specified by @doi_def, this function
+ * should only be called by external functions (i.e. NetLabel).   Returns zero
+ * on success and negative values on error.
+ *
+ */
+int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, 
+			       const char *domain)
+{
+	struct cipso_v4_domhsh_entry *iter;
+
+	BUG_ON(doi_def == NULL);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
+		if (iter->valid && 
+		    ((domain != NULL && strcmp(iter->domain, domain) == 0) ||
+		     (domain == NULL && iter->domain == NULL))) {
+			spin_lock(&cipso_v4_doi_list_lock);
+			iter->valid = 0;
+			list_del_rcu(&iter->list);
+			spin_unlock(&cipso_v4_doi_list_lock);
+			rcu_read_unlock();
+
+			call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
+			return 0;
+		}
+	rcu_read_unlock();
+
+	return -ENOENT;
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
+ * @doi_def: the DOI definition
+ * @level: the level to check
+ *
+ * Description:
+ * Checks the given level against the given DOI definition and returns a
+ * negative value if the level does not have a valid mapping and a zero value
+ * if the level is defined by the DOI.
+ *
+ */
+static inline int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def,
+					 const u8 level)
+{
+	BUG_ON(doi_def == NULL);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
+			return 0;
+		break;
+	case CIPSO_V4_MAP_PASS:
+		return 0;
+		break;
+	}
+
+	return -EFAULT;
+}
+
+/**
+ * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
+ * @doi_def: the DOI definition
+ * @host_lvl: the host MLS level
+ * @net_lvl: the network/CIPSO MLS level
+ *
+ * Description:
+ * Perform a label mapping to translate a local MLS level to the correct
+ * CIPSO level using the given DOI definition.  Returns zero on success,
+ * negative values otherwise.
+ *
+ */
+static inline int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
+					const u32 host_lvl,
+					u32 *net_lvl)
+{
+	BUG_ON(doi_def == NULL || net_lvl == NULL);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		if (host_lvl < doi_def->map.std->lvl.local_size) {
+			*net_lvl = doi_def->map.std->lvl.local[host_lvl];
+			return 0;
+		}
+		break;
+	case CIPSO_V4_MAP_PASS:
+		*net_lvl = host_lvl;
+		return 0;
+		break;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
+ * @doi_def: the DOI definition
+ * @net_lvl: the network/CIPSO MLS level
+ * @host_lvl: the host MLS level
+ *
+ * Description:
+ * Perform a label mapping to translate a CIPSO level to the correct local MLS
+ * level using the given DOI definition.  Returns zero on success, negative
+ * values otherwise.
+ *
+ */
+static inline int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
+					const u32 net_lvl,
+					u32 *host_lvl)
+{
+	BUG_ON(doi_def == NULL || host_lvl == NULL);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		if (net_lvl < doi_def->map.std->lvl.cipso_size) {
+			*host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
+			return 0;
+		}
+		break;
+	case CIPSO_V4_MAP_PASS:
+		*host_lvl = net_lvl;
+		return 0;
+		break;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
+ * @doi_def: the DOI definition
+ * @bitmap: category bitmap
+ * @bitmap_len: bitmap length in bytes
+ *
+ * Description:
+ * Checks the given category bitmap against the given DOI definition and
+ * returns a negative value if any of the categories in the bitmap do not have
+ * a valid mapping and a zero value if all of the categories are valid.
+ *
+ */
+static inline int cipso_v4_map_cat_rbm_valid(
+				           const struct cipso_v4_doi *doi_def,
+					   const unsigned char *bitmap, 
+					   const u32 bitmap_len)
+{
+	u32 offset = 0;
+	int cat;
+	u32 bitmap_len_bits = bitmap_len * 8;
+
+	BUG_ON(doi_def == NULL || bitmap_len_bits >= CIPSO_V4_MAX_REM_CATS);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		do {
+			cat = cipso_v4_bitmap_walk(bitmap, 
+						   bitmap_len_bits,
+						   offset,
+						   1);
+			if (cat >= 0 &&
+			    doi_def->map.std->cat.cipso[cat] >= 
+			    CIPSO_V4_INV_CAT)
+				return -EFAULT;
+			offset = cat + 1;
+		} while (cat >= 0 && offset <= bitmap_len_bits);
+		
+		if (cat == -1)
+			return 0;
+		break;
+	case CIPSO_V4_MAP_PASS:
+		return 0;
+		break;
+	}
+
+	return -EFAULT;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
+ * @doi_def: the DOI definition
+ * @host_cat: the category bitmap in host format
+ * @host_cat_len: the length of the host's category bitmap in bytes
+ * @net_cat: the zero'd out category bitmap in network/CIPSO format
+ * @net_cat_len: the length of the CIPSO bitmap in bytes
+ *
+ * Description:
+ * Perform a label mapping to translate a local MLS category bitmap to the
+ * correct CIPSO bitmap using the given DOI definition.  Returns the minimum
+ * size in bytes of the network bitmap on success, negative values otherwise.
+ *
+ */
+static inline int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
+					    const unsigned char *host_cat,
+					    const u32 host_cat_len,
+					    unsigned char *net_cat,
+					    const u32 net_cat_len)
+{
+	int ret_val;
+	int offset = 0;
+	int host_spot;
+	u32 net_spot;
+	u32 net_spot_max = 0;
+	u32 host_clen_bits = host_cat_len * 8;
+
+	BUG_ON(doi_def == NULL || host_cat == NULL || net_cat == NULL ||
+	       host_cat_len == 0);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		do {
+			host_spot = cipso_v4_bitmap_walk(host_cat,
+							 host_clen_bits,
+							 offset,
+							 1);
+			offset = host_spot + 1;
+			if (host_spot >= 0 &&
+			    host_spot < doi_def->map.std->cat.local_size) {
+				net_spot = 
+					doi_def->map.std->cat.local[host_spot];
+				if (net_spot / 8 >= net_cat_len)
+					return -ENOSPC;
+				ret_val = cipso_v4_bitmap_setbit(net_cat,
+								 net_spot,
+								 1);
+				if (ret_val != 0)
+					return ret_val;
+				if (net_spot > net_spot_max)
+					net_spot_max = net_spot;
+			}
+		} while (host_spot >= 0 && offset <= host_clen_bits);
+		
+		if (host_spot == -2)
+			return -EFAULT;
+
+		if (++net_spot_max % 8)
+			return net_spot_max / 8 + 1;
+		return net_spot_max / 8;
+		break;
+	case CIPSO_V4_MAP_PASS:
+		net_spot_max = host_cat_len - 1;
+		while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
+			net_spot_max--;
+		if (net_spot_max > net_cat_len)
+			return -EINVAL;
+		memcpy(net_cat, host_cat, net_spot_max);
+		return net_spot_max;
+		break;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
+ * @doi_def: the DOI definition
+ * @net_cat: the category bitmap in network/CIPSO format
+ * @net_cat_len: the length of the CIPSO bitmap in bytes
+ * @host_cat: the zero'd out category bitmap in host format
+ * @host_cat_len: the length of the host's category bitmap in bytes
+ *
+ * Description:
+ * Perform a label mapping to translate a CIPSO bitmap to the correct local 
+ * MLS category bitmap using the given DOI definition.  Returns the minimum
+ * size in bytes of the host bitmap on success, negative values otherwise.
+ *
+ */
+static inline int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
+					    const unsigned char *net_cat,
+					    const u32 net_cat_len,
+					    unsigned char *host_cat, 
+					    const u32 host_cat_len)
+{
+	int ret_val;
+	u32 offset = 0;
+	u32 host_spot;
+	u32 host_spot_max = 0;
+	int net_spot;
+	u32 net_clen_bits = net_cat_len * 8;
+
+	BUG_ON(doi_def == NULL || host_cat == NULL || net_cat == NULL ||
+	       net_cat_len == 0);
+
+	switch (doi_def->type) {
+	case CIPSO_V4_MAP_STD:
+		do {
+			net_spot = cipso_v4_bitmap_walk(net_cat,
+							net_clen_bits,
+							offset,
+							1);
+			offset = net_spot + 1;
+			if (net_spot >= 0 &&
+			    net_spot < doi_def->map.std->cat.cipso_size) {
+				host_spot = 
+					doi_def->map.std->cat.cipso[net_spot];
+				if (host_spot / 8 >= host_cat_len)
+					return -ENOSPC;
+				ret_val = cipso_v4_bitmap_setbit(host_cat,
+								 host_spot,
+								 1);
+				if (ret_val != 0)
+					return ret_val;
+				if (host_spot > host_spot_max)
+					host_spot_max = host_spot;
+			}
+		} while (net_spot >= 0 && offset <= net_clen_bits);
+		
+		if (net_spot == -2)
+		return -EFAULT;
+		
+		if (++host_spot_max % 8)
+			return host_spot_max / 8 + 1;
+		return host_spot_max / 8;
+		break;
+	case CIPSO_V4_MAP_PASS:
+		if (net_cat_len > host_cat_len)
+			return -EINVAL;
+		memcpy(host_cat, net_cat, net_cat_len);
+		return host_cat_len;
+		break;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Protocol Handling Functions
+ */
+
+#define CIPSO_V4_HDR_LEN              6
+
+/**
+ * cipso_v4_gentag_hdr - Generate a CIPSO option header
+ * @doi_def: the DOI definition
+ * @len: the total tag length in bytes
+ * @buf: the CIPSO option buffer
+ *
+ * Description:
+ * Write a CIPSO header into the beginning of @buffer.  Return zero on success,
+ * negative values on failure.
+ *
+ */
+static inline int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
+				      const u32 len, 
+				      unsigned char *buf)
+{
+	if (CIPSO_V4_HDR_LEN + len > 40)
+		return -ENOSPC;
+
+	buf[0] = IPOPT_CIPSO;
+	buf[1] = CIPSO_V4_HDR_LEN + len;
+	*(u32 *)&buf[2] = htonl(doi_def->doi);
+
+	return 0;
+}
+
+#define CIPSO_V4_TAG1_CAT_LEN         30
+
+/**
+ * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the restricted bitmap tag, tag type #1.  The
+ * actual buffer length may be larger than the indicated size due to
+ * translation between host and network category bitmaps.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static inline int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
+				      const struct netlbl_lsm_secattr *secattr,
+				      unsigned char **buffer,
+				      u32 *buffer_len)
+{
+	int ret_val = -EPERM;
+	unsigned char *buf = NULL;
+	u32 buf_len;
+	int cat_len = 0;
+	u32 level;
+
+	*buffer = NULL;
+	*buffer_len = 0;
+
+	buf_len = 4;
+	if (secattr->set_mls_cat)
+		buf_len += CIPSO_V4_TAG1_CAT_LEN;
+
+	buf = kzalloc(CIPSO_V4_HDR_LEN + buf_len, GFP_ATOMIC);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	if (secattr->set_mls_cat) {
+		cat_len = cipso_v4_map_cat_rbm_hton(doi_def,
+						    secattr->mls_cat,
+						    secattr->mls_cat_len,
+						    &buf[CIPSO_V4_HDR_LEN + 4],
+						    CIPSO_V4_TAG1_CAT_LEN);
+		if (cat_len < 0) {
+			ret_val = cat_len;
+			goto gentag_failure;
+		}
+		/* PM - make this a sysctl adjustable value? */
+#if 0
+		/* XXX - this will send packets using the "optimized" format 
+		   when possibile as specified in  section 3.4.2.6 of the 
+		   CIPSO draft */
+		if (cat_len > 0 && cat_len < 10)
+			cat_len = 10;
+#endif
+	}
+	buf_len = 4 + cat_len;
+
+	ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
+	if (ret_val != 0)
+		goto gentag_failure;
+
+	ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf);
+	if (ret_val != 0)
+		goto gentag_failure;
+
+	buf[CIPSO_V4_HDR_LEN + 0] = 0x01;
+	buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
+	buf[CIPSO_V4_HDR_LEN + 3] = level;
+
+	*buffer = buf;
+	*buffer_len = CIPSO_V4_HDR_LEN + 4 + cat_len;
+
+	return 0;
+
+gentag_failure:
+	if (buf)
+		kfree(buf);
+	return ret_val;
+}
+
+/**
+ * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
+ * attributes in @secattr.  Return zero on success, negatives values on
+ * failure.
+ *
+ */
+static inline int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
+					const unsigned char *tag,
+					struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	u8 tag_len = tag[1];
+	u32 level;
+
+	ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
+	if (ret_val != 0)
+		return ret_val;
+	secattr->mls_lvl = level;
+	secattr->set_mls_lvl = 1;
+
+	if (tag_len > 4) {
+		switch (doi_def->type) {
+		case CIPSO_V4_MAP_STD:
+			secattr->mls_cat_len = 
+				doi_def->map.std->cat.local_size;
+			break;
+		case CIPSO_V4_MAP_PASS:
+			secattr->mls_cat_len = tag_len - 4;
+			break;
+		}
+		secattr->mls_cat = kzalloc(secattr->mls_cat_len,
+						   GFP_ATOMIC);
+		if (secattr->mls_cat == NULL)
+			return -ENOMEM;
+
+		ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
+						    &tag[4],
+						    tag_len - 4,
+						    secattr->mls_cat,
+						    secattr->mls_cat_len);
+		if (ret_val < 0) {
+			kfree(secattr->mls_cat);
+			return ret_val;
+		}
+		secattr->mls_cat_len = ret_val;
+		secattr->set_mls_cat = 1;
+	}
+
+	return 0;
+}
+
+/** 
+ * cipso_v4_validate - Validate a CIPSO option
+ * @option: the start of the option, on error it is set to point to the error
+ *
+ * Description:
+ * This routine is called to validate a CIPSO option, it checks all of the
+ * fields to ensure that they are at least valid, see the draft snippet below
+ * for details.  If the option is valid then a zero value is returned and
+ * the value of @option is unchanged.  If the option is invalid then a
+ * non-zero value is returned and @option is adjusted to point to the
+ * offending portion of the option.  From the IETF draft ...
+ *
+ *  "If any field within the CIPSO options, such as the DOI identifier, is not
+ *   recognized the IP datagram is discarded and an ICMP 'parameter problem'
+ *   (type 12) is generated and returned.  The ICMP code field is set to 'bad
+ *   parameter' (code 0) and the pointer is set to the start of the CIPSO field
+ *   that is unrecognized."
+ *
+ */
+int cipso_v4_validate(unsigned char **option)
+{
+	unsigned char *opt = *option;
+	unsigned char *tag;
+	unsigned char opt_iter;
+	unsigned char err_offset = 0;
+	unsigned char locked = 0;
+	u8 opt_len;
+	u8 tag_len;
+	struct cipso_v4_doi *doi_def = NULL;
+	u32 tag_iter;
+
+	/* XXX: caller already checks for length values that are too large */
+	opt_len = opt[1];
+	if (opt_len < 9) {
+		err_offset = 1;
+		goto validate_return;
+	}
+
+	rcu_read_lock();
+	locked = 1;
+	doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *) & opt[2])));
+	if (doi_def == NULL) {
+		err_offset = 2;
+		goto validate_return;
+	}
+
+	opt_iter = 6;
+	tag = opt + opt_iter;
+	while (opt_iter < opt_len) {
+		for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
+			if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
+			    ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
+				err_offset = opt_iter;
+				goto validate_return;
+			}
+
+		tag_len = tag[1];
+		if (tag_len > (opt_len - opt_iter)) {
+			err_offset = opt_iter + 1;
+			goto validate_return;
+		}
+
+		switch (tag[0]) {
+		case CIPSO_V4_TAG_RBITMAP:
+			if (tag_len < 4) {
+				err_offset = opt_iter + 1;
+				goto validate_return;
+			}
+			if (tag[2] != 0) {
+				err_offset = opt_iter + 2;
+				goto validate_return;
+			}
+			/* PM - how detailed a check do we need to make, are
+			   these last two checks (level and category)
+			   neccessary at this level?  would our decoding
+			   at the upper levels fail if we don't check the
+			   values here?  need input from interop testing */
+			if (cipso_v4_map_lvl_valid(doi_def, tag[3]) < 0) {
+				err_offset = opt_iter + 3;
+				goto validate_return;
+			}
+			if (tag_len > 4 &&
+			    cipso_v4_map_cat_rbm_valid(doi_def,
+						       &tag[4],
+						       tag_len - 4) < 0) {
+				err_offset = opt_iter + 4;
+				goto validate_return;
+			}
+			break;
+		case CIPSO_V4_TAG_ENUM:
+		case CIPSO_V4_TAG_RANGE:
+		case CIPSO_V4_TAG_PBITMAP:
+		case CIPSO_V4_TAG_FREEFORM:
+		default:
+			err_offset = opt_iter;
+			goto validate_return;
+		}
+
+		tag += tag_len;
+		opt_iter += tag_len;
+	}
+
+validate_return:
+	if (locked)
+		rcu_read_unlock();
+	*option = opt + err_offset;
+	return err_offset;
+}
+
+/**
+ * cipso_v4_error - Send the correct reponse for a bad packet
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: CIPSO gateway flag
+ *
+ * Description:
+ * Based on the error code given in @error, send an ICMP error message back to
+ * the originating host.  Returns zero on success, negative values on failure.
+ * From the IETF draft ...
+ *
+ *  "If the contents of the CIPSO [option] are valid but the security label is
+ *   outside of the configured host or port label range, the datagram is 
+ *   discarded and an ICMP 'destination unreachable' (type 3) is generated and
+ *   returned.  The code field of the ICMP is set to 'communication with
+ *   destination network administratively prohibited' (code 9) or to
+ *   'communication with destination host administratively prohibited' 
+ *   (code 10).  The value of the code is dependent on whether the originator
+ *   of the ICMP message is acting as a CIPSO host or a CIPSO gateway.  The
+ *   recipient of the ICMP message MUST be able to handle either value.  The
+ *   same procedure is performed if a CIPSO [option] can not be added to an
+ *   IP packet because it is too large to fit in the IP options area."
+ *
+ *  "If the error is triggered by receipt of an ICMP message, the message is
+ *   discarded and no response is permitted (consistent with general ICMP
+ *   processing rules)." 
+ *
+ */
+int cipso_v4_error(struct sk_buff *skb, 
+		   const int error, 
+		   const u32 gateway)
+{
+	BUG_ON(skb == NULL);
+
+	switch (error) {
+	case -EACCES:
+		break;
+	default:
+		return 0;
+	}
+
+	if (skb->nh.iph->protocol == IPPROTO_ICMP)
+		return 0;
+
+	if (gateway)
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
+	else
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
+
+	return 0;
+}
+
+/**
+ * cipso_v4_socket_setattr - Add a CIPSO option to a socket
+ * @sock: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  Returns zero on success and
+ * negative values on failure.
+ *
+ */
+int cipso_v4_socket_setattr(const struct socket *sock,
+			    const struct cipso_v4_doi *doi_def,
+			    const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -EPERM;
+	u32 iter;
+	unsigned char *buf = NULL;
+	u32 buf_len;
+	struct ip_options *opt = NULL;
+	struct sock *sk;
+	struct inet_sock *sk_inet;
+	struct inet_connection_sock *sk_conn;
+
+	BUG_ON(sock == NULL || doi_def == NULL || secattr == NULL);
+
+	/* In the case of sock_create_lite(), the sock->sk field is not
+	   defined yet but it is not a problem as the only users of these
+	   "lite" PF_INET sockets are functions which do an accept() call
+	   afterwards so we will label the socket as part of the accept(). */
+	/* PM - test this, nfs/sunrpc is a "lite" socket user */
+	sk = sock->sk;
+	if (sk == NULL)
+		return 0;
+
+	/* XXX - this code assumes only one tag per CIPSO option which is
+	   technically against the IETF draft but since we only recognize
+	   the MAC tags right now it's okay */
+	iter = 0;
+	do {
+		switch (doi_def->tags[iter]) {
+		case CIPSO_V4_TAG_RBITMAP:
+			cipso_v4_gentag_rbm(doi_def, secattr, &buf, &buf_len);
+			break;
+		case CIPSO_V4_TAG_ENUM:
+		case CIPSO_V4_TAG_RANGE:
+		case CIPSO_V4_TAG_PBITMAP:
+		case CIPSO_V4_TAG_FREEFORM:
+		default:
+			ret_val = -EPERM;
+			goto socket_setattr_failure;
+		}
+
+		iter++;
+	} while (buf == NULL &&
+		 iter < CIPSO_V4_TAG_MAXCNT &&
+		 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
+
+	if (buf == NULL)
+		goto socket_setattr_failure;
+
+	ret_val = ip_options_get(&opt, buf, buf_len);
+	if (ret_val != 0)
+		goto socket_setattr_failure;
+#if 1
+	/* PM - ip_options_get() sets this, should we clear it?  i say lets
+	 try it as it just makes sense and i'm not sure anyone pays attention
+	 to this flag anyway, if it causes problems we can always remove it */
+	opt->is_setbyuser = 0;
+#endif
+	kfree(buf);
+	buf = NULL;
+
+	lock_sock(sk);
+	sk_inet = inet_sk(sk);
+	if (sk_inet->is_icsk) {
+		sk_conn = inet_csk(sk);
+		if (sk_inet->opt)
+			sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
+		sk_conn->icsk_ext_hdr_len += opt->optlen;
+		sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+	}
+	opt = xchg(&sk_inet->opt, opt);
+	release_sock(sk);
+	if (opt)
+		kfree(opt);
+
+	return 0;
+
+socket_setattr_failure:
+	if (buf)
+		kfree(buf);
+	if (opt)
+		kfree(opt);
+	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;
+	struct sock *sk;
+	struct inet_sock *sk_inet;
+	unsigned char *cipso_ptr;
+	u32 doi;
+	struct cipso_v4_doi *doi_def;
+
+	BUG_ON(sock == NULL || secattr == NULL);
+
+	sk = sock->sk;
+	lock_sock(sk);
+	sk_inet = inet_sk(sk);
+	if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) {
+		release_sock(sk);
+		return -ENOMSG;
+	}
+	cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso - 
+		sizeof(struct iphdr);
+	doi = ntohl(*(u32 *) & cipso_ptr[2]);
+	rcu_read_lock();
+	doi_def = cipso_v4_doi_getdef(doi);
+	if (doi_def == NULL) {
+		rcu_read_unlock();
+		release_sock(sk);
+		return -ENOMSG;
+	}
+	/* XXX - this code assumes only one tag per CIPSO option, the draft is
+	   a little unclear about supporting multiple tags per option
+	   but this seems safe for now */
+	switch (cipso_ptr[6]) {
+	case CIPSO_V4_TAG_RBITMAP:
+		ret_val = cipso_v4_parsetag_rbm(doi_def,
+						&cipso_ptr[6],
+						secattr);
+		break;
+	default:
+		ret_val = -ENOMSG;
+	}
+	rcu_read_unlock();
+	release_sock(sk);
+
+	return ret_val;
+}
+
+/**
+ * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse the given packet's CIPSO option and return the security attributes.
+ * Returns zero on success and negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 
+			    struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	unsigned char *cipso_ptr;
+	u32 doi;
+	struct cipso_v4_doi *doi_def;
+
+	BUG_ON(skb == NULL || secattr == NULL);
+
+	if (cipso_v4_cache_check(skb, secattr) == 0)
+		return 0;
+
+	cipso_ptr = CIPSO_V4_OPTPTR(skb);
+	doi = ntohl(*(u32 *) & cipso_ptr[2]);
+	rcu_read_lock();
+	doi_def = cipso_v4_doi_getdef(doi);
+	if (doi_def == NULL) {
+		rcu_read_unlock();
+		return -ENOMSG;
+	}
+	/* XXX - this code assumes only one tag per CIPSO option, the draft is
+	   a little unclear about supporting multiple tags per option
+	   but this seems safe for now */
+	switch (cipso_ptr[6]) {
+	case CIPSO_V4_TAG_RBITMAP:
+		ret_val = cipso_v4_parsetag_rbm(doi_def,
+						&cipso_ptr[6],
+						secattr);
+		break;
+	default:
+		ret_val = -ENOMSG;
+	}
+	rcu_read_unlock();
+
+	return ret_val;
+}
+
+/*
+ * Setup Functions
+ */
+
+/**
+ * cipso_v4_init - Initialize the CIPSO module
+ *
+ * Description:
+ * Initialize the CIPSO module and prepare it for use.  Returns zero on success
+ * and negative values on failure.
+ *
+ */
+static int __init cipso_v4_init(void)
+{
+	return cipso_v4_cache_init(CIPSO_V4_CACHE_BUCKETS);
+}
+
+/* PM - not sure there is any point to this now, delete this func? */
+/**
+ * cipso_v4_exit - Cleanup after the CIPSO module
+ *
+ * Description:
+ * Perform any necessary cleanup tasks before the CIPSO module goes away.
+ *
+ */
+static void __exit cipso_v4_exit(void)
+{
+	cipso_v4_cache_destroy();
+}
+
+subsys_initcall(cipso_v4_init);
+
diff -purN linux-2.6.16.i686/net/ipv4/ip_options.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/ip_options.c
--- linux-2.6.16.i686/net/ipv4/ip_options.c	2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/ip_options.c	2006-06-13 11:19:59.000000000 -0400
@@ -24,6 +24,7 @@
 #include <net/ip.h>
 #include <net/icmp.h>
 #include <net/route.h>
+#include <net/cipso_ipv4.h>
 
 /* 
  * Write options to IP header, record destination address to
@@ -194,6 +195,13 @@ int ip_options_echo(struct ip_options * 
 			dopt->is_strictroute = sopt->is_strictroute;
 		}
 	}
+	if (sopt->cipso) {
+		optlen  = sptr[sopt->cipso+1];
+		dopt->cipso = dopt->optlen+sizeof(struct iphdr);
+		memcpy(dptr, sptr+sopt->cipso, optlen);
+		dptr += optlen;
+		dopt->optlen += optlen;
+	}
 	while (dopt->optlen & 3) {
 		*dptr++ = IPOPT_END;
 		dopt->optlen++;
@@ -435,6 +443,17 @@ int ip_options_compile(struct ip_options
 			if (optptr[2] == 0 && optptr[3] == 0)
 				opt->router_alert = optptr - iph;
 			break;
+		      case IPOPT_CIPSO:
+		        if (opt->cipso) {
+				pp_ptr = optptr;
+				goto error;
+			}
+			opt->cipso = optptr - iph;
+		        if (cipso_v4_validate(&optptr)) {
+				pp_ptr = optptr;
+				goto error;
+			}
+			break;
 		      case IPOPT_SEC:
 		      case IPOPT_SID:
 		      default:
diff -purN linux-2.6.16.i686/net/ipv4/Makefile linux-2.6.16.i686-netlabel_06132006/net/ipv4/Makefile
--- linux-2.6.16.i686/net/ipv4/Makefile	2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/Makefile	2006-06-13 11:19:59.000000000 -0400
@@ -42,6 +42,7 @@ obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybl
 obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o
 obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o
 obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+obj-$(CONFIG_NETLABEL_CIPSOV4) += cipso_ipv4.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
 		      xfrm4_output.o
diff -purN linux-2.6.16.i686/net/Kconfig linux-2.6.16.i686-netlabel_06132006/net/Kconfig
--- linux-2.6.16.i686/net/Kconfig	2006-06-13 10:47:06.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/Kconfig	2006-06-13 11:19:59.000000000 -0400
@@ -228,6 +228,8 @@ source "net/tux/Kconfig"
 config WIRELESS_EXT
 	bool
 
+source "net/netlabel/Kconfig"
+
 endif   # if NET
 endmenu # Networking
 
diff -purN linux-2.6.16.i686/net/Makefile linux-2.6.16.i686-netlabel_06132006/net/Makefile
--- linux-2.6.16.i686/net/Makefile	2006-06-13 10:47:06.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/Makefile	2006-06-13 11:19:59.000000000 -0400
@@ -47,6 +47,7 @@ obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
+obj-$(CONFIG_NETLABEL)		+= netlabel/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff -purN linux-2.6.16.i686/net/netlabel/Kconfig linux-2.6.16.i686-netlabel_06132006/net/netlabel/Kconfig
--- linux-2.6.16.i686/net/netlabel/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/Kconfig	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,47 @@
+#
+# NetLabel configuration
+#
+
+config NETLABEL
+	bool "NetLabel subsystem support"
+	depends on NET && SECURITY
+	default n
+	---help---
+	  NetLabel provides support for network packet labeling protocols.  For
+	  more information see Documentation/netlabel.
+
+	  If you are unsure, say N.
+
+config NETLABEL_CIPSOV4
+	bool "CIPSO for IPv4"
+	depends on NETLABEL
+	default n
+	---help---
+	  The Commercial IP Security Option (CIPSO) is commonly used in
+	  trusted multi-level security networks.  This implementation is based
+	  on the IETF draft draft-ietf-cipso-ipsecurity-01.txt and FIPS-188.
+
+	  If you are unsure say N.
+
+config NETLABEL_UNLABELED
+	bool "Unlabeled packets"
+	depends on NETLABEL
+	default y
+	---help---
+	  This adds support for sending and receiving unlabeled packets through
+	  the NetLabel system.
+
+	  If you are unsure say Y.
+
+config NETLABEL_UNLABELED_DEFAULT
+	bool "Enable unlabeled traffic by default"
+	depends on NETLABEL_UNLABELED
+	default y
+	---help---
+	  Enabling this option allows unlabeled (i.e. normal) network traffic
+	  on the system without any user configuration at bootup.  Disabling
+	  this option means the user must configure the NetLabel subsystem
+	  before any type of network traffic can be sent or received on the
+	  system.
+
+	  If you are unsure say Y.
diff -purN linux-2.6.16.i686/net/netlabel/Makefile linux-2.6.16.i686-netlabel_06132006/net/netlabel/Makefile
--- linux-2.6.16.i686/net/netlabel/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/Makefile	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,15 @@
+#
+# Makefile for the NetLabel subsystem.
+#
+# Feb 9, 2006, Paul Moore <paul moore hp com>
+#
+
+# base objects
+obj-y	:= netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+
+# management objects
+obj-y	+= netlabel_mgmt.o
+
+# protocol modules
+obj-$(CONFIG_NETLABEL_UNLABELED)	+= netlabel_unlabeled.o
+obj-$(CONFIG_NETLABEL_CIPSOV4)		+= netlabel_cipso_v4.o
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.c
--- linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,580 @@
+/*
+ * NetLabel CIPSO/IPv4 Support
+ *
+ * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "netlabel_user.h"
+#include "netlabel_cipso_v4.h"
+
+/* PM - for debugging only, remove before release */
+#define NETLBL_PRINT(msg) printk msg
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_cipsov4_send_ack(const struct sk_buff *req_skb,
+				    const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_cipsov4_put_hdr - Write a CIPSO NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel CIPSOv4 opcode
+ * @doi: the CIPSO DOI value
+ *
+ * Description:
+ * Use the given values to write a NetLabel CIPSOv4 header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_cipsov4_put_hdr(unsigned char *buffer,
+					  const u32 opcode, 
+					  const u32 doi)
+{
+	struct netlbl_cipsov4_msghdr *hdr =
+		(struct netlbl_cipsov4_msghdr *)buffer;
+	hdr->opcode = opcode;
+	hdr->doi = doi;
+}
+
+/**
+ * netlbl_cipsov4_putinc_hdr - Write a CIPSO NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel CIPSOv4 opcode
+ * @doi: the CIPSO DOI value
+ *
+ * Description:
+ * Use the given values to write a NetLabel CIPSOv4 header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_cipsov4_putinc_hdr(unsigned char **buffer,
+					     const u32 opcode, 
+					     const u32 doi)
+{
+	netlbl_cipsov4_put_hdr(*buffer, opcode, doi);
+	*buffer += sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the CIPSO V4 NetLabel payload.
+ *
+ */
+static inline u32 netlbl_cipsov4_payload_len(const struct sk_buff *skb)
+{
+	const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+	if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_cipsov4_msghdr))
+		return 0;
+	return nlmsg_len(nl_hdr) - sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_payload_data - Returns a pointer to the start of the data
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns a pointer to the start of the CIPSO V4 NetLabel
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_cipsov4_payload_data(
+	const struct sk_buff *skb)
+{
+	return nlmsg_data((struct nlmsghdr *)skb->data) + 
+		sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
+{
+	struct cipso_v4_doi *ptr;
+
+	ptr = container_of(entry, struct cipso_v4_doi, rcu);
+	switch (ptr->type) {
+	case CIPSO_V4_MAP_STD:
+		if (ptr->map.std->lvl.cipso_size > 0)
+			kfree(ptr->map.std->lvl.cipso);
+		if (ptr->map.std->lvl.local_size > 0)
+			kfree(ptr->map.std->lvl.local);
+		if (ptr->map.std->cat.cipso_size > 0)
+			kfree(ptr->map.std->cat.cipso);
+		if (ptr->map.std->cat.local_size > 0)
+			kfree(ptr->map.std->cat.local);
+		break;
+	}
+	kfree(ptr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * 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
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
+ * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
+ * error.
+ *
+ */
+static int netlbl_cipsov4_add_std(const u32 doi,
+				  const unsigned char *msg,
+				  const u32 msg_size)
+{
+	int ret_val = -EPERM;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 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 < 4)
+		goto add_std_failure;
+	num_tags = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
+		goto add_std_failure;
+
+	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+	if (doi_def == NULL) {
+		ret_val = -ENOMEM;
+		goto add_std_failure;
+	}
+	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std),
+				   GFP_KERNEL);
+	if (doi_def->map.std == NULL) {
+		ret_val = -ENOMEM;
+		goto add_std_failure;
+	}
+	doi_def->type = CIPSO_V4_MAP_STD;
+
+	if (msg_len < num_tags)
+		goto add_std_failure;
+	msg_len -= num_tags;
+	for (iter = 0; iter < num_tags; iter++) {
+		doi_def->tags[iter] = netlbl_getinc_u8(&msg_ptr);
+		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 < 24)
+		goto add_std_failure;
+
+	num_lvls = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	if (num_lvls == 0)
+		goto add_std_failure;
+	doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS)
+		goto add_std_failure;
+	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
+					      sizeof(u32), GFP_KERNEL);
+	if (doi_def->map.std->lvl.local == NULL) {
+		ret_val = -ENOMEM;
+		goto add_std_failure;
+	}
+	doi_def->map.std->lvl.cipso_size = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	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);
+	if (doi_def->map.std->lvl.cipso == NULL) {
+		ret_val = -ENOMEM;
+		goto add_std_failure;
+	}
+
+	num_cats = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	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,
+					      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_u32(&msg_ptr);
+	msg_len -= 4;
+	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,
+					      sizeof(u32), GFP_KERNEL);
+	if (doi_def->map.std->cat.cipso == NULL) {
+		ret_val = -ENOMEM;
+		goto add_std_failure;
+	}
+
+	if (msg_len < num_lvls * 8 + num_cats * 8)
+		goto add_std_failure;
+	msg_len -= num_lvls * 8 + num_cats * 8;
+
+	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_ptr);
+		tmp_val_b = netlbl_getinc_u32(&msg_ptr);
+
+		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_ptr);
+		tmp_val_b = netlbl_getinc_u32(&msg_ptr);
+
+		if (tmp_val_a >= doi_def->map.std->cat.local_size ||
+		    tmp_val_b >= doi_def->map.std->cat.cipso_size)
+			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;
+	}
+
+	doi_def->doi = doi;
+	ret_val = cipso_v4_doi_add(doi_def);
+	if (ret_val != 0)
+		goto add_std_failure;
+	return 0;
+
+add_std_failure:
+	if (doi_def)
+		netlbl_cipsov4_doi_free(&doi_def->rcu);
+	return ret_val;
+}
+
+/**
+ * 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
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
+ * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
+ * error.
+ *
+ */
+static int netlbl_cipsov4_add_pass(const u32 doi,
+				   const unsigned char *msg,
+				   const u32 msg_size)
+{
+	int ret_val = -EPERM;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = msg_size;
+	u32 num_tags;
+	struct cipso_v4_doi *doi_def = NULL;
+	u32 iter;
+
+	if (msg_len < 4)
+		goto add_pass_failure;
+	num_tags = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
+		goto add_pass_failure;
+
+	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+	if (doi_def == NULL) {
+		ret_val = -ENOMEM;
+		goto add_pass_failure;
+	}
+	doi_def->type = CIPSO_V4_MAP_PASS;
+
+	if (msg_len < num_tags)
+		goto add_pass_failure;
+	msg_len -= num_tags;
+	for (iter = 0; iter < num_tags; iter++) {
+		doi_def->tags[iter] = netlbl_getinc_u8(&msg_ptr);
+		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;
+
+	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);
+	return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add - Handle an ADD message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Create a new DOI definition based on the given ADD message and add it to the
+ * CIPSO V4 engine.
+ *
+ */
+static void netlbl_cipsov4_add(const struct sk_buff *req_skb,
+			       const u32 doi,
+			       const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	u32 map_type;
+	u32 msg_len = netlbl_cipsov4_payload_len(req_skb);
+
+	if (msg_len < 4) {
+		netlbl_cipsov4_send_ack(req_skb, EINVAL);
+		return;
+	}
+
+	map_type = netlbl_get_u32(msg);
+	switch (map_type) {
+	case CIPSO_V4_MAP_STD:
+		ret_val = netlbl_cipsov4_add_std(doi, msg + 4, msg_len - 4);
+		break;
+	case CIPSO_V4_MAP_PASS:
+		ret_val = netlbl_cipsov4_add_pass(doi, msg + 4, msg_len - 4);
+		break;
+	}
+	netlbl_cipsov4_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_cipsov4_list - Handle a LIST message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Process a user generated LIST message and respond accordingly.
+ *
+ */
+static void netlbl_cipsov4_list(const struct sk_buff *req_skb,
+				const u32 doi,
+				const unsigned char *msg)
+{
+	int ret_val = -ENOMEM;
+	struct sk_buff *skb;
+	unsigned char *buf_ptr;
+
+	skb = cipso_v4_doi_dump(doi, sizeof(struct netlbl_cipsov4_msghdr));
+	if (skb == NULL)
+		goto list_return;
+	buf_ptr = skb_push(skb,
+			   NLMSG_SPACE(sizeof(struct netlbl_cipsov4_msghdr)));
+	if (buf_ptr == NULL) {
+		kfree(skb);
+		ret_val = -EAGAIN;
+		goto list_return;
+	}
+	netlbl_putinc_hdr(&buf_ptr,
+			  NETLBL_NLTYPE_CIPSOV4,
+			  skb->len,
+			  0,
+			  NETLINK_CB(req_skb).pid,
+			  0);
+	netlbl_cipsov4_putinc_hdr(&buf_ptr, NL_CV4_LIST, 0);
+
+	ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+list_return:
+	if (ret_val != 0)
+		netlbl_cipsov4_send_ack(skb, -ret_val);
+}
+
+/**
+ * netlbl_cipsov4_remove - Handle a REMOVE message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Process a user generated REMOVE message and respond accordingly.
+ *
+ */
+static void netlbl_cipsov4_remove(const struct sk_buff *req_skb,
+				 const u32 doi, 
+				 const unsigned char *msg)
+{
+	int ret_val;
+
+	ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
+	netlbl_cipsov4_send_ack(req_skb, -ret_val);
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_cipsov4_send_ack - Send an ACK message
+ * @req_skb: the NETLINK buffer
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @req_skb.
+ *
+ */
+static void netlbl_cipsov4_send_ack(const struct sk_buff *req_skb,
+				    const u32 ret_code)
+{
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_ack_hdr;
+	unsigned char *data;
+
+	data_size = sizeof(struct netlbl_cipsov4_msghdr) + 8;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL)
+		return;
+
+	nl_ack_hdr = NLMSG_PUT(skb,
+			       NETLINK_CB(req_skb).pid,
+			       0,
+			       NETLBL_NLTYPE_CIPSOV4,
+			       data_size);
+	nl_ack_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_ack_hdr);
+	netlbl_cipsov4_putinc_hdr(&data, NL_CV4_ACK, 0);
+	netlbl_putinc_u32(&data,
+			  ((struct nlmsghdr *)req_skb->data)->nlmsg_seq);
+	netlbl_putinc_u32(&data, ret_code);
+
+	netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+	return;
+
+nlmsg_failure:
+	kfree_skb(skb);
+}
+
+/**
+ * netlbl_cipsov4_rcv - Process incoming NetLabel packets
+ * @skb: the NETLINK buffer
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming CIPSO V4
+ * NetLabel traffic and dispatching it to the correct CIPSO V4 functions.
+ *
+ */
+void netlbl_cipsov4_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+	struct netlbl_cipsov4_msghdr *nl_cv4_hdr;
+
+	if (nlmsg_len((struct nlmsghdr *)skb->data) < 
+	    sizeof(struct netlbl_cipsov4_msghdr)) {
+		netlbl_cipsov4_send_ack(skb, EINVAL);
+		return;
+	}
+
+	nl_cv4_hdr = (struct netlbl_cipsov4_msghdr *)msg;
+	switch (nl_cv4_hdr->opcode) {
+	case NL_CV4_ADD:
+		netlbl_cipsov4_add(skb,
+				   nl_cv4_hdr->doi,
+				   netlbl_cipsov4_payload_data(skb));
+		break;
+	case NL_CV4_REMOVE:
+		netlbl_cipsov4_remove(skb,
+				      nl_cv4_hdr->doi,
+				      netlbl_cipsov4_payload_data(skb));
+		break;
+	case NL_CV4_LIST:
+		netlbl_cipsov4_list(skb,
+				    nl_cv4_hdr->doi,
+				    netlbl_cipsov4_payload_data(skb));
+		break;
+	default:
+		netlbl_cipsov4_send_ack(skb, EINVAL);
+		return;
+	}
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.h
--- linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,201 @@
+/*
+ * NetLabel CIPSO/IPv4 Support
+ *
+ * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_CIPSO_V4
+#define _NETLABEL_CIPSO_V4
+
+#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
+ *
+ * o ADD:
+ *   Sent by an application to add a new DOI mapping table, after completion
+ *   of the task the kernel should ACK this message.
+ *
+ *   +--------------------+---------------------+
+ *   | map type (32 bits) | tag count (32 bits) | ...
+ *   +--------------------+---------------------+
+ *
+ *   +-----------------+
+ *   | tag #X (8 bits) | ... repeated
+ *   +-----------------+
+ *
+ *   +-------------- ---- --- -- -
+ *   | mapping data
+ *   +-------------- ---- --- -- -
+ *
+ *     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 (32 bits) | ...
+ *   +------------------+-----------------------+-----------------------+
+ *
+ *   +----------------------+---------------------+---------------------+
+ *   | categories (32 bits) | max l cat (32 bits) | max r cat (32 bits) | ...
+ *   +----------------------+---------------------+---------------------+
+ *
+ *   +--------------------------+--------------------------+
+ *   | local level #X (32 bits) | CIPSO level #X (32 bits) | ... repeated
+ *   +--------------------------+--------------------------+
+ *
+ *   +-----------------------------+-----------------------------+
+ *   | local category #X (32 bits) | CIPSO category #X (32 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
+ *
+ *   CIPSO_V4_MAP_PASS
+ *
+ *   No mapping data is needed for this map type.
+ *
+ * o REMOVE:
+ *   Sent by an application to remove a specific DOI mapping table from the
+ *   CIPSO V4 system.  This message does not contain a payload.  The kernel
+ *   should ACK this message.
+ *
+ * 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.  If the application sets the DOI field
+ *   to zero in the CIPSO V4 message header then the kernel should respond
+ *   with a list of valid DOIs.  If the application sets the DOI field equal to
+ *   a non-zero value then the kernel should respond with the matching mapping
+ *   table.  In the case of an error the kernel should respond with an ACK
+ *   message.
+ *
+ *   DOI Listing (DOI == 0)
+ *
+ *   +---------------------+------------------+-----------------------+
+ *   | DOI count (32 bits) | DOI #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_*)
+ *
+ *   DOI Mapping Table (DOI != 0)
+ *
+ *   +--------------------+
+ *   | 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 (32 bits) | ... repeated
+ *   +--------------------------+--------------------------+
+ *
+ *   +-----------------------------+-----------------------------+
+ *   | local category #X (32 bits) | CIPSO category #X (32 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
+ *
+ */
+
+/* CIPSO V4 message header */
+struct netlbl_cipsov4_msghdr {
+	enum { NL_CV4_NOOP,
+	       NL_CV4_ACK,
+	       NL_CV4_ADD,
+	       NL_CV4_REMOVE,
+	       NL_CV4_LIST
+	} opcode;
+	u32 doi;
+};
+
+/* Process CIPSO V4 NetLabel messages */
+void netlbl_cipsov4_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_domainhash.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.c
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,629 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
+
+struct netlbl_domhsh_tbl {
+	struct list_head *tbl;
+	u32 size;
+};
+
+/* Domain hash table */
+/* XXX - updates should be so rare that having one spinlock for the entire
+   hash table should be okay */
+DEFINE_SPINLOCK(netlbl_domhsh_lock);
+static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
+
+/* Default domain mapping */
+DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
+static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
+
+/*
+ * Domain Hash Table Helper Functions
+ */
+
+/**
+ * netlbl_domhsh_free_entry - Frees a domain hash table entry
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to a hash table entry can be released
+ * safely.
+ *
+ */
+static void netlbl_domhsh_free_entry(struct rcu_head *entry)
+{
+	struct netlbl_dom_map *ptr;
+
+	ptr = container_of(entry, struct netlbl_dom_map, rcu);
+	if (ptr->domain)
+		kfree(ptr->domain);
+	kfree(ptr);
+}
+
+/**
+ * netlbl_domhsh_hash - Hashing function for the domain hash table
+ * @domain: the domain name to hash
+ *
+ * Description:
+ * This is the hashing function for the domain hash table, it returns the
+ * correct bucket number for the domain.  The caller is responsibile for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+static inline u32 netlbl_domhsh_hash(const char *domain)
+{
+	char *p;
+	char *keyp = (char *)domain;
+	u32 size;
+	u32 val = 0;
+
+	/* This is taken (with slight modification) from 
+	   security/selinux/ss/symtab.c:symhash() */
+
+	size = strlen(keyp);
+	for (p = keyp; (p - keyp) < size; p++)
+		val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ (*p);
+	return val & (rcu_dereference(netlbl_domhsh)->size - 1);
+}
+
+/**
+ * netlbl_domhsh_search - Search for a domain entry
+ * @domain: the domain
+ * @def: return default if no match is found
+ *
+ * Description:
+ * Searches the domain hash table and returns a pointer to the hash table
+ * entry if found, otherwise NULL is returned.  If @def is non-zero and a
+ * match is not found in the domain hash table the default mapping is returned
+ * if it exists.  The caller is responsibile for the rcu hash table locks
+ * (i.e. the caller much call rcu_read_[un]lock()).
+ *
+ */
+static inline struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, 
+							  const u32 def)
+{
+	u32 bkt;
+	struct netlbl_dom_map *iter;
+
+	if (domain != NULL) {
+		bkt = netlbl_domhsh_hash(domain);
+		list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list)
+			if (iter->valid && strcmp(iter->domain, domain) == 0)
+				return iter;
+	}
+
+	if (def != 0) {
+		iter = rcu_dereference(netlbl_domhsh_def);
+		if (iter != NULL && iter->valid)
+			return iter;
+	}
+
+	return NULL;
+}
+
+/*
+ * Domain Hash Table Functions
+ */
+
+/**
+ * netlbl_domhsh_init - Init for the domain hash
+ * @size: the number of bits to use for the hash buckets
+ *
+ * Description:
+ * Initializes the domain hash table, should be called only by
+ * netlbl_user_init() during module load.  Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+int __init netlbl_domhsh_init(const u32 size)
+{
+	u32 iter;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+
+	if (size <= 0)
+		return -EINVAL;
+
+	hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
+	if (hsh_tbl == NULL)
+		return -ENOMEM;
+	hsh_tbl->size = 1 << size;
+	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
+			       sizeof(struct list_head),
+			       GFP_KERNEL);
+	if (hsh_tbl->tbl == NULL) {
+		kfree(hsh_tbl);
+		return -ENOMEM;
+	}
+	for (iter = 0; iter < hsh_tbl->size; iter++)
+		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
+
+	rcu_read_lock();
+	spin_lock(&netlbl_domhsh_lock);
+	rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
+	spin_unlock(&netlbl_domhsh_lock);
+	rcu_read_unlock();
+
+	return 0;
+}
+
+/**
+ * netlbl_domhsh_exit - Cleanup for the domain hash
+ *
+ * Description:
+ * Clears and frees the domain hash table.  No real serious effort is made
+ * towards locking but that shouldn't be an issue since we should only be
+ * called when the module is being unloaded.  Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+void netlbl_domhsh_exit(void)
+{
+	u32 iter_bkt;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+	struct netlbl_dom_map *iter_list;
+
+	rcu_read_lock();
+	if (rcu_dereference(netlbl_domhsh) == NULL) {
+		rcu_read_unlock();
+		return;
+	}
+	iter_list = rcu_dereference(netlbl_domhsh_def);
+	spin_lock(&netlbl_domhsh_def_lock);
+	rcu_assign_pointer(netlbl_domhsh_def, NULL);
+	spin_unlock(&netlbl_domhsh_def_lock);
+	rcu_read_unlock();
+
+	if (iter_list) {
+		synchronize_rcu();
+		netlbl_domhsh_free_entry(&iter_list->rcu);
+	}
+
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	spin_lock(&netlbl_domhsh_lock);
+	rcu_assign_pointer(netlbl_domhsh, NULL);
+	spin_unlock(&netlbl_domhsh_lock);
+	rcu_read_unlock();
+
+	synchronize_rcu();
+
+	/* PM - it probably doesn't matter, but do we need to use the rcu list
+	   functions here since we are the only one who has access to the
+	   list now? */
+	for (iter_bkt = 0; iter_bkt < hsh_tbl->size; iter_bkt++)
+		list_for_each_entry_rcu(iter_list,
+					&hsh_tbl->tbl[iter_bkt], list) {
+			iter_list->valid = 0;
+			list_del_rcu(&iter_list->list);
+			netlbl_domhsh_free_entry(&iter_list->rcu);
+		}
+	kfree(hsh_tbl->tbl);
+	kfree(hsh_tbl);
+
+	return;
+}
+
+/**
+ * netlbl_domhsh_add - Adds a entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new entry to the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry)
+{
+	int ret_val = -EPERM;
+	u32 bkt;
+
+	BUG_ON(entry == NULL);
+
+	switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = 0;
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
+						  entry->domain);
+		break;
+#endif
+	default:
+		BUG();
+	}
+	if (ret_val != 0)
+		return ret_val;
+
+	entry->valid = 1;
+	INIT_RCU_HEAD(&entry->rcu);
+
+	rcu_read_lock();
+	if (entry->domain != NULL &&
+	    netlbl_domhsh_search(entry->domain, 0) == NULL) {
+		bkt = netlbl_domhsh_hash(entry->domain);
+		spin_lock(&netlbl_domhsh_lock);
+		list_add_tail_rcu(&entry->list, &netlbl_domhsh->tbl[bkt]);
+		spin_unlock(&netlbl_domhsh_lock);
+	} else if (entry->domain == NULL &&
+		   rcu_dereference(netlbl_domhsh_def) == NULL) {
+		INIT_LIST_HEAD(&entry->list);
+		spin_lock(&netlbl_domhsh_def_lock);
+		rcu_assign_pointer(netlbl_domhsh_def, entry);
+		spin_unlock(&netlbl_domhsh_def_lock);
+	} else {
+		rcu_read_unlock();
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+						       entry->domain) != 0)
+				BUG();
+			break;
+#endif
+		default:
+			BUG();
+		}
+		return -EPERM;
+	}
+	rcu_read_unlock();
+
+	return 0;
+}
+
+/**
+ * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new default entry to the domain hash table and handles any updates
+ * to the lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry)
+{
+	return netlbl_domhsh_add(entry);
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain)
+{
+	int ret_val = -EPERM;
+	struct netlbl_dom_map *entry;
+
+	rcu_read_lock();
+	if (domain != NULL)
+		entry = netlbl_domhsh_search(domain, 0);
+	else
+		entry = netlbl_domhsh_search(domain, 1);
+	if (entry == NULL)
+		goto remove_return;
+	switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+					       entry->domain) != 0)
+			goto remove_return;
+		break;
+#endif
+	default:
+		BUG();
+	}
+	if (entry != rcu_dereference(netlbl_domhsh_def)) {
+		spin_lock(&netlbl_domhsh_lock);
+		entry->valid = 0;
+		list_del_rcu(&entry->list);
+		spin_unlock(&netlbl_domhsh_lock);
+	} else {
+		spin_lock(&netlbl_domhsh_def_lock);
+		entry->valid = 0;
+		rcu_assign_pointer(netlbl_domhsh_def, NULL);
+		spin_unlock(&netlbl_domhsh_def_lock);
+	}
+	call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+
+	ret_val = 0;
+
+remove_return:
+	rcu_read_unlock();
+	return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove_default - Removes the default entry from the table
+ *
+ * Description:
+ * Removes/resets the default entry for the domain hash table and handles any
+ * updates to the lower level protocol handler (i.e. CIPSO).  Returns zero on
+ * success, non-zero on failure.
+ *
+ */
+int netlbl_domhsh_remove_default(void)
+{
+	return netlbl_domhsh_remove(NULL);
+}
+
+/**
+ * netlbl_domhsh_getentry - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain,
+ * return a pointer to a copy of the entry or NULL.  The caller is responsibile
+ * for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
+{
+	return netlbl_domhsh_search(domain, 1);
+}
+
+/**
+ * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff
+ *
+ * Description:
+ * Dump the domain hash table into a buffer suitable for returning to an
+ * application in response to a NetLabel management DOMAIN message.  This
+ * function may fail if another process is growing the hash table at the same
+ * time.  The returned sk_buff has room at the front of the sk_buff for
+ * a nlmsghdr struct and a netlbl_mgmt_msghdr struct.  See netlabel.h for the
+ * DOMAIN message format.  Returns a pointer to a sk_buff on success, NULL on
+ * error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump(void)
+{
+	struct sk_buff *skb;
+	unsigned char *buf;
+	u32 buf_len;
+	u32 bkt_iter;
+	u32 dom_cnt = 0;
+	struct netlbl_domhsh_tbl *hsh_tbl;
+	struct netlbl_dom_map *list_iter;
+	u32 tmp_len;
+
+	/* XXX - This is kinda ugly as we have to go through the table once to
+	   determine how large of a buffer we need, drop the locks, allocate
+	   the buffer, grab the locks, and finally fill the buffer.  The
+	   problem is that there is that open window where the table could
+	   grow and we will end up short on space. */
+
+	buf_len = 4;
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+		list_for_each_entry_rcu(list_iter,
+					&hsh_tbl->tbl[bkt_iter], list) {
+			buf_len += 9 + strlen(list_iter->domain);
+			switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+			case NETLBL_NLTYPE_UNLABELED:
+				break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+			case NETLBL_NLTYPE_CIPSOV4:
+				buf_len += 8;
+				break;
+#endif
+			default:
+				rcu_read_unlock();
+				BUG();
+			}
+			dom_cnt++;
+		}
+	rcu_read_unlock();
+
+	skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+				    buf_len), GFP_KERNEL);
+	if (skb == NULL)
+		return NULL;
+	skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	tmp_len = skb_tailroom(skb);
+	if (tmp_len < buf_len)
+		goto dump_failure;
+	buf = skb_put(skb, buf_len);
+	buf_len -= 4;
+	netlbl_putinc_u32(&buf, dom_cnt);
+
+	rcu_read_lock();
+	hsh_tbl = rcu_dereference(netlbl_domhsh);
+	for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+		list_for_each_entry_rcu(list_iter,
+					&hsh_tbl->tbl[bkt_iter], list) {
+			tmp_len = strlen(list_iter->domain) + 1;
+			if (buf_len < tmp_len + 8) {
+				rcu_read_unlock();
+				goto dump_failure;
+			}
+			buf_len -= tmp_len + 8;
+			netlbl_putinc_u32(&buf, tmp_len);
+			netlbl_putinc_str(&buf, list_iter->domain);
+			netlbl_putinc_u32(&buf, list_iter->type);
+			switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+			case NETLBL_NLTYPE_UNLABELED:
+				break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+			case NETLBL_NLTYPE_CIPSOV4:
+				if (buf_len < 8) {
+					rcu_read_unlock();
+					goto dump_failure;
+				}
+				buf_len -= 8;
+				netlbl_putinc_u32(&buf,
+					    list_iter->type_def.cipsov4->type);
+				netlbl_putinc_u32(&buf,
+					    list_iter->type_def.cipsov4->doi);
+				break;
+#endif
+			default:
+				rcu_read_unlock();
+				BUG();
+			}
+		}
+	rcu_read_unlock();
+
+	return skb;
+
+dump_failure:
+	kfree_skb(skb);
+	return NULL;
+}
+
+/**
+ * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff
+ *
+ * Description:
+ * Dump the default domain mapping into a buffer suitable for returning to an
+ * application in response to a NetLabel management DEFDOMAIN message.  This
+ * function may fail if another process is changing the default domain mapping
+ * at the same time.  The returned sk_buff has room at the front of the
+ * skb_buff for a nlmsghdr struct and a netlbl_mgmt_msghdr struct.  See
+ * netlabel.h for the DEFDOMAIN message format.  Returns a pointer to a
+ * sk_buff on success, NULL on error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump_default(void)
+{
+	struct sk_buff *skb;
+	unsigned char *buf;
+	u32 buf_len;
+	u32 tmp_len;
+	struct netlbl_dom_map *entry;
+
+	/* XXX - This is kinda ugly as we have to go look at the default 
+	   mapping once to determine how large of a buffer we need, drop the
+	   locks, allocate the buffer, grab the locks, and finally fill the
+	   buffer.  The problem is that there is that open window where the
+	   default mapping could change on us, if that is the case we fail. */
+
+	buf_len = 4;
+	rcu_read_lock();
+	entry = rcu_dereference(netlbl_domhsh_def);
+	if (entry != NULL)
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			buf_len += 8;
+			break;
+#endif
+		default:
+			BUG();
+		}
+	rcu_read_unlock();
+
+	skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+				    buf_len), GFP_KERNEL);
+	if (skb == NULL)
+		return NULL;
+	skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	tmp_len = skb_tailroom(skb);
+	if (tmp_len < buf_len)
+		goto dump_default_failure;
+	buf = skb_put(skb, buf_len);
+
+	rcu_read_lock();
+	if (entry != rcu_dereference(netlbl_domhsh_def)) {
+		rcu_read_unlock();
+		goto dump_default_failure;
+	}
+	buf_len -= 4;
+	if (entry != NULL) {
+		netlbl_putinc_u32(&buf, entry->type);
+		switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (buf_len < 8) {
+				rcu_read_unlock();
+				goto dump_default_failure;
+			}
+			buf_len -= 8;
+			netlbl_putinc_u32(&buf, entry->type_def.cipsov4->type);
+			netlbl_putinc_u32(&buf, entry->type_def.cipsov4->doi);
+			break;
+#endif
+		default:
+			rcu_read_unlock();
+			BUG();
+		}
+	} else
+		netlbl_putinc_u32(&buf, NETLBL_NLTYPE_NONE);
+	rcu_read_unlock();
+
+	return skb;
+
+dump_default_failure:
+	kfree_skb(skb);
+	return NULL;
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_domainhash.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.h
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,64 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_DOMAINHASH_H
+#define _NETLABEL_DOMAINHASH_H
+
+/* Domain hash table size */
+/* XXX - currently this number is an uneducated guess */
+#define NETLBL_DOMHSH_BITSIZE       7
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map {
+	char *domain;
+	u32 type;
+	union {
+		struct cipso_v4_doi *cipsov4;
+	} type_def;
+
+	u32 valid;
+	struct list_head list;
+	struct rcu_head rcu;
+};
+
+/* init/exit functions */
+int netlbl_domhsh_init(const u32 size) __init;
+void netlbl_domhsh_exit(void) __exit;
+
+/* Manipulate the domain hash table */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry);
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry);
+int netlbl_domhsh_remove_default(void);
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct sk_buff *netlbl_domhsh_dump(void);
+struct sk_buff *netlbl_domhsh_dump_default(void);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_kapi.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_kapi.c
--- linux-2.6.16.i686/net/netlabel/netlabel_kapi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_kapi.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,420 @@
+/*
+ * NetLabel Kernel API
+ *
+ * This file defines the kernel API for the NetLabel system.  The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <net/ip.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_unlabeled.h"
+
+/*
+ * LSM Functions
+ */
+
+/**
+ * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct
+ * @flags: the memory allocation flags
+ *
+ * Description:
+ * Allocate and initialize a netlbl_lsm_secattr struct.  Returns a valid
+ * pointer on success, or NULL on failure.
+ *
+ */
+struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags)
+{
+	return kzalloc(sizeof(struct netlbl_lsm_secattr), flags);
+}
+
+/**
+ * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
+ * @secattr: the struct to free
+ *
+ * Description:
+ * Frees @secattr including all of the internal buffers.
+ *
+ */
+void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	if (secattr->set_domain)
+		kfree(secattr->domain);
+	if (secattr->set_mls_cat)
+		kfree(secattr->mls_cat);
+	if (secattr->set_cache && secattr->cache.free)
+		secattr->cache.free(secattr->cache.data);
+	kfree(secattr);
+}
+
+/**
+ * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
+ * @secattr: the struct to initialize
+ *
+ * Description:
+ * Initialize an already allocated netlbl_lsm_secattr struct.  Returns zero on
+ * success, negative values on error.
+ *
+ */
+int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	memset(secattr, 0, sizeof(*secattr));
+	return 0;
+}
+
+/**
+ * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
+ * @secattr: the struct to clear
+ *
+ * Description:
+ * Destroys the @secattr struct, including freeing all of the internal buffers.
+ * On return the struct is suitable for reuse.
+ *
+ */
+void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+	if (secattr->set_domain)
+		kfree(secattr->domain);
+	if (secattr->set_mls_cat)
+		kfree(secattr->mls_cat);
+	if (secattr->set_cache && secattr->cache.free)
+		secattr->cache.free(secattr->cache.data);
+	memset(secattr, 0, sizeof(*secattr));
+}
+
+/**
+ * netlbl_socket_setattr - Label a socket using the correct protocol
+ * @sock: the socket to label
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given socket using the security attributes
+ * specified in @secattr.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_setattr(const struct socket *sock, 
+			  const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+	struct netlbl_dom_map *dom_entry;
+
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(sock == NULL);
+	BUG_ON(secattr == NULL);
+	BUG_ON(secattr->set_domain == 0);
+
+	rcu_read_lock();
+	dom_entry = netlbl_domhsh_getentry(secattr->domain);
+	if (dom_entry == NULL) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+	switch (dom_entry->type) {
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		ret_val = cipso_v4_socket_setattr(sock,
+						  dom_entry->type_def.cipsov4,
+						  secattr);
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		ret_val = 0;
+		break;
+#endif
+	default:
+		ret_val = -ENOENT;
+	}
+	rcu_read_unlock();
+
+	return ret_val;
+}
+
+/**
+ * netlbl_socket_peekattr - Get the security attributes on a queued packet
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Peek at the incoming packet queue of @sock and return the security
+ * attributes of the first packet in the queue.  If there are no packets in
+ * the queue or no packets with security attributes return -ENOMSG.  Otherwise
+ * return zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_peekattr(const struct socket *sock, 
+			   struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+	struct sk_buff_head *sock_queue;
+	struct sk_buff *skb;
+	struct sk_buff *skb_tmp = NULL;
+
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(sock == NULL);
+	BUG_ON(sock->sk == NULL);
+	BUG_ON(sock->sk->sk_family != PF_INET);
+	BUG_ON(secattr == NULL);
+
+	sock_queue = &sock->sk->sk_receive_queue;
+	/* XXX - We could just take the lock here and do a skb_peek() but we
+	         might end up holding the lock for a long time so grab the
+		 lock, do a peek, and clone the result */
+	spin_lock(&sock_queue->lock);
+	skb = skb_peek(sock_queue);
+	if (skb != NULL)
+		skb_tmp = skb_clone(skb, GFP_ATOMIC);
+	spin_unlock(&sock_queue->lock);
+	if (skb_tmp != NULL) {
+		ret_val = netlbl_skbuff_getattr(skb_tmp, secattr);
+		kfree_skb(skb_tmp);
+	} else
+		ret_val = -ENOMEM;
+
+	return ret_val;
+}
+
+/**
+ * netlbl_socket_getattr - Determine the security attributes of a socket
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given socket to see any NetLabel style labeling has been
+ * applied to the socket, if so it parses the socket label and returns the
+ * security attributes in @secattr.  Returns zero on success, negative values
+ * on failure.
+ *
+ */
+int netlbl_socket_getattr(const struct socket *sock, 
+			  struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val;
+
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(sock == NULL);
+	BUG_ON(sock->sk == NULL);
+	BUG_ON(sock->sk->sk_family != PF_INET);
+	BUG_ON(secattr == NULL);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	ret_val = cipso_v4_socket_getattr(sock, secattr);
+#endif
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+	if (ret_val != 0)
+		ret_val = netlbl_unlabel_getattr(secattr);
+#endif
+
+	return ret_val;
+}
+
+/**
+ * netlbl_skbuff_getattr - Determine the security attributes of a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given packet to see if a recognized form of packet labeling
+ * is present, if so it parses the packet label and returns the security
+ * attributes in @secattr.  Returns zero on success, negative values on 
+ * failure.
+ *
+ */
+int netlbl_skbuff_getattr(const struct sk_buff *skb, 
+			  struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(skb == NULL);
+	BUG_ON(secattr == NULL);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	if (CIPSO_V4_OPTEXIST(skb)) {
+		ret_val = cipso_v4_skbuff_getattr(skb, secattr);
+		goto skbuff_read_return;
+	}
+#endif
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+	ret_val = netlbl_unlabel_getattr(secattr);
+#endif
+
+skbuff_read_return:
+	return ret_val;
+}
+
+/**
+ * netlbl_skbuff_err - Handle a LSM error on a sk_buff
+ * @skb: the packet
+ * @error: the error code
+ *
+ * Description:
+ * Deal with a LSM problem when handling the packet in @skb, typically this is
+ * a permission denied problem (-EACCES).  The correct action is determined
+ * according to the packet's labeling protocol.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_skbuff_err(struct sk_buff *skb, int error)
+{
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(skb == NULL);
+	BUG_ON(error == 0);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	if (CIPSO_V4_OPTEXIST(skb))
+		return cipso_v4_error(skb, error, 0);
+#endif
+
+	return -ENOMSG;
+}
+
+/**
+ * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
+ *
+ * Description:
+ * For all of the NetLabel protocols that support some form of label mapping
+ * cache, invalidate the cache.  Returns zero on success, negative values on
+ * error.
+ *
+ */
+int netlbl_cache_invalidate(void)
+{
+	return cipso_v4_cache_invalidate();
+}
+
+/**
+ * netlbl_cache_add - Add an entry to a NetLabel protocol cache
+ * @skb: the packet
+ * @secattr: the packet's security attributes
+ *
+ * Description:
+ * Add the LSM security attributes for the given packet to the underlying
+ * NetLabel protocol's label mapping cache.  Returns zero on success, negative
+ * values on error.
+ *
+ */
+int netlbl_cache_add(const struct sk_buff *skb,
+		     const struct netlbl_lsm_secattr *secattr)
+{
+	int ret_val = -ENOMSG;
+
+	/* PM - split these into individual BUGs so we can pinpoint problems
+	   easier */
+	BUG_ON(skb == NULL);
+	BUG_ON(secattr == NULL);
+
+	if (secattr->set_cache != 1)
+		return -ENOMSG;
+
+	if (CIPSO_V4_OPTEXIST(skb))
+		ret_val = cipso_v4_cache_add(skb, secattr);
+
+	return ret_val;
+}
+
+/*
+ * Setup Functions
+ */
+
+/**
+ * netlbl_init - Init for the NetLabel module
+ *
+ * Description:
+ * Perform the initialization of the NetLabel module before first use.
+ *
+ */
+static int __init netlbl_init(void)
+{
+	int ret_val = 0;
+
+	printk(KERN_INFO "NetLabel: Initializing\n");
+	printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
+	       (1 << NETLBL_DOMHSH_BITSIZE));
+	printk(KERN_INFO "NetLabel:  protocols ="
+#ifdef CONFIG_NETLABEL_UNLABELED
+	       " UNLABELED"
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	       " CIPSOv4"
+#endif
+	       "\n");
+
+	ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
+	if (ret_val != 0)
+		goto init_return;
+
+	ret_val = netlbl_netlink_init();
+	if (ret_val != 0)
+		goto init_return;
+
+#ifdef CONFIG_NETLABEL_UNLABELED_DEFAULT
+	ret_val = netlbl_unlabel_defconf();
+	if (ret_val != 0)
+		goto init_return;
+	printk(KERN_INFO "NetLabel:  unlabeled traffic allowed by default\n");
+#endif
+
+init_return:
+	if (ret_val != 0) {
+		netlbl_netlink_exit();
+		netlbl_domhsh_exit();
+	}
+	return ret_val;
+}
+
+/* PM - not sure there is any point to this now, delete this func? */
+/**
+ * netlbl_exit - Cleanup for the NetLabel module
+ * 
+ * Description:
+ * Perform any cleanup required before removing the NetLabel module.
+ *
+ */
+static void __exit netlbl_exit(void)
+{
+	netlbl_netlink_exit();
+	netlbl_domhsh_exit();
+}
+
+subsys_initcall(netlbl_init);
+
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_mgmt.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.c
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,677 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_mgmt.h"
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_mgmt_send_ack(const struct sk_buff *req_skb,
+				 const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_mgmt_put_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_mgmt_put_hdr(unsigned char *buffer, const u32 opcode)
+{
+	((struct netlbl_mgmt_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_mgmt_putinc_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_mgmt_putinc_hdr(unsigned char **buffer, 
+					  const u32 opcode)
+{
+	netlbl_mgmt_put_hdr(*buffer, opcode);
+	*buffer += sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the NetLabel management payload.
+ *
+ */
+static inline u32 netlbl_mgmt_payload_len(const struct sk_buff *skb)
+{
+	const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+	if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_mgmt_msghdr))
+		return 0;
+	return nlmsg_len(nl_hdr) - sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_payload_data - Returns a pointer to the start of the data
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns a pointer to the start of the NetLabel management
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_mgmt_payload_data(
+	const struct sk_buff *skb)
+{
+	return nlmsg_data((struct nlmsghdr *)skb->data) + 
+		sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table.  See netlabel.h for a description of the message format.
+ *
+ */
+static void netlbl_mgmt_add(const struct sk_buff *req_skb,
+			    const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+	u32 count;
+	struct netlbl_dom_map *entry = NULL;
+	u32 iter;
+	u32 tmp_val;
+	u32 rcu_locked = 0;
+
+	if (msg_len < 4)
+		goto add_failure;
+	count = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) {
+		if (msg_len < 4)
+			goto add_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		if (tmp_val == 0)
+			goto add_failure;
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+		if (entry == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+
+		if (msg_len < tmp_val)
+			goto add_failure;
+		entry->domain = kmalloc(tmp_val, GFP_KERNEL);
+		if (entry->domain == NULL) {
+			ret_val = -ENOMEM;
+			goto add_failure;
+		}
+		strncpy(entry->domain, msg_ptr, tmp_val);
+		entry->domain[tmp_val - 1] = '\0';
+		msg_ptr += tmp_val;
+		msg_len -= tmp_val;
+
+		if (msg_len < 4)
+			goto add_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		entry->type = tmp_val;
+		switch (tmp_val) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			if (msg_len < 4)
+				goto add_failure;
+			tmp_val = netlbl_getinc_u32(&msg_ptr);
+			msg_len -= 4;
+			/* XXX - we should be holding a rcu_read_lock() here
+			   while we hold the result but since the entry
+			   will always be deleted when the CIPSO DOI
+			   is deleted we aren't going to keep the lock */
+			rcu_read_lock();
+			entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+			if (entry->type_def.cipsov4 == NULL) {
+				rcu_read_unlock();
+				goto add_failure;
+			}
+			rcu_locked = 1;
+			break;
+#endif
+		default:
+			goto add_failure;
+		}
+
+		ret_val = netlbl_domhsh_add(entry);
+		if (rcu_locked) {
+			rcu_read_unlock();
+			rcu_locked = 0;
+		}
+		if (ret_val != 0)
+			goto add_failure;
+	}
+
+	netlbl_mgmt_send_ack(req_skb, NETLBL_E_OK);
+	return;
+
+add_failure:
+	if (entry) {
+		if (entry->domain)
+			kfree(entry->domain);
+		kfree(entry);
+	}
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_remove - Handle a REMOVE message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVE message and remove the specified domain
+ * mappings.
+ *
+ */
+static void netlbl_mgmt_remove(const struct sk_buff *req_skb,
+			       const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+	u32 count;
+	u32 iter;
+	u32 tmp_val;
+
+	if (msg_len < 4)
+		goto remove_return;
+	count = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	for (iter = 0; iter < count && msg_len > 0; iter++) {
+		if (msg_len < 4)
+			goto remove_return;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		if (tmp_val == 0 ||
+		    msg_len < tmp_val || msg_ptr[tmp_val - 1] != '\0')
+			goto remove_return;
+		ret_val = netlbl_domhsh_remove(msg_ptr);
+		msg_ptr += tmp_val;
+		msg_len -= tmp_val;
+		if (ret_val != 0)
+			goto remove_return;
+	}
+
+	ret_val = 0;
+
+remove_return:
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_list - Handle a LIST message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LIST message and dumps the domain hash table in a
+ * form suitable for use in a kernel generated LIST message.
+ *
+ */
+static void netlbl_mgmt_list(const struct sk_buff *req_skb,
+			     const unsigned char *msg)
+{
+	int ret_val = -ENOMEM;
+	struct sk_buff *skb;
+	unsigned char *buf_ptr;
+
+	skb = netlbl_domhsh_dump();
+	if (skb == NULL)
+		goto list_return;
+	buf_ptr = skb_push(skb, 
+			   NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	if (buf_ptr == NULL) {
+		kfree_skb(skb);
+		ret_val = -EAGAIN;
+		goto list_return;
+	}
+	netlbl_putinc_hdr(&buf_ptr,
+			  NETLBL_NLTYPE_MGMT,
+			  skb->len,
+			  0,
+			  NETLINK_CB(req_skb).pid,
+			  0);
+	netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LIST);
+
+	ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+list_return:
+	if (ret_val != 0)
+		netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_adddef - Handle an ADDDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADDDEF message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_adddef(const struct sk_buff *req_skb,
+			       const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	unsigned char *msg_ptr = (unsigned char *)msg;
+	u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+	u32 type;
+	struct netlbl_dom_map *entry = NULL;
+	u32 tmp_val;
+	u32 rcu_locked = 0;
+
+	if (msg_len < 4)
+		goto adddef_failure;
+	type = netlbl_getinc_u32(&msg_ptr);
+	msg_len -= 4;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL) {
+		ret_val = -ENOMEM;
+		goto adddef_failure;
+	}
+	entry->type = type;
+
+	switch (type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+	case NETLBL_NLTYPE_UNLABELED:
+		break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	case NETLBL_NLTYPE_CIPSOV4:
+		if (msg_len < 4)
+			goto adddef_failure;
+		tmp_val = netlbl_getinc_u32(&msg_ptr);
+		msg_len -= 4;
+		/* XXX - we should be holding a rcu_read_lock here while we
+		   hold the result but since the entry will always be
+		   deleted when the CIPSO DOI is deleted we are going
+		   to skip the lock */
+		rcu_read_lock();
+		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+		if (entry->type_def.cipsov4 == NULL) {
+			rcu_read_unlock();
+			goto adddef_failure;
+		}
+		rcu_locked = 1;
+		break;
+#endif
+	default:
+		ret_val = -EINVAL;
+		goto adddef_failure;
+	}
+
+	ret_val = netlbl_domhsh_add_default(entry);
+	if (rcu_locked) {
+		rcu_read_unlock();
+		rcu_locked = 0;
+	}
+	if (ret_val != 0)
+		goto adddef_failure;
+
+	netlbl_mgmt_send_ack(req_skb, NETLBL_E_OK);
+	return;
+
+adddef_failure:
+	if (entry)
+		kfree(entry);
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_removedef - Handle a REMOVEDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVEDEF message and remove the default domain
+ * mapping.
+ *
+ */
+static void netlbl_mgmt_removedef(const struct sk_buff *req_skb,
+				  const unsigned char *msg)
+{
+	int ret_val;
+
+	ret_val = netlbl_domhsh_remove_default();
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_listdef - Handle a LISTDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LISTDEF message and dumps the default domain
+ * mapping in a form suitable for use in a kernel generated LISTDEF message.
+ *
+ */
+static void netlbl_mgmt_listdef(const struct sk_buff *req_skb,
+				const unsigned char *msg)
+{
+	int ret_val = -ENOMEM;
+	struct sk_buff *skb;
+	unsigned char *buf_ptr;
+
+	skb = netlbl_domhsh_dump_default();
+	if (skb == NULL)
+		goto listdef_return;
+	buf_ptr = skb_push(skb, 
+			   NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+	if (buf_ptr == NULL) {
+		kfree_skb(skb);
+		ret_val = -EAGAIN;
+		goto listdef_return;
+	}
+	netlbl_putinc_hdr(&buf_ptr,
+			  NETLBL_NLTYPE_MGMT,
+			  skb->len, 
+			  0,
+			  NETLINK_CB(req_skb).pid, 
+			  0);
+	netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LISTDEF);
+
+	ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+listdef_return:
+	if (ret_val != 0)
+		netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_modules - Handle a MODULES message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated MODULES message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_modules(const struct sk_buff *req_skb,
+				const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	u32 mod_count = 0;
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nl_mgmt_hdr;
+	unsigned char *data;
+
+	if (netlbl_mgmt_payload_len(req_skb) < 4)
+		goto nlmsg_failure;
+	mod_count = netlbl_get_u32(msg);
+	if (mod_count != 0)
+		goto nlmsg_failure;
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+	mod_count += 1;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	mod_count += 1;
+#endif
+
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 4 + mod_count * 4;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL) {
+		ret_val = -ENOMEM;
+		goto nlmsg_failure;
+	}
+
+	nl_mgmt_hdr = NLMSG_PUT(skb,
+				NETLINK_CB(req_skb).pid,
+				0,
+				NETLBL_NLTYPE_MGMT,
+				data_size);
+	nl_mgmt_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_mgmt_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_MODULES);
+	netlbl_putinc_u32(&data, mod_count);
+#ifdef CONFIG_NETLABEL_UNLABELED
+	netlbl_putinc_u32(&data, NETLBL_NLTYPE_UNLABELED);
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+	netlbl_putinc_u32(&data, NETLBL_NLTYPE_CIPSOV4);
+#endif
+
+	netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+	return;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_version - Handle a VERSION message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated VERSION message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_version(const struct sk_buff *req_skb,
+				const unsigned char *msg)
+{
+	int ret_val = -EINVAL;
+	u32 str_len;
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nl_mgmt_hdr;
+	unsigned char *data;
+
+	if (netlbl_mgmt_payload_len(req_skb) < 4)
+		goto nlmsg_failure;
+	str_len = netlbl_get_u32(msg);
+	if (str_len != 0)
+		goto nlmsg_failure;
+
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 4;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL) {
+		ret_val = -ENOMEM;
+		goto nlmsg_failure;
+	}
+
+	nl_mgmt_hdr = NLMSG_PUT(skb,
+				NETLINK_CB(req_skb).pid,
+				0,
+				NETLBL_NLTYPE_MGMT,
+				data_size);
+	nl_mgmt_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_mgmt_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_VERSION);
+	netlbl_putinc_u32(&data, NETLBL_PROTO_VERSION);
+
+	netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+	return;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_mgmt_send_ack - Send an ACK message
+ * @req_skb: the NETLINK buffer
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @req_skb.  Returns negative values on error. 
+ *
+ */
+static void netlbl_mgmt_send_ack(const struct sk_buff *req_skb,
+				 const u32 ret_code)
+{
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_ack_hdr;
+	unsigned char *data;
+
+	data_size = sizeof(struct netlbl_mgmt_msghdr) + 8;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL)
+		return;
+
+	nl_ack_hdr = NLMSG_PUT(skb,
+			       NETLINK_CB(req_skb).pid,
+			       0,
+			       NETLBL_NLTYPE_MGMT,
+			       data_size);
+	nl_ack_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_ack_hdr);
+	netlbl_mgmt_putinc_hdr(&data, NL_MGMT_ACK);
+	netlbl_putinc_u32(&data, 
+			  ((struct nlmsghdr *)req_skb->data)->nlmsg_seq);
+	netlbl_putinc_u32(&data, ret_code);
+
+	netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+	return;
+
+nlmsg_failure:
+	kfree_skb(skb);
+}
+
+/**
+ * netlbl_mgmt_rcv - Process incoming NetLabel packets
+ * @skb: the NETLINK buffer
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming NetLabel
+ * management traffic and dispatching it to the correct functions.
+ *
+ */
+void netlbl_mgmt_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+	if (nlmsg_len((struct nlmsghdr *)skb->data) < 
+	    sizeof(struct netlbl_mgmt_msghdr)) {
+		netlbl_mgmt_send_ack(skb, EINVAL);
+		return;
+	}
+
+	switch (((struct netlbl_mgmt_msghdr *)msg)->opcode) {
+	case NL_MGMT_ADD:
+		netlbl_mgmt_add(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_REMOVE:
+		netlbl_mgmt_remove(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_LIST:
+		netlbl_mgmt_list(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_ADDDEF:
+		netlbl_mgmt_adddef(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_REMOVEDEF:
+		netlbl_mgmt_removedef(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_LISTDEF:
+		netlbl_mgmt_listdef(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_MODULES:
+		netlbl_mgmt_modules(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	case NL_MGMT_VERSION:
+		netlbl_mgmt_version(skb, netlbl_mgmt_payload_data(skb));
+		break;
+	default:
+		netlbl_mgmt_send_ack(skb, EINVAL);
+		return;
+	}
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_mgmt.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.h
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,248 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_MGMT_H
+#define _NETLABEL_MGMT_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the management interface,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ *   Sent by the kernel in response to an applications message, applications
+ *   should never send this message.
+ *
+ *   +----------------------+-----------------------+
+ *   | seq number (32 bits) | return code (32 bits) |
+ *   +----------------------+-----------------------+
+ *
+ *     seq number:  the sequence number of the original message, taken from the
+ *                  nlmsghdr structure
+ *     return code: return value, based on errno values
+ *
+ * o ADD:
+ *   Sent by an application to add a domain mapping to the NetLabel system.
+ *   The kernel should respond with an ACK.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +---------------+
+ *   | doi (32 bits) |
+ *   +---------------+
+ *
+ *     doi:  the CIPSO DOI value
+ *
+ * o REMOVE:
+ *   Sent by an application to remove a domain mapping from the NetLabel
+ *   system.  The kernel should ACK this message.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *
+ * o LIST:
+ *   This message can be sent either from an application or by the kernel in
+ *   response to an application generated LIST message.  When sent by an
+ *   application there is no payload.  The kernel should respond to a LIST
+ *   message either with a LIST message on success or an ACK message on
+ *   failure.
+ *
+ *   +-------------------+
+ *   | domains (32 bits) | ...
+ *   +-------------------+
+ *
+ *     domains: the number of domains in the message
+ *
+ *   +-------------------------+--------------------------+
+ *   | domain length (32 bits) | domain string (variable) | ...
+ *   +-------------------------+--------------------------+
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     domain length: the length of the "domain string" in bytes
+ *     domain string: the domain string, NULL terminated
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o ADDDEF:
+ *   Sent by an application to set the default domain mapping for the NetLabel
+ *   system.  The kernel should respond with an ACK.
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +---------------+
+ *   | doi (32 bits) |
+ *   +---------------+
+ *
+ *     doi:  the CIPSO DOI value
+ *
+ * o REMOVEDEF:
+ *   Sent by an application to remove the default domain mapping from the
+ *   NetLabel system, there is no payload.  The kernel should ACK this message.
+ *
+ * o LISTDEF:
+ *   This message can be sent either from an application or by the kernel in
+ *   response to an application generated LISTDEF message.  When sent by an
+ *   application there is no payload.  The kernel should respond to a
+ *   LISTDEF message either with a LISTDEF message on success or an ACK message
+ *   on failure.
+ *
+ *   +-------------------------+-------------- ---- --- -- -
+ *   | protocol type (32 bits) | mapping data                ... repeated
+ *   +-------------------------+-------------- ---- --- -- -
+ *
+ *     protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ *     mapping data:  specific to the map type (see below)
+ *
+ *   NETLBL_NLTYPE_UNLABELED
+ *
+ *     No mapping data for this protocol type.
+ *
+ *   NETLBL_NLTYPE_CIPSOV4
+ *
+ *   +----------------+---------------+
+ *   | type (32 bits) | doi (32 bits) |
+ *   +----------------+---------------+
+ *
+ *     type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ *           as CIPSO_V4_MAP_*)
+ *     doi:  the CIPSO DOI value
+ *
+ * o MODULES:
+ *   Sent by an application to request a list of configured NetLabel modules
+ *   in the kernel.  This message type is also used by the kernel to respond
+ *   to an application's MODULES message.
+ *
+ *   +-------------------+
+ *   | modules (32 bits) | ...
+ *   +-------------------+
+ *
+ *     modules: the number of modules in the message, if this is an application
+ *              generated message and the value is zero then return a list of
+ *              the configured modules
+ *
+ *   +------------------+
+ *   | module (32 bits) | ... repeated
+ *   +------------------+
+ *
+ *     module: the module number as defined by NETLBL_NLTYPE_*
+ *
+ * o VERSION:
+ *   Sent by an application to request the NetLabel version string.  This
+ *   message type is also used by the kernel to respond to an VERSION request.
+ *
+ *   +-------------------+
+ *   | version (32 bits) |
+ *   +-------------------+
+ *
+ *     version: the protocol version number
+ *
+ */
+
+/* MGMT message header */
+struct netlbl_mgmt_msghdr {
+	enum { NL_MGMT_NOOP,
+	       NL_MGMT_ACK,
+	       NL_MGMT_ADD,
+	       NL_MGMT_REMOVE,
+	       NL_MGMT_LIST,
+	       NL_MGMT_ADDDEF,
+	       NL_MGMT_REMOVEDEF,
+	       NL_MGMT_LISTDEF,
+	       NL_MGMT_MODULES,
+	       NL_MGMT_VERSION
+	} opcode;
+};
+
+/* Process NetLabel management messages */
+void netlbl_mgmt_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.c
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,285 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system.  The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_user.h"
+#include "netlabel_domainhash.h"
+#include "netlabel_unlabeled.h"
+
+/* Accept unlabeled packets flag */
+static atomic_t netlabel_unlabel_accept_flg = ATOMIC_INIT(0);
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_unlabel_send_ack(const struct sk_buff *req_skb,
+				    const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_unlabel_put_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_unlabel_put_hdr(unsigned char *buffer,
+					  const u32 opcode)
+{
+	((struct netlbl_unlabel_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_unlabel_putinc_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_unlabel_putinc_hdr(unsigned char **buffer, 
+					     const u32 opcode)
+{
+	netlbl_unlabel_put_hdr(*buffer, opcode);
+	*buffer += sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the NetLabel unlabeled payload.
+ *
+ */
+static inline u32 netlbl_unlabel_payload_len(const struct sk_buff *skb)
+{
+	const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+	if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_unlabel_msghdr))
+		return 0;
+	return nlmsg_len(nl_hdr) - sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_data - Returns a pointer to the start of the data
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns a pointer to the start of the NetLabel unlabeled
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_unlabel_payload_data(
+	const struct sk_buff *skb)
+{
+	return nlmsg_data((struct nlmsghdr *)skb->data)
+		+ sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_unlabel_accept - Handle an ACCEPT message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ACCEPT message and set the accept flag accordingly.
+ *
+ */
+static void netlbl_unlabel_accept(const struct sk_buff *req_skb,
+				 const unsigned char *msg)
+{
+	u32 value;
+
+	if (netlbl_unlabel_payload_len(req_skb) == 4) {
+		value = netlbl_get_u32(msg);
+		if (value == 1 || value == 0) {
+			atomic_set(&netlabel_unlabel_accept_flg, value);
+			netlbl_unlabel_send_ack(req_skb, NETLBL_E_OK);
+			return;
+		}
+	}
+
+	netlbl_unlabel_send_ack(req_skb, EINVAL);
+	return;
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_unlabel_send_ack - Send an ACK message
+ * @req_skb: the NETLINK buffer
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @req_skb.
+ *
+ */
+static void netlbl_unlabel_send_ack(const struct sk_buff *req_skb,
+				    const u32 ret_code)
+{
+	size_t msg_size;
+	size_t data_size;
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_ack_hdr;
+	unsigned char *data;
+
+	data_size = sizeof(struct netlbl_unlabel_msghdr) + 8;
+	msg_size = NLMSG_SPACE(data_size);
+
+	skb = alloc_skb(msg_size, GFP_KERNEL);
+	if (skb == NULL)
+		return;
+
+	nl_ack_hdr = NLMSG_PUT(skb,
+			       NETLINK_CB(req_skb).pid,
+			       0,
+			       NETLBL_NLTYPE_UNLABELED,
+			       data_size);
+	nl_ack_hdr->nlmsg_len = msg_size;
+
+	data = NLMSG_DATA(nl_ack_hdr);
+	netlbl_unlabel_putinc_hdr(&data, NL_UNL_ACK);
+	netlbl_putinc_u32(&data,
+			  ((struct nlmsghdr *)req_skb->data)->nlmsg_seq);
+	netlbl_putinc_u32(&data, ret_code);
+
+	netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+	return;
+
+nlmsg_failure:
+	kfree_skb(skb);
+}
+
+/**
+ * netlbl_unlabel_rcv - Process incoming NetLabel packets
+ * @skb: the NETLINK buffer
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming Unlabeled
+ * NetLabel traffic and dispatching it to the correct Unlabeled functions.
+ *
+ */
+void netlbl_unlabel_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+	if (nlmsg_len((struct nlmsghdr *)skb->data) < 
+	    sizeof(struct netlbl_unlabel_msghdr)) {
+		netlbl_unlabel_send_ack(skb, EINVAL);
+		return;
+	}
+
+	switch (((struct netlbl_unlabel_msghdr *)msg)->opcode) {
+	case NL_UNL_ACCEPT:
+		netlbl_unlabel_accept(skb, netlbl_unlabel_payload_data(skb));
+		break;
+	default:
+		netlbl_unlabel_send_ack(skb, EINVAL);
+		return;
+	}
+}
+
+/*
+ * NetLabel KAPI Hooks
+ */
+
+/**
+ * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Determine the security attributes, if any, for an unlabled packet and return
+ * them in @secattr.  Returns zero on success and negative values on failure.
+ *
+ */
+int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
+{
+	BUG_ON(secattr == NULL);
+
+	if (atomic_read(&netlabel_unlabel_accept_flg) == 1) {
+		memset(secattr, 0, sizeof(*secattr));
+		return 0;
+	}
+
+	return -ENOMSG;
+}
+
+/**
+ * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
+ *
+ * Description:
+ * Set the default NetLabel configuration to allow incoming unlabeled packets
+ * and to send unlabeled network traffic by default.
+ *
+ */
+int netlbl_unlabel_defconf(void)
+{
+	int ret_val;
+	struct netlbl_dom_map *entry;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL)
+		return -ENOMEM;
+	entry->type = NETLBL_NLTYPE_UNLABELED;
+	ret_val = netlbl_domhsh_add_default(entry);
+	if (ret_val != 0)
+		return ret_val;
+
+	atomic_set(&netlabel_unlabel_accept_flg, 1);
+
+	return 0;
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.h
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,83 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system.  The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_UNLABELED_H
+#define _NETLABEL_UNLABELED_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the Unlabeled subsystem,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ *   Sent by the kernel in response to an applications message, applications
+ *   should never send this message.
+ *
+ *   +----------------------+-----------------------+
+ *   | seq number (32 bits) | return code (32 bits) |
+ *   +----------------------+-----------------------+
+ *
+ *     seq number:  the sequence number of the original message, taken from the
+ *                  nlmsghdr structure
+ *     return code: 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) |
+ *   +-----------------+
+ *
+ *     allow: if true (1) then allow the packets to pass, if false (0) then
+ *            reject the packets
+ *
+ */
+
+/* Unlabeled message header */
+struct netlbl_unlabel_msghdr {
+	enum { NL_UNL_NOOP,
+	       NL_UNL_ACK,
+	       NL_UNL_ACCEPT
+	} opcode;
+};
+
+/* Process Unlabeled NetLabel messages */
+void netlbl_unlabel_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+/* Process Unlabeled incoming network packets */
+int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr);
+
+/* Set the default configuration to allow Unlabeled packets */
+int netlbl_unlabel_defconf(void);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_user.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.c
--- linux-2.6.16.i686/net/netlabel/netlabel_user.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.c	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,174 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_unlabeled.h"
+#include "netlabel_cipso_v4.h"
+#include "netlabel_user.h"
+
+/* NETLINK socket */
+/* PM - do we need a lock (or something) around this? */
+static struct sock *netlbl_nl = NULL;
+
+/*
+ * NetLabel Functions
+ */
+
+/**
+ * netlbl_netlink_rcv - Catch incoming NETLINK packets
+ * @sk: the NETLINK socket
+ * @len: absolutely no clue, socket queue length maybe?
+ *
+ * Description:
+ * Receives the NETLINK packet, inspects the packet to determine the correct
+ * NetLabel subsystem and hands the packet off to the correct handler.
+ *
+ */
+static void netlbl_netlink_rcv(struct sock *sk, const int len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nl_hdr;
+
+	/* PM - verify that this is really what we want */
+	if (!capable(CAP_NET_ADMIN))
+		return;
+
+	/* XXX - should this use netlink_run_queue() instead? */
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+		nl_hdr = (struct nlmsghdr *)skb->data;
+		switch (nl_hdr->nlmsg_type) {
+		case NETLBL_NLTYPE_MGMT:
+			netlbl_mgmt_rcv(skb, nlmsg_data(nl_hdr));
+			break;
+#ifdef CONFIG_NETLABEL_UNLABELED
+		case NETLBL_NLTYPE_UNLABELED:
+			netlbl_unlabel_rcv(skb, nlmsg_data(nl_hdr));
+			break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+		case NETLBL_NLTYPE_CIPSOV4:
+			netlbl_cipsov4_rcv(skb, nlmsg_data(nl_hdr));
+			break;
+#endif
+		}
+		nlmsg_free(skb);
+	}
+}
+
+/**
+ * netlbl_netlink_init - Initialize the netlink socket
+ *
+ * Description:
+ * Create the netlink socket and do any other setup required.  Returns zero on
+ * success and non-zero on failure.
+ *
+ */
+int __init netlbl_netlink_init(void)
+{
+	/* XXX - it might be a good idea to spawn a thread here at startup to
+	   handle the updates to the label mapping databases and have the
+	   netlbl_netlink_rcv() function simply poke the thread but i am unsure
+	   and this approach is much simpler so it wins for now */
+	netlbl_nl = netlink_kernel_create(NETLINK_NETLABEL,
+					  NETLBL_NLGRP_MAX,
+					  netlbl_netlink_rcv, THIS_MODULE);
+	if (netlbl_nl == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * netlbl_exit - Release the netlink socket
+ * 
+ * Description:
+ * Close the netlink socket and do any other cleanup required.
+ *
+ */
+void netlbl_netlink_exit(void)
+{
+	/* XXX - if we do have a worker thread, see the above comment in 
+	   netlbl_netlink_init(), we should handle any cleanup here
+	   before we go away */
+	if (netlbl_nl != NULL)
+		sock_release(netlbl_nl->sk_socket);
+}
+
+/* 
+ * NETLINK I/O Functions
+ */
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: destination PID
+ *
+ * Description:
+ * Sends a unicast NetLabel message over the NETLINK socket.
+ *
+ */
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid)
+{
+	/* PM - verify that this is really what we want */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	return nlmsg_unicast(netlbl_nl, skb, pid);
+}
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: sending PID
+ * @group: multicast group id
+ *
+ * Description:
+ * Sends a multicast NetLabel message over the NETLINK socket to all members
+ * of @group except @pid.
+ *
+ */
+int netlbl_netlink_snd_multicast(struct sk_buff *skb, 
+				 const u32 pid, 
+				 const u32 group)
+{
+	/* PM - verify that this is really what we want */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	return nlmsg_multicast(netlbl_nl, skb, pid, group);
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_user.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.h
--- linux-2.6.16.i686/net/netlabel/netlabel_user.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.h	2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,42 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system.  The
+ * NetLabel system manages static and dynamic label mappings for network 
+ * protocols such as CIPSO and RIPSO.
+ * 
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;  if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_USER_H
+#define _NETLABEL_USER_H
+
+/* NetLabel NETLINK I/O functions */
+int netlbl_netlink_init(void) __init;
+void netlbl_netlink_exit(void) __exit;
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid);
+int netlbl_netlink_snd_multicast(struct sk_buff *skb, 
+				 const u32 pid,
+				 const u32 group);
+
+#endif
diff -purN linux-2.6.16.i686/security/selinux/hooks.c linux-2.6.16.i686-netlabel_06132006/security/selinux/hooks.c
--- linux-2.6.16.i686/security/selinux/hooks.c	2006-06-13 10:47:10.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/hooks.c	2006-06-13 11:19:59.000000000 -0400
@@ -12,6 +12,8 @@
  *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris redhat com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                          <dgoeddel trustedcs com>
+ *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ *                     Paul Moore, <paul moore hp com>
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License version 2,
@@ -69,6 +71,7 @@
 #include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/string.h>
+#include <net/netlabel.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -2935,6 +2938,16 @@ static void selinux_socket_post_create(s
 	isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
 	isec->initialized = 1;
 
+#ifdef CONFIG_NETLABEL        
+	if (family == PF_INET)
+		/* PM - this will throw errors unless netlabel is configured
+		   so if you enable netlabel you must make sure you configure
+		   it early in your init scripts (i.e. before you bring up
+		   networking) ... or should we just drop the BUG_ON() and
+		   audit the failure? */
+		BUG_ON(security_netlbl_socket_setsid(sock, isec->sid));
+#endif /* CONFIG_NETLABEL */
+
 	return;
 }
 
@@ -3113,6 +3126,19 @@ static int selinux_socket_accept(struct 
 	return 0;
 }
 
+#ifdef CONFIG_NETLABEL
+static void selinux_socket_post_accept(struct socket *sock,
+				       struct socket *newsock)
+{
+	if (newsock->sk != NULL && newsock->sk->sk_family == PF_INET)
+		/* PM - see my comments in the socket_post_create() hook, the
+		   problem is not quite as bad here since you have already
+		   created at least one pf_inet socket and gotten traffic on
+		   it but the core question still remains: BUG() or audit? */
+		BUG_ON(security_netlbl_socket_accept(sock, newsock));
+}
+#endif /* CONFIG_NETLABEL */
+
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
  				  int size)
 {
@@ -3221,6 +3247,9 @@ static int selinux_socket_sock_rcv_skb(s
 	struct socket *sock;
 	struct net_device *dev;
 	struct avc_audit_data ad;
+#ifdef CONFIG_NETLABEL
+	u32 netlbl_sid;
+#endif
 
 	family = sk->sk_family;
 	if (family != PF_INET && family != PF_INET6)
@@ -3270,6 +3299,7 @@ static int selinux_socket_sock_rcv_skb(s
 	default:
 		netif_perm = NETIF__RAWIP_RECV;
 		node_perm = NODE__RAWIP_RECV;
+		recv_perm = RAWIP_SOCKET__RECV_MSG;
 		break;
 	}
 
@@ -3294,7 +3324,7 @@ static int selinux_socket_sock_rcv_skb(s
 	if (err)
 		goto out;
 
-	if (recv_perm) {
+	if (recv_perm != 0 && recv_perm != RAWIP_SOCKET__RECV_MSG) {
 		u32 port_sid;
 
 		/* Fixme: make this more efficient */
@@ -3306,10 +3336,46 @@ static int selinux_socket_sock_rcv_skb(s
 
 		err = avc_has_perm(sock_sid, port_sid,
 				   sock_class, recv_perm, &ad);
+		if (err)
+			goto out;
 	}
 
-	if (!err)
-		err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
+	err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
+#ifdef CONFIG_NETLABEL
+	if (err == 0)
+		goto out;
+
+	err = security_netlbl_skbuff_getsid(skb, sock_sid, &netlbl_sid);
+	if (err)
+		goto out;
+        
+	if (netlbl_sid == SECINITSID_UNLABELED)
+		/* PM - this may look strange (it is) but it is here to
+		   preserve backward compatability */
+		err = avc_has_perm(sock_sid,
+				   SECINITSID_UNLABELED,
+				   SECCLASS_ASSOCIATION,
+				   ASSOCIATION__RECVFROM,
+				   NULL);
+	else
+		err = avc_has_perm(sock_sid, 
+				   netlbl_sid, 
+				   sock_class, 
+				   recv_perm,
+				   &ad);		
+
+	if (err)
+		netlbl_skbuff_err(skb, err);
+#else
+	if (err)
+		goto out;
+
+	err = avc_has_perm(sock_sid,
+			   SECINITSID_UNLABELED,
+			   SECCLASS_ASSOCIATION,
+			   ASSOCIATION__RECVFROM,
+			   NULL);
+#endif /* CONFIG_NETLABEL */
 
 out:	
 	return err;
@@ -3334,7 +3400,11 @@ static int selinux_socket_getpeersec_str
 	}
 	else if (isec->sclass == SECCLASS_TCP_SOCKET) {
 		peer_sid = selinux_socket_getpeer_stream(sock->sk);
-
+#ifdef CONFIG_NETLABEL
+		if (peer_sid == SECSID_NULL && 
+		    security_netlbl_socket_peeksid(sock, &peer_sid) != 0)
+			peer_sid = SECSID_NULL;
+#endif
 		if (peer_sid == SECSID_NULL) {
 			err = -ENOPROTOOPT;
 			goto out;
@@ -4353,6 +4423,9 @@ static struct security_operations selinu
 	.socket_connect =		selinux_socket_connect,
 	.socket_listen =		selinux_socket_listen,
 	.socket_accept =		selinux_socket_accept,
+#ifdef CONFIG_NETLABEL
+	.socket_post_accept =		selinux_socket_post_accept,
+#endif
 	.socket_sendmsg =		selinux_socket_sendmsg,
 	.socket_recvmsg =		selinux_socket_recvmsg,
 	.socket_getsockname =		selinux_socket_getsockname,
diff -purN linux-2.6.16.i686/security/selinux/include/av_inherit.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_inherit.h
--- linux-2.6.16.i686/security/selinux/include/av_inherit.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_inherit.h	2006-06-13 11:19:59.000000000 -0400
@@ -29,3 +29,4 @@
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL)
+   S_(SECCLASS_NETLINK_NETLABEL_SOCKET, socket, 0x00400000UL)
diff -purN linux-2.6.16.i686/security/selinux/include/av_permissions.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_permissions.h
--- linux-2.6.16.i686/security/selinux/include/av_permissions.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_permissions.h	2006-06-13 11:19:59.000000000 -0400
@@ -933,3 +933,4 @@
 #define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG   0x00100000UL
 #define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND  0x00200000UL
 
+#define NETLINK_NETLABEL_SOCKET__NLMSG_WRITE      0x00000001UL
diff -purN linux-2.6.16.i686/security/selinux/include/av_perm_to_string.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_perm_to_string.h
--- linux-2.6.16.i686/security/selinux/include/av_perm_to_string.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_perm_to_string.h	2006-06-13 11:19:59.000000000 -0400
@@ -239,3 +239,5 @@
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
+   S_(SECCLASS_NETLINK_NETLABEL_SOCKET, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE, "nlmsg_write")
+
diff -purN linux-2.6.16.i686/security/selinux/include/flask.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/flask.h
--- linux-2.6.16.i686/security/selinux/include/flask.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/flask.h	2006-06-13 11:20:00.000000000 -0400
@@ -60,6 +60,7 @@
 #define SECCLASS_NSCD                                    53
 #define SECCLASS_ASSOCIATION                             54
 #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET           55
+#define SECCLASS_NETLINK_NETLABEL_SOCKET                 56
 
 /*
  * Security identifier indices for initial entities
diff -purN linux-2.6.16.i686/security/selinux/include/security.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/security.h
--- linux-2.6.16.i686/security/selinux/include/security.h	2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/security.h	2006-06-13 11:20:00.000000000 -0400
@@ -8,6 +8,8 @@
 #ifndef _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 
+#include <linux/skbuff.h>
+
 #include "flask.h"
 
 #define SECSID_NULL			0x00000000 /* unspecified SID */
@@ -91,5 +93,12 @@ int security_fs_use(const char *fstype, 
 int security_genfs_sid(const char *fstype, char *name, u16 sclass,
 	u32 *sid);
 
+int security_netlbl_socket_peeksid(struct socket *sock, u32 *sid);
+int security_netlbl_skbuff_getsid(struct sk_buff *skb,
+				  const u32 base_sid,
+				  u32 *sid);
+int security_netlbl_socket_setsid(const struct socket *sock, const u32 sid);
+int security_netlbl_socket_accept(struct socket *sock, struct socket *newsock);
+
 #endif /* _SELINUX_SECURITY_H_ */
 
diff -purN linux-2.6.16.i686/security/selinux/nlmsgtab.c linux-2.6.16.i686-netlabel_06132006/security/selinux/nlmsgtab.c
--- linux-2.6.16.i686/security/selinux/nlmsgtab.c	2006-06-13 10:47:09.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/nlmsgtab.c	2006-06-13 11:20:00.000000000 -0400
@@ -19,6 +19,7 @@
 #include <linux/inet_diag.h>
 #include <linux/xfrm.h>
 #include <linux/audit.h>
+#include <net/netlabel.h>
 
 #include "flask.h"
 #include "av_permissions.h"
@@ -31,92 +32,101 @@ struct nlmsg_perm
 
 static struct nlmsg_perm nlmsg_route_perms[] =
 {
-	{ RTM_NEWLINK,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELLINK,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETLINK,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_SETLINK,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_NEWADDR,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELADDR,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETADDR,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWROUTE,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELROUTE,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETROUTE,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWNEIGH,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELNEIGH,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETNEIGH,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWRULE,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELRULE,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETRULE,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWQDISC,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELQDISC,		NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETQDISC,		NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWTCLASS,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELTCLASS,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETTCLASS,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWTFILTER,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELTFILTER,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETTFILTER,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWACTION,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_DELACTION,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETACTION,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_NEWPREFIX,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
-	{ RTM_GETPREFIX,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_GETMULTICAST,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_GETANYCAST,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_GETNEIGHTBL,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
-	{ RTM_SETNEIGHTBL,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_NEWLINK,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELLINK,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETLINK,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_SETLINK,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_NEWADDR,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELADDR,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETADDR,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWROUTE,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELROUTE,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETROUTE,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWNEIGH,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELNEIGH,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETNEIGH,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWRULE,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELRULE,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETRULE,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWQDISC,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELQDISC,		     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETQDISC,		     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWTCLASS,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELTCLASS,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETTCLASS,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWTFILTER,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELTFILTER,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETTFILTER,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWACTION,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELACTION,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETACTION,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_NEWPREFIX,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETPREFIX,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_GETMULTICAST,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_GETANYCAST,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_GETNEIGHTBL,	     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+	{ RTM_SETNEIGHTBL,	     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
 };
 
 static struct nlmsg_perm nlmsg_firewall_perms[] =
 {
-	{ IPQM_MODE,		NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
-	{ IPQM_VERDICT,		NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
+	{ IPQM_MODE,		     NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
+	{ IPQM_VERDICT,		     NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
 };
 
 static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
 {
-	{ TCPDIAG_GETSOCK,	NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
-	{ DCCPDIAG_GETSOCK,	NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+	{ TCPDIAG_GETSOCK,	     NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+	{ DCCPDIAG_GETSOCK,	     NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
 };
 
 static struct nlmsg_perm nlmsg_xfrm_perms[] =
 {
-	{ XFRM_MSG_NEWSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_DELSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_GETSA,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
-	{ XFRM_MSG_NEWPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_DELPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_GETPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
-	{ XFRM_MSG_ALLOCSPI,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_ACQUIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_EXPIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_UPDPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_UPDSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_POLEXPIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_FLUSHSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_FLUSHPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_NEWAE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-	{ XFRM_MSG_GETAE,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
+	{ XFRM_MSG_NEWSA,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_DELSA,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_GETSA,	     NETLINK_XFRM_SOCKET__NLMSG_READ  },
+	{ XFRM_MSG_NEWPOLICY,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_DELPOLICY,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_GETPOLICY,	     NETLINK_XFRM_SOCKET__NLMSG_READ  },
+	{ XFRM_MSG_ALLOCSPI,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_ACQUIRE,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_EXPIRE,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_UPDPOLICY,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_UPDSA,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_POLEXPIRE,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_FLUSHSA,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_FLUSHPOLICY,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_NEWAE,	     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_GETAE,	     NETLINK_XFRM_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_audit_perms[] =
 {
-	{ AUDIT_GET,		NETLINK_AUDIT_SOCKET__NLMSG_READ     },
-	{ AUDIT_SET,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_LIST,		NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
-	{ AUDIT_ADD,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_DEL,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_LIST_RULES,	NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
-	{ AUDIT_ADD_RULE,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_DEL_RULE,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_USER,		NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
-	{ AUDIT_SIGNAL_INFO,	NETLINK_AUDIT_SOCKET__NLMSG_READ     },
-	{ AUDIT_WATCH_INS,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_WATCH_REM,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
-	{ AUDIT_WATCH_LIST,	NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+	{ AUDIT_GET,		     NETLINK_AUDIT_SOCKET__NLMSG_READ     },
+	{ AUDIT_SET,		     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_LIST,		     NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+	{ AUDIT_ADD,		     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_DEL,		     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_LIST_RULES,	     NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+	{ AUDIT_ADD_RULE,	     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_DEL_RULE,	     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_USER,		     NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
+	{ AUDIT_SIGNAL_INFO,	     NETLINK_AUDIT_SOCKET__NLMSG_READ     },
+	{ AUDIT_WATCH_INS,	     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_WATCH_REM,	     NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_WATCH_LIST,	     NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+};
+
+static struct nlmsg_perm nlmsg_netlabel_perms[] =
+{
+	{ NETLBL_NLTYPE_NONE,        NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+	{ NETLBL_NLTYPE_MGMT,        NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+	{ NETLBL_NLTYPE_RIPSO,       NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+	{ NETLBL_NLTYPE_CIPSOV4,     NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+	{ NETLBL_NLTYPE_CIPSOV6,     NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+	{ NETLBL_NLTYPE_UNLABELED,   NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
 };
 
-
 static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize)
 {
 	int i, err = -EINVAL;
@@ -169,6 +179,19 @@ int selinux_nlmsg_lookup(u16 sclass, u16
 		}
 		break;
 
+	case SECCLASS_NETLINK_NETLABEL_SOCKET:
+		/* PM - This is really a poor fit right now as NetLabel uses
+		   the nlmsg_type value to specify the "class" of NetLabel
+		   message (i.e. management, cipso, etc.).  One way to fix
+		   this would be to refactor the NetLabel netlink API so 
+		   that it uses the nlmsg_type in a way that more closely
+		   resembles the other netlink consumers, however, that is
+		   going to require a non-trivial rework at this point so lets
+		   just leave it as is right now unless somebody complains. */
+		err = nlmsg_perm(nlmsg_type, perm, nlmsg_netlabel_perms,
+				 sizeof(nlmsg_netlabel_perms));
+		break;
+
 	/* No messaging from userspace, or class unknown/unhandled */
 	default:
 		err = -ENOENT;
diff -purN linux-2.6.16.i686/security/selinux/ss/ebitmap.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.c
--- linux-2.6.16.i686/security/selinux/ss/ebitmap.c	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.c	2006-06-13 11:20:00.000000000 -0400
@@ -3,6 +3,14 @@
  *
  * Author : Stephen Smalley, <sds epoch ncsc mil>
  */
+/*
+ * Updated: Hewlett-Packard <paul moore hp com>
+ *
+ *      Added ebitmap_export() and ebitmap_import()
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
@@ -59,6 +67,153 @@ int ebitmap_cpy(struct ebitmap *dst, str
 	return 0;
 }
 
+/**
+ * ebitmap_export - Export an ebitmap to a unsigned char bitmap string
+ * @src: the ebitmap to export
+ * @dst: the resulting bitmap string
+ * @dst_len: length of dst in bytes
+ *
+ * Description:
+ * Allocate a buffer at least src->highbit bits long and export the extensible
+ * bitmap into the buffer.  The bitmap string will be in little endian format,
+ * i.e. LSB first.  The value returned in dst_len may not the true size of the
+ * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE.
+ * The caller must free the buffer when finished. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int ebitmap_export(const struct ebitmap *src, 
+		   unsigned char **dst, 
+		   u32 *dst_len)
+{
+	u32 bitmap_len;
+	unsigned char *bitmap;
+	struct ebitmap_node *iter_node;
+	MAPTYPE node_val;
+	u32 bitmap_byte;
+	unsigned char bitmask;
+
+	if (src == NULL || dst == NULL || dst_len == NULL)
+		return -EINVAL;
+
+	*dst = NULL;
+	*dst_len = 0;
+
+	bitmap_len = src->highbit / 8;
+	if (src->highbit % 8 > 0)
+		bitmap_len += 1;
+	if (bitmap_len == 0)
+		return -EINVAL;
+
+	bitmap = kzalloc(bitmap_len + sizeof(MAPTYPE) - 
+			 (bitmap_len % sizeof(MAPTYPE)),
+			 GFP_ATOMIC);
+	if (bitmap == NULL)
+		return -ENOMEM;
+
+	/* PM - there _has_ to be a faster way to do this, work on this more */
+	iter_node = src->node;
+	do {
+		bitmap_byte = iter_node->startbit / 8;
+		bitmask = 0x80;
+		node_val = iter_node->map;
+		do {
+			if (bitmask == 0) {
+				bitmap_byte++;
+				bitmask = 0x80;
+			}
+			if (node_val & (MAPTYPE)0x01)
+				bitmap[bitmap_byte] |= bitmask;
+			node_val >>= 1;
+			bitmask >>= 1;
+		} while (node_val > 0);
+		iter_node = iter_node->next;
+	} while (iter_node);
+
+	*dst = bitmap;
+	*dst_len = bitmap_len;
+	return 0;
+}
+
+/**
+ * ebitmap_import - Import an unsigned char bitmap string into an ebitmap
+ * @src: the bitmap string
+ * @src_len: the bitmap length in bytes
+ * @dst: the empty ebitmap
+ *
+ * Description:
+ * This function takes a little endian bitmap string in src and imports it into
+ * the ebitmap pointed to by dst.  Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int ebitmap_import(const unsigned char *src,
+		   const u32 src_len,
+		   struct ebitmap *dst)
+{
+	u32 src_off = 0;
+	struct ebitmap_node *node_new;
+	struct ebitmap_node *node_last = NULL;
+	u32 src_rem = src_len;
+	MAPTYPE tmp_val;
+	u32 iter;
+	u32 iter_bit;
+	unsigned char src_byte;
+        
+	if (src == NULL || dst == NULL || src_len == 0)
+		return -EINVAL;
+
+	do {
+		node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC);
+		if (node_new == NULL) {
+			ebitmap_destroy(dst);
+			return -ENOMEM;
+		}
+
+		/* PM - there _has_ to be a faster way to do this, 
+		   work on this more */
+		if (src_rem >= sizeof(MAPTYPE))
+			iter = sizeof(MAPTYPE);
+		else
+			iter = src_rem;
+		tmp_val = 0;
+		while (iter > 0) {
+			src_byte = src[src_off + --iter];
+			if (src_byte > 0)
+				for (iter_bit = 0; iter_bit < 8; iter_bit++) {
+					tmp_val <<= 1;
+					tmp_val |= src_byte & 0x01;
+					src_byte >>= 1;
+				}
+			else
+				tmp_val <<= 8;
+		}
+		node_new->map = tmp_val;
+		node_new->startbit = src_off * 8;
+
+		if (node_last != NULL)
+			node_last->next = node_new;
+		else
+			dst->node = node_new;
+		node_last = node_new;
+
+		if (src_rem >= sizeof(MAPTYPE)) {
+			src_off += sizeof(MAPTYPE);
+			src_rem -= sizeof(MAPTYPE);
+		} else
+			src_off += src_rem;
+	} while (src_off < src_len);
+
+	tmp_val = node_last->map;
+	dst->highbit = node_last->startbit;
+	while (tmp_val >= 1) {
+		dst->highbit += 1;
+		tmp_val >>= 1;
+	}
+
+	return 0;
+}
+
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
 {
 	struct ebitmap_node *n1, *n2;
diff -purN linux-2.6.16.i686/security/selinux/ss/ebitmap.h linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.h
--- linux-2.6.16.i686/security/selinux/ss/ebitmap.h	2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.h	2006-06-13 11:20:00.000000000 -0400
@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(s
 
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
+int ebitmap_export(const struct ebitmap *src,
+		   unsigned char **dst,
+		   u32 *dst_len);
+int ebitmap_import(const unsigned char *src, 
+		   const u32 src_len,
+		   struct ebitmap *dst);
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
 int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
diff -purN linux-2.6.16.i686/security/selinux/ss/mls.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.c
--- linux-2.6.16.i686/security/selinux/ss/mls.c	2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.c	2006-06-13 11:20:00.000000000 -0400
@@ -10,6 +10,13 @@
  *
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
+/*
+ * Updated: Hewlett-Packard <paul moore hp com>
+ *
+ *      Added support to import/export the MLS label
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -585,3 +592,156 @@ int mls_compute_sid(struct context *scon
 	return -EINVAL;
 }
 
+/**
+ * mls_export_lvl - Export the MLS sensitivity levels
+ * @context: the security context
+ * @lvl_low: the low sensitivity level
+ * @lvl_high: the high sensitivity level
+ *
+ * Description:
+ * Given the security context copy the low MLS sensitivity level into lvl_low
+ * and the high sensitivity level in lvl_high.  The MLS levels are only
+ * exported if the pointers are not NULL, if they are NULL then that level is
+ * not exported.  Returns zero on success, negative values on failure.
+ *
+ */
+int mls_export_lvl(const struct context *context, u32 *lvl_low, u32 *lvl_high)
+{
+	if (!selinux_mls_enabled)
+		return 0;
+
+	if (lvl_low != NULL)
+		*lvl_low = context->range.level[0].sens - 1;
+	if (lvl_high != NULL)
+		*lvl_high = context->range.level[1].sens - 1;
+
+	return 0;
+}
+
+/**
+ * mls_import_lvl - Import the MLS sensitivity levels
+ * @context: the security context
+ * @lvl_low: the low sensitivity level
+ * @lvl_high: the high sensitivity level
+ *
+ * Description:
+ * Given the security context and the two sensitivty levels, set the MLS levels
+ * in the context according the two given as parameters.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int mls_import_lvl(struct context *context, 
+		   const u32 lvl_low, 
+		   const u32 lvl_high)
+{
+	if (!selinux_mls_enabled)
+		return 0;
+
+	context->range.level[0].sens = lvl_low + 1;
+	context->range.level[1].sens = lvl_high + 1;
+
+	return 0;
+}
+
+/**
+ * mls_export_cat - Export the MLS categories
+ * @context: the security context
+ * @cat_low: the low category
+ * @cat_low_len: length of the cat_low bitmap in bytes
+ * @cat_high: the high category
+ * @cat_high_len: length of the cat_high bitmap in bytes
+ *
+ * Description:
+ * Given the security context export the low MLS category bitmap into cat_low
+ * and the high category bitmap into cat_high.  The MLS categories are only
+ * exported if the pointers are not NULL, if they are NULL then that level is
+ * not exported.  The caller is responsibile for freeing the memory when
+ * finished.  Returns zero on success, negative values on failure.
+ *
+ */
+int mls_export_cat(const struct context *context,
+		   unsigned char **cat_low,
+		   u32 *cat_low_len,
+		   unsigned char **cat_high,
+		   u32 *cat_high_len)
+{
+	int ret_val = -EPERM;
+
+	if (!selinux_mls_enabled)
+		return 0;
+
+	if (cat_low != NULL && cat_low_len != NULL) {
+		ret_val = ebitmap_export(&context->range.level[0].cat,
+					 cat_low,
+					 cat_low_len);
+		if (ret_val != 0)
+			goto export_cat_failure;
+	}
+	if (cat_high != NULL && cat_high_len != NULL) {
+		ret_val = ebitmap_export(&context->range.level[1].cat,
+					 cat_high,
+					 cat_high_len);
+		if (ret_val != 0)
+			goto export_cat_failure;
+	}
+
+	return 0;
+
+export_cat_failure:
+	if (cat_low != NULL && *cat_low != NULL)
+		kfree(*cat_low);
+	if (cat_high != NULL && *cat_high != NULL)
+		kfree(*cat_high);
+	return ret_val;
+}
+
+/**
+ * mls_import_cat - Import the MLS categories
+ * @context: the security context
+ * @cat_low: the low category
+ * @cat_low_len: length of the cat_low bitmap in bytes
+ * @cat_high: the high category
+ * @cat_high_len: length of the cat_high bitmap in bytes
+ *
+ * Description:
+ * Given the security context and the two category bitmap strings import the
+ * categories into the security context.  The MLS categories are only imported
+ * if the pointers are not NULL, if they are NULL they are skipped.  Returns
+ * zero on success, negative values on failure.
+ * 
+ */
+int mls_import_cat(struct context *context,
+		   const unsigned char *cat_low,
+		   const u32 cat_low_len,
+		   const unsigned char *cat_high,
+		   const u32 cat_high_len)
+{
+	int ret_val = -EPERM;
+
+	if (!selinux_mls_enabled)
+		return 0;
+
+	if (cat_low != NULL && cat_low_len > 0) {
+		ret_val = ebitmap_import(cat_low,
+					 cat_low_len, 
+					 &context->range.level[0].cat);
+		if (ret_val != 0)
+			goto import_cat_failure;
+	}
+	if (cat_high != NULL && cat_high_len > 0) {
+		ret_val = ebitmap_import(cat_high,
+					 cat_high_len, 
+					 &context->range.level[1].cat);
+		if (ret_val != 0)
+			goto import_cat_failure;
+	}
+
+	return 0;
+
+import_cat_failure:
+	if (cat_low)
+		ebitmap_destroy(&context->range.level[0].cat);
+	if (cat_high)
+		ebitmap_destroy(&context->range.level[1].cat);
+	return ret_val;
+}
diff -purN linux-2.6.16.i686/security/selinux/ss/mls.h linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.h
--- linux-2.6.16.i686/security/selinux/ss/mls.h	2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.h	2006-06-13 11:20:00.000000000 -0400
@@ -10,6 +10,13 @@
  *
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
+/*
+ * Updated: Hewlett-Packard <paul moore hp com>
+ *
+ *      Added support to import/export the MLS label
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
 
 #ifndef _SS_MLS_H_
 #define _SS_MLS_H_
@@ -42,5 +49,23 @@ int mls_compute_sid(struct context *scon
 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
                          struct context *usercon);
 
+int mls_export_lvl(const struct context *context, 
+		   u32 *lvl_low,
+		   u32 *lvl_high);
+int mls_import_lvl(struct context *context, 
+		   const u32 lvl_low, 
+		   const u32 lvl_high);
+
+int mls_export_cat(const struct context *context,
+                   unsigned char **cat_low,
+                   u32 *cat_low_len,
+                   unsigned char **cat_high,
+                   u32 *cat_high_len);
+int mls_import_cat(struct context *context,
+                   const unsigned char *cat_low,
+                   const u32 cat_low_len,
+                   const unsigned char *cat_high,
+                   const u32 cat_high_len);
+
 #endif	/* _SS_MLS_H */
 
diff -purN linux-2.6.16.i686/security/selinux/ss/services.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/services.c
--- linux-2.6.16.i686/security/selinux/ss/services.c	2006-06-13 10:47:10.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/services.c	2006-06-13 11:20:00.000000000 -0400
@@ -13,6 +13,11 @@
  *
  * 	Added conditional policy language extensions
  *
+ * Updated: Hewlett-Packard <paul moore hp com>
+ *
+ *      Added support for NetLabel
+ *
+ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris redhat com>
@@ -29,6 +34,8 @@
 #include <linux/sched.h>
 #include <linux/audit.h>
 #include <linux/mutex.h>
+#include <net/netlabel.h>
+#include <net/sock.h>
 
 #include "flask.h"
 #include "avc.h"
@@ -40,6 +47,7 @@
 #include "services.h"
 #include "conditional.h"
 #include "mls.h"
+#include "objsec.h"
 
 extern void selnl_notify_policyload(u32 seqno);
 unsigned int policydb_loaded_version;
@@ -778,6 +786,40 @@ int security_context_to_sid_default(char
 	                                    sid, def_sid);
 }
 
+/**
+ * security_context_export_type - Exports the type of a given context
+ * @context: the security context
+ * @scontext: the resulting type string
+ * @scontext_len: the length of scontext including the NULL byte
+ *
+ * Description:
+ * Allocate a buffer for the type name specified in context and copy the type
+ * name into the buffer.  The caller must free the buffer when finished.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int security_context_export_type(const struct context *context, 
+					char **scontext, 
+					u32 *scontext_len)
+{
+	char *str;
+	u32 str_len;
+
+	*scontext = NULL;
+	if (scontext_len != NULL)
+		*scontext_len = 0;
+	str_len = strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+	str = kmalloc(str_len, GFP_ATOMIC);
+	if (str == NULL)
+		return -ENOMEM;
+	strcpy(str, policydb.p_type_val_to_name[context->type - 1]);
+
+	*scontext = str;
+	if (scontext_len != NULL)
+		*scontext_len = str_len;
+	return 0;
+}
+
 static int compute_sid_handle_invalid_context(
 	struct context *scontext,
 	struct context *tcontext,
@@ -1241,6 +1283,9 @@ int security_load_policy(void *data, siz
 		selinux_complete_init();
 		avc_ss_reset(seqno);
 		selnl_notify_policyload(seqno);
+#ifdef CONFIG_NETLABEL
+		netlbl_cache_invalidate();
+#endif
 		return 0;
 	}
 
@@ -1295,6 +1340,9 @@ int security_load_policy(void *data, siz
 
 	avc_ss_reset(seqno);
 	selnl_notify_policyload(seqno);
+#ifdef CONFIG_NETLABEL
+	netlbl_cache_invalidate();
+#endif
 
 	return 0;
 
@@ -1817,6 +1865,373 @@ out:
 	return rc;
 }
 
+#ifdef CONFIG_NETLABEL
+/*
+ * This is the structure we store inside the NetLabel cache block.
+ */
+#define NETLBL_CACHE(x)           ((struct netlbl_cache *)(x))
+#define NETLBL_CACHE_T_NONE       0
+#define NETLBL_CACHE_T_SID        1
+#define NETLBL_CACHE_T_MLSLBL     2
+struct netlbl_cache {
+	u32 type;
+	union {
+		u32 sid;
+		struct mls_level mls_label;
+	} data;
+};
+
+/**
+ * security_netlbl_cache_free - Free the NetLabel cached data
+ * @data: the data to free
+ *
+ * Description:
+ * This function is intended to be used as the free() callback inside the
+ * netlbl_lsm_cache structure.
+ *
+ */
+static void security_netlbl_cache_free(const void *data)
+{
+	struct netlbl_cache *cache = NETLBL_CACHE(data);
+	switch (cache->type) {
+	case NETLBL_CACHE_T_MLSLBL:
+		ebitmap_destroy(&cache->data.mls_label.cat);
+		break;
+	}
+	kfree(data);
+}
+
+/**
+ * security_netlbl_cache_add - Add an entry to the NetLabel cache
+ * @skb: the packet
+ * @ctx: the SELinux context
+ *
+ * Description:
+ * Attempt to cache the context in @ctx, which was derived from the packet in
+ * @skb, in the NetLabel subsystem cache.
+ *
+ */
+static inline void security_netlbl_cache_add(struct sk_buff *skb,
+					     struct context *ctx)
+{
+	struct netlbl_cache *cache = NULL;
+	struct netlbl_lsm_secattr secattr;
+
+	netlbl_secattr_init(&secattr);
+
+	cache = kzalloc(sizeof(*cache),	GFP_ATOMIC);
+	if (cache == NULL)
+		goto netlbl_cache_add_failure;
+
+	if (ebitmap_cpy(&cache->data.mls_label.cat,
+			&ctx->range.level[0].cat) != 0)
+		goto netlbl_cache_add_failure;
+	cache->data.mls_label.sens = ctx->range.level[0].sens;
+	cache->type = NETLBL_CACHE_T_MLSLBL;
+
+	netlbl_secattr_init(&secattr);
+	secattr.cache.free = security_netlbl_cache_free;
+	secattr.cache.data = (void *)cache;
+	secattr.set_cache = 1;
+	
+	if (netlbl_cache_add(skb, &secattr) != 0)
+		goto netlbl_cache_add_failure;
+
+	return;
+
+netlbl_cache_add_failure:
+	netlbl_secattr_destroy(&secattr);
+	if (cache)
+		security_netlbl_cache_free(cache);
+}
+
+/**
+ * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
+ * @skb: the network packet
+ * @secattr: the NetLabel packet security attributes
+ * @base_sid: the SELinux SID to use as a context for MLS only attributes
+ * @sid: the SELinux SID
+ *
+ * Description:
+ * Convert the given NetLabel packet security attributes in @secattr into a
+ * SELinux SID.  If the @secattr field does not contain a full SELinux 
+ * SID/context then use the context in @base_sid as the foundation.  If @skb
+ * is not NULL attempt to cache as much data as possibile.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static inline int security_netlbl_secattr_to_sid(
+	struct sk_buff *skb,
+	struct netlbl_lsm_secattr *secattr,
+	const u32 base_sid,
+	u32 *sid)
+{
+	int ret_val = -EIDRM;
+	struct context *ctx;
+	struct context ctx_new;
+	struct netlbl_cache *cache;
+	u32 ctx_new_destroy = 0;
+
+	if (secattr->set_cache) {
+		cache = NETLBL_CACHE(secattr->cache.data);
+		switch (cache->type) {
+		case NETLBL_CACHE_T_SID:
+			*sid = cache->data.sid;
+			break;
+		case NETLBL_CACHE_T_MLSLBL:
+			ctx = sidtab_search(&sidtab, base_sid);
+			if (ctx == NULL)
+				goto netlbl_secattr_to_sid_failure;
+			ret_val = context_cpy(&ctx_new, ctx);
+			if (ret_val != 0)
+				goto netlbl_secattr_to_sid_failure;
+			ctx_new_destroy = 1;
+			mls_context_destroy(&ctx_new);
+
+			ctx_new.range.level[0].sens = 
+				cache->data.mls_label.sens;
+			ret_val = ebitmap_cpy(&ctx_new.range.level[0].cat,
+					      &cache->data.mls_label.cat);
+			if (ret_val != 0)
+				goto netlbl_secattr_to_sid_failure;
+			ctx_new.range.level[1].sens = 
+				cache->data.mls_label.sens;
+			ret_val = ebitmap_cpy(&ctx_new.range.level[1].cat,
+					      &cache->data.mls_label.cat);
+			if (ret_val != 0)
+				goto netlbl_secattr_to_sid_failure;
+
+			ret_val = sidtab_context_to_sid(&sidtab, 
+							&ctx_new,
+							sid);
+			break;
+		default:
+			BUG();
+		}
+	} else if (secattr->set_mls_lvl) {
+		ctx = sidtab_search(&sidtab, base_sid);
+		if (ctx == NULL)
+			goto netlbl_secattr_to_sid_failure;
+		ret_val = context_cpy(&ctx_new, ctx);
+		if (ret_val != 0)
+			goto netlbl_secattr_to_sid_failure;
+		ctx_new_destroy = 1;
+		mls_context_destroy(&ctx_new);
+
+		if (mls_import_lvl(&ctx_new, 
+				   secattr->mls_lvl, 
+				   secattr->mls_lvl) != 0)
+			goto netlbl_secattr_to_sid_failure;
+		if (secattr->set_mls_cat) {
+			if (mls_import_cat(&ctx_new,
+					   secattr->mls_cat,
+					   secattr->mls_cat_len,
+					   secattr->mls_cat,
+					   secattr->mls_cat_len) != 0)
+				goto netlbl_secattr_to_sid_failure;
+		}
+
+		ret_val = mls_context_isvalid(&policydb, &ctx_new);
+		if (ret_val != 1)
+			goto netlbl_secattr_to_sid_failure;
+
+		if (skb != NULL)
+			security_netlbl_cache_add(skb, &ctx_new);
+
+		ret_val = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
+	} else
+		*sid = SECINITSID_UNLABELED;
+
+	ret_val = 0;
+
+netlbl_secattr_to_sid_failure:
+	if (ctx_new_destroy)
+		context_destroy(&ctx_new);
+	return ret_val;
+}
+
+/**
+ * security_netlbl_socket_peeksid - Get the SID of the first queued packet
+ * @sock: the socket to query
+ * @sid: the packet's SID
+ *
+ * Description:
+ * Examine the first incoming packet in the socket's queue and determine the
+ * packet's SELinux SID.  Return zero on success, negative values on failure.
+ *
+ */
+int security_netlbl_socket_peeksid(struct socket *sock, u32 *sid)
+{
+	int ret_val;
+	struct netlbl_lsm_secattr secattr;
+	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+
+	if (!ss_initialized)
+		return 0;
+
+	netlbl_secattr_init(&secattr);
+
+	ret_val = netlbl_socket_peekattr(sock, &secattr);
+	if (ret_val == 0)
+		ret_val = security_netlbl_secattr_to_sid(NULL, 
+							 &secattr, 
+							 isec->sid,
+							 sid);
+
+	secattr.set_cache = 0;
+	netlbl_secattr_destroy(&secattr);
+
+	return ret_val;
+}
+
+/**
+ * security_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
+ * @skb: the packet
+ * @base_sid: the SELinux SID to use as a context for MLS only attributes
+ * @sid: the SID
+ *
+ * Description:
+ * Call the NetLabel mechanism to get the security attributes of the given
+ * packet and use those attributes to determine the correct context/SID to
+ * assign to the packet.  Returns zero on success, negative values on failure.
+ *
+ */
+int security_netlbl_skbuff_getsid(struct sk_buff *skb, 
+				  const u32 base_sid,
+				  u32 *sid)
+{
+	int ret_val;
+	struct netlbl_lsm_secattr secattr;
+
+	if (!ss_initialized)
+		return 0;
+
+	netlbl_secattr_init(&secattr);
+
+	ret_val = netlbl_skbuff_getattr(skb, &secattr);
+	if (ret_val == 0)
+		ret_val = security_netlbl_secattr_to_sid(skb,
+							 &secattr,
+							 base_sid,
+							 sid);
+
+	secattr.set_cache = 0;
+	netlbl_secattr_destroy(&secattr);
+
+	return ret_val;
+}
+
+/**
+ * security_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
+ * @sock: the socket to label
+ * @sid: the SID to use as the basis for the label
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID.  Returns zero values on success, negative values on failure.
+ *
+ */
+int security_netlbl_socket_setsid(const struct socket *sock, const u32 sid)
+{
+	int ret_val;
+	struct netlbl_lsm_secattr secattr;
+	struct context *ctx;
+
+	if (!ss_initialized)
+		return 0;
+
+	ctx = sidtab_search(&sidtab, sid);
+	if (ctx != NULL) {
+		netlbl_secattr_init(&secattr);
+
+		if (security_context_export_type(ctx, 
+						 &secattr.domain,
+						 NULL) == 0)
+			secattr.set_domain = 1;
+		if (mls_export_lvl(ctx, &secattr.mls_lvl, NULL) == 0)
+			secattr.set_mls_lvl = 1;
+		if (mls_export_cat(ctx, 
+				   &secattr.mls_cat,
+				   &secattr.mls_cat_len,
+				   NULL,
+				   NULL) == 0)
+			secattr.set_mls_cat = 1;
+
+		ret_val = netlbl_socket_setattr(sock, &secattr);
+		netlbl_secattr_destroy(&secattr);
+	} else
+		ret_val = -ENOENT;
+
+	return ret_val;
+}
+
+/**
+ * security_netlbl_socket_accept - Handle the labeling of an accept()ed socket
+ * @sock: the original socket
+ * @newsock: the new accept()ed socket
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism based on the packets
+ * in the queue and the original socket's SID.  Returns zero values on success,
+ * negative values on failure.
+ *
+ */
+int security_netlbl_socket_accept(struct socket *sock, struct socket *newsock)
+{
+	int ret_val;
+	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+	struct netlbl_lsm_secattr secattr;
+	u32 newsock_sid;
+	u16 sock_class;
+	u32 relabelto_perm;
+
+	if (!ss_initialized)
+		return 0;
+	netlbl_secattr_init(&secattr);
+
+	ret_val = netlbl_socket_getattr(newsock, &secattr);
+	if (ret_val != 0)
+		goto netlbl_socket_accept_return;
+	ret_val = security_netlbl_secattr_to_sid(NULL,
+						 &secattr,
+						 isec->sid,
+						 &newsock_sid);
+	if (ret_val != 0 || newsock_sid == SECINITSID_UNLABELED)
+		goto netlbl_socket_accept_return;
+
+	sock_class = isec->sclass;
+	switch (sock_class) {
+	case SECCLASS_UDP_SOCKET:
+		relabelto_perm = UDP_SOCKET__RELABELTO;
+		break;
+	case SECCLASS_TCP_SOCKET:
+		relabelto_perm = TCP_SOCKET__RELABELTO;
+		break;
+	default:
+		relabelto_perm = RAWIP_SOCKET__RELABELTO;
+	}
+
+	/* PM - should we have a "RELABELFROM" check too? */
+	/* PM - i suspect we should audit this socket relabel */
+	ret_val = avc_has_perm(isec->sid, 
+			       newsock_sid,
+			       sock_class,
+			       relabelto_perm,
+			       NULL);
+	if (ret_val != 0)
+		goto netlbl_socket_accept_return;
+
+	isec = SOCK_INODE(newsock)->i_security;
+	isec->sid = newsock_sid;
+
+netlbl_socket_accept_return:
+	secattr.set_cache = 0;
+	netlbl_secattr_destroy(&secattr);
+
+	return security_netlbl_socket_setsid(newsock, isec->sid);
+}
+#endif /* CONFIG_NETLABEL */
+
 struct selinux_audit_rule {
 	u32 au_seqno;
 	struct context au_ctxt;
diff -purN linux-2.6.16.i686/security/selinux/xfrm.c linux-2.6.16.i686-netlabel_06132006/security/selinux/xfrm.c
--- linux-2.6.16.i686/security/selinux/xfrm.c	2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/xfrm.c	2006-06-13 11:20:00.000000000 -0400
@@ -295,13 +295,13 @@ u32 selinux_socket_getpeer_dgram(struct 
 /*
  * LSM hook that controls access to unlabelled packets.  If
  * a xfrm_state is authorizable (defined by macro) then it was
- * already authorized by the IPSec process.  If not, then
- * we need to check for unlabelled access since this may not have
- * gone thru the IPSec process.
+ * already authorized by the IPsec process.  Return zero when the
+ * packet has been approved by the IPsec process, negative values
+ * otherwise.
  */
 int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
 {
-	int i, rc = 0;
+	int i;
 	struct sec_path *sp;
 
 	sp = skb->sp;
@@ -317,21 +317,11 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_s
 			struct xfrm_state *x = sp->xvec[i];
 
 			if (x && selinux_authorizable_xfrm(x))
-				goto accept;
+				return 0;
 		}
 	}
 
-	/* check SELinux sock for unlabelled access */
-	rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
-			  ASSOCIATION__RECVFROM, NULL);
-	if (rc)
-		goto drop;
-
-accept:
-	return 0;
-
-drop:
-	return rc;
+	return -ENOMSG;
 }
 
 /*

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]