changeset 10934:e209937a4f19

PSARC/2008/252 Labeled IPsec phase 1 6886771 Labeled IPsec phase 1 6808727 Alignment error panic in tsol_can_accept_raw() 6894979 nightly -0 + -p builds then destroys SUNW0on
author Bill Sommerfeld <sommerfeld@sun.com>
date Mon, 02 Nov 2009 15:39:20 -0800
parents 7bba9f719ba5
children fb2b65d50333
files usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c usr/src/cmd/ptools/pfiles/pfiles.c usr/src/cmd/truss/print.c usr/src/cmd/tsol/tnctl/tnzonecfg usr/src/lib/libipsecutil/Makefile.com usr/src/lib/libipsecutil/common/ikedoor.h usr/src/lib/libipsecutil/common/ipsec_util.c usr/src/lib/libipsecutil/common/ipsec_util.h usr/src/lib/libipsecutil/common/mapfile-vers usr/src/tools/scripts/nightly.sh usr/src/uts/common/inet/ip/icmp.c usr/src/uts/common/inet/ip/icmp_opt_data.c usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip6.c usr/src/uts/common/inet/ip/ip_opt_data.c usr/src/uts/common/inet/ip/ip_sadb.c usr/src/uts/common/inet/ip/ipclassifier.c usr/src/uts/common/inet/ip/ipsecah.c usr/src/uts/common/inet/ip/ipsecesp.c usr/src/uts/common/inet/ip/sadb.c usr/src/uts/common/inet/ip/spd.c usr/src/uts/common/inet/ip/tn_ipopt.c usr/src/uts/common/inet/ip/tnet.c usr/src/uts/common/inet/ipclassifier.h usr/src/uts/common/inet/ipsec_impl.h usr/src/uts/common/inet/iptun/iptun.c usr/src/uts/common/inet/mib2.h usr/src/uts/common/inet/sadb.h usr/src/uts/common/inet/sctp/sctp.c usr/src/uts/common/inet/sctp/sctp_bind.c usr/src/uts/common/inet/sctp/sctp_common.c usr/src/uts/common/inet/sctp/sctp_cookie.c usr/src/uts/common/inet/sctp/sctp_error.c usr/src/uts/common/inet/sctp/sctp_impl.h usr/src/uts/common/inet/sctp/sctp_opt_data.c usr/src/uts/common/inet/sctp/sctp_snmp.c usr/src/uts/common/inet/tcp/tcp.c usr/src/uts/common/inet/tcp/tcp_opt_data.c usr/src/uts/common/inet/udp/udp.c usr/src/uts/common/inet/udp/udp_opt_data.c usr/src/uts/common/net/pfkeyv2.h usr/src/uts/common/os/policy.c usr/src/uts/common/os/priv_defs usr/src/uts/common/os/putnext.c usr/src/uts/common/sys/policy.h usr/src/uts/common/sys/socket.h usr/src/uts/common/sys/tsol/label.h usr/src/uts/common/sys/tsol/tnet.h
diffstat 50 files changed, 2337 insertions(+), 1058 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile	Mon Nov 02 15:39:20 2009 -0800
@@ -25,6 +25,7 @@
 
 PROG=		ikeadm ipsecalgs ipsecconf ipseckey ikecert
 SOCKETPROG=	ipsecalgs ipsecconf ipseckey 
+TSOLPROG=	ipseckey
 SRCS=           ikeadm.c ipsecalgs.c ipsecconf.c ipseckey.c
 
 include ../../../Makefile.cmd
@@ -57,6 +58,11 @@
 
 CFLAGS += $(XSTRCONST)
 LDLIBS += -lipsecutil -lnsl
+
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+
+$(TSOLPROG)	:=	LDLIBS += $(LAZYLIBS)
 $(SOCKETPROG)	:=      LDLIBS += -lsocket
 
 .KEEP_STATE:
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1284,6 +1284,8 @@
 		return (gettext("Door interface"));
 	case D_CONFIG:
 		return (gettext("Config file processing"));
+	case D_LABEL:
+		return (gettext("MAC label processing"));
 	default:
 		(void) snprintf(rtn, MAXLINESIZE,
 		    gettext("<unknown flag 0x%x>"), bit);
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c	Mon Nov 02 15:39:20 2009 -0800
@@ -399,6 +399,7 @@
 #define	NEXTIDENT	7
 #define	NEXTADDR4	8
 #define	NEXTADDR6	9
+#define	NEXTLABEL	10
 
 #define	TOK_EOF			0
 #define	TOK_UNKNOWN		1
@@ -455,6 +456,10 @@
 #define	TOK_IDLE_ADDTIME	52
 #define	TOK_IDLE_USETIME	53
 #define	TOK_RESERVED		54
+#define	TOK_LABEL		55
+#define	TOK_OLABEL		56
+#define	TOK_IMPLABEL		57
+
 
 static struct toktable {
 	char *string;
@@ -543,6 +548,11 @@
 	{"replay_value",	TOK_REPLAY_VALUE,	NEXTNUM},
 	{"idle_addtime",	TOK_IDLE_ADDTIME,	NEXTNUM},
 	{"idle_usetime",	TOK_IDLE_USETIME,	NEXTNUM},
+
+	{"label",		TOK_LABEL,		NEXTLABEL},
+	{"outer-label",		TOK_OLABEL,		NEXTLABEL},
+	{"implicit-label",	TOK_IMPLABEL,		NEXTLABEL},
+
 	{NULL,			TOK_UNKNOWN,		NEXTEOF}
 };
 
@@ -909,6 +919,58 @@
 	return (retval);
 }
 
+#include <tsol/label.h>
+
+#define	PARSELABEL_BAD_TOKEN ((struct sadb_sens *)-1)
+
+static struct sadb_sens *
+parselabel(int token, char *label)
+{
+	bslabel_t *sl = NULL;
+	int err, len;
+	sadb_sens_t *sens;
+	int doi = 1;  /* XXX XXX DEFAULT_DOI XXX XXX */
+
+	err = str_to_label(label, &sl, MAC_LABEL, L_DEFAULT, NULL);
+	if (err < 0)
+		return (NULL);
+
+	len = ipsec_convert_sl_to_sens(doi, sl, NULL);
+
+	sens = malloc(len);
+	if (sens == NULL) {
+		Bail("malloc parsed label");
+		/* Should exit before reaching here... */
+		return (NULL);
+	}
+
+	(void) ipsec_convert_sl_to_sens(doi, sl, sens);
+
+	switch (token) {
+	case TOK_LABEL:
+		break;
+
+	case TOK_OLABEL:
+		sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS;
+		break;
+
+	case TOK_IMPLABEL:
+		sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS;
+		sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT;
+		break;
+
+	default:
+		free(sens);
+		/*
+		 * Return a different return code for a bad label, but really,
+		 * this would be a caller error.
+		 */
+		return (PARSELABEL_BAD_TOKEN);
+	}
+
+	return (sens);
+}
+
 /*
  * Write a message to the PF_KEY socket.  If verbose, print the message
  * heading into the kernel.
@@ -1590,6 +1652,7 @@
 	struct sadb_lifetime *hard = NULL, *soft = NULL;  /* Current? */
 	struct sadb_lifetime *idle = NULL;
 	struct sadb_x_replay_ctr *replay_ctr = NULL;
+	struct sadb_sens *label = NULL, *olabel = NULL;
 	struct sockaddr_in6 *sin6;
 	/* MLS TODO:  Need sensitivity eventually. */
 	int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix;
@@ -2530,6 +2593,32 @@
 			    B_TRUE, ebuf);
 			argv++;
 			break;
+		case TOK_LABEL:
+			label = parselabel(token, *argv);
+			argv++;
+			if (label == NULL) {
+				ERROR(ep, ebuf,
+				    gettext("Malformed security label\n"));
+				break;
+			} else if (label == PARSELABEL_BAD_TOKEN) {
+				Bail("Internal token value error");
+			}
+			totallen += SADB_64TO8(label->sadb_sens_len);
+			break;
+
+		case TOK_OLABEL:
+		case TOK_IMPLABEL:
+			olabel = parselabel(token, *argv);
+			argv++;
+			if (label == NULL) {
+				ERROR(ep, ebuf,
+				    gettext("Malformed security label\n"));
+				break;
+			} else if (label == PARSELABEL_BAD_TOKEN) {
+				Bail("Internal token value error");
+			}
+			totallen += SADB_64TO8(olabel->sadb_sens_len);
+			break;
 		default:
 			ERROR1(ep, ebuf, gettext(
 			    "Don't use extension %s for add/update.\n"),
@@ -2830,6 +2919,20 @@
 		free(replay_ctr);
 	}
 
+	if (label != NULL) {
+		bcopy(label, nexthdr, SADB_64TO8(label->sadb_sens_len));
+		nexthdr += label->sadb_sens_len;
+		free(label);
+		label = NULL;
+	}
+
+	if (olabel != NULL) {
+		bcopy(olabel, nexthdr, SADB_64TO8(olabel->sadb_sens_len));
+		nexthdr += olabel->sadb_sens_len;
+		free(olabel);
+		olabel = NULL;
+	}
+
 	if (cflag) {
 		/*
 		 * Assume the checked cmd would have worked if it was actually
@@ -2855,7 +2958,6 @@
 		freehostent(natt_lhp);
 	if (natt_rhp != NULL && natt_rhp != &dummy.he)
 		freehostent(natt_rhp);
-
 	free(ebuf);
 	free(buffer);
 }
--- a/usr/src/cmd/ptools/pfiles/pfiles.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/ptools/pfiles/pfiles.c	Mon Nov 02 15:39:20 2009 -0800
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -591,6 +589,8 @@
 	    { SOL_SOCKET, SO_OOBINLINE,		"SO_OOBINLINE,"	},
 	    { SOL_SOCKET, SO_DGRAM_ERRIND,	"SO_DGRAM_ERRIND,"},
 	    { SOL_SOCKET, SO_ALLZONES,		"SO_ALLZONES,"	},
+	    { SOL_SOCKET, SO_MAC_EXEMPT,	"SO_MAC_EXEMPT," },
+	    { SOL_SOCKET, SO_MAC_IMPLICIT,	"SO_MAC_IMPLICIT," },
 	    { SOL_SOCKET, SO_EXCLBIND,		"SO_EXCLBIND," },
 	    { IPPROTO_UDP, UDP_NAT_T_ENDPOINT,	"UDP_NAT_T_ENDPOINT," },
 	};
--- a/usr/src/cmd/truss/print.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/truss/print.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1764,6 +1764,7 @@
 		case SO_ANON_MLP:	return ("SO_ANON_MLP");
 		case SO_MAC_EXEMPT:	return ("SO_MAC_EXEMPT");
 		case SO_ALLZONES:	return ("SO_ALLZONES");
+		case SO_MAC_IMPLICIT:	return ("SO_MAC_IMPLICIT");
 		case SO_EXCLBIND:	return ("SO_EXCLBIND");
 		case SO_DOMAIN:		return ("SO_DOMAIN");
 
--- a/usr/src/cmd/tsol/tnctl/tnzonecfg	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/cmd/tsol/tnctl/tnzonecfg	Mon Nov 02 15:39:20 2009 -0800
@@ -19,12 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#
 #There are five fields separated by colon in this configuration file:
 #First Field: 	Name for the corresponding zone.
 #		It is used when zone is configured.
@@ -52,9 +49,11 @@
 #	MLP			PURPOSE
 #	---			-------
 #	111			Port Mapper
+#	500			IKE (IPsec key management)
 #	515			BSD Multilevel Printing
 #	631			IPP Multilevel Printing
 #	2049			NFSv4 server
+#	4500			IKE NAT-T (IPsec/IKE nat traversal)
 #	6000-6003		Multilevel Desktop
 #
-global:ADMIN_LOW:1:111/tcp;111/udp;515/tcp;631/tcp;2049/tcp;6000-6003/tcp:6000-6003/tcp
+global:ADMIN_LOW:1:111/tcp;111/udp;500/udp;4500/udp;515/tcp;631/tcp;2049/tcp;6000-6003/tcp:6000-6003/tcp;500/udp;4500/udp
--- a/usr/src/lib/libipsecutil/Makefile.com	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/lib/libipsecutil/Makefile.com	Mon Nov 02 15:39:20 2009 -0800
@@ -34,6 +34,9 @@
 
 $(LINTLIB):=	SRCS = $(SRCDIR)/$(LINTSRC)
 LDLIBS +=	-ltecla -lsocket -lnsl -lc
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += $(LAZYLIBS)
 
 CFLAGS +=	$(CCVERBOSE)
 CPPFLAGS +=	-I$(SRCDIR)
--- a/usr/src/lib/libipsecutil/common/ikedoor.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/lib/libipsecutil/common/ikedoor.h	Mon Nov 02 15:39:20 2009 -0800
@@ -131,9 +131,10 @@
 #define	D_PROP		0x00000080	/* proposal construction */
 #define	D_DOOR		0x00000100	/* door server */
 #define	D_CONFIG	0x00000200	/* config file processing */
+#define	D_LABEL		0x00000400	/* MAC labels */
 
-#define	D_HIGHBIT	0x00000200
-#define	D_ALL		0x000003ff
+#define	D_HIGHBIT	0x00000400
+#define	D_ALL		0x000007ff
 
 /*
  * Access privilege levels: define level of access to keying information.
--- a/usr/src/lib/libipsecutil/common/ipsec_util.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.c	Mon Nov 02 15:39:20 2009 -0800
@@ -839,6 +839,7 @@
 	{ D_PROP,	"prop" },
 	{ D_DOOR,	"door" },
 	{ D_CONFIG,	"config" },
+	{ D_LABEL,	"label" },
 	{ D_ALL,	"all" },
 	{ 0,		"0" },
 };
@@ -2040,24 +2041,126 @@
 }
 
 /*
+ * Convert sadb_sens extension into binary security label.
+ */
+
+#include <tsol/label.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/label_macro.h>
+
+void
+ipsec_convert_sens_to_bslabel(const struct sadb_sens *sens, bslabel_t *sl)
+{
+	uint64_t *bitmap = (uint64_t *)(sens + 1);
+	int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
+
+	bsllow(sl);
+	LCLASS_SET((_bslabel_impl_t *)sl, sens->sadb_sens_sens_level);
+	bcopy(bitmap, &((_bslabel_impl_t *)sl)->compartments,
+	    bitmap_len);
+}
+
+void
+ipsec_convert_bslabel_to_string(bslabel_t *sl, char **plabel)
+{
+	if (label_to_str(sl, plabel, M_LABEL, DEF_NAMES) != 0) {
+		*plabel = strdup(dgettext(TEXT_DOMAIN,
+		    "** Label conversion failed **"));
+	}
+}
+
+void
+ipsec_convert_bslabel_to_hex(bslabel_t *sl, char **plabel)
+{
+	if (label_to_str(sl, plabel, M_INTERNAL, DEF_NAMES) != 0) {
+		*plabel = strdup(dgettext(TEXT_DOMAIN,
+		    "** Label conversion failed **"));
+	}
+}
+
+int
+ipsec_convert_sl_to_sens(int doi, bslabel_t *sl, sadb_sens_t *sens)
+{
+	uint8_t *bitmap;
+	int sens_len = sizeof (sadb_sens_t) + _C_LEN * 4;
+
+
+	if (sens == NULL)
+		return (sens_len);
+
+
+	(void) memset(sens, 0, sens_len);
+
+	sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+	sens->sadb_sens_len = SADB_8TO64(sens_len);
+	sens->sadb_sens_dpd = doi;
+
+	sens->sadb_sens_sens_level = LCLASS(sl);
+	sens->sadb_sens_integ_level = 0;
+	sens->sadb_sens_sens_len = _C_LEN >> 1;
+	sens->sadb_sens_integ_len = 0;
+
+	sens->sadb_x_sens_flags = 0;
+
+	bitmap = (uint8_t *)(sens + 1);
+	bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
+
+	return (sens_len);
+}
+
+
+/*
  * Print an SADB_SENSITIVITY extension.
  */
 void
-print_sens(FILE *file, char *prefix, struct sadb_sens *sens)
+print_sens(FILE *file, char *prefix, const struct sadb_sens *sens,
+	boolean_t ignore_nss)
 {
+	char *plabel;
+	char *hlabel;
 	uint64_t *bitmap = (uint64_t *)(sens + 1);
+	bslabel_t sl;
 	int i;
+	int sens_len = sens->sadb_sens_sens_len;
+	int integ_len = sens->sadb_sens_integ_len;
+	boolean_t inner = (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY);
+	const char *sensname = inner ?
+	    dgettext(TEXT_DOMAIN, "Plaintext Sensitivity") :
+	    dgettext(TEXT_DOMAIN, "Ciphertext Sensitivity");
+
+	ipsec_convert_sens_to_bslabel(sens, &sl);
 
 	(void) fprintf(file, dgettext(TEXT_DOMAIN,
-	    "%sSensitivity DPD %d, sens level=%d, integ level=%d\n"),
-	    prefix, sens->sadb_sens_dpd, sens->sadb_sens_sens_level,
-	    sens->sadb_sens_integ_level);
-	for (i = 0; sens->sadb_sens_sens_len-- > 0; i++, bitmap++)
+	    "%s%s DPD %d, sens level=%d, integ level=%d, flags=%x\n"),
+	    prefix, sensname, sens->sadb_sens_dpd, sens->sadb_sens_sens_level,
+	    sens->sadb_sens_integ_level, sens->sadb_x_sens_flags);
+
+	ipsec_convert_bslabel_to_hex(&sl, &hlabel);
+
+	if (ignore_nss) {
 		(void) fprintf(file, dgettext(TEXT_DOMAIN,
-		    "%s Sensitivity BM extended word %d 0x%" PRIx64 "\n"),
-		    prefix, i, *bitmap);
-	for (i = 0; sens->sadb_sens_integ_len-- > 0; i++, bitmap++)
-		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "%s %s Label: %s\n"), prefix, sensname, hlabel);
+
+		for (i = 0; i < sens_len; i++, bitmap++)
+			(void) fprintf(file, dgettext(TEXT_DOMAIN,
+			    "%s %s BM extended word %d 0x%" PRIx64 "\n"),
+			    prefix, sensname, i, *bitmap);
+
+	} else {
+		ipsec_convert_bslabel_to_string(&sl, &plabel);
+
+		(void) fprintf(file, dgettext(TEXT_DOMAIN,
+		    "%s %s Label: %s (%s)\n"),
+		    prefix, sensname, plabel, hlabel);
+		free(plabel);
+
+	}
+	free(hlabel);
+
+	bitmap = (uint64_t *)(sens + 1 + sens_len);
+
+	for (i = 0; i < integ_len; i++, bitmap++)
+		(void) fprintf(file, dgettext(TEXT_DOMAIN,
 		    "%s Integrity BM extended word %d 0x%" PRIx64 "\n"),
 		    prefix, i, *bitmap);
 }
@@ -2429,7 +2532,7 @@
 			break;
 		case SADB_EXT_SENSITIVITY:
 			print_sens(file, dgettext(TEXT_DOMAIN, "SNS: "),
-			    (struct sadb_sens *)current);
+			    (struct sadb_sens *)current, ignore_nss);
 			break;
 		case SADB_EXT_PROPOSAL:
 			print_prop(file, dgettext(TEXT_DOMAIN, "PRP: "),
@@ -2467,6 +2570,10 @@
 			print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "),
 			    (struct sadb_x_pair *)current);
 			break;
+		case SADB_X_EXT_OUTER_SENS:
+			print_sens(file, dgettext(TEXT_DOMAIN, "OSN: "),
+			    (struct sadb_sens *)current, ignore_nss);
+			break;
 		case SADB_X_EXT_REPLAY_VALUE:
 			(void) print_replay(file, dgettext(TEXT_DOMAIN,
 			    "RPL: "), (sadb_x_replay_ctr_t *)current);
@@ -2685,6 +2792,35 @@
 	return (B_TRUE);
 }
 
+boolean_t
+save_sens(struct sadb_sens *sens, FILE *ofile)
+{
+	char *prefix;
+	char *hlabel;
+	bslabel_t sl;
+
+	if (putc('\t', ofile) == EOF)
+		return (B_FALSE);
+
+	if (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY)
+		prefix = "label";
+	else if ((sens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) == 0)
+		prefix = "outer-label";
+	else
+		prefix = "implicit-label";
+
+	ipsec_convert_sens_to_bslabel(sens, &sl);
+	ipsec_convert_bslabel_to_hex(&sl, &hlabel);
+
+	if (fprintf(ofile, "%s %s ", prefix, hlabel) < 0) {
+		free(hlabel);
+		return (B_FALSE);
+	}
+	free(hlabel);
+
+	return (B_TRUE);
+}
+
 /*
  * "Save" a security association to an output file.
  *
@@ -2846,6 +2982,13 @@
 			savenl();
 			break;
 		case SADB_EXT_SENSITIVITY:
+		case SADB_X_EXT_OUTER_SENS:
+			if (!save_sens((struct sadb_sens *)ext, ofile)) {
+				tidyup();
+				bail(dgettext(TEXT_DOMAIN, "save_sens"));
+			}
+			savenl();
+			break;
 		default:
 			/* Skip over irrelevant extensions. */
 			break;
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.h	Mon Nov 02 15:39:20 2009 -0800
@@ -365,7 +365,7 @@
 extern void print_asn1_name(FILE *, const unsigned char *, long);
 extern void print_key(FILE *, char *, struct sadb_key *);
 extern void print_ident(FILE *, char *, struct sadb_ident *);
-extern void print_sens(FILE *, char *, struct sadb_sens *);
+extern void print_sens(FILE *, char *, const struct sadb_sens *, boolean_t);
 extern void print_prop(FILE *, char *, struct sadb_prop *);
 extern void print_eprop(FILE *, char *, struct sadb_prop *);
 extern void print_supp(FILE *, char *, struct sadb_supported *);
@@ -384,6 +384,18 @@
 extern const char *do_inet_ntop(const void *, char *, size_t);
 
 /*
+ * Label conversion convenience functions.
+ */
+
+#include <tsol/label.h>
+
+extern void ipsec_convert_sens_to_bslabel(const struct sadb_sens *,
+    bslabel_t *);
+extern int ipsec_convert_sl_to_sens(int doi, bslabel_t *, struct sadb_sens *);
+extern void ipsec_convert_bslabel_to_string(bslabel_t *, char **);
+extern void ipsec_convert_bslabel_to_hex(bslabel_t *, char **);
+
+/*
  * These exit macros give a consistent exit behaviour for all
  * programs that use libipsecutil. These wll work in usr/src/cmd
  * and usr/src/lib, but because macros in usr/src/lib don't get
--- a/usr/src/lib/libipsecutil/common/mapfile-vers	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/lib/libipsecutil/common/mapfile-vers	Mon Nov 02 15:39:20 2009 -0800
@@ -66,6 +66,10 @@
 	ipsecproto_get_exec_mode;
 	ipsecproto_set_exec_mode;
 	ipsecutil_exit;
+	ipsec_convert_sens_to_bslabel;
+	ipsec_convert_bslabel_to_string;
+	ipsec_convert_bslabel_to_hex;
+	ipsec_convert_sl_to_sens;
 	keysock_diag;
 	kmc_insert_mapping;
 	kmc_lookup_by_cookie;
--- a/usr/src/tools/scripts/nightly.sh	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/tools/scripts/nightly.sh	Mon Nov 02 15:39:20 2009 -0800
@@ -575,22 +575,6 @@
 	/bin/time $MAKE -e install 2>&1 | \
 	    tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
 
-	if [[ "$zero_FLAG" = "y" ]]; then
-		if [[ -d "${G11N_PKGDIR}" ]]; then
-			echo "\n==== Building globalization package" \
-			    "$(basename ${G11N_PKGDIR}) ($LABEL) ====\n" \
-			    >> $LOGFILE
-			cd $G11N_PKGDIR
-			/bin/time $MAKE -e install 2>&1 | \
-			    tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
-			cd $SRC
-		else
-			echo "\n==== Skipping nonexistent globalization" \
-			    "package $(basename ${G11N_PKGDIR})" \
-			    "($LABEL) ====\n" >> $LOGFILE
-		fi
-	fi
-
 	if [[ "$SCM_TYPE" = teamware ]]; then
 		echo "\n==== SCCS Noise ($LABEL) ====\n" >> $mail_msg_file
 		egrep 'sccs(check:| *get)' $SRC/${INSTALLOG}.out >> \
@@ -773,6 +757,22 @@
 		echo "\n==== Not creating $LABEL packages ====\n" >> $LOGFILE
 	fi
 
+	if [[ "$zero_FLAG" = "y" ]]; then
+		if [[ -d "${G11N_PKGDIR}" ]]; then
+			echo "\n==== Building globalization package" \
+			    "$(basename ${G11N_PKGDIR}) ($LABEL) ====\n" \
+			    >> $LOGFILE
+			cd $G11N_PKGDIR
+			/bin/time $MAKE -e install 2>&1 | \
+			    tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
+			cd $SRC
+		else
+			echo "\n==== Skipping nonexistent globalization" \
+			    "package $(basename ${G11N_PKGDIR})" \
+			    "($LABEL) ====\n" >> $LOGFILE
+		fi
+	fi
+
 	ROOT=$ORIGROOT
 }
 
--- a/usr/src/uts/common/inet/ip/icmp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/icmp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1683,7 +1683,7 @@
 	 * exempt mode.  This allows read-down to unlabeled hosts.
 	 */
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
-		connp->conn_mac_exempt = B_TRUE;
+		connp->conn_mac_mode = CONN_MAC_AWARE;
 
 	connp->conn_ulp_labeled = is_system_labeled();
 
@@ -1816,7 +1816,10 @@
 			*i1 = icmp->icmp_timestamp;
 			break;
 		case SO_MAC_EXEMPT:
-			*i1 = connp->conn_mac_exempt;
+			*i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+			break;
+		case SO_MAC_IMPLICIT:
+			*i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
 			break;
 		case SO_DOMAIN:
 			*i1 = icmp->icmp_family;
@@ -4447,7 +4450,7 @@
 	 * with a modified label or label flags.
 	 */
 	if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
-	    connp->conn_mac_exempt, &effective_cred)) != 0)
+	    connp->conn_mac_mode, &effective_cred)) != 0)
 		goto done;
 	if (effective_cred != NULL)
 		cred = effective_cred;
@@ -4890,7 +4893,7 @@
 	 * with a modified label or label flags.
 	 */
 	if ((err = tsol_check_dest(cred, dst, IPV6_VERSION,
-	    connp->conn_mac_exempt, &effective_cred)) != 0)
+	    connp->conn_mac_mode, &effective_cred)) != 0)
 		goto done;
 	if (effective_cred != NULL)
 		cred = effective_cred;
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c	Mon Nov 02 15:39:20 2009 -0800
@@ -91,6 +91,8 @@
 	},
 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
 	0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+	0 },
 
 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT, sizeof (int),
 	0 },
--- a/usr/src/uts/common/inet/ip/ip.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c	Mon Nov 02 15:39:20 2009 -0800
@@ -2056,9 +2056,7 @@
 		ii = (ipsec_in_t *)first_mp->b_rptr;
 		ii->ipsec_in_ns = ipst->ips_netstack;	/* No netstack_hold */
 	}
-	ii->ipsec_in_zoneid = zoneid;
-	ASSERT(zoneid != ALL_ZONES);
-	if (!ipsec_in_to_out(first_mp, ipha, NULL)) {
+	if (!ipsec_in_to_out(first_mp, ipha, NULL, zoneid)) {
 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 		return;
 	}
@@ -3262,7 +3260,7 @@
 			/*
 			 * Convert the IPSEC_IN to IPSEC_OUT.
 			 */
-			if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
+			if (!ipsec_in_to_out(ipsec_mp, ipha, NULL, zoneid)) {
 				BUMP_MIB(&ipst->ips_ip_mib,
 				    ipIfStatsOutDiscards);
 				return;
@@ -3304,20 +3302,12 @@
 
 		/* This is not a secure packet */
 		ii->ipsec_in_secure = B_FALSE;
-		/*
-		 * For trusted extensions using a shared IP address we can
-		 * send using any zoneid.
-		 */
-		if (zoneid == ALL_ZONES)
-			ii->ipsec_in_zoneid = GLOBAL_ZONEID;
-		else
-			ii->ipsec_in_zoneid = zoneid;
 		ipsec_mp->b_cont = mp;
 		ipha = (ipha_t *)mp->b_rptr;
 		/*
 		 * Convert the IPSEC_IN to IPSEC_OUT.
 		 */
-		if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
+		if (!ipsec_in_to_out(ipsec_mp, ipha, NULL, zoneid)) {
 			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
 			return;
 		}
@@ -4427,7 +4417,7 @@
 		if (is_system_labeled() && protocol == IPPROTO_UDP)
 			goto bad_addr;
 
-		if (connp->conn_mac_exempt)
+		if (connp->conn_mac_mode != CONN_MAC_DEFAULT)
 			goto bad_addr;
 
 		/* No hash here really.  The table is big enough. */
@@ -4778,7 +4768,7 @@
 	 */
 	if (is_system_labeled() && !IPCL_IS_TCP(connp)) {
 		if ((error = tsol_check_dest(cr, &dst_addr, IPV4_VERSION,
-		    connp->conn_mac_exempt, &effective_cred)) != 0) {
+		    connp->conn_mac_mode, &effective_cred)) != 0) {
 			if (ip_debug > 2) {
 				pr_addr_dbg(
 				    "ip_bind_connected_v4:"
@@ -7244,7 +7234,8 @@
 		while ((connp != NULL) &&
 		    (!IPCL_UDP_MATCH(connp, dstport, dst, srcport, src) ||
 		    (!IPCL_ZONE_MATCH(connp, zoneid) &&
-		    !(unlabeled && connp->conn_mac_exempt && shared_addr)))) {
+		    !(unlabeled && (connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+		    shared_addr)))) {
 			/*
 			 * We keep searching since the conn did not match,
 			 * or its zone did not match and it is not either
@@ -9827,7 +9818,7 @@
 	 * exempt mode.  This allows read-down to unlabeled hosts.
 	 */
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
-		connp->conn_mac_exempt = B_TRUE;
+		connp->conn_mac_mode = CONN_MAC_AWARE;
 
 	connp->conn_rq = q;
 	connp->conn_wq = WR(q);
@@ -10628,7 +10619,18 @@
 				return (EACCES);
 			if (!checkonly) {
 				mutex_enter(&connp->conn_lock);
-				connp->conn_mac_exempt = *i1 != 0 ? 1 : 0;
+				connp->conn_mac_mode = *i1 != 0 ?
+				    CONN_MAC_AWARE : CONN_MAC_DEFAULT;
+				mutex_exit(&connp->conn_lock);
+			}
+			break;	/* goto sizeof (int) option return */
+		case SO_MAC_IMPLICIT:
+			if (secpolicy_net_mac_implicit(cr) != 0)
+				return (EACCES);
+			if (!checkonly) {
+				mutex_enter(&connp->conn_lock);
+				connp->conn_mac_mode = *i1 != 0 ?
+				    CONN_MAC_IMPLICIT : CONN_MAC_DEFAULT;
 				mutex_exit(&connp->conn_lock);
 			}
 			break;	/* goto sizeof (int) option return */
@@ -13957,14 +13959,14 @@
 		if (ipst->ips_ip4_observe.he_interested) {
 			zoneid_t szone;
 
+			/*
+			 * Both of these functions expect b_rptr to be
+			 * where the IP header starts, so advance past the
+			 * link layer header if present.
+			 */
+			mp->b_rptr += hlen;
 			szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
 			    ipst, ALL_ZONES);
-			/*
-			 * The IP observability hook expects b_rptr to be
-			 * where the IP header starts, so advance past the
-			 * link layer header.
-			 */
-			mp->b_rptr += hlen;
 			ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
 			    ALL_ZONES, ill, ipst);
 			mp->b_rptr -= hlen;
@@ -20373,7 +20375,7 @@
 
 		credp = BEST_CRED(mp, connp, &pid);
 		err = tsol_check_label(credp, &mp,
-		    connp->conn_mac_exempt, ipst, pid);
+		    connp->conn_mac_mode, ipst, pid);
 		ipha = (ipha_t *)mp->b_rptr;
 		if (err != 0) {
 			first_mp = mp;
@@ -20436,12 +20438,11 @@
 			if (need_decref)
 				CONN_DEC_REF(connp);
 			return;
-		} else {
-			ASSERT(mp->b_datap->db_type == M_CTL);
-			first_mp = mp;
-			mp = mp->b_cont;
-			mctl_present = B_TRUE;
-		}
+		}
+		ASSERT(mp->b_datap->db_type == M_CTL);
+		first_mp = mp;
+		mp = mp->b_cont;
+		mctl_present = B_TRUE;
 	} else {
 		first_mp = mp;
 		mctl_present = B_FALSE;
@@ -20866,10 +20867,10 @@
 			if (connp != NULL) {
 				credp = BEST_CRED(mp, connp, &pid);
 				err = tsol_check_label(credp, &mp,
-				    connp->conn_mac_exempt, ipst, pid);
+				    connp->conn_mac_mode, ipst, pid);
 			} else if ((credp = msg_getcred(mp, &pid)) != NULL) {
 				err = tsol_check_label(credp, &mp,
-				    B_FALSE, ipst, pid);
+				    CONN_MAC_DEFAULT, ipst, pid);
 			}
 			ipha = (ipha_t *)mp->b_rptr;
 			if (mctl_present)
@@ -22166,9 +22167,10 @@
 		mp = first_mp->b_cont;
 		ipsec_len = ipsec_out_extra_length(first_mp);
 		ASSERT(ipsec_len >= 0);
+		if (zoneid == ALL_ZONES)
+			zoneid = GLOBAL_ZONEID;
 		/* We already picked up the zoneid from the M_CTL above */
 		ASSERT(zoneid == io->ipsec_out_zoneid);
-		ASSERT(zoneid != ALL_ZONES);
 
 		/*
 		 * Drop M_CTL here if IPsec processing is not needed.
@@ -25472,6 +25474,7 @@
 	hwaccel = io->ipsec_out_accelerated;
 	zoneid = io->ipsec_out_zoneid;
 	ASSERT(zoneid != ALL_ZONES);
+	ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
 	match_flags = MATCH_IRE_ILL | MATCH_IRE_SECATTR;
 	/* Multicast addresses should have non-zero ill_index. */
 	v6dstp = &ip6h->ip6_dst;
@@ -25532,6 +25535,7 @@
 			if (ill_need_rele)
 				ill_refrele(ill);
 			freemsg(ipsec_mp);
+			ipif_refrele(ipif);
 			return;
 		}
 
--- a/usr/src/uts/common/inet/ip/ip6.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ip6.c	Mon Nov 02 15:39:20 2009 -0800
@@ -442,9 +442,7 @@
 			ii->ipsec_in_secure = B_FALSE;
 			first_mp->b_cont = mp;
 		}
-		ii->ipsec_in_zoneid = zoneid;
-		ASSERT(zoneid != ALL_ZONES);
-		if (!ipsec_in_to_out(first_mp, NULL, ip6h)) {
+		if (!ipsec_in_to_out(first_mp, NULL, ip6h, zoneid)) {
 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 			return;
 		}
@@ -1517,7 +1515,7 @@
 			/*
 			 * Convert the IPSEC_IN to IPSEC_OUT.
 			 */
-			if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h)) {
+			if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h, zoneid)) {
 				BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 				ill_refrele(ill);
 				return;
@@ -1549,20 +1547,12 @@
 
 		/* This is not a secure packet */
 		ii->ipsec_in_secure = B_FALSE;
-		/*
-		 * For trusted extensions using a shared IP address we can
-		 * send using any zoneid.
-		 */
-		if (zoneid == ALL_ZONES)
-			ii->ipsec_in_zoneid = GLOBAL_ZONEID;
-		else
-			ii->ipsec_in_zoneid = zoneid;
 		ipsec_mp->b_cont = mp;
 		ip6h = (ip6_t *)mp->b_rptr;
 		/*
 		 * Convert the IPSEC_IN to IPSEC_OUT.
 		 */
-		if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h)) {
+		if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h, zoneid)) {
 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 			ill_refrele(ill);
 			return;
@@ -2077,8 +2067,8 @@
 			goto bad_addr;
 
 		/* Allow ipsec plumbing */
-		if (connp->conn_mac_exempt && protocol != IPPROTO_AH &&
-		    protocol != IPPROTO_ESP)
+		if ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+		    (protocol != IPPROTO_AH) && (protocol != IPPROTO_ESP))
 			goto bad_addr;
 
 		connp->conn_srcv6 = ipv6_all_zeros;
@@ -2477,7 +2467,7 @@
 	 */
 	if (is_system_labeled() && !IPCL_IS_TCP(connp)) {
 		if ((error = tsol_check_dest(cr, v6dst, IPV6_VERSION,
-		    connp->conn_mac_exempt, &effective_cred)) != 0) {
+		    connp->conn_mac_mode, &effective_cred)) != 0) {
 			if (ip_debug > 2) {
 				pr_addr_dbg(
 				    "ip_bind_connected: no label for dst %s\n",
@@ -9117,9 +9107,10 @@
 			ASSERT(CONN_CRED(connp) != NULL);
 			cr = BEST_CRED(mp, connp, &pid);
 			err = tsol_check_label_v6(cr, &mp,
-			    connp->conn_mac_exempt, ipst, pid);
+			    connp->conn_mac_mode, ipst, pid);
 		} else if ((cr = msg_getcred(mp, &pid)) != NULL) {
-			err = tsol_check_label_v6(cr, &mp, B_FALSE, ipst, pid);
+			err = tsol_check_label_v6(cr, &mp, CONN_MAC_DEFAULT,
+			    ipst, pid);
 		}
 		if (mctl_present)
 			first_mp->b_cont = mp;
@@ -11891,16 +11882,15 @@
 			if (ipst->ips_ip6_observe.he_interested) {
 				zoneid_t	szone;
 
-				szone = ip_get_zoneid_v6(&ip6h->ip6_src,
-				    mp_ip6h, out_ill, ipst, ALL_ZONES);
-
 				/*
-				 * The IP observability hook expects b_rptr to
+				 * Both of these functions expect b_rptr to
 				 * be where the IPv6 header starts, so advance
 				 * past the link layer header.
 				 */
 				if (fp_prepend)
 					mp_ip6h->b_rptr += hlen;
+				szone = ip_get_zoneid_v6(&ip6h->ip6_src,
+				    mp_ip6h, out_ill, ipst, ALL_ZONES);
 				ipobs_hook(mp_ip6h, IPOBS_HOOK_OUTBOUND, szone,
 				    ALL_ZONES, out_ill, ipst);
 				if (fp_prepend)
--- a/usr/src/uts/common/inet/ip/ip_opt_data.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ip_opt_data.c	Mon Nov 02 15:39:20 2009 -0800
@@ -61,8 +61,8 @@
 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 { SO_PROTOTYPE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
-{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
-	},
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 
 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
 	0 },
--- a/usr/src/uts/common/inet/ip/ip_sadb.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ip_sadb.c	Mon Nov 02 15:39:20 2009 -0800
@@ -25,6 +25,7 @@
 
 #include <sys/types.h>
 #include <sys/stream.h>
+#include <sys/strsubr.h>
 #include <sys/sunddi.h>
 #include <sys/ddi.h>
 #include <sys/strlog.h>
@@ -56,6 +57,48 @@
 	    ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid);
 }
 
+/* cr1 is packet cred; cr2 is SA credential */
+boolean_t
+ipsec_label_match(cred_t *cr1, cred_t *cr2)
+{
+	ts_label_t *l1, *l2;
+
+	if (!is_system_labeled())
+		return (B_TRUE);
+
+	/*
+	 * Check for NULL creds.  Unlabeled SA always matches;
+	 * unlabeled user with labeled  SA always fails
+	 */
+	if (cr2 == NULL)
+		return (B_TRUE);
+
+	if (cr1 == NULL)
+		return (B_FALSE);
+
+	/* If we reach here, we have two passed-in creds. */
+	ASSERT(cr2 != NULL && cr1 != NULL);
+
+	/* Check for NULL labels.  Two is good, one is bad, zero is good. */
+	l1 = crgetlabel(cr1);
+	l2 = crgetlabel(cr2);
+	if (l1 == NULL)
+		return (l2 == NULL);
+
+	if (l2 == NULL)
+		return (B_FALSE);
+
+	/* Simple IPsec MLS policy: labels must be equal */
+	/* In future will need bit in policy saying whether this is the case */
+
+	/*
+	 * label_equal() checks DOI and label contents.  We should be
+	 * good to go with this check.
+	 */
+	return (label_equal(l1, l2));
+}
+
+
 /*
  * Look up a security association based on the unique ID generated by IP and
  * transport or tunnel information, such as ports and upper-layer protocol,
@@ -67,7 +110,7 @@
  */
 ipsa_t *
 ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src,
-    uint32_t *dst, sa_family_t af, uint8_t protocol)
+    uint32_t *dst, sa_family_t af, uint8_t protocol, cred_t *cr)
 {
 	ipsa_t *retval, *candidate;
 	ipsec_action_t *candact;
@@ -287,6 +330,12 @@
 			goto next_ipsa;
 
 		/*
+		 * Do labels match?
+		 */
+		if (!ipsec_label_match(cr, retval->ipsa_cred))
+			goto next_ipsa;
+
+		/*
 		 * At this point, we know that we have at least a match on:
 		 *
 		 * - dest
@@ -546,6 +595,7 @@
 	sadbp_t *sadbp;
 	sadb_t *sp;
 	sa_family_t af;
+	cred_t *cr;
 	netstack_t	*ns;
 
 	data_mp = mp->b_cont;
@@ -601,8 +651,11 @@
 		dst_ptr = (uint32_t *)&dst6;
 	}
 
+	cr = msg_getcred(data_mp, NULL);
+
 	mutex_enter(&bucket->isaf_lock);
-	assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af, proto);
+	assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af,
+	    proto, cr);
 	mutex_exit(&bucket->isaf_lock);
 
 	if (assoc == NULL)
--- a/usr/src/uts/common/inet/ip/ipclassifier.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ipclassifier.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1019,8 +1019,8 @@
 	ip_stack_t	*ipst = connp->conn_netstack->netstack_ip;
 
 	ASSERT(connp != NULL);
-	ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
-	    protocol == IPPROTO_ESP);
+	ASSERT((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
+	    protocol == IPPROTO_AH || protocol == IPPROTO_ESP);
 
 	connp->conn_ulp = protocol;
 
@@ -1036,8 +1036,8 @@
 	ip_stack_t	*ipst = connp->conn_netstack->netstack_ip;
 
 	ASSERT(connp != NULL);
-	ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
-	    protocol == IPPROTO_ESP);
+	ASSERT((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
+	    protocol == IPPROTO_AH || protocol == IPPROTO_ESP);
 
 	connp->conn_ulp = protocol;
 
@@ -1221,7 +1221,8 @@
 		if (connp->conn_af_isv6 != tconn->conn_af_isv6)
 			continue;
 		/* If neither is exempt, then there's no conflict */
-		if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+		if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) &&
+		    (tconn->conn_mac_mode == CONN_MAC_DEFAULT))
 			continue;
 		/* We are only concerned about sockets for a different zone */
 		if (connp->conn_zoneid == tconn->conn_zoneid)
@@ -1252,7 +1253,8 @@
 		if (connp->conn_af_isv6 != tconn->conn_af_isv6)
 			continue;
 		/* If neither is exempt, then there's no conflict */
-		if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+		if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) &&
+		    (tconn->conn_mac_mode == CONN_MAC_DEFAULT))
 			continue;
 		/* We are only concerned about sockets for a different zone */
 		if (connp->conn_zoneid == tconn->conn_zoneid)
@@ -1751,8 +1753,8 @@
 		    connp = connp->conn_next) {
 			if (IPCL_BIND_MATCH(connp, protocol, ipha->ipha_dst,
 			    lport) && (IPCL_ZONE_MATCH(connp, zoneid) ||
-			    (unlabeled && connp->conn_mac_exempt &&
-			    shared_addr)))
+			    (unlabeled && shared_addr &&
+			    (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
 				break;
 		}
 
@@ -1828,8 +1830,8 @@
 			if (IPCL_UDP_MATCH(connp, lport, ipha->ipha_dst,
 			    fport, ipha->ipha_src) &&
 			    (IPCL_ZONE_MATCH(connp, zoneid) ||
-			    (unlabeled && connp->conn_mac_exempt &&
-			    shared_addr)))
+			    (unlabeled && shared_addr &&
+			    (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
 				break;
 		}
 
@@ -1957,8 +1959,8 @@
 			if (IPCL_BIND_MATCH_V6(connp, protocol,
 			    ip6h->ip6_dst, lport) &&
 			    (IPCL_ZONE_MATCH(connp, zoneid) ||
-			    (unlabeled && connp->conn_mac_exempt &&
-			    shared_addr)))
+			    (unlabeled && shared_addr &&
+			    (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
 				break;
 		}
 
@@ -2033,8 +2035,8 @@
 			if (IPCL_UDP_MATCH_V6(connp, lport, ip6h->ip6_dst,
 			    fport, ip6h->ip6_src) &&
 			    (IPCL_ZONE_MATCH(connp, zoneid) ||
-			    (unlabeled && connp->conn_mac_exempt &&
-			    shared_addr)))
+			    (unlabeled && shared_addr &&
+			    (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
 				break;
 		}
 
@@ -2180,7 +2182,9 @@
 		}
 
 		if (IPCL_ZONE_MATCH(connp, zoneid) ||
-		    (unlabeled && connp->conn_mac_exempt && shared_addr))
+		    (unlabeled &&
+		    (connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+		    shared_addr))
 			break;
 	}
 	/*
--- a/usr/src/uts/common/inet/ip/ipsecah.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ipsecah.c	Mon Nov 02 15:39:20 2009 -0800
@@ -70,6 +70,8 @@
 #include <sys/kstat.h>
 #include <sys/strsubr.h>
 
+#include <sys/tsol/tnet.h>
+
 /*
  * Table of ND variables supported by ipsecah. These are loaded into
  * ipsecah_g_nd in ipsecah_init_nd.
@@ -148,7 +150,8 @@
 static void ipsecah_rput(queue_t *, mblk_t *);
 static void ipsecah_wput(queue_t *, mblk_t *);
 static void ah_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
-static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *);
+static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
+    mblk_t *);
 static void	*ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
 static void	ipsecah_stack_fini(netstackid_t stackid, void *arg);
 
@@ -673,7 +676,7 @@
  */
 static boolean_t
 ah_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
-    ipsecah_stack_t *ahstack)
+    ipsecah_stack_t *ahstack, mblk_t *in_mp)
 {
 	mblk_t *mp;
 	boolean_t rc = B_TRUE;
@@ -685,6 +688,10 @@
 	ipsec_alginfo_t **authalgs;
 	uint_t num_aalgs;
 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
+	sadb_sens_t *sens;
+	size_t sens_len = 0;
+	sadb_ext_t *nextext;
+	cred_t *sens_cr = NULL;
 
 	/* Allocate the KEYSOCK_OUT. */
 	mp = sadb_keysock_out(serial);
@@ -693,6 +700,15 @@
 		return (B_FALSE);
 	}
 
+	if (is_system_labeled() && (in_mp != NULL)) {
+		sens_cr = msg_getcred(in_mp, NULL);
+
+		if (sens_cr != NULL) {
+			sens_len = sadb_sens_len_from_cred(sens_cr);
+			allocsize += sens_len;
+		}
+	}
+
 	/*
 	 * Allocate the PF_KEY message that follows KEYSOCK_OUT.
 	 * The alg reader lock needs to be held while allocating
@@ -727,10 +743,11 @@
 	}
 
 	mp->b_cont->b_wptr += allocsize;
+	nextext = (sadb_ext_t *)(mp->b_cont->b_rptr + sizeof (*samsg));
+
 	if (num_aalgs != 0) {
 
-		saalg = (sadb_alg_t *)(mp->b_cont->b_rptr + sizeof (*samsg) +
-		    sizeof (*sasupp));
+		saalg = (sadb_alg_t *)(((uint8_t *)nextext) + sizeof (*sasupp));
 		ASSERT(((ulong_t)saalg & 0x7) == 0);
 
 		numalgs_snap = 0;
@@ -764,10 +781,19 @@
 				cmn_err(CE_PANIC,
 				    "ah_register_out()!  Missed #%d.\n", i);
 #endif /* DEBUG */
+		nextext = (sadb_ext_t *)saalg;
 	}
 
 	mutex_exit(&ipss->ipsec_alg_lock);
 
+	if (sens_cr != NULL) {
+		sens = (sadb_sens_t *)nextext;
+		sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+		    sens_cr, sens_len);
+
+		nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
+	}
+
 	/* Now fill the restof the SADB_REGISTER message. */
 
 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
@@ -784,10 +810,10 @@
 	samsg->sadb_msg_seq = sequence;
 	samsg->sadb_msg_pid = pid;
 
-	if (allocsize > sizeof (*samsg)) {
+	if (num_aalgs != 0) {
 		sasupp = (sadb_supported_t *)(samsg + 1);
-		sasupp->sadb_supported_len =
-		    SADB_8TO64(allocsize - sizeof (sadb_msg_t));
+		sasupp->sadb_supported_len = SADB_8TO64(
+		    sizeof (*sasupp) + sizeof (*saalg) * num_aalgs);
 		sasupp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
 		sasupp->sadb_supported_reserved = 0;
 	}
@@ -816,7 +842,7 @@
 	 * Time to send a PF_KEY SADB_REGISTER message to AH listeners
 	 * everywhere.  (The function itself checks for NULL ah_pfkey_q.)
 	 */
-	(void) ah_register_out(0, 0, 0, ahstack);
+	(void) ah_register_out(0, 0, 0, ahstack, NULL);
 }
 
 /*
@@ -865,22 +891,17 @@
 ah_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
     int *diagnostic, ipsecah_stack_t *ahstack)
 {
-	isaf_t *primary = NULL, *secondary, *inbound, *outbound;
+	isaf_t *primary = NULL, *secondary;
+	boolean_t clone = B_FALSE, is_inbound = B_FALSE;
 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
-	struct sockaddr_in *dst;
-	struct sockaddr_in6 *dst6;
-	boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE;
-	uint32_t *dstaddr;
 	ipsa_t *larval;
 	ipsacq_t *acqrec;
 	iacqf_t *acq_bucket;
 	mblk_t *acq_msgs = NULL;
 	mblk_t *lpkt;
 	int rc;
-	sadb_t *sp;
-	int outhash;
+	ipsa_query_t sq;
+	int error;
 	netstack_t	*ns = ahstack->ipsecah_netstack;
 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
 
@@ -888,22 +909,13 @@
 	 * Locate the appropriate table(s).
 	 */
 
-	dst = (struct sockaddr_in *)(dstext + 1);
-	dst6 = (struct sockaddr_in6 *)dst;
-	is_ipv4 = (dst->sin_family == AF_INET);
-	if (is_ipv4) {
-		sp = &ahstack->ah_sadb.s_v4;
-		dstaddr = (uint32_t *)(&dst->sin_addr);
-		outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr);
-	} else {
-		ASSERT(dst->sin_family == AF_INET6);
-		sp = &ahstack->ah_sadb.s_v6;
-		dstaddr = (uint32_t *)(&dst6->sin6_addr);
-		outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr);
-	}
-
-	inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
-	outbound = &sp->sdb_of[outhash];
+	sq.spp = &ahstack->ah_sadb;
+	error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
+	    IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+	    &sq, diagnostic);
+	if (error)
+		return (error);
+
 	/*
 	 * Use the direction flags provided by the KMD to determine
 	 * if the inbound or outbound table should be the primary
@@ -911,18 +923,17 @@
 	 * decision based on the addresses.
 	 */
 	if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
-		primary = inbound;
-		secondary = outbound;
+		primary = sq.inbound;
+		secondary = sq.outbound;
 		is_inbound = B_TRUE;
 		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
 			clone = B_TRUE;
 	} else {
 		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
-			primary = outbound;
-			secondary = inbound;
+			primary = sq.outbound;
+			secondary = sq.inbound;
 		}
 	}
-
 	if (primary == NULL) {
 		/*
 		 * The KMD did not set a direction flag, determine which
@@ -943,12 +954,13 @@
 		 */
 		case KS_IN_ADDR_ME:
 			assoc->sadb_sa_flags |= IPSA_F_INBOUND;
-			primary = inbound;
-			secondary = outbound;
+			primary = sq.inbound;
+			secondary = sq.outbound;
 			if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
 				clone = B_TRUE;
 			is_inbound = B_TRUE;
 			break;
+
 		/*
 		 * If the source address literally not mine (either
 		 * unspecified or not mine), then this SA may have an
@@ -958,8 +970,8 @@
 		 */
 		case KS_IN_ADDR_NOTME:
 			assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
-			primary = outbound;
-			secondary = inbound;
+			primary = sq.outbound;
+			secondary = sq.inbound;
 			if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
 				assoc->sadb_sa_flags |= IPSA_F_INBOUND;
 				clone = B_TRUE;
@@ -980,7 +992,7 @@
 	 */
 
 	if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
-		acq_bucket = &sp->sdb_acq[outhash];
+		acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
 		mutex_enter(&acq_bucket->iacqf_lock);
 		for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
 		    acqrec = acqrec->ipsacq_next) {
@@ -991,7 +1003,7 @@
 			 *    that are queued up.
 			 */
 			if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
-			    IPSA_ARE_ADDR_EQUAL(dstaddr,
+			    IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
 			    acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
 				break;
 			mutex_exit(&acqrec->ipsacq_lock);
@@ -1019,10 +1031,10 @@
 	larval = NULL;
 
 	if (samsg->sadb_msg_type == SADB_UPDATE) {
-		mutex_enter(&inbound->isaf_lock);
-		larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi,
-		    ALL_ZEROES_PTR, dstaddr, dst->sin_family);
-		mutex_exit(&inbound->isaf_lock);
+		mutex_enter(&sq.inbound->isaf_lock);
+		larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
+		    ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
+		mutex_exit(&sq.inbound->isaf_lock);
 
 		if ((larval == NULL) ||
 		    (larval->ipsa_state != IPSA_STATE_LARVAL)) {
@@ -1071,11 +1083,14 @@
 				if (ah_outbound(mp) == IPSEC_STATUS_SUCCESS) {
 					ipha_t *ipha = (ipha_t *)
 					    mp->b_cont->b_rptr;
-					if (is_ipv4) {
+					if (sq.af == AF_INET) {
 						ip_wput_ipsec_out(NULL, mp,
 						    ipha, NULL, NULL);
 					} else {
 						ip6_t *ip6h = (ip6_t *)ipha;
+
+						ASSERT(sq.af == AF_INET6);
+
 						ip_wput_ipsec_out_v6(NULL,
 						    mp, ip6h, NULL, NULL);
 					}
@@ -1172,14 +1187,22 @@
 	ASSERT(src->sin_family == dst->sin_family);
 
 	/* Stuff I don't support, for now.  XXX Diagnostic? */
-	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL ||
-	    ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
 		return (EOPNOTSUPP);
 
+	if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) {
+		if (!is_system_labeled())
+			return (EOPNOTSUPP);
+	}
+
+	if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL) {
+		if (!is_system_labeled())
+			return (EOPNOTSUPP);
+	}
 	/*
-	 * XXX Policy : I'm not checking identities or sensitivity
-	 * labels at this time, but if I did, I'd do them here, before I sent
-	 * the weak key check up to the algorithm.
+	 * XXX Policy : I'm not checking identities at this time, but
+	 * if I did, I'd do them here, before I sent the weak key
+	 * check up to the algorithm.
 	 */
 
 	/* verify that there is a mapping for the specified algorithm */
@@ -1214,6 +1237,7 @@
 	    diagnostic, ahstack));
 }
 
+/* Refactor me */
 /*
  * Update a security association.  Updates come in two varieties.  The first
  * is an update of lifetimes on a non-larval SA.  The second is an update of
@@ -1249,6 +1273,7 @@
 	return (rcode);
 }
 
+/* Refactor me */
 /*
  * Delete a security association.  This is REALLY likely to be code common to
  * both AH and ESP.  Find the association, then unlink it.
@@ -1275,14 +1300,15 @@
 		}
 		return (sadb_purge_sa(mp, ksi,
 		    (sin->sin_family == AF_INET6) ? &ahstack->ah_sadb.s_v6 :
-		    &ahstack->ah_sadb.s_v4,
-		    ahstack->ah_pfkey_q, ahstack->ah_sadb.s_ip_q));
+		    &ahstack->ah_sadb.s_v4, diagnostic, ahstack->ah_pfkey_q,
+		    ahstack->ah_sadb.s_ip_q));
 	}
 
 	return (sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
 	    ahstack->ah_pfkey_q, sadb_msg_type));
 }
 
+/* Refactor me */
 /*
  * Convert the entire contents of all of AH's SA tables into PF_KEY SADB_DUMP
  * messages.
@@ -1423,7 +1449,7 @@
 		 * Keysock takes care of the PF_KEY bookkeeping for this.
 		 */
 		if (ah_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
-		    ksi->ks_in_serial, ahstack)) {
+		    ksi->ks_in_serial, ahstack, mp)) {
 			freemsg(mp);
 		} else {
 			/*
@@ -1595,6 +1621,7 @@
 	}
 }
 
+/* Refactor me */
 /*
  * Updating use times can be tricky business if the ipsa_haspeer flag is
  * set.  This function is called once in an SA's lifetime.
@@ -1693,6 +1720,7 @@
 	}
 }
 
+/* Refactor me */
 /*
  * Add a number of bytes to what the SA has protected so far.  Return
  * B_TRUE if the SA can still protect that many bytes.
@@ -1953,6 +1981,7 @@
 	putnext(ahstack->ah_pfkey_q, pfkeymp);
 }
 
+/* Refactor me */
 /*
  * Handle the SADB_GETSPI message.  Create a larval SA.
  */
@@ -3386,6 +3415,27 @@
 	assoc = oi->ipsec_out_ah_sa;
 	ASSERT(assoc != NULL);
 
+
+	/*
+	 * Get the outer IP header in shape to escape this system..
+	 */
+	if (is_system_labeled() && (assoc->ipsa_ocred != NULL)) {
+		int whack;
+
+		mblk_setcred(mp, assoc->ipsa_ocred, NOPID);
+		if (oi->ipsec_out_v4)
+			whack = sadb_whack_label(&mp, assoc);
+		else
+			whack = sadb_whack_label_v6(&mp, assoc);
+		if (whack != 0) {
+			ip_drop_packet(ipsec_out, B_FALSE, NULL,
+			    NULL, DROPPER(ipss, ipds_ah_nomem),
+			    &ahstack->ah_dropper);
+			return (IPSEC_STATUS_FAILED);
+		}
+		ipsec_out->b_cont = mp;
+	}
+
 	/*
 	 * Age SA according to number of bytes that will be sent after
 	 * adding the AH header, ICV, and padding to the packet.
@@ -3415,6 +3465,11 @@
 		return (IPSEC_STATUS_FAILED);
 	}
 
+	/*
+	 * XXX We need to have fixed up the outer label before we get here.
+	 * (AH is computing the checksum over the outer label).
+	 */
+
 	if (oi->ipsec_out_is_capab_ill) {
 		ah3dbg(ahstack, ("ah_outbound: pkt can be accelerated\n"));
 		if (oi->ipsec_out_v4)
@@ -4237,14 +4292,22 @@
 		while (--dest >= mp->b_rptr)
 			*dest = *(dest - newpos);
 	}
+	ipsec_in->b_cont = mp;
+	phdr_mp->b_cont = NULL;
 	/*
 	 * If a db_credp exists in phdr_mp, it must also exist in mp.
 	 */
 	ASSERT(DB_CRED(phdr_mp) == NULL ||
 	    msg_getcred(mp, NULL) != NULL);
-
 	freeb(phdr_mp);
-	ipsec_in->b_cont = mp;
+
+	/*
+	 * If SA is labelled, use its label, else inherit the label
+	 */
+	if (is_system_labeled() && (assoc->ipsa_cred != NULL)) {
+		mblk_setcred(mp, assoc->ipsa_cred, NOPID);
+	}
+
 	if (assoc->ipsa_state == IPSA_STATE_IDLE) {
 		/*
 		 * Cluster buffering case.  Tell caller that we're
@@ -4253,6 +4316,7 @@
 		sadb_buf_pkt(assoc, ipsec_in, ns);
 		return (IPSEC_STATUS_PENDING);
 	}
+
 	return (IPSEC_STATUS_SUCCESS);
 
 ah_in_discard:
@@ -4393,6 +4457,7 @@
 	return (IPSEC_STATUS_SUCCESS);
 }
 
+/* Refactor me */
 /*
  * Wrapper to allow IP to trigger an AH association failure message
  * during SA inbound selection.
--- a/usr/src/uts/common/inet/ip/ipsecesp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -62,12 +62,15 @@
 #include <sys/kstat.h>
 #include <sys/policy.h>
 #include <sys/strsun.h>
+#include <sys/strsubr.h>
 #include <inet/udp_impl.h>
 #include <sys/taskq.h>
 #include <sys/note.h>
 
 #include <sys/iphada.h>
 
+#include <sys/tsol/tnet.h>
+
 /*
  * Table of ND variables supported by ipsecesp. These are loaded into
  * ipsecesp_g_nd in ipsecesp_init_nd.
@@ -139,7 +142,7 @@
     boolean_t, ipsa_t *);
 
 static boolean_t esp_register_out(uint32_t, uint32_t, uint_t,
-    ipsecesp_stack_t *);
+    ipsecesp_stack_t *, mblk_t *);
 static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
     kstat_named_t **, ipsecesp_stack_t *);
 static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t);
@@ -1473,6 +1476,7 @@
 	putnext(espstack->esp_pfkey_q, pfkeymp);
 }
 
+/* XXX refactor me */
 /*
  * Handle the SADB_GETSPI message.  Create a larval SA.
  */
@@ -1861,9 +1865,20 @@
 
 	if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter,
 	    espstack)) {
+
+		if (is_system_labeled()) {
+			cred_t *cr = assoc->ipsa_cred;
+
+			if (cr != NULL) {
+				mblk_setcred(data_mp, cr, NOPID);
+			}
+
+		}
 		if (is_natt)
 			return (esp_fix_natt_checksums(data_mp, assoc));
 
+		ASSERT(!is_system_labeled() || (DB_CRED(data_mp) != NULL));
+
 		if (assoc->ipsa_state == IPSA_STATE_IDLE) {
 			/*
 			 * Cluster buffering case.  Tell caller that we're
@@ -2665,10 +2680,33 @@
 		data_mp = ipsec_out_mp->b_cont;
 	}
 
+	assoc = io->ipsec_out_esp_sa;
+	ASSERT(assoc != NULL);
+
+	/*
+	 * Get the outer IP header in shape to escape this system..
+	 */
+	if (is_system_labeled() && (assoc->ipsa_ocred != NULL)) {
+		int whack;
+
+		mblk_setcred(data_mp, assoc->ipsa_ocred, NOPID);
+		if (io->ipsec_out_v4)
+			whack = sadb_whack_label(&data_mp, assoc);
+		else
+			whack = sadb_whack_label_v6(&data_mp, assoc);
+		if (whack != 0) {
+			ip_drop_packet(ipsec_out_mp, B_FALSE, NULL,
+			    NULL, DROPPER(ipss, ipds_esp_nomem),
+			    &espstack->esp_dropper);
+			return (IPSEC_STATUS_FAILED);
+		}
+		ipsec_out_mp->b_cont = data_mp;
+	}
+
+
 	/*
 	 * Reality check....
 	 */
-
 	ipha = (ipha_t *)data_mp->b_rptr;  /* So we can call esp_acquire(). */
 
 	if (io->ipsec_out_v4) {
@@ -2710,13 +2748,11 @@
 			nhp = &ip6h->ip6_nxt;
 		}
 	}
-	assoc = io->ipsec_out_esp_sa;
-	ASSERT(assoc != NULL);
 
 	mac_len = assoc->ipsa_mac_len;
 
 	if (assoc->ipsa_flags & IPSA_F_NATT) {
-		/* wedge in fake UDP */
+		/* wedge in UDP header */
 		is_natt = B_TRUE;
 		esplen += UDPH_SIZE;
 	}
@@ -3066,7 +3102,7 @@
  */
 static boolean_t
 esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
-    ipsecesp_stack_t *espstack)
+    ipsecesp_stack_t *espstack, mblk_t *in_mp)
 {
 	mblk_t *pfkey_msg_mp, *keysock_out_mp;
 	sadb_msg_t *samsg;
@@ -3082,6 +3118,10 @@
 	ipsec_alginfo_t **encralgs;
 	uint_t num_ealgs;
 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
+	sadb_sens_t *sens;
+	size_t sens_len = 0;
+	sadb_ext_t *nextext;
+	cred_t *sens_cr = NULL;
 
 	/* Allocate the KEYSOCK_OUT. */
 	keysock_out_mp = sadb_keysock_out(serial);
@@ -3090,12 +3130,20 @@
 		return (B_FALSE);
 	}
 
+	if (is_system_labeled() && (in_mp != NULL)) {
+		sens_cr = msg_getcred(in_mp, NULL);
+
+		if (sens_cr != NULL) {
+			sens_len = sadb_sens_len_from_cred(sens_cr);
+			allocsize += sens_len;
+		}
+	}
+
 	/*
 	 * Allocate the PF_KEY message that follows KEYSOCK_OUT.
 	 */
 
 	mutex_enter(&ipss->ipsec_alg_lock);
-
 	/*
 	 * Fill SADB_REGISTER message's algorithm descriptors.  Hold
 	 * down the lock while filling it.
@@ -3128,12 +3176,13 @@
 		freemsg(keysock_out_mp);
 		return (B_FALSE);
 	}
-
 	pfkey_msg_mp = keysock_out_mp->b_cont;
 	pfkey_msg_mp->b_wptr += allocsize;
+
+	nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
+
 	if (num_aalgs != 0) {
-		sasupp_auth = (sadb_supported_t *)
-		    (pfkey_msg_mp->b_rptr + sizeof (*samsg));
+		sasupp_auth = (sadb_supported_t *)nextext;
 		saalg = (sadb_alg_t *)(sasupp_auth + 1);
 
 		ASSERT(((ulong_t)saalg & 0x7) == 0);
@@ -3169,12 +3218,11 @@
 			}
 		}
 #endif /* DEBUG */
-	} else {
-		saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
+		nextext = (sadb_ext_t *)saalg;
 	}
 
 	if (num_ealgs != 0) {
-		sasupp_encr = (sadb_supported_t *)saalg;
+		sasupp_encr = (sadb_supported_t *)nextext;
 		saalg = (sadb_alg_t *)(sasupp_encr + 1);
 
 		numalgs_snap = 0;
@@ -3212,6 +3260,7 @@
 			}
 		}
 #endif /* DEBUG */
+		nextext = (sadb_ext_t *)saalg;
 	}
 
 	current_aalgs = num_aalgs;
@@ -3219,6 +3268,14 @@
 
 	mutex_exit(&ipss->ipsec_alg_lock);
 
+	if (sens_cr != NULL) {
+		sens = (sadb_sens_t *)nextext;
+		sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+		    sens_cr, sens_len);
+
+		nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
+	}
+
 	/* Now fill the rest of the SADB_REGISTER message. */
 
 	samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
@@ -3274,7 +3331,7 @@
 	 * Time to send a PF_KEY SADB_REGISTER message to ESP listeners
 	 * everywhere.  (The function itself checks for NULL esp_pfkey_q.)
 	 */
-	(void) esp_register_out(0, 0, 0, espstack);
+	(void) esp_register_out(0, 0, 0, espstack, NULL);
 }
 
 /*
@@ -3323,43 +3380,27 @@
 esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
     int *diagnostic, ipsecesp_stack_t *espstack)
 {
-	isaf_t *primary = NULL, *secondary, *inbound, *outbound;
-	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
-	struct sockaddr_in *dst;
-	struct sockaddr_in6 *dst6;
-	boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE;
-	uint32_t *dstaddr;
+	isaf_t *primary = NULL, *secondary;
+	boolean_t clone = B_FALSE, is_inbound = B_FALSE;
 	ipsa_t *larval = NULL;
 	ipsacq_t *acqrec;
 	iacqf_t *acq_bucket;
 	mblk_t *acq_msgs = NULL;
 	int rc;
-	sadb_t *sp;
-	int outhash;
 	mblk_t *lpkt;
+	int error;
+	ipsa_query_t sq;
 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
 
 	/*
 	 * Locate the appropriate table(s).
 	 */
-
-	dst = (struct sockaddr_in *)(dstext + 1);
-	dst6 = (struct sockaddr_in6 *)dst;
-	is_ipv4 = (dst->sin_family == AF_INET);
-	if (is_ipv4) {
-		sp = &espstack->esp_sadb.s_v4;
-		dstaddr = (uint32_t *)(&dst->sin_addr);
-		outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr);
-	} else {
-		sp = &espstack->esp_sadb.s_v6;
-		dstaddr = (uint32_t *)(&dst6->sin6_addr);
-		outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr);
-	}
-
-	inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
-	outbound = &sp->sdb_of[outhash];
+	sq.spp = &espstack->esp_sadb;	/* XXX */
+	error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
+	    IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+	    &sq, diagnostic);
+	if (error)
+		return (error);
 
 	/*
 	 * Use the direction flags provided by the KMD to determine
@@ -3367,17 +3408,15 @@
 	 * for this SA. If these flags were absent then make this
 	 * decision based on the addresses.
 	 */
-	if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
-		primary = inbound;
-		secondary = outbound;
+	if (sq.assoc->sadb_sa_flags & IPSA_F_INBOUND) {
+		primary = sq.inbound;
+		secondary = sq.outbound;
 		is_inbound = B_TRUE;
-		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
+		if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
 			clone = B_TRUE;
-	} else {
-		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
-			primary = outbound;
-			secondary = inbound;
-		}
+	} else if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
+		primary = sq.outbound;
+		secondary = sq.inbound;
 	}
 
 	if (primary == NULL) {
@@ -3388,7 +3427,7 @@
 		switch (ksi->ks_in_dsttype) {
 		case KS_IN_ADDR_MBCAST:
 			clone = B_TRUE;	/* All mcast SAs can be bidirectional */
-			assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
+			sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
 			/* FALLTHRU */
 		/*
 		 * If the source address is either one of mine, or unspecified
@@ -3399,9 +3438,9 @@
 		 * SA (which allows me to receive the outbound traffic).
 		 */
 		case KS_IN_ADDR_ME:
-			assoc->sadb_sa_flags |= IPSA_F_INBOUND;
-			primary = inbound;
-			secondary = outbound;
+			sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
+			primary = sq.inbound;
+			secondary = sq.outbound;
 			if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
 				clone = B_TRUE;
 			is_inbound = B_TRUE;
@@ -3414,11 +3453,11 @@
 		 * SA.
 		 */
 		case KS_IN_ADDR_NOTME:
-			assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
-			primary = outbound;
-			secondary = inbound;
+			sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
+			primary = sq.outbound;
+			secondary = sq.inbound;
 			if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
-				assoc->sadb_sa_flags |= IPSA_F_INBOUND;
+				sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
 				clone = B_TRUE;
 			}
 			break;
@@ -3437,7 +3476,7 @@
 	 */
 
 	if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
-		acq_bucket = &sp->sdb_acq[outhash];
+		acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
 		mutex_enter(&acq_bucket->iacqf_lock);
 		for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
 		    acqrec = acqrec->ipsacq_next) {
@@ -3448,7 +3487,7 @@
 			 *    that are queued up.
 			 */
 			if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
-			    IPSA_ARE_ADDR_EQUAL(dstaddr,
+			    IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
 			    acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
 				break;
 			mutex_exit(&acqrec->ipsacq_lock);
@@ -3473,12 +3512,11 @@
 	 * Find PF_KEY message, and see if I'm an update.  If so, find entry
 	 * in larval list (if there).
 	 */
-
 	if (samsg->sadb_msg_type == SADB_UPDATE) {
-		mutex_enter(&inbound->isaf_lock);
-		larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi,
-		    ALL_ZEROES_PTR, dstaddr, dst->sin_family);
-		mutex_exit(&inbound->isaf_lock);
+		mutex_enter(&sq.inbound->isaf_lock);
+		larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
+		    ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
+		mutex_exit(&sq.inbound->isaf_lock);
 
 		if ((larval == NULL) ||
 		    (larval->ipsa_state != IPSA_STATE_LARVAL)) {
@@ -3532,7 +3570,8 @@
 					ipha = (ipha_t *)mp->b_cont->b_rptr;
 
 					/* finish IPsec processing */
-					if (is_ipv4) {
+					if (IPH_HDR_VERSION(ipha) ==
+					    IP_VERSION) {
 						ip_wput_ipsec_out(NULL, mp,
 						    ipha, NULL, NULL);
 					} else {
@@ -3587,6 +3626,8 @@
 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
 
+
+
 	/* I need certain extensions present for an ADD message. */
 	if (srcext == NULL) {
 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
@@ -3676,13 +3717,15 @@
 
 
 	/* Stuff I don't support, for now.  XXX Diagnostic? */
-	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL ||
-	    ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
 		return (EOPNOTSUPP);
 
+	if ((*diagnostic = sadb_labelchk(ksi)) != 0)
+		return (EINVAL);
+
 	/*
-	 * XXX Policy :  I'm not checking identities or sensitivity
-	 * labels at this time, but if I did, I'd do them here, before I sent
+	 * XXX Policy :  I'm not checking identities at this time,
+	 * but if I did, I'd do them here, before I sent
 	 * the weak key check up to the algorithm.
 	 */
 
@@ -3812,6 +3855,7 @@
 	return (rcode);
 }
 
+/* XXX refactor me */
 /*
  * Delete a security association.  This is REALLY likely to be code common to
  * both AH and ESP.  Find the association, then unlink it.
@@ -3838,14 +3882,15 @@
 		}
 		return (sadb_purge_sa(mp, ksi,
 		    (sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 :
-		    &espstack->esp_sadb.s_v4, espstack->esp_pfkey_q,
-		    espstack->esp_sadb.s_ip_q));
+		    &espstack->esp_sadb.s_v4, diagnostic,
+		    espstack->esp_pfkey_q, espstack->esp_sadb.s_ip_q));
 	}
 
 	return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic,
 	    espstack->esp_pfkey_q, sadb_msg_type));
 }
 
+/* XXX refactor me */
 /*
  * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP
  * messages.
@@ -3979,7 +4024,7 @@
 		 * Keysock takes care of the PF_KEY bookkeeping for this.
 		 */
 		if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
-		    ksi->ks_in_serial, espstack)) {
+		    ksi->ks_in_serial, espstack, mp)) {
 			freemsg(mp);
 		} else {
 			/*
@@ -4332,6 +4377,9 @@
 
 	freeb(hada_mp);
 
+	if (is_system_labeled() && (assoc->ipsa_cred != NULL))
+		mblk_setcred(data_mp, assoc->ipsa_cred, NOPID);
+
 	/*
 	 * Account for usage..
 	 */
--- a/usr/src/uts/common/inet/ip/sadb.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/sadb.c	Mon Nov 02 15:39:20 2009 -0800
@@ -60,10 +60,13 @@
 #include <sys/random.h>
 #include <sys/dlpi.h>
 #include <sys/iphada.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
 #include <inet/ip_if.h>
 #include <inet/ipdrop.h>
 #include <inet/ipclassifier.h>
 #include <inet/sctp_ip.h>
+#include <sys/tsol/tnet.h>
 
 /*
  * This source file contains Security Association Database (SADB) common
@@ -72,7 +75,8 @@
  */
 
 static mblk_t *sadb_extended_acquire(ipsec_selector_t *, ipsec_policy_t *,
-    ipsec_action_t *, boolean_t, uint32_t, uint32_t, netstack_t *);
+    ipsec_action_t *, boolean_t, uint32_t, uint32_t, sadb_sens_t *,
+    netstack_t *);
 static void sadb_ill_df(ill_t *, mblk_t *, isaf_t *, int, boolean_t);
 static ipsa_t *sadb_torch_assoc(isaf_t *, ipsa_t *, boolean_t, mblk_t **);
 static void sadb_drain_torchq(queue_t *, mblk_t *);
@@ -80,10 +84,16 @@
 			    netstack_t *);
 static void sadb_destroy(sadb_t *, netstack_t *);
 static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *);
+static cred_t *sadb_cred_from_sens(sadb_sens_t *, uint64_t *);
+static sadb_sens_t *sadb_make_sens_ext(cred_t *cr, int *len);
 
 static time_t sadb_add_time(time_t, uint64_t);
 static void lifetime_fuzz(ipsa_t *);
 static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t);
+static int get_ipsa_pair(ipsa_query_t *, ipsap_t *, int *);
+static void init_ipsa_pair(ipsap_t *);
+static void destroy_ipsa_pair(ipsap_t *);
+static int update_pairing(ipsap_t *, ipsa_query_t *, keysock_in_t *, int *);
 static void ipsa_set_replay(ipsa_t *ipsa, uint32_t offset);
 
 extern void (*cl_inet_getspi)(netstackid_t stack_id, uint8_t protocol,
@@ -271,6 +281,17 @@
 	ip_drop_packet(ipsa->ipsa_lpkt, B_TRUE, NULL, NULL,
 	    DROPPER(ipss, ipds_sadb_inlarval_timeout),
 	    &ipss->ipsec_sadb_dropper);
+
+	if (ipsa->ipsa_cred != NULL) {
+		crfree(ipsa->ipsa_cred);
+		ipsa->ipsa_cred = NULL;
+	}
+
+	if (ipsa->ipsa_ocred != NULL) {
+		crfree(ipsa->ipsa_ocred);
+		ipsa->ipsa_ocred = NULL;
+	}
+
 	ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_AUTH);
 	ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_ENCR);
 	mutex_exit(&ipsa->ipsa_lock);
@@ -294,10 +315,6 @@
 	if (ipsa->ipsa_dst_cid != NULL) {
 		IPSID_REFRELE(ipsa->ipsa_dst_cid);
 	}
-	if (ipsa->ipsa_integ != NULL)
-		kmem_free(ipsa->ipsa_integ, ipsa->ipsa_integlen);
-	if (ipsa->ipsa_sens != NULL)
-		kmem_free(ipsa->ipsa_sens, ipsa->ipsa_senslen);
 	if (ipsa->ipsa_emech.cm_param != NULL)
 		kmem_free(ipsa->ipsa_emech.cm_param,
 		    ipsa->ipsa_emech.cm_param_len);
@@ -1201,6 +1218,25 @@
 }
 
 /*
+ * Sanity check sensitivity labels.
+ *
+ * For now, just reject labels on unlabeled systems.
+ */
+int
+sadb_labelchk(keysock_in_t *ksi)
+{
+	if (!is_system_labeled()) {
+		if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+			return (SADB_X_DIAGNOSTIC_BAD_LABEL);
+
+		if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL)
+			return (SADB_X_DIAGNOSTIC_BAD_LABEL);
+	}
+
+	return (0);
+}
+
+/*
  * Clone a security association for the purposes of inserting a single SA
  * into inbound and outbound tables respectively. This function should only
  * be called from sadb_common_add().
@@ -1223,6 +1259,12 @@
 	/* bzero and initialize locks, in case *_init() allocates... */
 	mutex_init(&newbie->ipsa_lock, NULL, MUTEX_DEFAULT, NULL);
 
+	if (newbie->ipsa_cred != NULL)
+		crhold(newbie->ipsa_cred);
+
+	if (newbie->ipsa_ocred != NULL)
+		crhold(newbie->ipsa_ocred);
+
 	/*
 	 * While somewhat dain-bramaged, the most graceful way to
 	 * recover from errors is to keep plowing through the
@@ -1268,28 +1310,6 @@
 	newbie->ipsa_encrtmpl = NULL;
 	newbie->ipsa_haspeer = B_TRUE;
 
-	if (ipsa->ipsa_integ != NULL) {
-		newbie->ipsa_integ = kmem_alloc(newbie->ipsa_integlen,
-		    KM_NOSLEEP);
-		if (newbie->ipsa_integ == NULL) {
-			error = B_TRUE;
-		} else {
-			bcopy(ipsa->ipsa_integ, newbie->ipsa_integ,
-			    newbie->ipsa_integlen);
-		}
-	}
-
-	if (ipsa->ipsa_sens != NULL) {
-		newbie->ipsa_sens = kmem_alloc(newbie->ipsa_senslen,
-		    KM_NOSLEEP);
-		if (newbie->ipsa_sens == NULL) {
-			error = B_TRUE;
-		} else {
-			bcopy(ipsa->ipsa_sens, newbie->ipsa_sens,
-			    newbie->ipsa_senslen);
-		}
-	}
-
 	if (ipsa->ipsa_src_cid != NULL) {
 		newbie->ipsa_src_cid = ipsa->ipsa_src_cid;
 		IPSID_REFHOLD(ipsa->ipsa_src_cid);
@@ -1407,7 +1427,7 @@
 sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
 {
 	int alloclen, addrsize, paddrsize, authsize, encrsize;
-	int srcidsize, dstidsize;
+	int srcidsize, dstidsize, senslen, osenslen;
 	sa_family_t fam, pfam;	/* Address family for SADB_EXT_ADDRESS */
 				/* src/dst and proxy sockaddrs. */
 	/*
@@ -1425,16 +1445,18 @@
 	sadb_x_pair_t *pair_ext;
 
 	mblk_t *mp;
-	uint64_t *bitmap;
 	uint8_t *cur, *end;
 	/* These indicate the presence of the above extension fields. */
-	boolean_t soft, hard, isrc, idst, auth, encr, sensinteg, srcid, dstid;
+	boolean_t soft = B_FALSE, hard = B_FALSE;
+	boolean_t isrc = B_FALSE, idst = B_FALSE;
+	boolean_t auth = B_FALSE, encr = B_FALSE;
+	boolean_t sensinteg = B_FALSE, osensinteg = B_FALSE;
+	boolean_t srcid = B_FALSE, dstid = B_FALSE;
 	boolean_t idle;
 	boolean_t paired;
 	uint32_t otherspi;
 
 	/* First off, figure out the allocation length for this message. */
-
 	/*
 	 * Constant stuff.  This includes base, SA, address (src, dst),
 	 * and lifetime (current).
@@ -1478,16 +1500,12 @@
 	    ipsa->ipsa_softbyteslt != 0 || ipsa->ipsa_softalloc != 0) {
 		alloclen += sizeof (sadb_lifetime_t);
 		soft = B_TRUE;
-	} else {
-		soft = B_FALSE;
 	}
 
 	if (ipsa->ipsa_hardaddlt != 0 || ipsa->ipsa_harduselt != 0 ||
 	    ipsa->ipsa_hardbyteslt != 0 || ipsa->ipsa_hardalloc != 0) {
 		alloclen += sizeof (sadb_lifetime_t);
 		hard = B_TRUE;
-	} else {
-		hard = B_FALSE;
 	}
 
 	if (ipsa->ipsa_idleaddlt != 0 || ipsa->ipsa_idleuselt != 0) {
@@ -1498,10 +1516,7 @@
 	}
 
 	/* Inner addresses. */
-	if (ipsa->ipsa_innerfam == 0) {
-		isrc = B_FALSE;
-		idst = B_FALSE;
-	} else {
+	if (ipsa->ipsa_innerfam != 0) {
 		pfam = ipsa->ipsa_innerfam;
 		switch (pfam) {
 		case AF_INET6:
@@ -1528,8 +1543,6 @@
 		    sizeof (uint64_t));
 		alloclen += authsize;
 		auth = B_TRUE;
-	} else {
-		auth = B_FALSE;
 	}
 
 	if (ipsa->ipsa_encrkeylen != 0) {
@@ -1541,13 +1554,16 @@
 		encr = B_FALSE;
 	}
 
-	/* No need for roundup on sens and integ. */
-	if (ipsa->ipsa_integlen != 0 || ipsa->ipsa_senslen != 0) {
-		alloclen += sizeof (sadb_key_t) + ipsa->ipsa_integlen +
-		    ipsa->ipsa_senslen;
+	if (ipsa->ipsa_cred != NULL) {
+		senslen = sadb_sens_len_from_cred(ipsa->ipsa_cred);
+		alloclen += senslen;
 		sensinteg = B_TRUE;
-	} else {
-		sensinteg = B_FALSE;
+	}
+
+	if (ipsa->ipsa_ocred != NULL) {
+		osenslen = sadb_sens_len_from_cred(ipsa->ipsa_ocred);
+		alloclen += osenslen;
+		osensinteg = B_TRUE;
 	}
 
 	/*
@@ -1560,8 +1576,6 @@
 		    sizeof (uint64_t));
 		alloclen += srcidsize;
 		srcid = B_TRUE;
-	} else {
-		srcid = B_FALSE;
 	}
 
 	if (ipsa->ipsa_dst_cid != NULL) {
@@ -1570,8 +1584,6 @@
 		    sizeof (uint64_t));
 		alloclen += dstidsize;
 		dstid = B_TRUE;
-	} else {
-		dstid = B_FALSE;
 	}
 
 	if ((ipsa->ipsa_kmp != 0) || (ipsa->ipsa_kmc != 0))
@@ -1588,6 +1600,7 @@
 	mp = allocb(alloclen, BPRI_HI);
 	if (mp == NULL)
 		return (NULL);
+	bzero(mp->b_rptr, alloclen);
 
 	mp->b_wptr += alloclen;
 	end = mp->b_wptr;
@@ -1779,21 +1792,21 @@
 
 	if (sensinteg) {
 		sens = (sadb_sens_t *)walker;
-		sens->sadb_sens_len = SADB_8TO64(sizeof (sadb_sens_t *) +
-		    ipsa->ipsa_senslen + ipsa->ipsa_integlen);
-		sens->sadb_sens_dpd = ipsa->ipsa_dpd;
-		sens->sadb_sens_sens_level = ipsa->ipsa_senslevel;
-		sens->sadb_sens_integ_level = ipsa->ipsa_integlevel;
-		sens->sadb_sens_sens_len = SADB_8TO64(ipsa->ipsa_senslen);
-		sens->sadb_sens_integ_len = SADB_8TO64(ipsa->ipsa_integlen);
-		sens->sadb_sens_reserved = 0;
-		bitmap = (uint64_t *)(sens + 1);
-		if (ipsa->ipsa_sens != NULL) {
-			bcopy(ipsa->ipsa_sens, bitmap, ipsa->ipsa_senslen);
-			bitmap += sens->sadb_sens_sens_len;
-		}
-		if (ipsa->ipsa_integ != NULL)
-			bcopy(ipsa->ipsa_integ, bitmap, ipsa->ipsa_integlen);
+		sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+		    ipsa->ipsa_cred, senslen);
+
+		walker = (sadb_ext_t *)((uint64_t *)walker +
+		    walker->sadb_ext_len);
+	}
+
+	if (osensinteg) {
+		sens = (sadb_sens_t *)walker;
+
+		sadb_sens_from_cred(sens, SADB_X_EXT_OUTER_SENS,
+		    ipsa->ipsa_ocred, osenslen);
+		if (ipsa->ipsa_mac_exempt)
+			sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT;
+
 		walker = (sadb_ext_t *)((uint64_t *)walker +
 		    walker->sadb_ext_len);
 	}
@@ -2493,6 +2506,251 @@
 	return (KS_IN_ADDR_NOTME);
 }
 
+/*
+ * Match primitives..
+ * !!! TODO: short term: inner selectors
+ *		ipv6 scope id (ifindex)
+ * longer term:  zone id.  sensitivity label. uid.
+ */
+boolean_t
+sadb_match_spi(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return (sq->spi == sa->ipsa_spi);
+}
+
+boolean_t
+sadb_match_dst_v6(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_dstaddr, sq->dstaddr, AF_INET6));
+}
+
+boolean_t
+sadb_match_src_v6(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_srcaddr, sq->srcaddr, AF_INET6));
+}
+
+boolean_t
+sadb_match_dst_v4(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return (sq->dstaddr[0] == sa->ipsa_dstaddr[0]);
+}
+
+boolean_t
+sadb_match_src_v4(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return (sq->srcaddr[0] == sa->ipsa_srcaddr[0]);
+}
+
+boolean_t
+sadb_match_dstid(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return ((sa->ipsa_dst_cid != NULL) &&
+	    (sq->didtype == sa->ipsa_dst_cid->ipsid_type) &&
+	    (strcmp(sq->didstr, sa->ipsa_dst_cid->ipsid_cid) == 0));
+
+}
+boolean_t
+sadb_match_srcid(ipsa_query_t *sq, ipsa_t *sa)
+{
+	return ((sa->ipsa_src_cid != NULL) &&
+	    (sq->sidtype == sa->ipsa_src_cid->ipsid_type) &&
+	    (strcmp(sq->sidstr, sa->ipsa_src_cid->ipsid_cid) == 0));
+}
+
+boolean_t
+sadb_match_kmc(ipsa_query_t *sq, ipsa_t *sa)
+{
+#define	M(a, b) (((a) == 0) || ((b) == 0) || ((a) == (b)))
+
+	return (M(sq->kmc, sa->ipsa_kmc) && M(sq->kmp, sa->ipsa_kmp));
+
+#undef M
+}
+
+/*
+ * Common function which extracts several PF_KEY extensions for ease of
+ * SADB matching.
+ *
+ * XXX TODO: weed out ipsa_query_t fields not used during matching
+ * or afterwards?
+ */
+int
+sadb_form_query(keysock_in_t *ksi, uint32_t req, uint32_t match,
+    ipsa_query_t *sq, int *diagnostic)
+{
+	int i;
+	ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
+
+	for (i = 0; i < IPSA_NMATCH; i++)
+		sq->matchers[i] = NULL;
+
+	ASSERT((req & ~match) == 0);
+
+	sq->req = req;
+	sq->dstext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
+	sq->srcext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
+	sq->assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
+
+	if ((req & IPSA_Q_DST) && (sq->dstext == NULL)) {
+		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
+		return (EINVAL);
+	}
+	if ((req & IPSA_Q_SRC) && (sq->srcext == NULL)) {
+		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
+		return (EINVAL);
+	}
+	if ((req & IPSA_Q_SA) && (sq->assoc == NULL)) {
+		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
+		return (EINVAL);
+	}
+
+	if (match & IPSA_Q_SA) {
+		*mfpp++ = sadb_match_spi;
+		sq->spi = sq->assoc->sadb_sa_spi;
+	}
+
+	if (sq->dstext != NULL)
+		sq->dst = (struct sockaddr_in *)(sq->dstext + 1);
+	else {
+		sq->dst = NULL;
+		sq->dst6 = NULL;
+		sq->dstaddr = NULL;
+	}
+
+	if (sq->srcext != NULL)
+		sq->src = (struct sockaddr_in *)(sq->srcext + 1);
+	else {
+		sq->src = NULL;
+		sq->src6 = NULL;
+		sq->srcaddr = NULL;
+	}
+
+	if (sq->dst != NULL)
+		sq->af = sq->dst->sin_family;
+	else if (sq->src != NULL)
+		sq->af = sq->src->sin_family;
+	else
+		sq->af = AF_INET;
+
+	if (sq->af == AF_INET6) {
+		if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
+			*mfpp++ = sadb_match_dst_v6;
+			sq->dst6 = (struct sockaddr_in6 *)sq->dst;
+			sq->dstaddr = (uint32_t *)&(sq->dst6->sin6_addr);
+		} else {
+			match &= ~IPSA_Q_DST;
+			sq->dstaddr = ALL_ZEROES_PTR;
+		}
+
+		if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
+			sq->src6 = (struct sockaddr_in6 *)(sq->srcext + 1);
+			sq->srcaddr = (uint32_t *)&sq->src6->sin6_addr;
+			if (sq->src6->sin6_family != AF_INET6) {
+				*diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
+				return (EINVAL);
+			}
+			*mfpp++ = sadb_match_src_v6;
+		} else {
+			match &= ~IPSA_Q_SRC;
+			sq->srcaddr = ALL_ZEROES_PTR;
+		}
+	} else {
+		sq->src6 = sq->dst6 = NULL;
+		if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
+			*mfpp++ = sadb_match_dst_v4;
+			sq->dstaddr = (uint32_t *)&sq->dst->sin_addr;
+		} else {
+			match &= ~IPSA_Q_DST;
+			sq->dstaddr = ALL_ZEROES_PTR;
+		}
+		if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
+			sq->srcaddr = (uint32_t *)&sq->src->sin_addr;
+			if (sq->src->sin_family != AF_INET) {
+				*diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
+				return (EINVAL);
+			}
+			*mfpp++ = sadb_match_src_v4;
+		} else {
+			match &= ~IPSA_Q_SRC;
+			sq->srcaddr = ALL_ZEROES_PTR;
+		}
+	}
+
+	sq->dstid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
+	if ((match & IPSA_Q_DSTID) && (sq->dstid != NULL)) {
+		sq->didstr = (char *)(sq->dstid + 1);
+		sq->didtype = sq->dstid->sadb_ident_type;
+		*mfpp++ = sadb_match_dstid;
+	}
+
+	sq->srcid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
+
+	if ((match & IPSA_Q_SRCID) && (sq->srcid != NULL)) {
+		sq->sidstr = (char *)(sq->srcid + 1);
+		sq->sidtype = sq->srcid->sadb_ident_type;
+		*mfpp++ = sadb_match_srcid;
+	}
+
+	sq->kmcext = (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
+	sq->kmc = 0;
+	sq->kmp = 0;
+
+	if ((match & IPSA_Q_KMC) && (sq->kmcext)) {
+		sq->kmc = sq->kmcext->sadb_x_kmc_cookie;
+		sq->kmp = sq->kmcext->sadb_x_kmc_proto;
+		*mfpp++ = sadb_match_kmc;
+	}
+
+	if (match & (IPSA_Q_INBOUND|IPSA_Q_OUTBOUND)) {
+		if (sq->af == AF_INET6)
+			sq->sp = &sq->spp->s_v6;
+		else
+			sq->sp = &sq->spp->s_v4;
+	} else {
+		sq->sp = NULL;
+	}
+
+	if (match & IPSA_Q_INBOUND) {
+		sq->inhash = INBOUND_HASH(sq->sp, sq->assoc->sadb_sa_spi);
+		sq->inbound = &sq->sp->sdb_if[sq->inhash];
+	} else {
+		sq->inhash = 0;
+		sq->inbound = NULL;
+	}
+
+	if (match & IPSA_Q_OUTBOUND) {
+		if (sq->af == AF_INET6) {
+			sq->outhash = OUTBOUND_HASH_V6(sq->sp, *(sq->dstaddr));
+		} else {
+			sq->outhash = OUTBOUND_HASH_V4(sq->sp, *(sq->dstaddr));
+		}
+		sq->outbound = &sq->sp->sdb_of[sq->outhash];
+	} else {
+		sq->outhash = 0;
+		sq->outbound = NULL;
+	}
+	sq->match = match;
+	return (0);
+}
+
+/*
+ * Match an initialized query structure with a security association;
+ * return B_TRUE on a match, B_FALSE on a miss.
+ * Applies match functions set up by sadb_form_query() until one returns false.
+ */
+boolean_t
+sadb_match_query(ipsa_query_t *sq, ipsa_t *sa)
+{
+	ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
+	ipsa_match_fn_t mfp;
+
+	for (mfp = *mfpp++; mfp != NULL; mfp = *mfpp++) {
+		if (!mfp(sq, sa))
+			return (B_FALSE);
+	}
+	return (B_TRUE);
+}
 
 /*
  * Walker callback function to delete sa's based on src/dst address.
@@ -2500,21 +2758,12 @@
  * Conveniently, and not coincidentally, this is both what sadb_walker
  * gives us and also what sadb_unlinkassoc expects.
  */
-
 struct sadb_purge_state
 {
-	uint32_t *src;
-	uint32_t *dst;
-	sa_family_t af;
+	ipsa_query_t sq;
 	boolean_t inbnd;
-	char *sidstr;
-	char *didstr;
-	uint16_t sidtype;
-	uint16_t didtype;
-	uint32_t kmproto;
 	uint8_t sadb_sa_state;
 	mblk_t *mq;
-	sadb_t *sp;
 };
 
 static void
@@ -2526,18 +2775,8 @@
 
 	mutex_enter(&entry->ipsa_lock);
 
-	if ((entry->ipsa_state == IPSA_STATE_LARVAL) ||
-	    (ps->src != NULL &&
-	    !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, ps->src, ps->af)) ||
-	    (ps->dst != NULL &&
-	    !IPSA_ARE_ADDR_EQUAL(entry->ipsa_dstaddr, ps->dst, ps->af)) ||
-	    (ps->didstr != NULL && (entry->ipsa_dst_cid != NULL) &&
-	    !(ps->didtype == entry->ipsa_dst_cid->ipsid_type &&
-	    strcmp(ps->didstr, entry->ipsa_dst_cid->ipsid_cid) == 0)) ||
-	    (ps->sidstr != NULL && (entry->ipsa_src_cid != NULL) &&
-	    !(ps->sidtype == entry->ipsa_src_cid->ipsid_type &&
-	    strcmp(ps->sidstr, entry->ipsa_src_cid->ipsid_cid) == 0)) ||
-	    (ps->kmproto <= SADB_X_KMP_MAX && ps->kmproto != entry->ipsa_kmp)) {
+	if (entry->ipsa_state == IPSA_STATE_LARVAL ||
+	    !sadb_match_query(&ps->sq, entry)) {
 		mutex_exit(&entry->ipsa_lock);
 		return;
 	}
@@ -2554,88 +2793,18 @@
  * Don't kill larval SA's in such a purge.
  */
 int
-sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp, queue_t *pfkey_q,
-    queue_t *ip_q)
-{
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
-	sadb_address_t *srcext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
-	sadb_ident_t *dstid =
-	    (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
-	sadb_ident_t *srcid =
-	    (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
-	sadb_x_kmc_t *kmc =
-	    (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
-	struct sockaddr_in *src, *dst;
-	struct sockaddr_in6 *src6, *dst6;
+sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp,
+	int *diagnostic, queue_t *pfkey_q, queue_t *ip_q)
+{
 	struct sadb_purge_state ps;
-
-	/*
-	 * Don't worry about IPv6 v4-mapped addresses, sadb_addrcheck()
-	 * takes care of them.
-	 */
-
-	/* enforced by caller */
-	ASSERT((dstext != NULL) || (srcext != NULL));
-
-	ps.src = NULL;
-	ps.dst = NULL;
-#ifdef DEBUG
-	ps.af = (sa_family_t)-1;
-#endif
+	int error = sadb_form_query(ksi, 0,
+	    IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
+	    &ps.sq, diagnostic);
+
 	ps.mq = NULL;
-	ps.sidstr = NULL;
-	ps.didstr = NULL;
-	ps.kmproto = SADB_X_KMP_MAX + 1;
-
-	if (dstext != NULL) {
-		dst = (struct sockaddr_in *)(dstext + 1);
-		ps.af = dst->sin_family;
-		if (dst->sin_family == AF_INET6) {
-			dst6 = (struct sockaddr_in6 *)dst;
-			ps.dst = (uint32_t *)&dst6->sin6_addr;
-		} else {
-			ps.dst = (uint32_t *)&dst->sin_addr;
-		}
-	}
-
-	if (srcext != NULL) {
-		src = (struct sockaddr_in *)(srcext + 1);
-		ps.af = src->sin_family;
-		if (src->sin_family == AF_INET6) {
-			src6 = (struct sockaddr_in6 *)(srcext + 1);
-			ps.src = (uint32_t *)&src6->sin6_addr;
-		} else {
-			ps.src = (uint32_t *)&src->sin_addr;
-		}
-		ASSERT(dstext == NULL || src->sin_family == dst->sin_family);
-	}
-
-	ASSERT(ps.af != (sa_family_t)-1);
-
-	if (dstid != NULL) {
-		/*
-		 * NOTE:  May need to copy string in the future
-		 * if the inbound keysock message disappears for some strange
-		 * reason.
-		 */
-		ps.didstr = (char *)(dstid + 1);
-		ps.didtype = dstid->sadb_ident_type;
-	}
-
-	if (srcid != NULL) {
-		/*
-		 * NOTE:  May need to copy string in the future
-		 * if the inbound keysock message disappears for some strange
-		 * reason.
-		 */
-		ps.sidstr = (char *)(srcid + 1);
-		ps.sidtype = srcid->sadb_ident_type;
-	}
-
-	if (kmc != NULL)
-		ps.kmproto = kmc->sadb_x_kmc_proto;
+
+	if (error != 0)
+		return (error);
 
 	/*
 	 * This is simple, crude, and effective.
@@ -2660,19 +2829,20 @@
 }
 
 static void
-sadb_delpair_state(isaf_t *head, ipsa_t *entry, void *cookie)
+sadb_delpair_state_one(isaf_t *head, ipsa_t *entry, void *cookie)
 {
 	struct sadb_purge_state *ps = (struct sadb_purge_state *)cookie;
 	isaf_t  *inbound_bucket;
 	ipsa_t *peer_assoc;
+	ipsa_query_t *sq = &ps->sq;
 
 	ASSERT(MUTEX_HELD(&head->isaf_lock));
 
 	mutex_enter(&entry->ipsa_lock);
 
 	if ((entry->ipsa_state != ps->sadb_sa_state) ||
-	    ((ps->src != NULL) &&
-	    !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, ps->src, ps->af))) {
+	    ((sq->srcaddr != NULL) &&
+	    !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, sq->srcaddr, sq->af))) {
 		mutex_exit(&entry->ipsa_lock);
 		return;
 	}
@@ -2686,13 +2856,13 @@
 	 */
 
 	if (entry->ipsa_haspeer) {
-		inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_spi);
+		inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_spi);
 		mutex_enter(&inbound_bucket->isaf_lock);
 		peer_assoc = ipsec_getassocbyspi(inbound_bucket,
 		    entry->ipsa_spi, entry->ipsa_srcaddr,
 		    entry->ipsa_dstaddr, entry->ipsa_addrfam);
 	} else {
-		inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_otherspi);
+		inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_otherspi);
 		mutex_enter(&inbound_bucket->isaf_lock);
 		peer_assoc = ipsec_getassocbyspi(inbound_bucket,
 		    entry->ipsa_otherspi, entry->ipsa_dstaddr,
@@ -2710,6 +2880,37 @@
 	mutex_exit(&inbound_bucket->isaf_lock);
 }
 
+static int
+sadb_delpair_state(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
+    int *diagnostic, queue_t *pfkey_q)
+{
+	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
+	struct sadb_purge_state ps;
+	int error;
+
+	ps.sq.spp = spp;		/* XXX param */
+	ps.mq = NULL;
+
+	error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SRC,
+	    IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
+	    &ps.sq, diagnostic);
+	if (error != 0)
+		return (error);
+
+	ps.inbnd = B_FALSE;
+	ps.sadb_sa_state = assoc->sadb_sa_state;
+	sadb_walker(ps.sq.sp->sdb_of, ps.sq.sp->sdb_hashsize,
+	    sadb_delpair_state_one, &ps);
+
+	if (ps.mq != NULL)
+		sadb_drain_torchq(pfkey_q, ps.mq);
+
+	ASSERT(mp->b_cont != NULL);
+	sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
+	    ksi, NULL);
+	return (0);
+}
+
 /*
  * Common code to delete/get an SA.
  */
@@ -2717,70 +2918,30 @@
 sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
     int *diagnostic, queue_t *pfkey_q, uint8_t sadb_msg_type)
 {
-	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
-	sadb_address_t *srcext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
+	ipsa_query_t sq;
 	ipsa_t *echo_target = NULL;
-	ipsap_t *ipsapp;
+	ipsap_t ipsapp;
 	mblk_t *torchq = NULL;
 	uint_t	error = 0;
 
-	if (assoc == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
-		return (EINVAL);
-	}
-
-	if (sadb_msg_type == SADB_X_DELPAIR_STATE) {
-		struct sockaddr_in *src;
-		struct sockaddr_in6 *src6;
-		struct sadb_purge_state ps;
-
-		if (srcext == NULL) {
-			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
-			return (EINVAL);
-		}
-		ps.src = NULL;
-		ps.mq = NULL;
-		src = (struct sockaddr_in *)(srcext + 1);
-		ps.af = src->sin_family;
-		if (src->sin_family == AF_INET6) {
-			src6 = (struct sockaddr_in6 *)(srcext + 1);
-			ps.src = (uint32_t *)&src6->sin6_addr;
-			ps.sp = &spp->s_v6;
-		} else {
-			ps.src = (uint32_t *)&src->sin_addr;
-			ps.sp = &spp->s_v4;
-		}
-		ps.inbnd = B_FALSE;
-		ps.sadb_sa_state = assoc->sadb_sa_state;
-		sadb_walker(ps.sp->sdb_of, ps.sp->sdb_hashsize,
-		    sadb_delpair_state, &ps);
-
-		if (ps.mq != NULL)
-			sadb_drain_torchq(pfkey_q, ps.mq);
-
-		ASSERT(mp->b_cont != NULL);
-		sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
-		    ksi, NULL);
-		return (0);
-	}
-
-	if (dstext == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
-		return (EINVAL);
-	}
-
-	ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
-	if (ipsapp == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
-		return (ESRCH);
-	}
-
-	echo_target = ipsapp->ipsap_sa_ptr;
+	if (sadb_msg_type == SADB_X_DELPAIR_STATE)
+		return (sadb_delpair_state(mp, ksi, spp, diagnostic, pfkey_q));
+
+	sq.spp = spp;		/* XXX param */
+	error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SA,
+	    IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+	    &sq, diagnostic);
+	if (error != 0)
+		return (error);
+
+	error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+	if (error != 0) {
+		return (error);
+	}
+
+	echo_target = ipsapp.ipsap_sa_ptr;
 	if (echo_target == NULL)
-		echo_target = ipsapp->ipsap_psa_ptr;
+		echo_target = ipsapp.ipsap_psa_ptr;
 
 	if (sadb_msg_type == SADB_DELETE || sadb_msg_type == SADB_X_DELPAIR) {
 		/*
@@ -2789,58 +2950,58 @@
 		 * if it can't find a pair SA pointer. To prevent a potential
 		 * deadlock, always lock the outbound bucket before the inbound.
 		 */
-		if (ipsapp->in_inbound_table) {
-			mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
-			mutex_enter(&ipsapp->ipsap_bucket->isaf_lock);
+		if (ipsapp.in_inbound_table) {
+			mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
+			mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
 		} else {
-			mutex_enter(&ipsapp->ipsap_bucket->isaf_lock);
-			mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
-		}
-
-		if (ipsapp->ipsap_sa_ptr != NULL) {
-			mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
-			if (ipsapp->ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
-				sadb_delete_cluster(ipsapp->ipsap_sa_ptr);
+			mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
+			mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
+		}
+
+		if (ipsapp.ipsap_sa_ptr != NULL) {
+			mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+			if (ipsapp.ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
+				sadb_delete_cluster(ipsapp.ipsap_sa_ptr);
 			}
-			ipsapp->ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
-			(void) sadb_torch_assoc(ipsapp->ipsap_bucket,
-			    ipsapp->ipsap_sa_ptr, B_FALSE, &torchq);
+			ipsapp.ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
+			(void) sadb_torch_assoc(ipsapp.ipsap_bucket,
+			    ipsapp.ipsap_sa_ptr, B_FALSE, &torchq);
 			/*
 			 * sadb_torch_assoc() releases the ipsa_lock
 			 * and calls sadb_unlinkassoc() which does a
 			 * IPSA_REFRELE.
 			 */
 		}
-		if (ipsapp->ipsap_psa_ptr != NULL) {
-			mutex_enter(&ipsapp->ipsap_psa_ptr->ipsa_lock);
+		if (ipsapp.ipsap_psa_ptr != NULL) {
+			mutex_enter(&ipsapp.ipsap_psa_ptr->ipsa_lock);
 			if (sadb_msg_type == SADB_X_DELPAIR ||
-			    ipsapp->ipsap_psa_ptr->ipsa_haspeer) {
-				if (ipsapp->ipsap_psa_ptr->ipsa_flags &
+			    ipsapp.ipsap_psa_ptr->ipsa_haspeer) {
+				if (ipsapp.ipsap_psa_ptr->ipsa_flags &
 				    IPSA_F_INBOUND) {
-					sadb_delete_cluster(
-					    ipsapp->ipsap_psa_ptr);
+					sadb_delete_cluster
+					    (ipsapp.ipsap_psa_ptr);
 				}
-				ipsapp->ipsap_psa_ptr->ipsa_state =
+				ipsapp.ipsap_psa_ptr->ipsa_state =
 				    IPSA_STATE_DEAD;
-				(void) sadb_torch_assoc(ipsapp->ipsap_pbucket,
-				    ipsapp->ipsap_psa_ptr, B_FALSE, &torchq);
+				(void) sadb_torch_assoc(ipsapp.ipsap_pbucket,
+				    ipsapp.ipsap_psa_ptr, B_FALSE, &torchq);
 			} else {
 				/*
 				 * Only half of the "pair" has been deleted.
 				 * Update the remaining SA and remove references
 				 * to its pair SA, which is now gone.
 				 */
-				ipsapp->ipsap_psa_ptr->ipsa_otherspi = 0;
-				ipsapp->ipsap_psa_ptr->ipsa_flags &=
+				ipsapp.ipsap_psa_ptr->ipsa_otherspi = 0;
+				ipsapp.ipsap_psa_ptr->ipsa_flags &=
 				    ~IPSA_F_PAIRED;
-				mutex_exit(&ipsapp->ipsap_psa_ptr->ipsa_lock);
+				mutex_exit(&ipsapp.ipsap_psa_ptr->ipsa_lock);
 			}
 		} else if (sadb_msg_type == SADB_X_DELPAIR) {
 			*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
 			error = ESRCH;
 		}
-		mutex_exit(&ipsapp->ipsap_bucket->isaf_lock);
-		mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
+		mutex_exit(&ipsapp.ipsap_bucket->isaf_lock);
+		mutex_exit(&ipsapp.ipsap_pbucket->isaf_lock);
 	}
 
 	if (torchq != NULL)
@@ -2852,7 +3013,7 @@
 		sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)
 		    mp->b_cont->b_rptr, ksi, echo_target);
 
-	destroy_ipsa_pair(ipsapp);
+	destroy_ipsa_pair(&ipsapp);
 
 	return (error);
 }
@@ -2883,115 +3044,66 @@
  * found, the pair ipsa_t will be NULL. Both isaf_t values are valid
  * provided at least one ipsa_t is found.
  */
-ipsap_t *
-get_ipsa_pair(sadb_sa_t *assoc, sadb_address_t *srcext, sadb_address_t *dstext,
-    sadbp_t *spp)
-{
-	struct sockaddr_in *src, *dst;
-	struct sockaddr_in6 *src6, *dst6;
-	sadb_t *sp;
-	uint32_t *srcaddr, *dstaddr;
-	isaf_t *outbound_bucket, *inbound_bucket;
-	ipsap_t *ipsapp;
-	sa_family_t af;
-
+static int
+get_ipsa_pair(ipsa_query_t *sq, ipsap_t *ipsapp, int *diagnostic)
+{
 	uint32_t pair_srcaddr[IPSA_MAX_ADDRLEN];
 	uint32_t pair_dstaddr[IPSA_MAX_ADDRLEN];
 	uint32_t pair_spi;
 
-	ipsapp = kmem_zalloc(sizeof (*ipsapp), KM_NOSLEEP);
-	if (ipsapp == NULL)
-		return (NULL);
+	init_ipsa_pair(ipsapp);
 
 	ipsapp->in_inbound_table = B_FALSE;
 
-	/*
-	 * Don't worry about IPv6 v4-mapped addresses, sadb_addrcheck()
-	 * takes care of them.
-	 */
-
-	dst = (struct sockaddr_in *)(dstext + 1);
-	af = dst->sin_family;
-	if (af == AF_INET6) {
-		sp = &spp->s_v6;
-		dst6 = (struct sockaddr_in6 *)dst;
-		dstaddr = (uint32_t *)&dst6->sin6_addr;
-		if (srcext != NULL) {
-			src6 = (struct sockaddr_in6 *)(srcext + 1);
-			srcaddr = (uint32_t *)&src6->sin6_addr;
-			ASSERT(src6->sin6_family == af);
-			ASSERT(src6->sin6_family == AF_INET6);
-		} else {
-			srcaddr = ALL_ZEROES_PTR;
-		}
-		outbound_bucket = OUTBOUND_BUCKET_V6(sp,
-		    *(uint32_t *)dstaddr);
-	} else {
-		sp = &spp->s_v4;
-		dstaddr = (uint32_t *)&dst->sin_addr;
-		if (srcext != NULL) {
-			src = (struct sockaddr_in *)(srcext + 1);
-			srcaddr = (uint32_t *)&src->sin_addr;
-			ASSERT(src->sin_family == af);
-			ASSERT(src->sin_family == AF_INET);
-		} else {
-			srcaddr = ALL_ZEROES_PTR;
-		}
-		outbound_bucket = OUTBOUND_BUCKET_V4(sp,
-		    *(uint32_t *)dstaddr);
-	}
-
-	inbound_bucket = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
-
 	/* Lock down both buckets. */
-	mutex_enter(&outbound_bucket->isaf_lock);
-	mutex_enter(&inbound_bucket->isaf_lock);
-
-	if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
-		ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(inbound_bucket,
-		    assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+	mutex_enter(&sq->outbound->isaf_lock);
+	mutex_enter(&sq->inbound->isaf_lock);
+
+	if (sq->assoc->sadb_sa_flags & IPSA_F_INBOUND) {
+		ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
+		    sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
 		if (ipsapp->ipsap_sa_ptr != NULL) {
-			ipsapp->ipsap_bucket = inbound_bucket;
-			ipsapp->ipsap_pbucket = outbound_bucket;
+			ipsapp->ipsap_bucket = sq->inbound;
+			ipsapp->ipsap_pbucket = sq->outbound;
 			ipsapp->in_inbound_table = B_TRUE;
 		} else {
-			ipsapp->ipsap_sa_ptr =
-			    ipsec_getassocbyspi(outbound_bucket,
-			    assoc->sadb_sa_spi, srcaddr, dstaddr, af);
-			ipsapp->ipsap_bucket = outbound_bucket;
-			ipsapp->ipsap_pbucket = inbound_bucket;
+			ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->outbound,
+			    sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
+			    sq->af);
+			ipsapp->ipsap_bucket = sq->outbound;
+			ipsapp->ipsap_pbucket = sq->inbound;
 		}
 	} else {
 		/* IPSA_F_OUTBOUND is set *or* no directions flags set. */
 		ipsapp->ipsap_sa_ptr =
-		    ipsec_getassocbyspi(outbound_bucket,
-		    assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+		    ipsec_getassocbyspi(sq->outbound,
+		    sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
 		if (ipsapp->ipsap_sa_ptr != NULL) {
-			ipsapp->ipsap_bucket = outbound_bucket;
-			ipsapp->ipsap_pbucket = inbound_bucket;
+			ipsapp->ipsap_bucket = sq->outbound;
+			ipsapp->ipsap_pbucket = sq->inbound;
 		} else {
-			ipsapp->ipsap_sa_ptr =
-			    ipsec_getassocbyspi(inbound_bucket,
-			    assoc->sadb_sa_spi, srcaddr, dstaddr, af);
-			ipsapp->ipsap_bucket = inbound_bucket;
-			ipsapp->ipsap_pbucket = outbound_bucket;
+			ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
+			    sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
+			    sq->af);
+			ipsapp->ipsap_bucket = sq->inbound;
+			ipsapp->ipsap_pbucket = sq->outbound;
 			if (ipsapp->ipsap_sa_ptr != NULL)
 				ipsapp->in_inbound_table = B_TRUE;
 		}
 	}
 
 	if (ipsapp->ipsap_sa_ptr == NULL) {
-		mutex_exit(&outbound_bucket->isaf_lock);
-		mutex_exit(&inbound_bucket->isaf_lock);
-		kmem_free(ipsapp, sizeof (*ipsapp));
-		return (NULL);
+		mutex_exit(&sq->outbound->isaf_lock);
+		mutex_exit(&sq->inbound->isaf_lock);
+		*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
+		return (ESRCH);
 	}
 
 	if ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) &&
 	    ipsapp->in_inbound_table) {
-		mutex_exit(&outbound_bucket->isaf_lock);
-		mutex_exit(&inbound_bucket->isaf_lock);
-		return (ipsapp);
+		mutex_exit(&sq->outbound->isaf_lock);
+		mutex_exit(&sq->inbound->isaf_lock);
+		return (0);
 	}
 
 	mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
@@ -3002,48 +3114,48 @@
 		 */
 		ipsapp->ipsap_psa_ptr =
 		    ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
-		    assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+		    sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
 		mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
-		mutex_exit(&outbound_bucket->isaf_lock);
-		mutex_exit(&inbound_bucket->isaf_lock);
-		return (ipsapp);
+		mutex_exit(&sq->outbound->isaf_lock);
+		mutex_exit(&sq->inbound->isaf_lock);
+		return (0);
 	}
 	pair_spi = ipsapp->ipsap_sa_ptr->ipsa_otherspi;
 	IPSA_COPY_ADDR(&pair_srcaddr,
-	    ipsapp->ipsap_sa_ptr->ipsa_srcaddr, af);
+	    ipsapp->ipsap_sa_ptr->ipsa_srcaddr, sq->af);
 	IPSA_COPY_ADDR(&pair_dstaddr,
-	    ipsapp->ipsap_sa_ptr->ipsa_dstaddr, af);
+	    ipsapp->ipsap_sa_ptr->ipsa_dstaddr, sq->af);
 	mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
-	mutex_exit(&outbound_bucket->isaf_lock);
-	mutex_exit(&inbound_bucket->isaf_lock);
+	mutex_exit(&sq->inbound->isaf_lock);
+	mutex_exit(&sq->outbound->isaf_lock);
 
 	if (pair_spi == 0) {
 		ASSERT(ipsapp->ipsap_bucket != NULL);
 		ASSERT(ipsapp->ipsap_pbucket != NULL);
-		return (ipsapp);
+		return (0);
 	}
 
 	/* found sa in outbound sadb, peer should be inbound */
 
 	if (ipsapp->in_inbound_table) {
 		/* Found SA in inbound table, pair will be in outbound. */
-		if (af == AF_INET6) {
-			ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V6(sp,
+		if (sq->af == AF_INET6) {
+			ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V6(sq->sp,
 			    *(uint32_t *)pair_srcaddr);
 		} else {
-			ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V4(sp,
+			ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V4(sq->sp,
 			    *(uint32_t *)pair_srcaddr);
 		}
 	} else {
-		ipsapp->ipsap_pbucket = INBOUND_BUCKET(sp, pair_spi);
+		ipsapp->ipsap_pbucket = INBOUND_BUCKET(sq->sp, pair_spi);
 	}
 	mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
 	ipsapp->ipsap_psa_ptr = ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
-	    pair_spi, pair_dstaddr, pair_srcaddr, af);
+	    pair_spi, pair_dstaddr, pair_srcaddr, sq->af);
 	mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
 	ASSERT(ipsapp->ipsap_bucket != NULL);
 	ASSERT(ipsapp->ipsap_pbucket != NULL);
-	return (ipsapp);
+	return (0);
 }
 
 /*
@@ -3163,7 +3275,7 @@
     netstack_t *ns, sadbp_t *spp)
 {
 	ipsa_t *newbie_clone = NULL, *scratch;
-	ipsap_t *ipsapp = NULL;
+	ipsap_t ipsapp;
 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
 	sadb_address_t *srcext =
 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
@@ -3177,6 +3289,10 @@
 	    (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
 	sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
 	sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
+	sadb_sens_t *sens =
+	    (sadb_sens_t *)ksi->ks_in_extv[SADB_EXT_SENSITIVITY];
+	sadb_sens_t *osens =
+	    (sadb_sens_t *)ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS];
 	sadb_x_pair_t *pair_ext =
 	    (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
 	sadb_x_replay_ctr_t *replayext =
@@ -3185,13 +3301,6 @@
 	    (samsg->sadb_msg_satype == SADB_SATYPE_AH) ? IPPROTO_AH:IPPROTO_ESP;
 	int salt_offset;
 	uint8_t *buf_ptr;
-#if 0
-	/*
-	 * XXXMLS - When Trusted Solaris or Multi-Level Secure functionality
-	 * comes to ON, examine these if 0'ed fragments.  Look for XXXMLS.
-	 */
-	sadb_sens_t *sens = (sadb_sens_t *);
-#endif
 	struct sockaddr_in *src, *dst, *isrc, *idst;
 	struct sockaddr_in6 *src6, *dst6, *isrc6, *idst6;
 	sadb_lifetime_t *soft =
@@ -3206,9 +3315,12 @@
 	uint32_t *src_addr_ptr, *dst_addr_ptr, *isrc_addr_ptr, *idst_addr_ptr;
 	mblk_t *ctl_mp = NULL;
 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
+	ip_stack_t 	*ipst = ns->netstack_ip;
 	ipsec_alginfo_t *alg;
 	int		rcode;
 
+	init_ipsa_pair(&ipsapp);
+
 	if (srcext == NULL) {
 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
 		return (EINVAL);
@@ -3692,42 +3804,59 @@
 		}
 	}
 
-#if 0
-	/* XXXMLS  SENSITIVITY handling code. */
+	/*
+	 * sensitivity label handling code:
+	 * Convert sens + bitmap into cred_t, and associate it
+	 * with the new SA.
+	 */
 	if (sens != NULL) {
-		int i;
 		uint64_t *bitmap = (uint64_t *)(sens + 1);
 
-		newbie->ipsa_dpd = sens->sadb_sens_dpd;
-		newbie->ipsa_senslevel = sens->sadb_sens_sens_level;
-		newbie->ipsa_integlevel = sens->sadb_sens_integ_level;
-		newbie->ipsa_senslen = SADB_64TO8(sens->sadb_sens_sens_len);
-		newbie->ipsa_integlen = SADB_64TO8(sens->sadb_sens_integ_len);
-		newbie->ipsa_integ = kmem_alloc(newbie->ipsa_integlen,
-		    KM_NOSLEEP);
-		if (newbie->ipsa_integ == NULL) {
-			error = ENOMEM;
+		newbie->ipsa_cred = sadb_cred_from_sens(sens, bitmap);
+	}
+
+	/*
+	 * Likewise for outer sensitivity.
+	 */
+	if (osens != NULL) {
+		uint64_t *bitmap = (uint64_t *)(osens + 1);
+		cred_t *cred, *effective_cred;
+		uint32_t *peer_addr_ptr;
+
+		peer_addr_ptr = is_inbound ? src_addr_ptr : dst_addr_ptr;
+
+		cred = sadb_cred_from_sens(osens, bitmap);
+		newbie->ipsa_mac_exempt = CONN_MAC_DEFAULT;
+
+		if (osens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) {
+			newbie->ipsa_mac_exempt = CONN_MAC_IMPLICIT;
+		}
+
+		error = tsol_check_dest(cred, peer_addr_ptr,
+		    (af == AF_INET6)?IPV6_VERSION:IPV4_VERSION,
+		    newbie->ipsa_mac_exempt, &effective_cred);
+		if (error != 0) {
+			crfree(cred);
 			mutex_exit(&newbie->ipsa_lock);
 			goto error;
 		}
-		newbie->ipsa_sens = kmem_alloc(newbie->ipsa_senslen,
-		    KM_NOSLEEP);
-		if (newbie->ipsa_sens == NULL) {
-			error = ENOMEM;
-			mutex_exit(&newbie->ipsa_lock);
-			goto error;
-		}
-		for (i = 0; i < sens->sadb_sens_sens_len; i++) {
-			newbie->ipsa_sens[i] = *bitmap;
-			bitmap++;
-		}
-		for (i = 0; i < sens->sadb_sens_integ_len; i++) {
-			newbie->ipsa_integ[i] = *bitmap;
-			bitmap++;
-		}
-	}
-
-#endif
+
+		if (effective_cred != NULL) {
+			crfree(cred);
+			cred = effective_cred;
+		}
+
+		newbie->ipsa_ocred = cred;
+
+		if (af == AF_INET6) {
+			tsol_compute_label_v6(cred, (in6_addr_t *)peer_addr_ptr,
+			    newbie->ipsa_opt_storage, ipst);
+		} else {
+			tsol_compute_label(cred, *peer_addr_ptr,
+			    newbie->ipsa_opt_storage, ipst);
+		}
+	}
+
 
 	if (replayext != NULL) {
 		if ((replayext->sadb_x_rc_replay32 == 0) &&
@@ -3867,16 +3996,25 @@
 
 	if (pair_ext != NULL && error == 0) {
 		/* update pair_spi if it exists. */
-		ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
-		if (ipsapp == NULL) {
-			error = ESRCH;
-			*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
-		} else if (ipsapp->ipsap_psa_ptr != NULL) {
+		ipsa_query_t sq;
+
+		sq.spp = spp;		/* XXX param */
+		error = sadb_form_query(ksi, IPSA_Q_DST, IPSA_Q_SRC|IPSA_Q_DST|
+		    IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND, &sq, diagnostic);
+		if (error)
+			return (error);
+
+		error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+
+		if (error != 0)
+			goto error;
+
+		if (ipsapp.ipsap_psa_ptr != NULL) {
 			*diagnostic = SADB_X_DIAGNOSTIC_PAIR_ALREADY;
 			error = EINVAL;
 		} else {
 			/* update_pairing() sets diagnostic */
-			error = update_pairing(ipsapp, ksi, diagnostic, spp);
+			error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
 		}
 	}
 	/* Common error point for this routine. */
@@ -3909,7 +4047,7 @@
 		sadb_pfkey_echo(pfkey_q, mp, samsg, ksi, NULL);
 	}
 
-	destroy_ipsa_pair(ipsapp);
+	destroy_ipsa_pair(&ipsapp);
 	return (error);
 }
 
@@ -4710,6 +4848,49 @@
 }
 
 /*
+ * Check a proposed KMC update for sanity.
+ */
+static int
+sadb_check_kmc(ipsa_query_t *sq, ipsa_t *sa, int *diagnostic)
+{
+	uint32_t kmp = sq->kmp;
+	uint32_t kmc = sq->kmc;
+
+	if (sa == NULL)
+		return (0);
+
+	if (sa->ipsa_state == IPSA_STATE_DEAD)
+		return (ESRCH);	/* DEAD == Not there, in this case. */
+
+	if ((kmp != 0) && ((sa->ipsa_kmp != 0) || (sa->ipsa_kmp != kmp))) {
+		*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
+		return (EINVAL);
+	}
+
+	if ((kmc != 0) && ((sa->ipsa_kmc != 0) || (sa->ipsa_kmc != kmc))) {
+		*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+/*
+ * Actually update the KMC info.
+ */
+static void
+sadb_update_kmc(ipsa_query_t *sq, ipsa_t *sa)
+{
+	uint32_t kmp = sq->kmp;
+	uint32_t kmc = sq->kmc;
+
+	if (kmp != 0)
+		sa->ipsa_kmp = kmp;
+	if (kmc != 0)
+		sa->ipsa_kmc = kmc;
+}
+
+/*
  * Common code to update an SA.
  */
 
@@ -4719,13 +4900,6 @@
     int (*add_sa_func)(mblk_t *, keysock_in_t *, int *, netstack_t *),
     netstack_t *ns, uint8_t sadb_msg_type)
 {
-	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
-	sadb_address_t *srcext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
-	sadb_x_kmc_t *kmcext =
-	    (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
 	sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
 	sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
 	sadb_x_replay_ctr_t *replext =
@@ -4739,44 +4913,29 @@
 	sadb_x_pair_t *pair_ext =
 	    (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
 	ipsa_t *echo_target = NULL;
-	int error = 0;
-	ipsap_t *ipsapp = NULL;
-	uint32_t kmp = 0, kmc = 0;
+	ipsap_t ipsapp;
+	ipsa_query_t sq;
 	time_t current = gethrestime_sec();
 
-
-	/* I need certain extensions present for either UPDATE message. */
-	if (srcext == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
-		return (EINVAL);
-	}
-	if (dstext == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
-		return (EINVAL);
-	}
-	if (assoc == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
-		return (EINVAL);
-	}
-
-	if (kmcext != NULL) {
-		kmp = kmcext->sadb_x_kmc_proto;
-		kmc = kmcext->sadb_x_kmc_cookie;
-	}
-
-	ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
-	if (ipsapp == NULL) {
-		*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
-		return (ESRCH);
-	}
-
-	if (ipsapp->ipsap_psa_ptr == NULL && ipsapp->ipsap_sa_ptr != NULL) {
-		if (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) {
+	sq.spp = spp;		/* XXX param */
+	int error = sadb_form_query(ksi, IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA,
+	    IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+	    &sq, diagnostic);
+
+	if (error != 0)
+		return (error);
+
+	error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+	if (error != 0)
+		return (error);
+
+	if (ipsapp.ipsap_psa_ptr == NULL && ipsapp.ipsap_sa_ptr != NULL) {
+		if (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) {
 			/*
 			 * REFRELE the target and let the add_sa_func()
 			 * deal with updating a larval SA.
 			 */
-			destroy_ipsa_pair(ipsapp);
+			destroy_ipsa_pair(&ipsapp);
 			return (add_sa_func(mp, ksi, diagnostic, ns));
 		}
 	}
@@ -4796,39 +4955,39 @@
 		goto bail;
 	}
 
-	if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
-		if (ipsapp->ipsap_sa_ptr != NULL &&
-		    ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
-			if ((error = sadb_update_state(ipsapp->ipsap_sa_ptr,
-			    assoc->sadb_sa_state, NULL)) != 0) {
+	if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
+		if (ipsapp.ipsap_sa_ptr != NULL &&
+		    ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+			if ((error = sadb_update_state(ipsapp.ipsap_sa_ptr,
+			    sq.assoc->sadb_sa_state, NULL)) != 0) {
 				*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
 				goto bail;
 			}
 		}
-		if (ipsapp->ipsap_psa_ptr != NULL &&
-		    ipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
-			if ((error = sadb_update_state(ipsapp->ipsap_psa_ptr,
-			    assoc->sadb_sa_state, NULL)) != 0) {
+		if (ipsapp.ipsap_psa_ptr != NULL &&
+		    ipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+			if ((error = sadb_update_state(ipsapp.ipsap_psa_ptr,
+			    sq.assoc->sadb_sa_state, NULL)) != 0) {
 				*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
 				goto bail;
 			}
 		}
 	}
-	if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
-		if (ipsapp->ipsap_sa_ptr != NULL) {
-			error = sadb_update_state(ipsapp->ipsap_sa_ptr,
-			    assoc->sadb_sa_state,
-			    (ipsapp->ipsap_sa_ptr->ipsa_flags &
+	if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
+		if (ipsapp.ipsap_sa_ptr != NULL) {
+			error = sadb_update_state(ipsapp.ipsap_sa_ptr,
+			    sq.assoc->sadb_sa_state,
+			    (ipsapp.ipsap_sa_ptr->ipsa_flags &
 			    IPSA_F_INBOUND) ? ipkt_lst : NULL);
 			if (error) {
 				*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
 				goto bail;
 			}
 		}
-		if (ipsapp->ipsap_psa_ptr != NULL) {
-			error = sadb_update_state(ipsapp->ipsap_psa_ptr,
-			    assoc->sadb_sa_state,
-			    (ipsapp->ipsap_psa_ptr->ipsa_flags &
+		if (ipsapp.ipsap_psa_ptr != NULL) {
+			error = sadb_update_state(ipsapp.ipsap_psa_ptr,
+			    sq.assoc->sadb_sa_state,
+			    (ipsapp.ipsap_psa_ptr->ipsa_flags &
 			    IPSA_F_INBOUND) ? ipkt_lst : NULL);
 			if (error) {
 				*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
@@ -4847,19 +5006,17 @@
 	 * XXX STATS : logging/stats here?
 	 */
 
-	if (!((assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
-	    (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
+	if (!((sq.assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
+	    (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
 		error = EINVAL;
 		goto bail;
 	}
-
-	if (assoc->sadb_sa_flags & ~spp->s_updateflags) {
+	if (sq.assoc->sadb_sa_flags & ~spp->s_updateflags) {
 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
 		error = EINVAL;
 		goto bail;
 	}
-
 	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL) {
 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_LIFETIME;
 		error = EOPNOTSUPP;
@@ -4871,107 +5028,73 @@
 		goto bail;
 	}
 
-	if (ipsapp->ipsap_sa_ptr != NULL) {
-		if (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_DEAD) {
-			error = ESRCH;	/* DEAD == Not there, in this case. */
-			*diagnostic = SADB_X_DIAGNOSTIC_SA_EXPIRED;
-			goto bail;
-		}
-		if ((kmp != 0) &&
-		    ((ipsapp->ipsap_sa_ptr->ipsa_kmp != 0) ||
-		    (ipsapp->ipsap_sa_ptr->ipsa_kmp != kmp))) {
-			*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
-			error = EINVAL;
-			goto bail;
-		}
-		if ((kmc != 0) &&
-		    ((ipsapp->ipsap_sa_ptr->ipsa_kmc != 0) ||
-		    (ipsapp->ipsap_sa_ptr->ipsa_kmc != kmc))) {
-			*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
-			error = EINVAL;
-			goto bail;
-		}
+	if ((*diagnostic = sadb_labelchk(ksi)) != 0)
+		return (EINVAL);
+
+	error = sadb_check_kmc(&sq, ipsapp.ipsap_sa_ptr, diagnostic);
+	if (error != 0)
+		goto bail;
+
+	error = sadb_check_kmc(&sq, ipsapp.ipsap_psa_ptr, diagnostic);
+	if (error != 0)
+		goto bail;
+
+
+	if (ipsapp.ipsap_sa_ptr != NULL) {
 		/*
 		 * Do not allow replay value change for MATURE or LARVAL SA.
 		 */
 
 		if ((replext != NULL) &&
-		    ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
-		    (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
+		    ((ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
+		    (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
 			error = EINVAL;
 			goto bail;
 		}
 	}
 
-	if (ipsapp->ipsap_psa_ptr != NULL) {
-		if (ipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) {
-			*diagnostic = SADB_X_DIAGNOSTIC_SA_EXPIRED;
-			error = ESRCH;	/* DEAD == Not there, in this case. */
-			goto bail;
-		}
-		if ((kmp != 0) &&
-		    ((ipsapp->ipsap_psa_ptr->ipsa_kmp != 0) ||
-		    (ipsapp->ipsap_psa_ptr->ipsa_kmp != kmp))) {
-			*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
-			error = EINVAL;
-			goto bail;
-		}
-		if ((kmc != 0) &&
-		    ((ipsapp->ipsap_psa_ptr->ipsa_kmc != 0) ||
-		    (ipsapp->ipsap_psa_ptr->ipsa_kmc != kmc))) {
-			*diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
-			error = EINVAL;
-			goto bail;
-		}
-	}
-
-	if (ipsapp->ipsap_sa_ptr != NULL) {
-		sadb_update_lifetimes(ipsapp->ipsap_sa_ptr, hard, soft,
+
+	if (ipsapp.ipsap_sa_ptr != NULL) {
+		sadb_update_lifetimes(ipsapp.ipsap_sa_ptr, hard, soft,
 		    idle, B_TRUE);
-		if (kmp != 0)
-			ipsapp->ipsap_sa_ptr->ipsa_kmp = kmp;
-		if (kmc != 0)
-			ipsapp->ipsap_sa_ptr->ipsa_kmc = kmc;
+		sadb_update_kmc(&sq, ipsapp.ipsap_sa_ptr);
 		if ((replext != NULL) &&
-		    (ipsapp->ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
+		    (ipsapp.ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
 			/*
 			 * If an inbound SA, update the replay counter
 			 * and check off all the other sequence number
 			 */
 			if (ksi->ks_in_dsttype == KS_IN_ADDR_ME) {
-				if (!sadb_replay_check(ipsapp->ipsap_sa_ptr,
+				if (!sadb_replay_check(ipsapp.ipsap_sa_ptr,
 				    replext->sadb_x_rc_replay32)) {
 					*diagnostic =
 					    SADB_X_DIAGNOSTIC_INVALID_REPLAY;
 					error = EINVAL;
 					goto bail;
 				}
-				mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
-				ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+				mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+				ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
 				    current +
-				    ipsapp->ipsap_sa_ptr->ipsa_idletime;
-				mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+				    ipsapp.ipsap_sa_ptr->ipsa_idletime;
+				mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
 			} else {
-				mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
-				ipsapp->ipsap_sa_ptr->ipsa_replay =
+				mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+				ipsapp.ipsap_sa_ptr->ipsa_replay =
 				    replext->sadb_x_rc_replay32;
-				ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+				ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
 				    current +
-				    ipsapp->ipsap_sa_ptr->ipsa_idletime;
-				mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+				    ipsapp.ipsap_sa_ptr->ipsa_idletime;
+				mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
 			}
 		}
 	}
 
 	if (sadb_msg_type == SADB_X_UPDATEPAIR) {
-		if (ipsapp->ipsap_psa_ptr != NULL) {
-			sadb_update_lifetimes(ipsapp->ipsap_psa_ptr, hard, soft,
+		if (ipsapp.ipsap_psa_ptr != NULL) {
+			sadb_update_lifetimes(ipsapp.ipsap_psa_ptr, hard, soft,
 			    idle, B_FALSE);
-			if (kmp != 0)
-				ipsapp->ipsap_psa_ptr->ipsa_kmp = kmp;
-			if (kmc != 0)
-				ipsapp->ipsap_psa_ptr->ipsa_kmc = kmc;
+			sadb_update_kmc(&sq, ipsapp.ipsap_psa_ptr);
 		} else {
 			*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
 			error = ESRCH;
@@ -4980,32 +5103,28 @@
 	}
 
 	if (pair_ext != NULL)
-		error = update_pairing(ipsapp, ksi, diagnostic, spp);
+		error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
 
 	if (error == 0)
 		sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
 		    ksi, echo_target);
 bail:
 
-	destroy_ipsa_pair(ipsapp);
+	destroy_ipsa_pair(&ipsapp);
 
 	return (error);
 }
 
 
-int
-update_pairing(ipsap_t *ipsapp, keysock_in_t *ksi, int *diagnostic,
-    sadbp_t *spp)
+static int
+update_pairing(ipsap_t *ipsapp, ipsa_query_t *sq, keysock_in_t *ksi,
+    int *diagnostic)
 {
 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
-	sadb_address_t *srcext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
-	sadb_address_t *dstext =
-	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
 	sadb_x_pair_t *pair_ext =
 	    (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
 	int error = 0;
-	ipsap_t *oipsapp = NULL;
+	ipsap_t oipsapp;
 	boolean_t undo_pair = B_FALSE;
 	uint32_t ipsa_flags;
 
@@ -5035,24 +5154,23 @@
 	 * good, complete the update. IPSA_REFRELE the first pair_pointer
 	 * after this update to ensure its not deleted until we are done.
 	 */
-	oipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
-	if (oipsapp == NULL) {
+	error = get_ipsa_pair(sq, &oipsapp, diagnostic);
+	if (error != 0) {
 		/*
 		 * This should never happen, calling function still has
 		 * IPSA_REFHELD on the SA we just updated.
 		 */
-		*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
-		return (EINVAL);
-	}
-
-	if (oipsapp->ipsap_psa_ptr == NULL) {
+		return (error);	/* XXX EINVAL instead of ESRCH? */
+	}
+
+	if (oipsapp.ipsap_psa_ptr == NULL) {
 		*diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
 		error = EINVAL;
 		undo_pair = B_TRUE;
 	} else {
-		ipsa_flags = oipsapp->ipsap_psa_ptr->ipsa_flags;
-		if ((oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
-		    (oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
+		ipsa_flags = oipsapp.ipsap_psa_ptr->ipsa_flags;
+		if ((oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
+		    (oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
 			/* Its dead Jim! */
 			*diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
 			undo_pair = B_TRUE;
@@ -5075,13 +5193,13 @@
 		ipsapp->ipsap_sa_ptr->ipsa_otherspi = 0;
 		mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
 	} else {
-		mutex_enter(&oipsapp->ipsap_psa_ptr->ipsa_lock);
-		oipsapp->ipsap_psa_ptr->ipsa_otherspi = assoc->sadb_sa_spi;
-		oipsapp->ipsap_psa_ptr->ipsa_flags |= IPSA_F_PAIRED;
-		mutex_exit(&oipsapp->ipsap_psa_ptr->ipsa_lock);
-	}
-
-	destroy_ipsa_pair(oipsapp);
+		mutex_enter(&oipsapp.ipsap_psa_ptr->ipsa_lock);
+		oipsapp.ipsap_psa_ptr->ipsa_otherspi = assoc->sadb_sa_spi;
+		oipsapp.ipsap_psa_ptr->ipsa_flags |= IPSA_F_PAIRED;
+		mutex_exit(&oipsapp.ipsap_psa_ptr->ipsa_lock);
+	}
+
+	destroy_ipsa_pair(&oipsapp);
 	return (error);
 }
 
@@ -5098,11 +5216,13 @@
 /*
  * Check the ACQUIRE lists.  If there's an existing ACQUIRE record,
  * grab it, lock it, and return it.  Otherwise return NULL.
+ *
+ * XXX MLS number of arguments getting unwieldy here
  */
 static ipsacq_t *
 sadb_checkacquire(iacqf_t *bucket, ipsec_action_t *ap, ipsec_policy_t *pp,
     uint32_t *src, uint32_t *dst, uint32_t *isrc, uint32_t *idst,
-    uint64_t unique_id)
+    uint64_t unique_id, cred_t *cr)
 {
 	ipsacq_t *walker;
 	sa_family_t fam;
@@ -5131,7 +5251,8 @@
 		    (ap == walker->ipsacq_act) &&
 		    (pp == walker->ipsacq_policy) &&
 		    /* XXX do deep compares of ap/pp? */
-		    (unique_id == walker->ipsacq_unique_id))
+		    (unique_id == walker->ipsacq_unique_id) &&
+		    (ipsec_label_match(cr, walker->ipsacq_cred)))
 			break;			/* everything matched */
 		mutex_exit(&walker->ipsacq_lock);
 	}
@@ -5169,12 +5290,16 @@
 	uint64_t unique_id = 0;
 	ipsec_selector_t sel;
 	boolean_t tunnel_mode = io->ipsec_out_tunnel;
+	cred_t 		*cr = NULL;
 	netstack_t	*ns = io->ipsec_out_ns;
 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
+	sadb_sens_t 	*sens = NULL;
+	int 		sens_len;
 
 	ASSERT((pp != NULL) || (ap != NULL));
 
 	ASSERT(need_ah != NULL || need_esp != NULL);
+
 	/* Assign sadb pointers */
 	if (need_esp) { /* ESP for AH+ESP */
 		ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
@@ -5187,6 +5312,11 @@
 	}
 	sp = io->ipsec_out_v4 ? &spp->s_v4 : &spp->s_v6;
 
+	ASSERT(mp->b_cont != NULL);
+
+	if (is_system_labeled())
+		cr = msg_getcred(mp->b_cont, NULL);
+
 	if (ap == NULL)
 		ap = pp->ipsp_act;
 
@@ -5247,7 +5377,7 @@
 	bucket = &(sp->sdb_acq[hashoffset]);
 	mutex_enter(&bucket->iacqf_lock);
 	newbie = sadb_checkacquire(bucket, ap, pp, src, dst, isrc, idst,
-	    unique_id);
+	    unique_id, cr);
 
 	if (newbie == NULL) {
 		/*
@@ -5272,11 +5402,24 @@
 		newbie->ipsacq_ptpn = &bucket->iacqf_ipsacq;
 		if (newbie->ipsacq_next != NULL)
 			newbie->ipsacq_next->ipsacq_ptpn = &newbie->ipsacq_next;
+
 		bucket->iacqf_ipsacq = newbie;
 		mutex_init(&newbie->ipsacq_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_enter(&newbie->ipsacq_lock);
 	}
 
+	/*
+	 * XXX MLS does it actually help us to drop the bucket lock here?
+	 * we have inserted a half-built, locked acquire record into the
+	 * bucket.  any competing thread will now be able to lock the bucket
+	 * to scan it, but will immediately pile up on the new acquire
+	 * record's lock; I don't think we gain anything here other than to
+	 * disperse blame for lock contention.
+	 *
+	 * we might be able to dispense with acquire record locks entirely..
+	 * just use the bucket locks..
+	 */
+
 	mutex_exit(&bucket->iacqf_lock);
 
 	/*
@@ -5318,6 +5461,11 @@
 			newbie->ipsacq_proto = io->ipsec_out_proto;
 		}
 		newbie->ipsacq_unique_id = unique_id;
+
+		if (cr != NULL) {
+			crhold(cr);
+			newbie->ipsacq_cred = cr;
+		}
 	} else {
 		/* Scan to the end of the list & insert. */
 		mblk_t *lastone = newbie->ipsacq_mp;
@@ -5358,44 +5506,61 @@
 		return;
 	}
 
-	if (keysock_extended_reg(ns)) {
+	if (!keysock_extended_reg(ns))
+		goto punt_extended;
+	/*
+	 * Construct an extended ACQUIRE.  There are logging
+	 * opportunities here in failure cases.
+	 */
+	(void) memset(&sel, 0, sizeof (sel));
+	sel.ips_isv4 = io->ipsec_out_v4;
+	if (tunnel_mode) {
+		sel.ips_protocol = (io->ipsec_out_inaf == AF_INET) ?
+		    IPPROTO_ENCAP : IPPROTO_IPV6;
+	} else {
+		sel.ips_protocol = io->ipsec_out_proto;
+		sel.ips_local_port = io->ipsec_out_src_port;
+		sel.ips_remote_port = io->ipsec_out_dst_port;
+	}
+	sel.ips_icmp_type = io->ipsec_out_icmp_type;
+	sel.ips_icmp_code = io->ipsec_out_icmp_code;
+	sel.ips_is_icmp_inv_acq = 0;
+	if (af == AF_INET) {
+		sel.ips_local_addr_v4 = ipha->ipha_src;
+		sel.ips_remote_addr_v4 = ipha->ipha_dst;
+	} else {
+		sel.ips_local_addr_v6 = ip6h->ip6_src;
+		sel.ips_remote_addr_v6 = ip6h->ip6_dst;
+	}
+
+	extended = sadb_keysock_out(0);
+	if (extended == NULL)
+		goto punt_extended;
+
+	if (cr != NULL) {
 		/*
-		 * Construct an extended ACQUIRE.  There are logging
-		 * opportunities here in failure cases.
+		 * XXX MLS correct condition here?
+		 * XXX MLS other credential attributes in acquire?
+		 * XXX malloc failure?  don't fall back to original?
 		 */
-
-		(void) memset(&sel, 0, sizeof (sel));
-		sel.ips_isv4 = io->ipsec_out_v4;
-		if (tunnel_mode) {
-			sel.ips_protocol = (io->ipsec_out_inaf == AF_INET) ?
-			    IPPROTO_ENCAP : IPPROTO_IPV6;
-		} else {
-			sel.ips_protocol = io->ipsec_out_proto;
-			sel.ips_local_port = io->ipsec_out_src_port;
-			sel.ips_remote_port = io->ipsec_out_dst_port;
-		}
-		sel.ips_icmp_type = io->ipsec_out_icmp_type;
-		sel.ips_icmp_code = io->ipsec_out_icmp_code;
-		sel.ips_is_icmp_inv_acq = 0;
-		if (af == AF_INET) {
-			sel.ips_local_addr_v4 = ipha->ipha_src;
-			sel.ips_remote_addr_v4 = ipha->ipha_dst;
-		} else {
-			sel.ips_local_addr_v6 = ip6h->ip6_src;
-			sel.ips_remote_addr_v6 = ip6h->ip6_dst;
-		}
-
-		extended = sadb_keysock_out(0);
-		if (extended != NULL) {
-			extended->b_cont = sadb_extended_acquire(&sel, pp, ap,
-			    tunnel_mode, seq, 0, ns);
-			if (extended->b_cont == NULL) {
-				freeb(extended);
-				extended = NULL;
-			}
-		}
-	} else
-		extended = NULL;
+		sens = sadb_make_sens_ext(cr, &sens_len);
+
+		if (sens == NULL) {
+			freeb(extended);
+			goto punt_extended;
+		}
+	}
+
+	extended->b_cont = sadb_extended_acquire(&sel, pp, ap, tunnel_mode,
+	    seq, 0, sens, ns);
+
+	if (sens != NULL)
+		kmem_free(sens, sens_len);
+
+	if (extended->b_cont == NULL) {
+		freeb(extended);
+		goto punt_extended;
+	}
 
 	/*
 	 * Send an ACQUIRE message (and possible an extended ACQUIRE) based on
@@ -5403,6 +5568,10 @@
 	 * already locked.
 	 */
 	(*spp->s_acqfn)(newbie, extended, ns);
+	return;
+
+punt_extended:
+	(*spp->s_acqfn)(newbie, NULL, ns);
 }
 
 /*
@@ -5428,6 +5597,11 @@
 	if (acqrec->ipsacq_next != NULL)
 		acqrec->ipsacq_next->ipsacq_ptpn = acqrec->ipsacq_ptpn;
 
+	if (acqrec->ipsacq_cred) {
+		crfree(acqrec->ipsacq_cred);
+		acqrec->ipsacq_cred = NULL;
+	}
+
 	/*
 	 * Free hanging mp's.
 	 *
@@ -5605,6 +5779,101 @@
 	return (cur);
 }
 
+#include <sys/tsol/label_macro.h> /* XXX should not need this */
+
+/*
+ * From a cred_t, construct a sensitivity label extension
+ *
+ * We send up a fixed-size sensitivity label bitmap, and are perhaps
+ * overly chummy with the underlying data structures here.
+ */
+
+/* ARGSUSED */
+int
+sadb_sens_len_from_cred(cred_t *cr)
+{
+	int baselen = sizeof (sadb_sens_t) + _C_LEN * 4;
+	return (roundup(baselen, sizeof (uint64_t)));
+}
+
+void
+sadb_sens_from_cred(sadb_sens_t *sens, int exttype, cred_t *cr, int senslen)
+{
+	uint8_t *bitmap;
+	bslabel_t *sl;
+	ts_label_t *tsl;
+
+	/* LINTED */
+	ASSERT((_C_LEN & 1) == 0);
+	ASSERT((senslen & 7) == 0);
+
+	tsl = crgetlabel(cr);
+	sl = label2bslabel(tsl);
+
+	sens->sadb_sens_exttype = exttype;
+	sens->sadb_sens_len = SADB_8TO64(senslen);
+
+	sens->sadb_sens_dpd = tsl->tsl_doi;
+	sens->sadb_sens_sens_level = LCLASS(sl);
+	sens->sadb_sens_integ_level = 0; /* TBD */
+	sens->sadb_sens_sens_len = _C_LEN >> 1;
+	sens->sadb_sens_integ_len = 0; /* TBD */
+	sens->sadb_x_sens_flags = 0;
+
+	bitmap = (uint8_t *)(sens + 1);
+	bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
+}
+
+static sadb_sens_t *
+sadb_make_sens_ext(cred_t *cr, int *len)
+{
+	/* XXX allocation failure? */
+	int sens_len = sadb_sens_len_from_cred(cr);
+
+	sadb_sens_t *sens = kmem_alloc(sens_len, KM_SLEEP);
+
+	sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY, cr, sens_len);
+
+	*len = sens_len;
+
+	return (sens);
+}
+
+/*
+ * Okay, how do we report errors/invalid labels from this?
+ * With a special designated "not a label" cred_t ?
+ */
+/* ARGSUSED */
+cred_t *
+sadb_cred_from_sens(sadb_sens_t *sens, uint64_t *bitmap)
+{
+	int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
+	bslabel_t sl;
+	cred_t *cr;
+
+	if (sens->sadb_sens_integ_level != 0)
+		return (NULL);
+	if (sens->sadb_sens_integ_len != 0)
+		return (NULL);
+	if (bitmap_len > _C_LEN * 4)
+		return (NULL);
+
+	bsllow(&sl);
+	LCLASS_SET((_bslabel_impl_t *)&sl, sens->sadb_sens_sens_level);
+	bcopy(bitmap, &((_bslabel_impl_t *)&sl)->compartments,
+	    bitmap_len);
+
+	cr = newcred_from_bslabel(&sl, sens->sadb_sens_dpd, KM_NOSLEEP);
+	if (cr == NULL)
+		return (cr);
+
+	if (sens->sadb_x_sens_flags & SADB_X_SENS_UNLABELED)
+		crgetlabel(cr)->tsl_flags |= TSLF_UNLABELED;
+	return (cr);
+}
+
+/* End XXX label-library-leakage */
+
 /*
  * Construct an extended ACQUIRE message based on a selector and the resulting
  * IPsec action.
@@ -5616,7 +5885,7 @@
 static mblk_t *
 sadb_extended_acquire(ipsec_selector_t *sel, ipsec_policy_t *pol,
     ipsec_action_t *act, boolean_t tunnel_mode, uint32_t seq, uint32_t pid,
-    netstack_t *ns)
+    sadb_sens_t *sens, netstack_t *ns)
 {
 	mblk_t *mp;
 	sadb_msg_t *samsg;
@@ -5781,6 +6050,18 @@
 		return (NULL);
 	}
 
+	if (sens != NULL) {
+		uint8_t *sensext = cur;
+		int senslen = SADB_64TO8(sens->sadb_sens_len);
+
+		cur += senslen;
+		if (cur > end) {
+			freeb(mp);
+			return (NULL);
+		}
+		bcopy(sens, sensext, senslen);
+	}
+
 	/*
 	 * This section will change a lot as policy evolves.
 	 * For now, it'll be relatively simple.
@@ -6827,6 +7108,9 @@
  * in this function so the caller can extract them where appropriately.
  *
  * The SRC address is the local one - just like an outbound ACQUIRE message.
+ *
+ * XXX MLS: key management supplies a label which we just reflect back up
+ * again.  clearly we need to involve the label in the rest of the checks.
  */
 mblk_t *
 ipsec_construct_inverse_acquire(sadb_msg_t *samsg, sadb_ext_t *extv[],
@@ -6838,6 +7122,7 @@
 	    *dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST],
 	    *innsrcext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_SRC],
 	    *inndstext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_DST];
+	sadb_sens_t *sens = (sadb_sens_t *)extv[SADB_EXT_SENSITIVITY];
 	struct sockaddr_in6 *src, *dst;
 	struct sockaddr_in6 *isrc, *idst;
 	ipsec_tun_pol_t *itp = NULL;
@@ -6846,6 +7131,7 @@
 	mblk_t *retmp = NULL;
 	ip_stack_t	*ipst = ns->netstack_ip;
 
+
 	/* Normalize addresses */
 	if (sadb_addrcheck(NULL, (mblk_t *)samsg, (sadb_ext_t *)srcext, 0, ns)
 	    == KS_IN_ADDR_UNKNOWN) {
@@ -6989,7 +7275,7 @@
 	 */
 	retmp = sadb_extended_acquire(&sel, pp, NULL,
 	    (itp != NULL && (itp->itp_flags & ITPF_P_TUNNEL)),
-	    samsg->sadb_msg_seq, samsg->sadb_msg_pid, ns);
+	    samsg->sadb_msg_seq, samsg->sadb_msg_pid, sens, ns);
 	if (pp != NULL) {
 		IPPOL_REFRELE(pp, ns);
 	}
@@ -7396,6 +7682,180 @@
 
 	return (-1);
 }
+
+/*
+ * Whack options in the outer IP header when ipsec changes the outer label
+ *
+ * This is inelegant and really could use refactoring.
+ */
+int
+sadb_whack_label(mblk_t **mpp, ipsa_t *assoc)
+{
+	int delta;
+	int plen;
+	dblk_t *db;
+	int hlen;
+	uint8_t *opt_storage = assoc->ipsa_opt_storage;
+	mblk_t *mp = *mpp;
+	ipha_t *ipha = (ipha_t *)mp->b_rptr;
+
+	plen = ntohs(ipha->ipha_length);
+
+	delta = tsol_remove_secopt(ipha, MBLKL(mp));
+	mp->b_wptr += delta;
+	plen += delta;
+
+	/* XXX XXX code copied from tsol_check_label */
+
+	/* Make sure we have room for the worst-case addition */
+	hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN];
+	hlen = (hlen + 3) & ~3;
+	if (hlen > IP_MAX_HDR_LENGTH)
+		hlen = IP_MAX_HDR_LENGTH;
+	hlen -= IPH_HDR_LENGTH(ipha);
+
+	db = mp->b_datap;
+	if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
+		int copylen;
+		mblk_t *new_mp;
+
+		/* allocate enough to be meaningful, but not *too* much */
+		copylen = MBLKL(mp);
+		if (copylen > 256)
+			copylen = 256;
+		new_mp = allocb_tmpl(hlen + copylen +
+		    (mp->b_rptr - mp->b_datap->db_base), mp);
+
+		if (new_mp == NULL)
+			return (ENOMEM);
+
+		/* keep the bias */
+		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+		new_mp->b_wptr = new_mp->b_rptr + copylen;
+		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+		new_mp->b_cont = mp;
+		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+			new_mp->b_cont = mp->b_cont;
+			freeb(mp);
+		}
+		*mpp = mp = new_mp;
+		ipha = (ipha_t *)mp->b_rptr;
+	}
+
+	delta = tsol_prepend_option(assoc->ipsa_opt_storage, ipha, MBLKL(mp));
+
+	ASSERT(delta != -1);
+
+	plen += delta;
+	mp->b_wptr += delta;
+
+	/*
+	 * Paranoia
+	 */
+	db = mp->b_datap;
+
+	ASSERT3P(mp->b_wptr, <=, db->db_lim);
+	ASSERT3P(mp->b_rptr, <=, db->db_lim);
+
+	ASSERT3P(mp->b_wptr, >=, db->db_base);
+	ASSERT3P(mp->b_rptr, >=, db->db_base);
+	/* End paranoia */
+
+	ipha->ipha_length = htons(plen);
+
+	return (0);
+}
+
+int
+sadb_whack_label_v6(mblk_t **mpp, ipsa_t *assoc)
+{
+	int delta;
+	int plen;
+	dblk_t *db;
+	int hlen;
+	uint8_t *opt_storage = assoc->ipsa_opt_storage;
+	uint_t sec_opt_len; /* label option length not including type, len */
+	mblk_t *mp = *mpp;
+	ip6_t *ip6h = (ip6_t *)mp->b_rptr;
+
+	plen = ntohs(ip6h->ip6_plen);
+
+	delta = tsol_remove_secopt_v6(ip6h, MBLKL(mp));
+	mp->b_wptr += delta;
+	plen += delta;
+
+	/* XXX XXX code copied from tsol_check_label_v6 */
+	/*
+	 * Make sure we have room for the worst-case addition. Add 2 bytes for
+	 * the hop-by-hop ext header's next header and length fields. Add
+	 * another 2 bytes for the label option type, len and then round
+	 * up to the next 8-byte multiple.
+	 */
+	sec_opt_len = opt_storage[1];
+
+	db = mp->b_datap;
+	hlen = (4 + sec_opt_len + 7) & ~7;
+
+	if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
+		int copylen;
+		mblk_t *new_mp;
+		uint16_t hdr_len;
+
+		hdr_len = ip_hdr_length_v6(mp, ip6h);
+		/*
+		 * Allocate enough to be meaningful, but not *too* much.
+		 * Also all the IPv6 extension headers must be in the same mblk
+		 */
+		copylen = MBLKL(mp);
+		if (copylen > 256)
+			copylen = 256;
+		if (copylen < hdr_len)
+			copylen = hdr_len;
+		new_mp = allocb_tmpl(hlen + copylen +
+		    (mp->b_rptr - mp->b_datap->db_base), mp);
+		if (new_mp == NULL)
+			return (ENOMEM);
+
+		/* keep the bias */
+		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+		new_mp->b_wptr = new_mp->b_rptr + copylen;
+		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+		new_mp->b_cont = mp;
+		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+			new_mp->b_cont = mp->b_cont;
+			freeb(mp);
+		}
+		*mpp = mp = new_mp;
+		ip6h = (ip6_t *)mp->b_rptr;
+	}
+
+	delta = tsol_prepend_option_v6(assoc->ipsa_opt_storage,
+	    ip6h, MBLKL(mp));
+
+	ASSERT(delta != -1);
+
+	plen += delta;
+	mp->b_wptr += delta;
+
+	/*
+	 * Paranoia
+	 */
+	db = mp->b_datap;
+
+	ASSERT3P(mp->b_wptr, <=, db->db_lim);
+	ASSERT3P(mp->b_rptr, <=, db->db_lim);
+
+	ASSERT3P(mp->b_wptr, >=, db->db_base);
+	ASSERT3P(mp->b_rptr, >=, db->db_base);
+	/* End paranoia */
+
+	ip6h->ip6_plen = htons(plen);
+
+	return (0);
+}
+
+
+
 /*
  * If this is an outgoing SA then add some fuzz to the
  * SOFT EXPIRE time. The reason for this is to stop
@@ -7405,7 +7865,7 @@
  * sadb_ager(), although this is only a guide as it
  * selftunes.
  */
-void
+static void
 lifetime_fuzz(ipsa_t *assoc)
 {
 	uint8_t rnd;
@@ -7418,12 +7878,10 @@
 	assoc->ipsa_softexpiretime -= rnd;
 	assoc->ipsa_softaddlt -= rnd;
 }
-void
+
+static void
 destroy_ipsa_pair(ipsap_t *ipsapp)
 {
-	if (ipsapp == NULL)
-		return;
-
 	/*
 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
 	 * them in { }.
@@ -7434,8 +7892,16 @@
 	if (ipsapp->ipsap_psa_ptr != NULL) {
 		IPSA_REFRELE(ipsapp->ipsap_psa_ptr);
 	}
-
-	kmem_free(ipsapp, sizeof (*ipsapp));
+	init_ipsa_pair(ipsapp);
+}
+
+static void
+init_ipsa_pair(ipsap_t *ipsapp)
+{
+	ipsapp->ipsap_bucket = NULL;
+	ipsapp->ipsap_sa_ptr = NULL;
+	ipsapp->ipsap_pbucket = NULL;
+	ipsapp->ipsap_psa_ptr = NULL;
 }
 
 /*
--- a/usr/src/uts/common/inet/ip/spd.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/spd.c	Mon Nov 02 15:39:20 2009 -0800
@@ -35,6 +35,7 @@
 #include <sys/stropts.h>
 #include <sys/sysmacros.h>
 #include <sys/strsubr.h>
+#include <sys/strsun.h>
 #include <sys/strlog.h>
 #include <sys/cmn_err.h>
 #include <sys/zone.h>
@@ -2221,6 +2222,27 @@
 			IPPOL_REFHOLD(p);
 		}
 		/*
+		 * The caller may have mistakenly assigned an ip6i_t as the
+		 * ip6h for this packet, so take that corner-case into
+		 * account.
+		 */
+		if (ip6h != NULL && ip6h->ip6_nxt == IPPROTO_RAW) {
+			ip6h++;
+			/* First check for bizarro split-mblk headers. */
+			if ((uintptr_t)ip6h > (uintptr_t)data_mp->b_wptr ||
+			    ((uintptr_t)ip6h) + sizeof (ip6_t) >
+			    (uintptr_t)data_mp->b_wptr) {
+				ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
+				    "ipsec_check_global_policy", ipha, ip6h,
+				    B_TRUE, ns);
+				counter = DROPPER(ipss, ipds_spd_nomem);
+				goto fail;
+			}
+			/* Next, see if ip6i is at the end of an mblk. */
+			if (ip6h == (ip6_t *)data_mp->b_wptr)
+				ip6h = (ip6_t *)data_mp->b_cont->b_rptr;
+		}
+		/*
 		 * Fudge sel for UNIQUE_ID setting below.
 		 */
 		pkt_unique = conn_to_unique(connp, data_mp, ipha, ip6h);
@@ -2233,7 +2255,7 @@
 			 * an internal failure.
 			 */
 			ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
-			    "ipsec_init_inbound_sel", ipha, ip6h, B_FALSE, ns);
+			    "ipsec_init_inbound_sel", ipha, ip6h, B_TRUE, ns);
 			counter = DROPPER(ipss, ipds_spd_nomem);
 			goto fail;
 		}
@@ -2708,6 +2730,43 @@
 }
 
 /*
+ * Handle all sorts of cases like tunnel-mode, ICMP, and ip6i prepending.
+ */
+static int
+prepended_length(mblk_t *mp, uintptr_t hptr)
+{
+	int rc = 0;
+
+	while (mp != NULL) {
+		if (hptr >= (uintptr_t)mp->b_rptr && hptr <
+		    (uintptr_t)mp->b_wptr) {
+			rc += (int)(hptr - (uintptr_t)mp->b_rptr);
+			break;	/* out of while loop */
+		}
+		rc += (int)MBLKL(mp);
+		mp = mp->b_cont;
+	}
+
+	if (mp == NULL) {
+		/*
+		 * IF (big IF) we make it here by naturally exiting the loop,
+		 * then ip6h isn't in the mblk chain "mp" at all.
+		 *
+		 * The only case where this happens is with a reversed IP
+		 * header that gets passed up by inbound ICMP processing.
+		 * This unfortunately triggers longstanding bug 6478464.  For
+		 * now, just pass up 0 for the answer.
+		 */
+#ifdef DEBUG_NOT_UNTIL_6478464
+		ASSERT(mp != NULL);
+#endif
+		rc = 0;
+	}
+
+	return (rc);
+}
+
+/*
  * Returns:
  *
  * SELRET_NOMEM --> msgpullup() needed to gather things failed.
@@ -2726,13 +2785,12 @@
     ip6_t *ip6h, uint8_t sel_flags)
 {
 	uint16_t *ports;
+	int outer_hdr_len = 0;	/* For ICMP, tunnel-mode, or ip6i cases... */
 	ushort_t hdr_len;
-	int outer_hdr_len = 0;	/* For ICMP tunnel-mode cases... */
 	mblk_t *spare_mp = NULL;
-	uint8_t *nexthdrp;
+	uint8_t *nexthdrp, *transportp;
 	uint8_t nexthdr;
-	uint8_t *typecode;
-	uint8_t check_proto;
+	uint8_t icmp_proto;
 	ip6_pkt_t ipp;
 	boolean_t port_policy_present = (sel_flags & SEL_PORT_POLICY);
 	boolean_t is_icmp = (sel_flags & SEL_IS_ICMP);
@@ -2743,10 +2801,39 @@
 	    (ipha != NULL && ip6h == NULL));
 
 	if (ip6h != NULL) {
-		if (is_icmp || tunnel_mode)
-			outer_hdr_len = ((uint8_t *)ip6h) - mp->b_rptr;
-
-		check_proto = IPPROTO_ICMPV6;
+		outer_hdr_len = prepended_length(mp, (uintptr_t)ip6h);
+
+		nexthdr = ip6h->ip6_nxt;
+
+		/*
+		 * The caller may have mistakenly assigned an ip6i_t as the
+		 * ip6h for this packet, so take that corner-case into
+		 * account.
+		 */
+		if (nexthdr == IPPROTO_RAW) {
+			ip6h++;
+			/* First check for bizarro split-mblk headers. */
+			if ((uintptr_t)ip6h > (uintptr_t)mp->b_wptr ||
+			    ((uintptr_t)ip6h) + sizeof (ip6_t) >
+			    (uintptr_t)mp->b_wptr) {
+				return (SELRET_BADPKT);
+			}
+			/* Next, see if ip6i is at the end of an mblk. */
+			if (ip6h == (ip6_t *)mp->b_wptr)
+				ip6h = (ip6_t *)mp->b_cont->b_rptr;
+
+			nexthdr = ip6h->ip6_nxt;
+
+			/*
+			 * Finally, if we haven't adjusted for ip6i, do so
+			 * now.  ip6i_t structs are prepended, so an ICMP
+			 * or tunnel packet would just be overwritten.
+			 */
+			if (outer_hdr_len == 0)
+				outer_hdr_len = sizeof (ip6i_t);
+		}
+
+		icmp_proto = IPPROTO_ICMPV6;
 		sel->ips_isv4 = B_FALSE;
 		sel->ips_local_addr_v6 = ip6h->ip6_dst;
 		sel->ips_remote_addr_v6 = ip6h->ip6_src;
@@ -2754,7 +2841,6 @@
 		bzero(&ipp, sizeof (ipp));
 		(void) ip_find_hdr_v6(mp, ip6h, &ipp, NULL);
 
-		nexthdr = ip6h->ip6_nxt;
 		switch (nexthdr) {
 		case IPPROTO_HOPOPTS:
 		case IPPROTO_ROUTING:
@@ -2766,6 +2852,7 @@
 			 */
 			if ((spare_mp = msgpullup(mp, -1)) == NULL)
 				return (SELRET_NOMEM);
+
 			if (!ip_hdr_length_nexthdr_v6(spare_mp,
 			    (ip6_t *)(spare_mp->b_rptr + outer_hdr_len),
 			    &hdr_len, &nexthdrp)) {
@@ -2786,10 +2873,10 @@
 			ipsec_freemsg_chain(spare_mp);
 			return (SELRET_TUNFRAG);
 		}
+		transportp = (uint8_t *)ip6h + hdr_len;
 	} else {
-		if (is_icmp || tunnel_mode)
-			outer_hdr_len = ((uint8_t *)ipha) - mp->b_rptr;
-		check_proto = IPPROTO_ICMP;
+		outer_hdr_len = prepended_length(mp, (uintptr_t)ipha);
+		icmp_proto = IPPROTO_ICMP;
 		sel->ips_isv4 = B_TRUE;
 		sel->ips_local_addr_v4 = ipha->ipha_dst;
 		sel->ips_remote_addr_v4 = ipha->ipha_src;
@@ -2803,19 +2890,19 @@
 			ipsec_freemsg_chain(spare_mp);
 			return (SELRET_TUNFRAG);
 		}
-
+		transportp = (uint8_t *)ipha + hdr_len;
 	}
 	sel->ips_protocol = nexthdr;
 
 	if ((nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP &&
-	    nexthdr != IPPROTO_SCTP && nexthdr != check_proto) ||
+	    nexthdr != IPPROTO_SCTP && nexthdr != icmp_proto) ||
 	    (!port_policy_present && !post_frag && tunnel_mode)) {
 		sel->ips_remote_port = sel->ips_local_port = 0;
 		ipsec_freemsg_chain(spare_mp);
 		return (SELRET_SUCCESS);
 	}
 
-	if (&mp->b_rptr[hdr_len] + 4 > mp->b_wptr) {
+	if (transportp + 4 > mp->b_wptr) {
 		/* If we didn't pullup a copy already, do so now. */
 		/*
 		 * XXX performance, will upper-layers frequently split TCP/UDP
@@ -2827,17 +2914,15 @@
 		    (spare_mp = msgpullup(mp, -1)) == NULL) {
 			return (SELRET_NOMEM);
 		}
-		ports = (uint16_t *)&spare_mp->b_rptr[hdr_len + outer_hdr_len];
-	} else {
-		ports = (uint16_t *)&mp->b_rptr[hdr_len + outer_hdr_len];
-	}
-
-	if (nexthdr == check_proto) {
-		typecode = (uint8_t *)ports;
-		sel->ips_icmp_type = *typecode++;
-		sel->ips_icmp_code = *typecode;
+		transportp = &spare_mp->b_rptr[hdr_len + outer_hdr_len];
+	}
+
+	if (nexthdr == icmp_proto) {
+		sel->ips_icmp_type = *transportp++;
+		sel->ips_icmp_code = *transportp;
 		sel->ips_remote_port = sel->ips_local_port = 0;
 	} else {
+		ports = (uint16_t *)transportp;
 		sel->ips_remote_port = *ports++;
 		sel->ips_local_port = *ports;
 	}
@@ -3983,7 +4068,7 @@
  *		in IP proper.
  */
 boolean_t
-ipsec_in_to_out(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h)
+ipsec_in_to_out(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h, zoneid_t zoneid)
 {
 	ipsec_in_t  *ii;
 	ipsec_out_t  *io;
@@ -3993,7 +4078,6 @@
 	uint_t ifindex;
 	ipsec_selector_t sel;
 	ipsec_action_t *reflect_action = NULL;
-	zoneid_t zoneid;
 	netstack_t	*ns;
 
 	ASSERT(ipsec_mp->b_datap->db_type == M_CTL);
@@ -4013,14 +4097,25 @@
 		reflect_action = ipsec_in_to_out_action(ii);
 	secure = ii->ipsec_in_secure;
 	ifindex = ii->ipsec_in_ill_index;
-	zoneid = ii->ipsec_in_zoneid;
-	ASSERT(zoneid != ALL_ZONES);
 	ns = ii->ipsec_in_ns;
 	v4 = ii->ipsec_in_v4;
 
 	ipsec_in_release_refs(ii);	/* No netstack_rele/hold needed */
 
 	/*
+	 * Use the global zone's id if we don't have a specific zone
+	 * identified. This is likely to happen when the received packet's
+	 * destination is a Trusted Extensions all-zones address. We did
+	 * not copy the zoneid from ii->ipsec_in_zone id because that
+	 * information represents the zoneid we started input processing
+	 * with. The caller should have a better idea of which zone the
+	 * received packet was destined for.
+	 */
+
+	if (zoneid == ALL_ZONES)
+		zoneid = GLOBAL_ZONEID;
+
+	/*
 	 * The caller is going to send the datagram out which might
 	 * go on the wire or delivered locally through ip_wput_local.
 	 *
@@ -4460,6 +4555,8 @@
 	ii->ipsec_in_frtn.free_func = ipsec_in_free;
 	ii->ipsec_in_frtn.free_arg = (char *)ii;
 
+	ii->ipsec_in_zoneid = ALL_ZONES; /* default for received packets */
+
 	ipsec_in = desballoc((uint8_t *)ii, sizeof (ipsec_info_t), BPRI_HI,
 	    &ii->ipsec_in_frtn);
 	if (ipsec_in == NULL) {
--- a/usr/src/uts/common/inet/ip/tn_ipopt.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/tn_ipopt.c	Mon Nov 02 15:39:20 2009 -0800
@@ -272,7 +272,7 @@
  *
  * This routine verifies if a destination is allowed to recieve messages
  * based on the message cred's security label. If any adjustments to
- * the cred are needed due to the connection's MAC-exempt status or
+ * the cred are needed due to the connection's MAC mode or
  * the destination's ability to receive labels, an "effective cred"
  * will be returned.
  *
@@ -287,7 +287,7 @@
  */
 int
 tsol_check_dest(const cred_t *credp, const void *dst, uchar_t version,
-    boolean_t mac_exempt, cred_t **effective_cred)
+    uint_t mac_mode, cred_t **effective_cred)
 {
 	ts_label_t	*tsl, *newtsl = NULL;
 	tsol_tpc_t	*dst_rhtp;
@@ -307,6 +307,14 @@
 		return (0);
 	}
 
+	if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
+		DTRACE_PROBE3(tx__tnopt__log__info__labeling__unresolved__label,
+		    char *,
+		    "implicit-in packet to ip(1) reached tsol_check_dest "
+		    "with implied security label sl(2)",
+		    ipaddr_t, dst, ts_label_t *, tsl);
+	}
+
 	/* Always pass multicast */
 	if (version == IPV4_VERSION &&
 	    CLASSD(*(ipaddr_t *)dst)) {
@@ -335,8 +343,10 @@
 		/*
 		 * Can talk to unlabeled hosts if
 		 * (1) zone's label matches the default label, or
-		 * (2) SO_MAC_EXEMPT is on and we dominate the peer's label
-		 * (3) SO_MAC_EXEMPT is on and this is the global zone
+		 * (2) SO_MAC_EXEMPT is on and we
+		 * dominate the peer's label, or
+		 * (3) SO_MAC_EXEMPT is on and
+		 * this is the global zone
 		 */
 		if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi) {
 			DTRACE_PROBE4(tx__tnopt__log__info__labeling__doi,
@@ -349,7 +359,7 @@
 		if (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
 		    &tsl->tsl_label)) {
 			zoneid = crgetzoneid(credp);
-			if (!mac_exempt ||
+			if (mac_mode != CONN_MAC_AWARE ||
 			    !(zoneid == GLOBAL_ZONEID ||
 			    bldominates(&tsl->tsl_label,
 			    &dst_rhtp->tpc_tp.tp_def_label))) {
@@ -403,16 +413,22 @@
 			TPC_RELE(dst_rhtp);
 			return (EHOSTUNREACH);
 		}
-		if (tsl->tsl_flags & TSLF_UNLABELED) {
+		if ((tsl->tsl_flags & TSLF_UNLABELED) ||
+		    (mac_mode == CONN_MAC_IMPLICIT)) {
 			/*
-			 * The security label is a match but we need to
-			 * clear the unlabeled flag for this remote node.
+			 * Copy label so we can modify the flags
 			 */
 			if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
 				TPC_RELE(dst_rhtp);
 				return (ENOMEM);
 			}
-			newtsl->tsl_flags ^= TSLF_UNLABELED;
+			/*
+			 * The security label is a match but we need to
+			 * clear the unlabeled flag for this remote node.
+			 */
+			newtsl->tsl_flags &= ~TSLF_UNLABELED;
+			if (mac_mode == CONN_MAC_IMPLICIT)
+				newtsl->tsl_flags |= TSLF_IMPLICIT_OUT;
 		}
 		break;
 
@@ -473,6 +489,9 @@
 	if (CLASSD(dst))
 		return (0);
 
+	if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
+		return (0);
+
 	if (tsl->tsl_flags & TSLF_UNLABELED) {
 
 		/*
@@ -807,7 +826,7 @@
  *	EINVAL		Label cannot be computed
  */
 int
-tsol_check_label(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
+tsol_check_label(const cred_t *credp, mblk_t **mpp, uint_t mac_mode,
     ip_stack_t *ipst, pid_t pid)
 {
 	mblk_t *mp = *mpp;
@@ -832,7 +851,7 @@
 	 * for use in future routing decisions.
 	 */
 	retv = tsol_check_dest(credp, &ipha->ipha_dst, IPV4_VERSION,
-	    isexempt, &effective_cred);
+	    mac_mode, &effective_cred);
 	if (retv != 0)
 		return (retv);
 
@@ -871,6 +890,10 @@
 			return (0);
 	}
 
+	if (msg_getcred(mp, NULL) == NULL) {
+		mblk_setcred(mp, (cred_t *)credp, NOPID);
+	}
+
 	/*
 	 * If there is an option there, then it must be the wrong one; delete.
 	 */
@@ -983,6 +1006,9 @@
 	 * that the maximum size of this label is reflected in sys/tsol/tnet.h
 	 * as TSOL_MAX_IPV6_OPTION.
 	 */
+	if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
+		return (0);
+
 	if (tsl->tsl_flags & TSLF_UNLABELED) {
 		/*
 		 * The destination is unlabeled. Only add a label if the
@@ -1352,7 +1378,7 @@
  *      ENOMEM		Memory allocation failure.
  */
 int
-tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
+tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, uint_t mode,
     ip_stack_t *ipst, pid_t pid)
 {
 	mblk_t *mp = *mpp;
@@ -1382,7 +1408,7 @@
 	 */
 	ip6h = (ip6_t *)mp->b_rptr;
 	retv = tsol_check_dest(credp, &ip6h->ip6_dst, IPV6_VERSION,
-	    isexempt, &effective_cred);
+	    mode, &effective_cred);
 	if (retv != 0)
 		return (retv);
 
@@ -1430,6 +1456,11 @@
 		 */
 		return (0);
 	}
+
+	if (msg_getcred(mp, NULL) == NULL) {
+		mblk_setcred(mp, (cred_t *)credp, NOPID);
+	}
+
 	if (secopt != NULL && sec_opt_len != 0 &&
 	    (bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) {
 		/* The packet has the correct label already */
--- a/usr/src/uts/common/inet/ip/tnet.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ip/tnet.c	Mon Nov 02 15:39:20 2009 -0800
@@ -632,6 +632,34 @@
 	kmem_free(gcgrp, sizeof (*gcgrp));
 }
 
+
+/*
+ * Assign a sensitivity label to inbound traffic which arrived without
+ * an explicit on-the-wire label.
+ *
+ * In the case of CIPSO-type hosts, we assume packets arriving without
+ * a label are at the most sensitive label known for the host, most
+ * likely involving out-of-band key management traffic (such as IKE,
+ * etc.,)
+ */
+static boolean_t
+tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi)
+{
+	*doi = rhtp->tpc_tp.tp_doi;
+	switch (rhtp->tpc_tp.host_type) {
+	case UNLABELED:
+		*sl = rhtp->tpc_tp.tp_def_label;
+		break;
+	case SUN_CIPSO:
+		*sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound;
+		break;
+	default:
+		return (B_FALSE);
+	}
+	setbltype(sl, SUN_SL_ID);
+	return (B_TRUE);
+}
+
 /*
  * Converts CIPSO option to sensitivity label.
  * Validity checks based on restrictions defined in
@@ -658,13 +686,14 @@
 }
 
 /*
- * Parse the CIPSO label in the incoming packet and construct a ts_label_t
- * that reflects the CIPSO label and attach it to the dblk cred. Later as
- * the mblk flows up through the stack any code that needs to examine the
- * packet label can inspect the label from the dblk cred. This function is
- * called right in ip_rput for all packets, i.e. locally destined and
- * to be forwarded packets. The forwarding path needs to examine the label
- * to determine how to forward the packet.
+ * If present, parse a CIPSO label in the incoming packet and
+ * construct a ts_label_t that reflects the CIPSO label and attach it
+ * to the dblk cred.  Later as the mblk flows up through the stack any
+ * code that needs to examine the packet label can inspect the label
+ * from the dblk cred. This function is called right in ip_rput for
+ * all packets, i.e. locally destined and to be forwarded packets. The
+ * forwarding path needs to examine the label to determine how to
+ * forward the packet.
  *
  * This routine pulls all message text up into the first mblk.
  * For IPv4, only the first 20 bytes of the IP header are guaranteed
@@ -673,17 +702,19 @@
 boolean_t
 tsol_get_pkt_label(mblk_t *mp, int version)
 {
-	tsol_tpc_t	*src_rhtp;
+	tsol_tpc_t	*src_rhtp = NULL;
 	uchar_t		*opt_ptr = NULL;
 	const ipha_t	*ipha;
 	bslabel_t	sl;
 	uint32_t	doi;
 	tsol_ip_label_t	label_type;
+	uint32_t	label_flags = 0; /* flags to set in label */
 	const cipso_option_t *co;
 	const void	*src;
 	const ip6_t	*ip6h;
 	cred_t		*credp;
 	pid_t		cpid;
+	int 		proto;
 
 	ASSERT(DB_TYPE(mp) == M_DATA);
 
@@ -725,21 +756,37 @@
 		if (!cipso_to_sl(opt_ptr, &sl))
 			return (B_FALSE);
 		setbltype(&sl, SUN_SL_ID);
+
+		/*
+		 * If the source was unlabeled, then flag as such,
+		 * (since CIPSO routers may add headers)
+		 */
+
+		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
+			return (B_FALSE);
+
+		if (src_rhtp->tpc_tp.host_type == UNLABELED)
+			label_flags = TSLF_UNLABELED;
+
+		TPC_RELE(src_rhtp);
+
 		break;
 
 	case OPT_NONE:
 		/*
-		 * Handle special cases that are not currently labeled, even
+		 * Handle special cases that may not be labeled, even
 		 * though the sending system may otherwise be configured as
 		 * labeled.
 		 *	- IGMP
 		 *	- IPv4 ICMP Router Discovery
 		 *	- IPv6 Neighbor Discovery
+		 *	- IPsec ESP
 		 */
 		if (version == IPV4_VERSION) {
-			if (ipha->ipha_protocol == IPPROTO_IGMP)
+			proto = ipha->ipha_protocol;
+			if (proto == IPPROTO_IGMP)
 				return (B_TRUE);
-			if (ipha->ipha_protocol == IPPROTO_ICMP) {
+			if (proto == IPPROTO_ICMP) {
 				const struct icmp *icmp = (const struct icmp *)
 				    (mp->b_rptr + IPH_HDR_LENGTH(ipha));
 
@@ -750,7 +797,8 @@
 					return (B_TRUE);
 			}
 		} else {
-			if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
+			proto = ip6h->ip6_nxt;
+			if (proto == IPPROTO_ICMPV6) {
 				const icmp6_t *icmp6 = (const icmp6_t *)
 				    (mp->b_rptr + IPV6_HDR_LEN);
 
@@ -765,23 +813,32 @@
 
 		/*
 		 * Look up the tnrhtp database and get the implicit label
-		 * that is associated with this unlabeled host and attach
+		 * that is associated with the sending host and attach
 		 * it to the packet.
 		 */
 		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
 			return (B_FALSE);
 
-		/* If the sender is labeled, drop the unlabeled packet. */
-		if (src_rhtp->tpc_tp.host_type != UNLABELED) {
+		/*
+		 * If peer is label-aware, mark as "implicit" rather than
+		 * "unlabeled" to cause appropriate mac-exempt processing
+		 * to happen.
+		 */
+		if (src_rhtp->tpc_tp.host_type == SUN_CIPSO)
+			label_flags = TSLF_IMPLICIT_IN;
+		else if (src_rhtp->tpc_tp.host_type == UNLABELED)
+			label_flags = TSLF_UNLABELED;
+		else {
+			DTRACE_PROBE2(tx__get__pkt__label, char *,
+			    "template(1) has unknown hosttype",
+			    tsol_tpc_t *, src_rhtp);
+		}
+
+
+		if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) {
 			TPC_RELE(src_rhtp);
-			pr_addr_dbg("unlabeled packet forged from %s\n",
-			    version == IPV4_VERSION ? AF_INET : AF_INET6, src);
 			return (B_FALSE);
 		}
-
-		sl = src_rhtp->tpc_tp.tp_def_label;
-		setbltype(&sl, SUN_SL_ID);
-		doi = src_rhtp->tpc_tp.tp_doi;
 		TPC_RELE(src_rhtp);
 		break;
 
@@ -805,23 +862,12 @@
 	}
 	if (credp == NULL)
 		return (B_FALSE);
+
+	crgetlabel(credp)->tsl_flags |= label_flags;
+
 	mblk_setcred(mp, credp, cpid);
 	crfree(credp);			/* mblk has ref on cred */
 
-	/*
-	 * If the source was unlabeled, then flag as such,
-	 * while remembering that CIPSO routers add headers.
-	 */
-	if (label_type == OPT_NONE) {
-		crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
-	} else if (label_type == OPT_CIPSO) {
-		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
-			return (B_FALSE);
-		if (src_rhtp->tpc_tp.host_type == UNLABELED)
-			crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
-		TPC_RELE(src_rhtp);
-	}
-
 	return (B_TRUE);
 }
 
@@ -870,6 +916,23 @@
 	label = label2bslabel(plabel);
 	conn_label = label2bslabel(crgetlabel(connp->conn_cred));
 
+
+	/*
+	 * Implicitly labeled packets from label-aware sources
+	 * go only to privileged receivers
+	 */
+	if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) &&
+	    (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) {
+		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl,
+		    char *,
+		    "implicitly labeled packet mp(1) for conn(2) "
+		    "which isn't in implicit mac mode",
+		    mblk_t *, mp, conn_t *, connp);
+
+		return (B_FALSE);
+	}
+
+
 	/*
 	 * MLPs are always validated using the range and set of the local
 	 * address, even when the remote host is unlabeled.
@@ -895,7 +958,7 @@
 		 * conn_zoneid is global for an exclusive stack, thus we use
 		 * conn_cred to get the zoneid
 		 */
-		if (!connp->conn_mac_exempt ||
+		if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
 		    (crgetzoneid(connp->conn_cred) != GLOBAL_ZONEID &&
 		    (plabel->tsl_doi != conn_plabel->tsl_doi ||
 		    !bldominates(conn_label, label)))) {
@@ -1106,6 +1169,16 @@
 	if (plabel == NULL)
 		return (B_TRUE);
 
+	if (plabel->tsl_flags & TSLF_IMPLICIT_IN) {
+		DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label,
+		    char *,
+		    "cannot send error report for packet mp(1) with "
+		    "unresolved security label sl(2)",
+		    mblk_t *, mp, ts_label_t *, plabel);
+		return (B_FALSE);
+	}
+
+
 	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
 		ipha = (const ipha_t *)mp->b_rptr;
 		rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
@@ -1212,10 +1285,10 @@
 	 */
 	if (tsl == NULL || ire->ire_gw_secattr == NULL) {
 		if (tsl != NULL) {
-			DTRACE_PROBE3(tx__ip__log__drop__irematch__nogwsec,
-			    char *,
-			    "ire(1) lacks ire_gw_secattr matching label(2)",
-			    ire_t *, ire, ts_label_t *, tsl);
+			DTRACE_PROBE3(
+			    tx__ip__log__drop__irematch__nogwsec, char *,
+			    "ire(1) lacks ire_gw_secattr when matching "
+			    "label(2)", ire_t *, ire, ts_label_t *, tsl);
 			error = EACCES;
 		}
 		goto done;
@@ -1498,6 +1571,17 @@
 	if ((tsl = msg_getlabel(mp)) == NULL)
 		return (mp);
 
+	if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
+		DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label,
+		    char *,
+		    "cannot forward packet mp(1) with unresolved "
+		    "security label sl(2)",
+		    mblk_t *, mp, ts_label_t *, tsl);
+
+		return (NULL);
+	}
+
+
 	ASSERT(psrc != NULL && pdst != NULL);
 	dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
 
@@ -1648,9 +1732,10 @@
 
 	credp = msg_getcred(mp, &pid);
 	if ((af == AF_INET &&
-	    tsol_check_label(credp, &mp, B_FALSE, ipst, pid) != 0) ||
+	    tsol_check_label(credp, &mp, CONN_MAC_DEFAULT, ipst, pid) != 0) ||
 	    (af == AF_INET6 &&
-	    tsol_check_label_v6(credp, &mp, B_FALSE, ipst, pid) != 0)) {
+	    tsol_check_label_v6(credp, &mp, CONN_MAC_DEFAULT, ipst,
+	    pid) != 0)) {
 		mp = NULL;
 		goto keep_label;
 	}
--- a/usr/src/uts/common/inet/ipclassifier.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ipclassifier.h	Mon Nov 02 15:39:20 2009 -0800
@@ -165,6 +165,21 @@
 } ip_helper_stream_info_t;
 
 /*
+ * Mandatory Access Control mode, in conn_t's conn_mac_mode field.
+ * 	CONN_MAC_DEFAULT: strict enforcement of MAC.
+ * 	CONN_MAC_AWARE:   allows communications between unlabeled systems
+ *			  and privileged daemons
+ *	CONN_MAC_IMPLICIT: allows communications without explicit labels
+ *		           on the wire with privileged daemons.
+ *
+ * CONN_MAC_IMPLICIT is intended specifically for labeled IPsec key management
+ * in networks which don't pass CIPSO-labeled packets.
+ */
+#define	CONN_MAC_DEFAULT 0
+#define	CONN_MAC_AWARE 1
+#define	CONN_MAC_IMPLICIT 2
+
+/*
  * The initial fields in the conn_t are setup by the kmem_cache constructor,
  * and are preserved when it is freed. Fields after that are bzero'ed when
  * the conn_t is freed.
@@ -329,7 +344,7 @@
 		conn_anon_mlp : 1,		/* user wants anon MLP */
 
 		conn_anon_port : 1,		/* user bound anonymously */
-		conn_mac_exempt : 1,		/* unlabeled with loose MAC */
+		conn_mac_mode : 2,		/* normal/loose/implicit MAC */
 		conn_spare : 26;
 
 	boolean_t	conn_flow_cntrld;
@@ -421,6 +436,22 @@
 	    ((zoneid) == ALL_ZONES) ||					\
 	    (connp)->conn_zoneid == (zoneid))
 
+/*
+ * On a labeled system, we must treat bindings to ports
+ * on shared IP addresses by sockets with MAC exemption
+ * privilege as being in all zones, as there's
+ * otherwise no way to identify the right receiver.
+ */
+
+#define	IPCL_CONNS_MAC(conn1, conn2)					\
+	(((conn1)->conn_mac_mode != CONN_MAC_DEFAULT) ||		\
+	((conn2)->conn_mac_mode != CONN_MAC_DEFAULT))
+
+#define	IPCL_BIND_ZONE_MATCH(conn1, conn2)				\
+	(IPCL_CONNS_MAC(conn1, conn2) ||				\
+	IPCL_ZONE_MATCH(conn1, conn2->conn_zoneid) ||			\
+	IPCL_ZONE_MATCH(conn2, conn1->conn_zoneid))
+
 
 #define	_IPCL_V4_MATCH(v6addr, v4addr)	\
 	(V4_PART_OF_V6((v6addr)) == (v4addr) && IN6_IS_ADDR_V4MAPPED(&(v6addr)))
--- a/usr/src/uts/common/inet/ipsec_impl.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/ipsec_impl.h	Mon Nov 02 15:39:20 2009 -0800
@@ -847,7 +847,7 @@
 extern mblk_t *ipsec_check_inbound_policy(mblk_t *, conn_t *, ipha_t *, ip6_t *,
     boolean_t);
 
-extern boolean_t ipsec_in_to_out(mblk_t *, ipha_t *, ip6_t *);
+extern boolean_t ipsec_in_to_out(mblk_t *, ipha_t *, ip6_t *, zoneid_t);
 extern void ipsec_log_policy_failure(int, char *, ipha_t *, ip6_t *, boolean_t,
 		    netstack_t *);
 extern boolean_t ipsec_inbound_accept_clear(mblk_t *, ipha_t *, ip6_t *);
@@ -923,6 +923,8 @@
 extern void ipsec_insert_always(avl_tree_t *tree, void *new_node);
 
 extern int32_t ipsec_act_ovhd(const ipsec_act_t *act);
+extern int sadb_whack_label(mblk_t **, ipsa_t *);
+extern int sadb_whack_label_v6(mblk_t **, ipsa_t *);
 extern boolean_t update_iv(uint8_t *, queue_t *, ipsa_t *, ipsecesp_stack_t *);
 
 /*
@@ -1017,6 +1019,7 @@
  * Common functions
  */
 extern boolean_t ip_addr_match(uint8_t *, int, in6_addr_t *);
+extern boolean_t ipsec_label_match(cred_t *, cred_t *);
 
 /*
  * AH and ESP counters types.
--- a/usr/src/uts/common/inet/iptun/iptun.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/iptun/iptun.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1850,6 +1850,8 @@
 		switch (iptun->iptun_typeinfo->iti_ipvers) {
 		case IPV4_VERSION:
 			header_size = sizeof (ipha_t);
+			if (is_system_labeled())
+				header_size += IP_MAX_OPT_LENGTH;
 			break;
 		case IPV6_VERSION:
 			header_size = sizeof (iptun_ipv6hdrs_t);
@@ -2650,7 +2652,7 @@
 		if (tsol_check_dest(msg_cred, (outer4 != NULL ?
 		    (void *)&outer4->ipha_dst : (void *)&outer6->ip6_dst),
 		    (outer4 != NULL ? IPV4_VERSION : IPV6_VERSION),
-		    B_FALSE, NULL) != 0)
+		    CONN_MAC_DEFAULT, NULL) != 0)
 			goto drop;
 	}
 
--- a/usr/src/uts/common/inet/mib2.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/mib2.h	Mon Nov 02 15:39:20 2009 -0800
@@ -953,7 +953,7 @@
 #define	MIB2_TMEF_ANONMLP	0x00000004	/* Anonymous MLP port */
 #define	MIB2_TMEF_MACEXEMPT	0x00000008	/* MAC-Exempt port */
 #define	MIB2_TMEF_IS_LABELED	0x00000010	/* tme_doi & tme_label exists */
-
+#define	MIB2_TMEF_MACIMPLICIT	0x00000020	/* MAC-Implicit */
 /*
  * List of IPv4 source addresses being filtered per interface
  */
--- a/usr/src/uts/common/inet/sadb.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sadb.h	Mon Nov 02 15:39:20 2009 -0800
@@ -125,8 +125,6 @@
 
 	struct ipsid_s *ipsa_src_cid;	/* Source certificate identity */
 	struct ipsid_s *ipsa_dst_cid;	/* Destination certificate identity */
-	uint64_t *ipsa_integ;	/* Integrity bitmap */
-	uint64_t *ipsa_sens;	/* Sensitivity bitmap */
 	mblk_t	*ipsa_lpkt;	/* Packet received while larval (CAS me) */
 	mblk_t	*ipsa_bpkt_head;	/* Packets received while idle */
 	mblk_t	*ipsa_bpkt_tail;
@@ -221,13 +219,7 @@
 	uint_t ipsa_hardalloc;	/* Allocations allowed (hard). */
 	uint_t ipsa_alloc;	/* Allocations made. */
 
-	uint_t ipsa_integlen;	/* Length of the integrity bitmap (bytes). */
-	uint_t ipsa_senslen;	/* Length of the sensitivity bitmap (bytes). */
-
 	uint_t ipsa_type;	/* Type of security association. (AH/etc.) */
-	uint_t ipsa_dpd;	/* Domain for sensitivity bit vectors. */
-	uint_t ipsa_senslevel;	/* Sensitivity level. */
-	uint_t ipsa_integlevel;	/* Integrity level. */
 	uint_t ipsa_state;	/* State of my association. */
 	uint_t ipsa_replay_wsize; /* Size of replay window */
 	uint32_t ipsa_flags;	/* Flags for security association. */
@@ -296,10 +288,12 @@
 	 * Soft reference to paired SA
 	 */
 	uint32_t	ipsa_otherspi;
+	netstack_t	*ipsa_netstack;	/* Does not have a netstack_hold */
 
-	/* MLS boxen will probably need more fields in here. */
-
-	netstack_t	*ipsa_netstack;	/* Does not have a netstack_hold */
+	cred_t *ipsa_cred;			/* MLS: cred_t attributes */
+	cred_t *ipsa_ocred;			/* MLS: outer label */
+	uint8_t	ipsa_mac_exempt;		/* MLS: mac exempt flag */
+	uchar_t	ipsa_opt_storage[IP_MAX_OPT_LENGTH];
 } ipsa_t;
 
 /*
@@ -508,6 +502,9 @@
 	/* icmp type and code of triggering packet (if applicable) */
 	uint8_t	ipsacq_icmp_type;
 	uint8_t ipsacq_icmp_code;
+
+	/* credentials associated with triggering packet */
+	cred_t	*ipsacq_cred;
 } ipsacq_t;
 
 /*
@@ -638,6 +635,61 @@
 #define	SA_SRCPORT(ipsa) ((ipsa)->ipsa_unique_id & 0xffff)
 #define	SA_DSTPORT(ipsa) (((ipsa)->ipsa_unique_id >> 16) & 0xffff)
 
+typedef struct ipsa_query_s ipsa_query_t;
+
+typedef boolean_t (*ipsa_match_fn_t)(ipsa_query_t *, ipsa_t *);
+
+#define	IPSA_NMATCH	10
+
+/*
+ * SADB query structure.
+ *
+ * Provide a generalized mechanism for matching entries in the SADB;
+ * one of these structures is initialized using sadb_form_query(),
+ * and then can be used as a parameter to sadb_match_query() which returns
+ * B_TRUE if the SA matches the query.
+ *
+ * Under the covers, sadb_form_query populates the matchers[] array with
+ * functions which are called one at a time until one fails to match.
+ */
+struct ipsa_query_s {
+	uint32_t req, match;
+	sadb_address_t *srcext, *dstext;
+	sadb_ident_t *srcid, *dstid;
+	sadb_x_kmc_t *kmcext;
+	sadb_sa_t *assoc;
+	uint32_t spi;
+	struct sockaddr_in *src;
+	struct sockaddr_in6 *src6;
+	struct sockaddr_in *dst;
+	struct sockaddr_in6 *dst6;
+	sa_family_t af;
+	uint32_t *srcaddr, *dstaddr;
+	uint32_t ifindex;
+	uint32_t kmc, kmp;
+	char *didstr, *sidstr;
+	uint16_t didtype, sidtype;
+	sadbp_t *spp;
+	sadb_t *sp;
+	isaf_t	*inbound, *outbound;
+	uint32_t outhash;
+	uint32_t inhash;
+	ipsa_match_fn_t matchers[IPSA_NMATCH];
+};
+
+#define	IPSA_Q_SA		0x00000001
+#define	IPSA_Q_DST		0x00000002
+#define	IPSA_Q_SRC		0x00000004
+#define	IPSA_Q_DSTID		0x00000008
+#define	IPSA_Q_SRCID		0x00000010
+#define	IPSA_Q_KMC		0x00000020
+#define	IPSA_Q_INBOUND		0x00000040 /* fill in inbound isaf_t */
+#define	IPSA_Q_OUTBOUND		0x00000080 /* fill in outbound isaf_t */
+
+int sadb_form_query(keysock_in_t *, uint32_t, uint32_t, ipsa_query_t *, int *);
+boolean_t sadb_match_query(ipsa_query_t *q, ipsa_t *sa);
+
+
 /*
  * All functions that return an ipsa_t will return it with IPSA_REFHOLD()
  * already called.
@@ -647,11 +699,7 @@
 ipsa_t *ipsec_getassocbyspi(isaf_t *, uint32_t, uint32_t *, uint32_t *,
     sa_family_t);
 ipsa_t *ipsec_getassocbyconn(isaf_t *, ipsec_out_t *, uint32_t *, uint32_t *,
-    sa_family_t, uint8_t);
-ipsap_t *get_ipsa_pair(sadb_sa_t *, sadb_address_t *, sadb_address_t *,
-    sadbp_t *);
-void destroy_ipsa_pair(ipsap_t *);
-int update_pairing(ipsap_t *, keysock_in_t *, int *, sadbp_t *);
+    sa_family_t, uint8_t, cred_t *);
 
 /* SA insertion. */
 int sadb_insertassoc(ipsa_t *, isaf_t *);
@@ -668,6 +716,7 @@
 /* Support routines to interface a keysock consumer to PF_KEY. */
 mblk_t *sadb_keysock_out(minor_t);
 int sadb_hardsoftchk(sadb_lifetime_t *, sadb_lifetime_t *, sadb_lifetime_t *);
+int sadb_labelchk(struct keysock_in_s *);
 void sadb_pfkey_echo(queue_t *, mblk_t *, sadb_msg_t *, struct keysock_in_s *,
     ipsa_t *);
 void sadb_pfkey_error(queue_t *, mblk_t *, int, int, uint_t);
@@ -678,8 +727,8 @@
 int sadb_addrset(ire_t *);
 int sadb_delget_sa(mblk_t *, keysock_in_t *, sadbp_t *, int *, queue_t *,
     uint8_t);
-
-int sadb_purge_sa(mblk_t *, keysock_in_t *, sadb_t *, queue_t *, queue_t *);
+int sadb_purge_sa(mblk_t *, keysock_in_t *, sadb_t *, int *, queue_t *,
+    queue_t *);
 int sadb_common_add(queue_t *, queue_t *, mblk_t *, sadb_msg_t *,
     keysock_in_t *, isaf_t *, isaf_t *, ipsa_t *, boolean_t, boolean_t, int *,
     netstack_t *, sadbp_t *);
@@ -840,6 +889,9 @@
 extern void sadb_alg_update(ipsec_algtype_t, uint8_t, boolean_t,
     netstack_t *);
 
+extern int sadb_sens_len_from_cred(cred_t *);
+extern void sadb_sens_from_cred(sadb_sens_t *, int, cred_t *, int);
+
 /*
  * Context templates management.
  */
--- a/usr/src/uts/common/inet/sctp/sctp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -237,7 +237,7 @@
 		 * MAC exempt mode.  This allows read-down to unlabeled hosts.
 		 */
 		if (getpflags(NET_MAC_AWARE, credp) != 0)
-			connp->conn_mac_exempt = B_TRUE;
+			connp->conn_mac_mode = CONN_MAC_AWARE;
 	}
 
 	connp->conn_allzones = pconnp->conn_allzones;
@@ -1521,7 +1521,7 @@
 	 * exempt mode.  This allows read-down to unlabeled hosts.
 	 */
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
-		sctp_connp->conn_mac_exempt = B_TRUE;
+		sctp_connp->conn_mac_mode = CONN_MAC_AWARE;
 
 	/* Initialize SCTP instance values,  our verf tag must never be 0 */
 	(void) random_get_pseudo_bytes((uint8_t *)&sctp->sctp_lvtag,
--- a/usr/src/uts/common/inet/sctp/sctp_bind.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_bind.c	Mon Nov 02 15:39:20 2009 -0800
@@ -535,7 +535,8 @@
 			 * otherwise no way to identify the right receiver.
 			 */
 			if (lsctp->sctp_zoneid != zoneid &&
-			    !lsctp->sctp_mac_exempt && !sctp->sctp_mac_exempt)
+			    lsctp->sctp_mac_mode == CONN_MAC_DEFAULT &&
+			    sctp->sctp_mac_mode == CONN_MAC_DEFAULT)
 				continue;
 
 			addrcmp = sctp_compare_saddrs(sctp, lsctp);
--- a/usr/src/uts/common/inet/sctp/sctp_common.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_common.c	Mon Nov 02 15:39:20 2009 -0800
@@ -526,11 +526,11 @@
 			uint32_t dst;
 			IN6_V4MAPPED_TO_IPADDR(addr, dst);
 			err = tsol_check_dest(CONN_CRED(sctp->sctp_connp),
-			    &dst, IPV4_VERSION, sctp->sctp_mac_exempt,
+			    &dst, IPV4_VERSION, sctp->sctp_mac_mode,
 			    &effective_cred);
 		} else {
 			err = tsol_check_dest(CONN_CRED(sctp->sctp_connp),
-			    addr, IPV6_VERSION, sctp->sctp_mac_exempt,
+			    addr, IPV6_VERSION, sctp->sctp_mac_mode,
 			    &effective_cred);
 		}
 		if (err != 0)
--- a/usr/src/uts/common/inet/sctp/sctp_cookie.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c	Mon Nov 02 15:39:20 2009 -0800
@@ -783,11 +783,11 @@
 
 		if (isv4)
 			err = tsol_check_label(cr, &iackmp,
-			    connp->conn_mac_exempt,
+			    connp->conn_mac_mode,
 			    sctps->sctps_netstack->netstack_ip, pid);
 		else
 			err = tsol_check_label_v6(cr, &iackmp,
-			    connp->conn_mac_exempt,
+			    connp->conn_mac_mode,
 			    sctps->sctps_netstack->netstack_ip, pid);
 		if (err != 0) {
 			sctp_send_abort(sctp, sctp_init2vtag(ch),
--- a/usr/src/uts/common/inet/sctp/sctp_error.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_error.c	Mon Nov 02 15:39:20 2009 -0800
@@ -276,12 +276,12 @@
 	if (is_system_labeled() && (cr = msg_getcred(inmp, &pid)) != NULL &&
 	    crgetlabel(cr) != NULL) {
 		int err;
-		boolean_t exempt = connp->conn_mac_exempt;
+		uint_t mode = connp->conn_mac_mode;
 
 		if (isv4)
-			err = tsol_check_label(cr, &hmp, exempt, ipst, pid);
+			err = tsol_check_label(cr, &hmp, mode, ipst, pid);
 		else
-			err = tsol_check_label_v6(cr, &hmp, exempt, ipst, pid);
+			err = tsol_check_label_v6(cr, &hmp, mode, ipst, pid);
 		if (err != 0) {
 			freemsg(hmp);
 			return;
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h	Mon Nov 02 15:39:20 2009 -0800
@@ -639,7 +639,7 @@
 	conn_t		*sctp_connp;		/* conn_t stuff */
 #define	sctp_zoneid	sctp_connp->conn_zoneid
 #define	sctp_allzones	sctp_connp->conn_allzones
-#define	sctp_mac_exempt	sctp_connp->conn_mac_exempt
+#define	sctp_mac_mode	sctp_connp->conn_mac_mode
 #define	sctp_credp	sctp_connp->conn_cred
 #define	sctp_reuseaddr	sctp_connp->conn_reuseaddr
 
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c	Mon Nov 02 15:39:20 2009 -0800
@@ -734,7 +734,10 @@
 			*i1 = connp->conn_allzones;
 			break;
 		case SO_MAC_EXEMPT:
-			*i1 = connp->conn_mac_exempt;
+			*i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+			break;
+		case SO_MAC_IMPLICIT:
+			*i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
 			break;
 		case SO_PROTOTYPE:
 			*i1 = IPPROTO_SCTP;
@@ -1326,7 +1329,20 @@
 				retval = EINVAL;
 				break;
 			}
-			connp->conn_mac_exempt = onoff;
+			connp->conn_mac_mode = onoff ?
+			    CONN_MAC_AWARE : CONN_MAC_DEFAULT;
+			break;
+		case SO_MAC_IMPLICIT:
+			if (secpolicy_net_mac_implicit(sctp->sctp_credp) != 0) {
+				retval = EACCES;
+				break;
+			}
+			if (sctp->sctp_state >= SCTPS_BOUND) {
+				retval = EINVAL;
+				break;
+			}
+			connp->conn_mac_mode = onoff ?
+			    CONN_MAC_AWARE : CONN_MAC_IMPLICIT;
 			break;
 		default:
 			retval = ENOPROTOOPT;
--- a/usr/src/uts/common/inet/sctp/sctp_snmp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -647,9 +647,17 @@
 			mlp.tme_flags |= MIB2_TMEF_ANONMLP;
 			needattr = B_TRUE;
 		}
-		if (connp->conn_mac_exempt) {
+		switch (connp->conn_mac_mode) {
+		case CONN_MAC_DEFAULT:
+			break;
+		case CONN_MAC_AWARE:
 			mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
 			needattr = B_TRUE;
+			break;
+		case CONN_MAC_IMPLICIT:
+			mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+			needattr = B_TRUE;
+			break;
 		}
 		if (connp->conn_fully_bound &&
 		    connp->conn_effective_cred != NULL) {
--- a/usr/src/uts/common/inet/tcp/tcp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -2454,7 +2454,7 @@
 	econnp->conn_zoneid = aconnp->conn_zoneid;
 	econnp->conn_allzones = aconnp->conn_allzones;
 
-	aconnp->conn_mac_exempt = B_FALSE;
+	aconnp->conn_mac_mode = CONN_MAC_DEFAULT;
 
 	/* Do the IPC initialization */
 	CONN_INC_REF(econnp);
@@ -3119,7 +3119,6 @@
 	/* maximum number of times to run around the loop */
 	int loopmax;
 	conn_t *connp = tcp->tcp_connp;
-	zoneid_t zoneid = connp->conn_zoneid;
 	tcp_stack_t	*tcps = tcp->tcp_tcps;
 
 	/*
@@ -3192,11 +3191,7 @@
 			 * privilege as being in all zones, as there's
 			 * otherwise no way to identify the right receiver.
 			 */
-			if (!(IPCL_ZONE_MATCH(ltcp->tcp_connp, zoneid) ||
-			    IPCL_ZONE_MATCH(connp,
-			    ltcp->tcp_connp->conn_zoneid)) &&
-			    !lconnp->conn_mac_exempt &&
-			    !connp->conn_mac_exempt)
+			if (!IPCL_BIND_ZONE_MATCH(ltcp->tcp_connp, connp))
 				continue;
 
 			/*
@@ -3250,7 +3245,8 @@
 			    TCP_IS_SOCKET(tcp));
 			exclbind = ltcp->tcp_exclbind || tcp->tcp_exclbind;
 
-			if (lconnp->conn_mac_exempt || connp->conn_mac_exempt ||
+			if ((lconnp->conn_mac_mode != CONN_MAC_DEFAULT) ||
+			    (connp->conn_mac_mode != CONN_MAC_DEFAULT) ||
 			    (exclbind && (not_socket ||
 			    ltcp->tcp_state <= TCPS_ESTABLISHED))) {
 				if (V6_OR_V4_INADDR_ANY(
@@ -5452,7 +5448,7 @@
 		if ((cr = msg_getcred(mp, NULL)) != NULL &&
 		    (tsl = crgetlabel(cr)) != NULL &&
 		    (connp->conn_mlp_type != mlptSingle ||
-		    (connp->conn_mac_exempt == B_TRUE &&
+		    (connp->conn_mac_mode != CONN_MAC_AWARE &&
 		    (tsl->tsl_flags & TSLF_UNLABELED)))) {
 			if ((econnp->conn_effective_cred =
 			    copycred_from_tslabel(econnp->conn_cred,
@@ -6191,7 +6187,7 @@
 	if (is_system_labeled()) {
 		ASSERT(tcp->tcp_connp->conn_effective_cred == NULL);
 		if ((error = tsol_check_dest(CONN_CRED(tcp->tcp_connp),
-		    &dstaddr, IPV4_VERSION, tcp->tcp_connp->conn_mac_exempt,
+		    &dstaddr, IPV4_VERSION, tcp->tcp_connp->conn_mac_mode,
 		    &tcp->tcp_connp->conn_effective_cred)) != 0) {
 			if (error != EHOSTUNREACH)
 				error = -TSYSERR;
@@ -6392,7 +6388,7 @@
 	if (is_system_labeled()) {
 		ASSERT(tcp->tcp_connp->conn_effective_cred == NULL);
 		if ((error = tsol_check_dest(CONN_CRED(tcp->tcp_connp),
-		    dstaddrp, IPV6_VERSION, tcp->tcp_connp->conn_mac_exempt,
+		    dstaddrp, IPV6_VERSION, tcp->tcp_connp->conn_mac_mode,
 		    &tcp->tcp_connp->conn_effective_cred)) != 0) {
 			if (error != EHOSTUNREACH)
 				error = -TSYSERR;
@@ -6535,7 +6531,7 @@
 		connp->conn_ulp = IPPROTO_TCP;
 
 		if (ipst->ips_ipcl_proto_fanout_v6[IPPROTO_TCP].connf_head !=
-		    NULL || connp->conn_mac_exempt) {
+		    NULL || (connp->conn_mac_mode != CONN_MAC_DEFAULT)) {
 			error = -TBADADDR;
 		} else {
 			connp->conn_srcv6 = ipv6_all_zeros;
@@ -9333,7 +9329,7 @@
 	 * exempt mode.  This allows read-down to unlabeled hosts.
 	 */
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
-		connp->conn_mac_exempt = B_TRUE;
+		connp->conn_mac_mode = CONN_MAC_AWARE;
 
 	connp->conn_dev = NULL;
 	if (issocket) {
@@ -9618,7 +9614,10 @@
 			*i1 = connp->conn_anon_mlp;
 			break;
 		case SO_MAC_EXEMPT:
-			*i1 = connp->conn_mac_exempt;
+			*i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+			break;
+		case SO_MAC_IMPLICIT:
+			*i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
 			break;
 		case SO_EXCLBIND:
 			*i1 = tcp->tcp_exclbind ? SO_EXCLBIND : 0;
@@ -15981,9 +15980,17 @@
 				mlp.tme_flags |= MIB2_TMEF_ANONMLP;
 				needattr = B_TRUE;
 			}
-			if (connp->conn_mac_exempt) {
+			switch (connp->conn_mac_mode) {
+			case CONN_MAC_DEFAULT:
+				break;
+			case CONN_MAC_AWARE:
 				mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
 				needattr = B_TRUE;
+				break;
+			case CONN_MAC_IMPLICIT:
+				mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+				needattr = B_TRUE;
+				break;
 			}
 			if (connp->conn_fully_bound &&
 			    connp->conn_effective_cred != NULL) {
@@ -18644,15 +18651,14 @@
 		if (ipst->ips_ip4_observe.he_interested) {
 			zoneid_t szone;
 
+			/*
+			 * Both of these functions expect b_rptr to be
+			 * where the IP header starts, so advance past the
+			 * link layer header if present.
+			 */
+			mp->b_rptr += ire_fp_mp_len;
 			szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
 			    ipst, ALL_ZONES);
-
-			/*
-			 * The IP observability hook expects b_rptr to be
-			 * where the IP header starts, so advance past the
-			 * link layer header.
-			 */
-			mp->b_rptr += ire_fp_mp_len;
 			ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
 			    ALL_ZONES, ill, ipst);
 			mp->b_rptr -= ire_fp_mp_len;
@@ -20650,10 +20656,10 @@
 		if (ipst->ips_ip4_observe.he_interested) {
 			zoneid_t szone;
 
+			if (ire_fp_mp_len != 0)
+				mp->b_rptr += ire_fp_mp_len;
 			szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
 			    ipst, ALL_ZONES);
-			if (ire_fp_mp_len != 0)
-				mp->b_rptr += ire_fp_mp_len;
 			ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
 			    ALL_ZONES, ill, ipst);
 			if (ire_fp_mp_len != 0)
@@ -22226,11 +22232,11 @@
 
 		if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION)
 			err = tsol_check_label(cr, &mp,
-			    tcp->tcp_connp->conn_mac_exempt,
+			    tcp->tcp_connp->conn_mac_mode,
 			    tcps->tcps_netstack->netstack_ip, pid);
 		else
 			err = tsol_check_label_v6(cr, &mp,
-			    tcp->tcp_connp->conn_mac_exempt,
+			    tcp->tcp_connp->conn_mac_mode,
 			    tcps->tcps_netstack->netstack_ip, pid);
 		if (mctl_present)
 			ipsec_mp->b_cont = mp;
@@ -22251,7 +22257,7 @@
 		ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
 
 		ASSERT(ii->ipsec_in_type == IPSEC_IN);
-		if (!ipsec_in_to_out(ipsec_mp, ipha, ip6h)) {
+		if (!ipsec_in_to_out(ipsec_mp, ipha, ip6h, zoneid)) {
 			return;
 		}
 	}
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Mon Nov 02 15:39:20 2009 -0800
@@ -80,6 +80,8 @@
 	0 },
 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
 	0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+	0 },
 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT, sizeof (int),
 	0 },
 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
--- a/usr/src/uts/common/inet/udp/udp.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/udp/udp.c	Mon Nov 02 15:39:20 2009 -0800
@@ -1849,8 +1849,11 @@
 			*i1 = connp->conn_anon_mlp;
 			break;	/* goto sizeof (int) option return */
 		case SO_MAC_EXEMPT:
-			*i1 = connp->conn_mac_exempt;
-			break;	/* goto sizeof (int) option return */
+			*i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+			break;
+		case SO_MAC_IMPLICIT:
+			*i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
+			break;
 		case SO_ALLZONES:
 			*i1 = connp->conn_allzones;
 			break;	/* goto sizeof (int) option return */
@@ -2231,19 +2234,9 @@
 				udp->udp_timestamp = onoff;
 			break;
 		case SO_ANON_MLP:
-			if (!checkonly) {
-				connp->conn_anon_mlp = onoff;
-				PASS_OPT_TO_IP(connp);
-			}
-			break;
 		case SO_MAC_EXEMPT:
-			if (secpolicy_net_mac_aware(cr) != 0 ||
-			    udp->udp_state != TS_UNBND)
-				return (EACCES);
-			if (!checkonly) {
-				connp->conn_mac_exempt = onoff;
-				PASS_OPT_TO_IP(connp);
-			}
+		case SO_MAC_IMPLICIT:
+			PASS_OPT_TO_IP(connp);
 			break;
 		case SCM_UCRED: {
 			struct ucred_s *ucr;
@@ -4381,9 +4374,17 @@
 				mlp.tme_flags |= MIB2_TMEF_ANONMLP;
 				needattr = B_TRUE;
 			}
-			if (connp->conn_mac_exempt) {
+			switch (connp->conn_mac_mode) {
+			case CONN_MAC_DEFAULT:
+				break;
+			case CONN_MAC_AWARE:
 				mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
 				needattr = B_TRUE;
+				break;
+			case CONN_MAC_IMPLICIT:
+				mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+				needattr = B_TRUE;
+				break;
 			}
 
 			/*
@@ -4714,7 +4715,7 @@
 	 * from the message to handle MLP
 	 */
 	if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
-	    udp->udp_connp->conn_mac_exempt, &effective_cred)) != 0)
+	    udp->udp_connp->conn_mac_mode, &effective_cred)) != 0)
 		goto done;
 	if (effective_cred != NULL)
 		cred = effective_cred;
@@ -5457,15 +5458,14 @@
 	if (ipst->ips_ip4_observe.he_interested && mp != NULL) {
 		zoneid_t szone;
 
+		/*
+		 * Both of these functions expect b_rptr to be
+		 * where the IP header starts, so advance past the
+		 * link layer header if present.
+		 */
+		mp->b_rptr += ire_fp_mp_len;
 		szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
 		    ipst, ALL_ZONES);
-
-		/*
-		 * The IP observability hook expects b_rptr to be
-		 * where the IP header starts, so advance past the
-		 * link layer header.
-		 */
-		mp->b_rptr += ire_fp_mp_len;
 		ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
 		    ALL_ZONES, ill, ipst);
 		mp->b_rptr -= ire_fp_mp_len;
@@ -5558,7 +5558,7 @@
 	 * cred/label from the message to handle MLP.
 	 */
 	if ((err = tsol_check_dest(cred, dst, IPV6_VERSION,
-	    udp->udp_connp->conn_mac_exempt, &effective_cred)) != 0)
+	    udp->udp_connp->conn_mac_mode, &effective_cred)) != 0)
 		goto done;
 	if (effective_cred != NULL)
 		cred = effective_cred;
@@ -7489,7 +7489,7 @@
 	 * exempt mode.  This allows read-down to unlabeled hosts.
 	 */
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
-		connp->conn_mac_exempt = B_TRUE;
+		connp->conn_mac_mode = CONN_MAC_AWARE;
 
 	connp->conn_ulp_labeled = is_system_labeled();
 
@@ -7679,7 +7679,6 @@
 	int		loopmax;
 	udp_fanout_t	*udpf;
 	in_port_t	lport;		/* Network byte order */
-	zoneid_t	zoneid;
 	udp_t		*udp;
 	boolean_t	is_inaddr_any;
 	mlp_type_t	addrtype, mlptype;
@@ -7873,7 +7872,6 @@
 	}
 
 	is_inaddr_any = V6_OR_V4_INADDR_ANY(v6src);
-	zoneid = connp->conn_zoneid;
 
 	for (;;) {
 		udp_t		*udp1;
@@ -7898,11 +7896,7 @@
 			 * privilege as being in all zones, as there's
 			 * otherwise no way to identify the right receiver.
 			 */
-			if (!(IPCL_ZONE_MATCH(udp1->udp_connp, zoneid) ||
-			    IPCL_ZONE_MATCH(connp,
-			    udp1->udp_connp->conn_zoneid)) &&
-			    !connp->conn_mac_exempt && \
-			    !udp1->udp_connp->conn_mac_exempt)
+			if (!IPCL_BIND_ZONE_MATCH(udp1->udp_connp, connp))
 				continue;
 
 			/*
@@ -7925,8 +7919,7 @@
 			 * as UDP_EXCLBIND, except that zoneid is ignored.
 			 */
 			if (udp1->udp_exclbind || udp->udp_exclbind ||
-			    udp1->udp_connp->conn_mac_exempt ||
-			    connp->conn_mac_exempt) {
+			    IPCL_CONNS_MAC(udp1->udp_connp, connp)) {
 				if (V6_OR_V4_INADDR_ANY(
 				    udp1->udp_bound_v6src) ||
 				    is_inaddr_any ||
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c	Mon Nov 02 15:39:20 2009 -0800
@@ -81,6 +81,8 @@
     0 },
 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
     0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+    0 },
 { SCM_UCRED, SOL_SOCKET, OA_W, OA_W, OP_NP, OP_VARLEN|OP_NODEFAULT, 512, 0 },
 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
 { SO_DOMAIN,	SOL_SOCKET, OA_R, OA_R, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
--- a/usr/src/uts/common/net/pfkeyv2.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/net/pfkeyv2.h	Mon Nov 02 15:39:20 2009 -0800
@@ -206,7 +206,7 @@
 	uint8_t sadb_sens_sens_len;		/* 64-bit words */
 	uint8_t sadb_sens_integ_level;
 	uint8_t sadb_sens_integ_len;		/* 64-bit words */
-	uint32_t sadb_sens_reserved;
+	uint32_t sadb_x_sens_flags;
 	/*
 	 * followed by two uint64_t arrays
 	 * uint64_t sadb_sens_bitmap[sens_bitmap_len];
@@ -215,7 +215,16 @@
 } sadb_sens_t;
 
 /*
- * A proposal extension.  This is found in an ACQUIRE message, and it
+ * We recycled the formerly reserved word for flags.
+ */
+
+#define	sadb_sens_reserved sadb_x_sens_flags
+
+#define	SADB_X_SENS_IMPLICIT 0x1	 /* implicit labelling */
+#define	SADB_X_SENS_UNLABELED 0x2	 /* peer is unlabeled */
+
+/*
+ * a proposal extension.  This is found in an ACQUIRE message, and it
  * proposes what sort of SA the kernel would like to ACQUIRE.
  */
 
@@ -662,8 +671,9 @@
 #define	SADB_X_EXT_REPLAY_VALUE		24
 #define	SADB_X_EXT_EDUMP		25
 #define	SADB_X_EXT_LIFETIME_IDLE	26
+#define	SADB_X_EXT_OUTER_SENS		27
 
-#define	SADB_EXT_MAX			26
+#define	SADB_EXT_MAX			27
 
 /*
  * Identity types.
@@ -809,7 +819,9 @@
 #define	SADB_X_DIAGNOSTIC_BAD_CTX		80
 #define	SADB_X_DIAGNOSTIC_INVALID_REPLAY	81
 #define	SADB_X_DIAGNOSTIC_MISSING_LIFETIME	82
-#define	SADB_X_DIAGNOSTIC_MAX			82
+
+#define	SADB_X_DIAGNOSTIC_BAD_LABEL		83
+#define	SADB_X_DIAGNOSTIC_MAX			83
 
 /* Algorithm type for sadb_x_algdesc above... */
 
--- a/usr/src/uts/common/os/policy.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/os/policy.c	Mon Nov 02 15:39:20 2009 -0800
@@ -602,6 +602,15 @@
 }
 
 /*
+ * Allow a privileged process to transmit traffic without explicit labels
+ */
+int
+secpolicy_net_mac_implicit(const cred_t *cr)
+{
+	return (PRIV_POLICY(cr, PRIV_NET_MAC_IMPLICIT, B_FALSE, EACCES, NULL));
+}
+
+/*
  * Common routine which determines whether a given credential can
  * act on a given mount.
  * When called through mount, the parameter needoptcheck is a pointer
--- a/usr/src/uts/common/os/priv_defs	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/os/priv_defs	Mon Nov 02 15:39:20 2009 -0800
@@ -223,6 +223,14 @@
 	This privilege is interpreted only if the system is configured
 	with Trusted Extensions.
 
+privilege PRIV_NET_MAC_IMPLICIT
+
+	Allows a process to set SO_MAC_IMPLICIT option by using 
+	setsockopt(3SOCKET).  This allows a privileged process to 
+	transmit implicitly-labeled packets to a peer.
+	This privilege is interpreted only if the system is configured
+	with Trusted Extensions.
+
 privilege PRIV_NET_OBSERVABILITY
 
 	Allows a process to access /dev/lo0 and the devices in /dev/ipnet/
--- a/usr/src/uts/common/os/putnext.c	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/os/putnext.c	Mon Nov 02 15:39:20 2009 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 1991-2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,8 +27,6 @@
 /*	  All Rights Reserved  	*/
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  *		UNIX Device Driver Interface functions
  *	This file contains the C-versions of putnext() and put().
@@ -61,9 +58,9 @@
  *
  * The redzone value is chosen dependent on the default stack size which is 8K
  * on 32-bit kernels and on x86 and 16K on 64-bit kernels. The values are chosen
- * empirically. For 64-bit kernels it is 5000 and for 32-bit kernels it is 2500.
- * Experiments showed that 2500 is not enough for 64-bit kernels and 2048 is not
- * enough for 32-bit.
+ * empirically. For 64-bit kernels it is 5000 and for 32-bit kernels it is 3000.
+ * Experiments showed that 2500 is not enough for either 32-bit or 64-bit
+ * kernels.
  *
  * The redzone value is a tuneable rather then a constant to allow adjustments
  * in the field.
@@ -83,7 +80,7 @@
 #ifdef	_LP64
 #define	PUT_STACK_NEEDED 5000
 #else
-#define	PUT_STACK_NEEDED 2500
+#define	PUT_STACK_NEEDED 3000
 #endif
 
 int put_stack_needed = PUT_STACK_NEEDED;
@@ -160,7 +157,7 @@
 	ushort_t	*sqcipcount = NULL;
 
 	TRACE_2(TR_FAC_STREAMS_FR, TR_PUTNEXT_START,
-		"putnext_start:(%p, %p)", qp, mp);
+	    "putnext_start:(%p, %p)", qp, mp);
 
 	ASSERT(mp->b_datap->db_ref != 0);
 	ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
@@ -198,7 +195,7 @@
 		queued = qp->q_sqflags & Q_SQQUEUED;
 		mutex_exit(sqciplock);
 	} else {
-	    slowlock:
+	slowlock:
 		ASSERT(sqciplock == NULL);
 		mutex_enter(SQLOCK(sq));
 		mutex_exit(sdlock);
@@ -440,7 +437,7 @@
 	ushort_t	*sqcipcount = NULL;
 
 	TRACE_2(TR_FAC_STREAMS_FR, TR_PUT_START,
-		"put:(%X, %X)", qp, mp);
+	    "put:(%X, %X)", qp, mp);
 	ASSERT(mp->b_datap->db_ref != 0);
 	ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
 
@@ -466,7 +463,7 @@
 		queued = qp->q_sqflags & Q_SQQUEUED;
 		mutex_exit(sqciplock);
 	} else {
-	    slowlock:
+	slowlock:
 		ASSERT(sqciplock == NULL);
 		mutex_enter(SQLOCK(sq));
 		flags = sq->sq_flags;
--- a/usr/src/uts/common/sys/policy.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/sys/policy.h	Mon Nov 02 15:39:20 2009 -0800
@@ -112,6 +112,7 @@
 int secpolicy_net_config(const cred_t *, boolean_t);
 int secpolicy_net_icmpaccess(const cred_t *);
 int secpolicy_net_mac_aware(const cred_t *);
+int secpolicy_net_mac_implicit(const cred_t *);
 int secpolicy_net_observability(const cred_t *);
 int secpolicy_net_privaddr(const cred_t *, in_port_t, int proto);
 int secpolicy_net_rawaccess(const cred_t *);
--- a/usr/src/uts/common/sys/socket.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/sys/socket.h	Mon Nov 02 15:39:20 2009 -0800
@@ -176,6 +176,7 @@
 #define	SCM_TIMESTAMP	SO_TIMESTAMP	/* socket control message timestamp */
 #define	SO_ALLZONES	0x1014		/* bind in all zones */
 #define	SO_EXCLBIND	0x1015		/* exclusive binding */
+#define	SO_MAC_IMPLICIT	0x1016		/* hide mac labels on wire */
 
 #ifdef	_KERNEL
 #define	SO_SRCADDR	0x2001		/* Internal: AF_UNIX source address */
--- a/usr/src/uts/common/sys/tsol/label.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/sys/tsol/label.h	Mon Nov 02 15:39:20 2009 -0800
@@ -103,7 +103,21 @@
 
 #define	DEFAULT_DOI 1
 
-#define	TSLF_UNLABELED	0x00000001	/* peer is unlabeled */
+/*
+ * TSLF_UNLABELED is set in tsl_flags for  packets with no explicit label
+ * when the peer is unlabeled.
+ *
+ * TSLF_IMPLICIT_IN is set when a packet is received with no explicit label
+ * from a peer which is flagged in the tnrhdb as label-aware.
+ *
+ * TSLF_IMPLICIT_OUT is set when the packet should be sent without an
+ * explict label even if the peer or next-hop router is flagged in the
+ * tnrhdb as label-aware.
+ */
+
+#define	TSLF_UNLABELED		0x00000001	/* peer is unlabeled */
+#define	TSLF_IMPLICIT_IN	0x00000002	/* inbound implicit */
+#define	TSLF_IMPLICIT_OUT	0x00000004	/* outbound implicit */
 
 #define	CR_SL(cr)	(label2bslabel(crgetlabel(cr)))
 
--- a/usr/src/uts/common/sys/tsol/tnet.h	Mon Nov 02 15:57:35 2009 -0700
+++ b/usr/src/uts/common/sys/tsol/tnet.h	Mon Nov 02 15:39:20 2009 -0800
@@ -46,15 +46,15 @@
 
 extern int tsol_tnrh_chk(tsol_tpent_t *, bslabel_t *, int);
 extern tsol_tnrhc_t *find_rhc(const void *, uchar_t, boolean_t);
-extern int tsol_check_dest(const cred_t *, const void *, uchar_t, boolean_t,
+extern int tsol_check_dest(const cred_t *, const void *, uchar_t, uint_t,
     cred_t **);
 extern int tsol_compute_label(const cred_t *, ipaddr_t, uchar_t *,
     ip_stack_t *);
 extern int tsol_compute_label_v6(const cred_t *, const in6_addr_t *, uchar_t *,
     ip_stack_t *);
-extern int tsol_check_label(const cred_t *, mblk_t **, boolean_t,
+extern int tsol_check_label(const cred_t *, mblk_t **, uint_t,
     ip_stack_t *, pid_t);
-extern int tsol_check_label_v6(const cred_t *, mblk_t **, boolean_t,
+extern int tsol_check_label_v6(const cred_t *, mblk_t **, uint_t,
     ip_stack_t *, pid_t);
 extern int tsol_prepend_option(uchar_t *, ipha_t *, int);
 extern int tsol_prepend_option_v6(uchar_t *, ip6_t *, int);