Home | History | Annotate | Download | only in ip
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/stream.h>
     28 #include <sys/strsubr.h>
     29 #include <sys/stropts.h>
     30 #include <sys/sunddi.h>
     31 #include <sys/cred.h>
     32 #include <sys/debug.h>
     33 #include <sys/kmem.h>
     34 #include <sys/errno.h>
     35 #include <sys/disp.h>
     36 #include <netinet/in.h>
     37 #include <netinet/in_systm.h>
     38 #include <netinet/ip.h>
     39 #include <netinet/ip_icmp.h>
     40 #include <netinet/tcp.h>
     41 #include <inet/common.h>
     42 #include <inet/ipclassifier.h>
     43 #include <inet/ip.h>
     44 #include <inet/mib2.h>
     45 #include <inet/nd.h>
     46 #include <inet/tcp.h>
     47 #include <inet/ip_rts.h>
     48 #include <inet/ip_ire.h>
     49 #include <inet/ip_if.h>
     50 #include <sys/modhash.h>
     51 
     52 #include <sys/tsol/label.h>
     53 #include <sys/tsol/label_macro.h>
     54 #include <sys/tsol/tnet.h>
     55 #include <sys/tsol/tndb.h>
     56 #include <sys/strsun.h>
     57 
     58 /* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */
     59 int tsol_strict_error;
     60 
     61 /*
     62  * Some notes on the Trusted Solaris IRE gateway security attributes:
     63  *
     64  * When running in Trusted mode, the routing subsystem determines whether or
     65  * not a packet can be delivered to an off-link host (not directly reachable
     66  * through an interface) based on the accreditation checks of the packet's
     67  * security attributes against those associated with the next-hop gateway.
     68  *
     69  * The next-hop gateway's security attributes can be derived from two sources
     70  * (in order of preference): route-related and the host database.  A Trusted
     71  * system must be configured with at least the host database containing an
     72  * entry for the next-hop gateway, or otherwise no accreditation checks can
     73  * be performed, which may result in the inability to send packets to any
     74  * off-link destination host.
     75  *
     76  * The major differences between the two sources are the number and type of
     77  * security attributes used for accreditation checks.  A host database entry
     78  * can contain at most one set of security attributes, specific only to the
     79  * next-hop gateway.  On contrast, route-related security attributes are made
     80  * up of a collection of security attributes for the distant networks, and
     81  * are grouped together per next-hop gateway used to reach those networks.
     82  * This is the preferred method, and the routing subsystem will fallback to
     83  * the host database entry only if there are no route-related attributes
     84  * associated with the next-hop gateway.
     85  *
     86  * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/
     87  * INTERFACE type) are initialized to contain a placeholder to store this
     88  * information.  The ire_gw_secattr structure gets allocated, initialized
     89  * and associated with the IRE during the time of the IRE creation.  The
     90  * initialization process also includes resolving the host database entry
     91  * of the next-hop gateway for fallback purposes.  It does not include any
     92  * route-related attribute setup, as that process comes separately as part
     93  * of the route requests (add/change) made to the routing subsystem.
     94  *
     95  * The underlying logic which involves associating IREs with the gateway
     96  * security attributes are represented by the following data structures:
     97  *
     98  * tsol_gcdb_t, or "gcdb"
     99  *
    100  *	- This is a system-wide collection of records containing the
    101  *	  currently used route-related security attributes, which are fed
    102  *	  through the routing socket interface, e.g. "route add/change".
    103  *
    104  * tsol_gc_t, or "gc"
    105  *
    106  *	- This is the gateway credential structure, and it provides for the
    107  *	  only mechanism to access the contents of gcdb.  More than one gc
    108  *	  entries may refer to the same gcdb record.  gc's in the system are
    109  *	  grouped according to the next-hop gateway address.
    110  *
    111  * tsol_gcgrp_t, or "gcgrp"
    112  *
    113  *	- Group of gateway credentials, and is unique per next-hop gateway
    114  *	  address.  When the group is not empty, i.e. when gcgrp_count is
    115  *	  greater than zero, it contains one or more gc's, each pointing to
    116  *	  a gcdb record which indicates the gateway security attributes
    117  *	  associated with the next-hop gateway.
    118  *
    119  * The fields of the tsol_ire_gw_secattr_t used from within the IRE are:
    120  *
    121  * igsa_lock
    122  *
    123  *	- Lock that protects all fields within tsol_ire_gw_secattr_t.
    124  *
    125  * igsa_rhc
    126  *
    127  *	- Remote host cache database entry of next-hop gateway.  This is
    128  *	  used in the case when there are no route-related attributes
    129  *	  configured for the IRE.
    130  *
    131  * igsa_gc
    132  *
    133  *	- A set of route-related attributes that only get set for prefix
    134  *	  IREs.  If this is non-NULL, the prefix IRE has been associated
    135  *	  with a set of gateway security attributes by way of route add/
    136  *	  change functionality.  This field stays NULL for IRE_CACHEs.
    137  *
    138  * igsa_gcgrp
    139  *
    140  *	- Group of gc's which only gets set for IRE_CACHEs.  Each of the gc
    141  *	  points to a gcdb record that contains the security attributes
    142  *	  used to perform the credential checks of the packet which uses
    143  *	  the IRE.  If the group is not empty, the list of gc's can be
    144  *	  traversed starting at gcgrp_head.  This field stays NULL for
    145  *	  prefix IREs.
    146  */
    147 
    148 static kmem_cache_t *ire_gw_secattr_cache;
    149 
    150 #define	GCDB_HASH_SIZE	101
    151 #define	GCGRP_HASH_SIZE	101
    152 
    153 #define	GCDB_REFRELE(p) {		\
    154 	mutex_enter(&gcdb_lock);	\
    155 	ASSERT((p)->gcdb_refcnt > 0);	\
    156 	if (--((p)->gcdb_refcnt) == 0)	\
    157 		gcdb_inactive(p);	\
    158 	ASSERT(MUTEX_HELD(&gcdb_lock));	\
    159 	mutex_exit(&gcdb_lock);		\
    160 }
    161 
    162 static int gcdb_hash_size = GCDB_HASH_SIZE;
    163 static int gcgrp_hash_size = GCGRP_HASH_SIZE;
    164 static mod_hash_t *gcdb_hash;
    165 static mod_hash_t *gcgrp4_hash;
    166 static mod_hash_t *gcgrp6_hash;
    167 
    168 static kmutex_t gcdb_lock;
    169 kmutex_t gcgrp_lock;
    170 
    171 static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t);
    172 static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t);
    173 static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t);
    174 static void gcdb_inactive(tsol_gcdb_t *);
    175 
    176 static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t);
    177 static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t);
    178 
    179 static int ire_gw_secattr_constructor(void *, void *, int);
    180 static void ire_gw_secattr_destructor(void *, void *);
    181 
    182 void
    183 tnet_init(void)
    184 {
    185 	ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache",
    186 	    sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor,
    187 	    ire_gw_secattr_destructor, NULL, NULL, NULL, 0);
    188 
    189 	gcdb_hash = mod_hash_create_extended("gcdb_hash",
    190 	    gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
    191 	    gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP);
    192 
    193 	gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash",
    194 	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
    195 	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
    196 
    197 	gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash",
    198 	    gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
    199 	    gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
    200 
    201 	mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL);
    202 	mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL);
    203 }
    204 
    205 void
    206 tnet_fini(void)
    207 {
    208 	kmem_cache_destroy(ire_gw_secattr_cache);
    209 	mod_hash_destroy_hash(gcdb_hash);
    210 	mod_hash_destroy_hash(gcgrp4_hash);
    211 	mod_hash_destroy_hash(gcgrp6_hash);
    212 	mutex_destroy(&gcdb_lock);
    213 	mutex_destroy(&gcgrp_lock);
    214 }
    215 
    216 /* ARGSUSED */
    217 static int
    218 ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags)
    219 {
    220 	tsol_ire_gw_secattr_t *attrp = buf;
    221 
    222 	mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL);
    223 
    224 	attrp->igsa_rhc = NULL;
    225 	attrp->igsa_gc = NULL;
    226 	attrp->igsa_gcgrp = NULL;
    227 
    228 	return (0);
    229 }
    230 
    231 /* ARGSUSED */
    232 static void
    233 ire_gw_secattr_destructor(void *buf, void *cdrarg)
    234 {
    235 	tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf;
    236 
    237 	mutex_destroy(&attrp->igsa_lock);
    238 }
    239 
    240 tsol_ire_gw_secattr_t *
    241 ire_gw_secattr_alloc(int kmflags)
    242 {
    243 	return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags));
    244 }
    245 
    246 void
    247 ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp)
    248 {
    249 	ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock));
    250 
    251 	if (attrp->igsa_rhc != NULL) {
    252 		TNRHC_RELE(attrp->igsa_rhc);
    253 		attrp->igsa_rhc = NULL;
    254 	}
    255 
    256 	if (attrp->igsa_gc != NULL) {
    257 		GC_REFRELE(attrp->igsa_gc);
    258 		attrp->igsa_gc = NULL;
    259 	}
    260 	if (attrp->igsa_gcgrp != NULL) {
    261 		GCGRP_REFRELE(attrp->igsa_gcgrp);
    262 		attrp->igsa_gcgrp = NULL;
    263 	}
    264 
    265 	ASSERT(attrp->igsa_rhc == NULL);
    266 	ASSERT(attrp->igsa_gc == NULL);
    267 	ASSERT(attrp->igsa_gcgrp == NULL);
    268 
    269 	kmem_cache_free(ire_gw_secattr_cache, attrp);
    270 }
    271 
    272 /* ARGSUSED */
    273 static uint_t
    274 gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key)
    275 {
    276 	const struct rtsa_s *rp = (struct rtsa_s *)key;
    277 	const uint32_t *up, *ue;
    278 	uint_t hash;
    279 	int i;
    280 
    281 	ASSERT(rp != NULL);
    282 
    283 	/* See comments in hash_bylabel in zone.c for details */
    284 	hash = rp->rtsa_doi + (rp->rtsa_doi << 1);
    285 	up = (const uint32_t *)&rp->rtsa_slrange;
    286 	ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up);
    287 	i = 1;
    288 	while (up < ue) {
    289 		/* using 2^n + 1, 1 <= n <= 16 as source of many primes */
    290 		hash += *up + (*up << ((i % 16) + 1));
    291 		up++;
    292 		i++;
    293 	}
    294 	return (hash);
    295 }
    296 
    297 static int
    298 gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
    299 {
    300 	struct rtsa_s *rp1 = (struct rtsa_s *)key1;
    301 	struct rtsa_s *rp2 = (struct rtsa_s *)key2;
    302 
    303 	ASSERT(rp1 != NULL && rp2 != NULL);
    304 
    305 	if (blequal(&rp1->rtsa_slrange.lower_bound,
    306 	    &rp2->rtsa_slrange.lower_bound) &&
    307 	    blequal(&rp1->rtsa_slrange.upper_bound,
    308 	    &rp2->rtsa_slrange.upper_bound) &&
    309 	    rp1->rtsa_doi == rp2->rtsa_doi)
    310 		return (0);
    311 
    312 	/* No match; not found */
    313 	return (-1);
    314 }
    315 
    316 /* ARGSUSED */
    317 static uint_t
    318 gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key)
    319 {
    320 	tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key;
    321 	uint_t		idx = 0;
    322 	uint32_t	*ap;
    323 
    324 	ASSERT(ga != NULL);
    325 	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
    326 
    327 	ap = (uint32_t *)&ga->ga_addr.s6_addr32[0];
    328 	idx ^= *ap++;
    329 	idx ^= *ap++;
    330 	idx ^= *ap++;
    331 	idx ^= *ap;
    332 
    333 	return (idx);
    334 }
    335 
    336 static int
    337 gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
    338 {
    339 	tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1;
    340 	tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2;
    341 
    342 	ASSERT(ga1 != NULL && ga2 != NULL);
    343 
    344 	/* Address family must match */
    345 	if (ga1->ga_af != ga2->ga_af)
    346 		return (-1);
    347 
    348 	if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] &&
    349 	    ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] &&
    350 	    ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] &&
    351 	    ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3])
    352 		return (0);
    353 
    354 	/* No match; not found */
    355 	return (-1);
    356 }
    357 
    358 #define	RTSAFLAGS	"\20\11cipso\3doi\2max_sl\1min_sl"
    359 
    360 int
    361 rtsa_validate(const struct rtsa_s *rp)
    362 {
    363 	uint32_t mask = rp->rtsa_mask;
    364 
    365 	/* RTSA_CIPSO must be set, and DOI must not be zero */
    366 	if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) {
    367 		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
    368 		    "rtsa(1) lacks flag or has 0 doi.",
    369 		    rtsa_s *, rp);
    370 		return (EINVAL);
    371 	}
    372 	/*
    373 	 * SL range must be specified, and it must have its
    374 	 * upper bound dominating its lower bound.
    375 	 */
    376 	if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE ||
    377 	    !bldominates(&rp->rtsa_slrange.upper_bound,
    378 	    &rp->rtsa_slrange.lower_bound)) {
    379 		DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
    380 		    "rtsa(1) min_sl and max_sl not set or max_sl is "
    381 		    "not dominating.", rtsa_s *, rp);
    382 		return (EINVAL);
    383 	}
    384 	return (0);
    385 }
    386 
    387 /*
    388  * A brief explanation of the reference counting scheme:
    389  *
    390  * Prefix IREs have a non-NULL igsa_gc and a NULL igsa_gcgrp;
    391  * IRE_CACHEs have it vice-versa.
    392  *
    393  * Apart from dynamic references due to to reference holds done
    394  * actively by threads, we have the following references:
    395  *
    396  * gcdb_refcnt:
    397  *	- Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference
    398  *	  to the gcdb_refcnt.
    399  *
    400  * gc_refcnt:
    401  *	- A prefix IRE that points to an igsa_gc contributes a reference
    402  *	  to the gc_refcnt.
    403  *
    404  * gcgrp_refcnt:
    405  *	- An IRE_CACHE that points to an igsa_gcgrp contributes a reference
    406  *	  to the gcgrp_refcnt of the associated tsol_gcgrp_t.
    407  *	- Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes
    408  *	  a reference to the gcgrp_refcnt.
    409  */
    410 static tsol_gcdb_t *
    411 gcdb_lookup(struct rtsa_s *rp, boolean_t alloc)
    412 {
    413 	tsol_gcdb_t *gcdb = NULL;
    414 
    415 	if (rtsa_validate(rp) != 0)
    416 		return (NULL);
    417 
    418 	mutex_enter(&gcdb_lock);
    419 	/* Find a copy in the cache; otherwise, create one and cache it */
    420 	if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp,
    421 	    (mod_hash_val_t *)&gcdb) == 0) {
    422 		gcdb->gcdb_refcnt++;
    423 		ASSERT(gcdb->gcdb_refcnt != 0);
    424 
    425 		DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *,
    426 		    "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb);
    427 	} else if (alloc) {
    428 		gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP);
    429 		if (gcdb != NULL) {
    430 			gcdb->gcdb_refcnt = 1;
    431 			gcdb->gcdb_mask = rp->rtsa_mask;
    432 			gcdb->gcdb_doi = rp->rtsa_doi;
    433 			gcdb->gcdb_slrange = rp->rtsa_slrange;
    434 
    435 			if (mod_hash_insert(gcdb_hash,
    436 			    (mod_hash_key_t)&gcdb->gcdb_attr,
    437 			    (mod_hash_val_t)gcdb) != 0) {
    438 				mutex_exit(&gcdb_lock);
    439 				kmem_free(gcdb, sizeof (*gcdb));
    440 				return (NULL);
    441 			}
    442 
    443 			DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *,
    444 			    "gcdb(1) inserted in gcdb_hash(global)",
    445 			    tsol_gcdb_t *, gcdb);
    446 		}
    447 	}
    448 	mutex_exit(&gcdb_lock);
    449 	return (gcdb);
    450 }
    451 
    452 static void
    453 gcdb_inactive(tsol_gcdb_t *gcdb)
    454 {
    455 	ASSERT(MUTEX_HELD(&gcdb_lock));
    456 	ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0);
    457 
    458 	(void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr,
    459 	    (mod_hash_val_t *)&gcdb);
    460 
    461 	DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *,
    462 	    "gcdb(1) removed from gcdb_hash(global)",
    463 	    tsol_gcdb_t *, gcdb);
    464 	kmem_free(gcdb, sizeof (*gcdb));
    465 }
    466 
    467 tsol_gc_t *
    468 gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp)
    469 {
    470 	tsol_gc_t *gc;
    471 	tsol_gcdb_t *gcdb;
    472 
    473 	*gcgrp_xtrarefp = B_TRUE;
    474 
    475 	rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER);
    476 	if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) {
    477 		rw_exit(&gcgrp->gcgrp_rwlock);
    478 		return (NULL);
    479 	}
    480 
    481 	for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) {
    482 		if (gc->gc_db == gcdb) {
    483 			ASSERT(gc->gc_grp == gcgrp);
    484 
    485 			gc->gc_refcnt++;
    486 			ASSERT(gc->gc_refcnt != 0);
    487 
    488 			GCDB_REFRELE(gcdb);
    489 
    490 			DTRACE_PROBE3(tx__gcdb__log__info__gc__create,
    491 			    char *, "found gc(1) in gcgrp(2)",
    492 			    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
    493 			rw_exit(&gcgrp->gcgrp_rwlock);
    494 			return (gc);
    495 		}
    496 	}
    497 
    498 	gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP);
    499 	if (gc != NULL) {
    500 		if (gcgrp->gcgrp_head == NULL) {
    501 			gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc;
    502 		} else {
    503 			gcgrp->gcgrp_tail->gc_next = gc;
    504 			gc->gc_prev = gcgrp->gcgrp_tail;
    505 			gcgrp->gcgrp_tail = gc;
    506 		}
    507 		gcgrp->gcgrp_count++;
    508 		ASSERT(gcgrp->gcgrp_count != 0);
    509 
    510 		/* caller has incremented gcgrp reference for us */
    511 		gc->gc_grp = gcgrp;
    512 
    513 		gc->gc_db = gcdb;
    514 		gc->gc_refcnt = 1;
    515 
    516 		DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *,
    517 		    "added gc(1) to gcgrp(2)", tsol_gc_t *, gc,
    518 		    tsol_gcgrp_t *, gcgrp);
    519 
    520 		*gcgrp_xtrarefp = B_FALSE;
    521 	}
    522 	rw_exit(&gcgrp->gcgrp_rwlock);
    523 
    524 	return (gc);
    525 }
    526 
    527 void
    528 gc_inactive(tsol_gc_t *gc)
    529 {
    530 	tsol_gcgrp_t *gcgrp = gc->gc_grp;
    531 
    532 	ASSERT(gcgrp != NULL);
    533 	ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock));
    534 	ASSERT(gc->gc_refcnt == 0);
    535 
    536 	if (gc->gc_prev != NULL)
    537 		gc->gc_prev->gc_next = gc->gc_next;
    538 	else
    539 		gcgrp->gcgrp_head = gc->gc_next;
    540 	if (gc->gc_next != NULL)
    541 		gc->gc_next->gc_prev = gc->gc_prev;
    542 	else
    543 		gcgrp->gcgrp_tail = gc->gc_prev;
    544 	ASSERT(gcgrp->gcgrp_count > 0);
    545 	gcgrp->gcgrp_count--;
    546 
    547 	/* drop lock before it's destroyed */
    548 	rw_exit(&gcgrp->gcgrp_rwlock);
    549 
    550 	DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *,
    551 	    "removed inactive gc(1) from gcgrp(2)",
    552 	    tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
    553 
    554 	GCGRP_REFRELE(gcgrp);
    555 
    556 	gc->gc_grp = NULL;
    557 	gc->gc_prev = gc->gc_next = NULL;
    558 
    559 	if (gc->gc_db != NULL)
    560 		GCDB_REFRELE(gc->gc_db);
    561 
    562 	kmem_free(gc, sizeof (*gc));
    563 }
    564 
    565 tsol_gcgrp_t *
    566 gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc)
    567 {
    568 	tsol_gcgrp_t *gcgrp = NULL;
    569 	mod_hash_t *hashp;
    570 
    571 	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
    572 
    573 	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
    574 
    575 	mutex_enter(&gcgrp_lock);
    576 	if (mod_hash_find(hashp, (mod_hash_key_t)ga,
    577 	    (mod_hash_val_t *)&gcgrp) == 0) {
    578 		gcgrp->gcgrp_refcnt++;
    579 		ASSERT(gcgrp->gcgrp_refcnt != 0);
    580 
    581 		DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *,
    582 		    "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp,
    583 		    mod_hash_t *, hashp);
    584 
    585 	} else if (alloc) {
    586 		gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP);
    587 		if (gcgrp != NULL) {
    588 			gcgrp->gcgrp_refcnt = 1;
    589 			rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL);
    590 			bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga));
    591 
    592 			if (mod_hash_insert(hashp,
    593 			    (mod_hash_key_t)&gcgrp->gcgrp_addr,
    594 			    (mod_hash_val_t)gcgrp) != 0) {
    595 				mutex_exit(&gcgrp_lock);
    596 				kmem_free(gcgrp, sizeof (*gcgrp));
    597 				return (NULL);
    598 			}
    599 
    600 			DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert,
    601 			    char *, "inserted gcgrp(1) in hash(2)",
    602 			    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
    603 		}
    604 	}
    605 	mutex_exit(&gcgrp_lock);
    606 	return (gcgrp);
    607 }
    608 
    609 void
    610 gcgrp_inactive(tsol_gcgrp_t *gcgrp)
    611 {
    612 	tsol_gcgrp_addr_t *ga;
    613 	mod_hash_t *hashp;
    614 
    615 	ASSERT(MUTEX_HELD(&gcgrp_lock));
    616 	ASSERT(!RW_LOCK_HELD(&gcgrp->gcgrp_rwlock));
    617 	ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0);
    618 	ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0);
    619 
    620 	ga = &gcgrp->gcgrp_addr;
    621 	ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
    622 
    623 	hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
    624 	(void) mod_hash_remove(hashp, (mod_hash_key_t)ga,
    625 	    (mod_hash_val_t *)&gcgrp);
    626 	rw_destroy(&gcgrp->gcgrp_rwlock);
    627 
    628 	DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *,
    629 	    "removed inactive gcgrp(1) from hash(2)",
    630 	    tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
    631 
    632 	kmem_free(gcgrp, sizeof (*gcgrp));
    633 }
    634 
    635 
    636 /*
    637  * Assign a sensitivity label to inbound traffic which arrived without
    638  * an explicit on-the-wire label.
    639  *
    640  * In the case of CIPSO-type hosts, we assume packets arriving without
    641  * a label are at the most sensitive label known for the host, most
    642  * likely involving out-of-band key management traffic (such as IKE,
    643  * etc.,)
    644  */
    645 static boolean_t
    646 tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi)
    647 {
    648 	*doi = rhtp->tpc_tp.tp_doi;
    649 	switch (rhtp->tpc_tp.host_type) {
    650 	case UNLABELED:
    651 		*sl = rhtp->tpc_tp.tp_def_label;
    652 		break;
    653 	case SUN_CIPSO:
    654 		*sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound;
    655 		break;
    656 	default:
    657 		return (B_FALSE);
    658 	}
    659 	setbltype(sl, SUN_SL_ID);
    660 	return (B_TRUE);
    661 }
    662 
    663 /*
    664  * Converts CIPSO option to sensitivity label.
    665  * Validity checks based on restrictions defined in
    666  * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity)
    667  */
    668 static boolean_t
    669 cipso_to_sl(const uchar_t *option, bslabel_t *sl)
    670 {
    671 	const struct cipso_option *co = (const struct cipso_option *)option;
    672 	const struct cipso_tag_type_1 *tt1;
    673 
    674 	tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0];
    675 	if (tt1->tag_type != 1 ||
    676 	    tt1->tag_length < TSOL_TT1_MIN_LENGTH ||
    677 	    tt1->tag_length > TSOL_TT1_MAX_LENGTH ||
    678 	    tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length)
    679 		return (B_FALSE);
    680 
    681 	bsllow(sl);	/* assumed: sets compartments to all zeroes */
    682 	LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl);
    683 	bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments,
    684 	    tt1->tag_length - TSOL_TT1_MIN_LENGTH);
    685 	return (B_TRUE);
    686 }
    687 
    688 /*
    689  * If present, parse a CIPSO label in the incoming packet and
    690  * construct a ts_label_t that reflects the CIPSO label and attach it
    691  * to the dblk cred.  Later as the mblk flows up through the stack any
    692  * code that needs to examine the packet label can inspect the label
    693  * from the dblk cred. This function is called right in ip_rput for
    694  * all packets, i.e. locally destined and to be forwarded packets. The
    695  * forwarding path needs to examine the label to determine how to
    696  * forward the packet.
    697  *
    698  * This routine pulls all message text up into the first mblk.
    699  * For IPv4, only the first 20 bytes of the IP header are guaranteed
    700  * to exist. For IPv6, only the IPv6 header is guaranteed to exist.
    701  */
    702 boolean_t
    703 tsol_get_pkt_label(mblk_t *mp, int version)
    704 {
    705 	tsol_tpc_t	*src_rhtp = NULL;
    706 	uchar_t		*opt_ptr = NULL;
    707 	const ipha_t	*ipha;
    708 	bslabel_t	sl;
    709 	uint32_t	doi;
    710 	tsol_ip_label_t	label_type;
    711 	uint32_t	label_flags = 0; /* flags to set in label */
    712 	const cipso_option_t *co;
    713 	const void	*src;
    714 	const ip6_t	*ip6h;
    715 	cred_t		*credp;
    716 	pid_t		cpid;
    717 	int 		proto;
    718 
    719 	ASSERT(DB_TYPE(mp) == M_DATA);
    720 
    721 	if (mp->b_cont != NULL && !pullupmsg(mp, -1))
    722 		return (B_FALSE);
    723 
    724 	if (version == IPV4_VERSION) {
    725 		ASSERT(MBLKL(mp) >= IP_SIMPLE_HDR_LENGTH);
    726 		ipha = (const ipha_t *)mp->b_rptr;
    727 		src = &ipha->ipha_src;
    728 		if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
    729 			return (B_FALSE);
    730 	} else {
    731 		ASSERT(MBLKL(mp) >= IPV6_HDR_LEN);
    732 		ip6h = (const ip6_t *)mp->b_rptr;
    733 		src = &ip6h->ip6_src;
    734 		if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
    735 			return (B_FALSE);
    736 	}
    737 
    738 	switch (label_type) {
    739 	case OPT_CIPSO:
    740 		/*
    741 		 * Convert the CIPSO label to the internal format
    742 		 * and attach it to the dblk cred.
    743 		 * Validity checks based on restrictions defined in
    744 		 * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
    745 		 * (draft-ietf-cipso-ipsecurity)
    746 		 */
    747 		if (version == IPV6_VERSION && ip6opt_ls == 0)
    748 			return (B_FALSE);
    749 		co = (const struct cipso_option *)opt_ptr;
    750 		if ((co->cipso_length <
    751 		    TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) ||
    752 		    (co->cipso_length > IP_MAX_OPT_LENGTH))
    753 			return (B_FALSE);
    754 		bcopy(co->cipso_doi, &doi, sizeof (doi));
    755 		doi = ntohl(doi);
    756 		if (!cipso_to_sl(opt_ptr, &sl))
    757 			return (B_FALSE);
    758 		setbltype(&sl, SUN_SL_ID);
    759 
    760 		/*
    761 		 * If the source was unlabeled, then flag as such,
    762 		 * (since CIPSO routers may add headers)
    763 		 */
    764 
    765 		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
    766 			return (B_FALSE);
    767 
    768 		if (src_rhtp->tpc_tp.host_type == UNLABELED)
    769 			label_flags = TSLF_UNLABELED;
    770 
    771 		TPC_RELE(src_rhtp);
    772 
    773 		break;
    774 
    775 	case OPT_NONE:
    776 		/*
    777 		 * Handle special cases that may not be labeled, even
    778 		 * though the sending system may otherwise be configured as
    779 		 * labeled.
    780 		 *	- IGMP
    781 		 *	- IPv4 ICMP Router Discovery
    782 		 *	- IPv6 Neighbor Discovery
    783 		 *	- IPsec ESP
    784 		 */
    785 		if (version == IPV4_VERSION) {
    786 			proto = ipha->ipha_protocol;
    787 			if (proto == IPPROTO_IGMP)
    788 				return (B_TRUE);
    789 			if (proto == IPPROTO_ICMP) {
    790 				const struct icmp *icmp = (const struct icmp *)
    791 				    (mp->b_rptr + IPH_HDR_LENGTH(ipha));
    792 
    793 				if ((uchar_t *)icmp + ICMP_MINLEN > mp->b_wptr)
    794 					return (B_FALSE);
    795 				if (icmp->icmp_type == ICMP_ROUTERADVERT ||
    796 				    icmp->icmp_type == ICMP_ROUTERSOLICIT)
    797 					return (B_TRUE);
    798 			}
    799 		} else {
    800 			proto = ip6h->ip6_nxt;
    801 			if (proto == IPPROTO_ICMPV6) {
    802 				const icmp6_t *icmp6 = (const icmp6_t *)
    803 				    (mp->b_rptr + IPV6_HDR_LEN);
    804 
    805 				if ((uchar_t *)icmp6 + ICMP6_MINLEN >
    806 				    mp->b_wptr)
    807 					return (B_FALSE);
    808 				if (icmp6->icmp6_type >= MLD_LISTENER_QUERY &&
    809 				    icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE)
    810 					return (B_TRUE);
    811 			}
    812 		}
    813 
    814 		/*
    815 		 * Look up the tnrhtp database and get the implicit label
    816 		 * that is associated with the sending host and attach
    817 		 * it to the packet.
    818 		 */
    819 		if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
    820 			return (B_FALSE);
    821 
    822 		/*
    823 		 * If peer is label-aware, mark as "implicit" rather than
    824 		 * "unlabeled" to cause appropriate mac-exempt processing
    825 		 * to happen.
    826 		 */
    827 		if (src_rhtp->tpc_tp.host_type == SUN_CIPSO)
    828 			label_flags = TSLF_IMPLICIT_IN;
    829 		else if (src_rhtp->tpc_tp.host_type == UNLABELED)
    830 			label_flags = TSLF_UNLABELED;
    831 		else {
    832 			DTRACE_PROBE2(tx__get__pkt__label, char *,
    833 			    "template(1) has unknown hosttype",
    834 			    tsol_tpc_t *, src_rhtp);
    835 		}
    836 
    837 
    838 		if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) {
    839 			TPC_RELE(src_rhtp);
    840 			return (B_FALSE);
    841 		}
    842 		TPC_RELE(src_rhtp);
    843 		break;
    844 
    845 	default:
    846 		return (B_FALSE);
    847 	}
    848 
    849 	/* Make sure no other thread is messing with this mblk */
    850 	ASSERT(DB_REF(mp) == 1);
    851 	/* Preserve db_cpid */
    852 	credp = msg_extractcred(mp, &cpid);
    853 	if (credp == NULL) {
    854 		credp = newcred_from_bslabel(&sl, doi, KM_NOSLEEP);
    855 	} else {
    856 		cred_t	*newcr;
    857 
    858 		newcr = copycred_from_bslabel(credp, &sl, doi,
    859 		    KM_NOSLEEP);
    860 		crfree(credp);
    861 		credp = newcr;
    862 	}
    863 	if (credp == NULL)
    864 		return (B_FALSE);
    865 
    866 	crgetlabel(credp)->tsl_flags |= label_flags;
    867 
    868 	mblk_setcred(mp, credp, cpid);
    869 	crfree(credp);			/* mblk has ref on cred */
    870 
    871 	return (B_TRUE);
    872 }
    873 
    874 /*
    875  * This routine determines whether the given packet should be accepted locally.
    876  * It does a range/set check on the packet's label by looking up the given
    877  * address in the remote host database.
    878  */
    879 boolean_t
    880 tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
    881     boolean_t shared_addr, const conn_t *connp)
    882 {
    883 	const cred_t *credp;
    884 	ts_label_t *plabel, *conn_plabel;
    885 	tsol_tpc_t *tp;
    886 	boolean_t retv;
    887 	const bslabel_t *label, *conn_label;
    888 
    889 	/*
    890 	 * The cases in which this can happen are:
    891 	 *	- IPv6 Router Alert, where ip_rput_data_v6 deliberately skips
    892 	 *	  over the label attachment process.
    893 	 *	- MLD output looped-back to ourselves.
    894 	 *	- IPv4 Router Discovery, where tsol_get_pkt_label intentionally
    895 	 *	  avoids the labeling process.
    896 	 * We trust that all valid paths in the code set the cred pointer when
    897 	 * needed.
    898 	 */
    899 	if ((credp = msg_getcred(mp, NULL)) == NULL)
    900 		return (B_TRUE);
    901 
    902 	/*
    903 	 * If this packet is from the inside (not a remote host) and has the
    904 	 * same zoneid as the selected destination, then no checks are
    905 	 * necessary.  Membership in the zone is enough proof.  This is
    906 	 * intended to be a hot path through this function.
    907 	 */
    908 	if (!crisremote(credp) &&
    909 	    crgetzone(credp) == crgetzone(connp->conn_cred))
    910 		return (B_TRUE);
    911 
    912 	plabel = crgetlabel(credp);
    913 	conn_plabel = crgetlabel(connp->conn_cred);
    914 	ASSERT(plabel != NULL && conn_plabel != NULL);
    915 
    916 	label = label2bslabel(plabel);
    917 	conn_label = label2bslabel(crgetlabel(connp->conn_cred));
    918 
    919 
    920 	/*
    921 	 * Implicitly labeled packets from label-aware sources
    922 	 * go only to privileged receivers
    923 	 */
    924 	if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) &&
    925 	    (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) {
    926 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl,
    927 		    char *,
    928 		    "implicitly labeled packet mp(1) for conn(2) "
    929 		    "which isn't in implicit mac mode",
    930 		    mblk_t *, mp, conn_t *, connp);
    931 
    932 		return (B_FALSE);
    933 	}
    934 
    935 
    936 	/*
    937 	 * MLPs are always validated using the range and set of the local
    938 	 * address, even when the remote host is unlabeled.
    939 	 */
    940 	if (connp->conn_mlp_type == mlptBoth ||
    941 	/* LINTED: no consequent */
    942 	    connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) {
    943 		;
    944 
    945 	/*
    946 	 * If this is a packet from an unlabeled sender, then we must apply
    947 	 * different rules.  If the label is equal to the zone's label, then
    948 	 * it's allowed.  If it's not equal, but the zone is either the global
    949 	 * zone or the label is dominated by the zone's label, then allow it
    950 	 * as long as it's in the range configured for the destination.
    951 	 */
    952 	} else if (plabel->tsl_flags & TSLF_UNLABELED) {
    953 		if (plabel->tsl_doi == conn_plabel->tsl_doi &&
    954 		    blequal(label, conn_label))
    955 			return (B_TRUE);
    956 
    957 		/*
    958 		 * conn_zoneid is global for an exclusive stack, thus we use
    959 		 * conn_cred to get the zoneid
    960 		 */
    961 		if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
    962 		    (crgetzoneid(connp->conn_cred) != GLOBAL_ZONEID &&
    963 		    (plabel->tsl_doi != conn_plabel->tsl_doi ||
    964 		    !bldominates(conn_label, label)))) {
    965 			DTRACE_PROBE3(
    966 			    tx__ip__log__drop__receivelocal__mac_unl,
    967 			    char *,
    968 			    "unlabeled packet mp(1) fails mac for conn(2)",
    969 			    mblk_t *, mp, conn_t *, connp);
    970 			return (B_FALSE);
    971 		}
    972 
    973 	/*
    974 	 * If this is a packet from a labeled sender, verify the
    975 	 * label on the packet matches the connection label.
    976 	 */
    977 	} else {
    978 		if (plabel->tsl_doi != conn_plabel->tsl_doi ||
    979 		    !blequal(label, conn_label)) {
    980 			DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp,
    981 			    char *,
    982 			    "packet mp(1) failed label match to SLP conn(2)",
    983 			    mblk_t *, mp, conn_t *, connp);
    984 			return (B_FALSE);
    985 		}
    986 		/*
    987 		 * No further checks will be needed if this is a zone-
    988 		 * specific address because (1) The process for bringing up
    989 		 * the interface ensures the zone's label is within the zone-
    990 		 * specific address's valid label range; (2) For cases where
    991 		 * the conn is bound to the unspecified addresses, ip fanout
    992 		 * logic ensures conn's zoneid equals the dest addr's zoneid;
    993 		 * (3) Mac-exempt and mlp logic above already handle all
    994 		 * cases where the zone label may not be the same as the
    995 		 * conn label.
    996 		 */
    997 		if (!shared_addr)
    998 			return (B_TRUE);
    999 	}
   1000 
   1001 	tp = find_tpc(addr, version, B_FALSE);
   1002 	if (tp == NULL) {
   1003 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr,
   1004 		    char *, "dropping mp(1), host(2) lacks entry",
   1005 		    mblk_t *, mp, void *, addr);
   1006 		return (B_FALSE);
   1007 	}
   1008 
   1009 	/*
   1010 	 * The local host address should not be unlabeled at this point.  The
   1011 	 * only way this can happen is that the destination isn't unicast.  We
   1012 	 * assume that the packet should not have had a label, and thus should
   1013 	 * have been handled by the TSLF_UNLABELED logic above.
   1014 	 */
   1015 	if (tp->tpc_tp.host_type == UNLABELED) {
   1016 		retv = B_FALSE;
   1017 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *,
   1018 		    "mp(1) unlabeled source, but tp is not unlabeled.",
   1019 		    mblk_t *, mp, tsol_tpc_t *, tp);
   1020 
   1021 	} else if (tp->tpc_tp.host_type != SUN_CIPSO) {
   1022 		retv = B_FALSE;
   1023 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *,
   1024 		    "delivering mp(1), found unrecognized tpc(2) type.",
   1025 		    mblk_t *, mp, tsol_tpc_t *, tp);
   1026 
   1027 	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
   1028 		retv = B_FALSE;
   1029 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
   1030 		    "mp(1) could not be delievered to tp(2), doi mismatch",
   1031 		    mblk_t *, mp, tsol_tpc_t *, tp);
   1032 
   1033 	} else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) &&
   1034 	    !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) {
   1035 		retv = B_FALSE;
   1036 		DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
   1037 		    "mp(1) could not be delievered to tp(2), bad mac",
   1038 		    mblk_t *, mp, tsol_tpc_t *, tp);
   1039 	} else {
   1040 		retv = B_TRUE;
   1041 	}
   1042 
   1043 	TPC_RELE(tp);
   1044 
   1045 	return (retv);
   1046 }
   1047 
   1048 boolean_t
   1049 tsol_can_accept_raw(mblk_t *mp, boolean_t check_host)
   1050 {
   1051 	ts_label_t	*plabel = NULL;
   1052 	tsol_tpc_t	*src_rhtp, *dst_rhtp;
   1053 	boolean_t	retv;
   1054 	cred_t		*credp;
   1055 
   1056 	credp = msg_getcred(mp, NULL);
   1057 	if (credp != NULL)
   1058 		plabel = crgetlabel(credp);
   1059 
   1060 	/* We are bootstrapping or the internal template was never deleted */
   1061 	if (plabel == NULL)
   1062 		return (B_TRUE);
   1063 
   1064 	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
   1065 		ipha_t *ipha = (ipha_t *)mp->b_rptr;
   1066 
   1067 		src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION,
   1068 		    B_FALSE);
   1069 		if (src_rhtp == NULL)
   1070 			return (B_FALSE);
   1071 		dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION,
   1072 		    B_FALSE);
   1073 	} else {
   1074 		ip6_t *ip6h = (ip6_t *)mp->b_rptr;
   1075 
   1076 		src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION,
   1077 		    B_FALSE);
   1078 		if (src_rhtp == NULL)
   1079 			return (B_FALSE);
   1080 		dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION,
   1081 		    B_FALSE);
   1082 	}
   1083 	if (dst_rhtp == NULL) {
   1084 		TPC_RELE(src_rhtp);
   1085 		return (B_FALSE);
   1086 	}
   1087 
   1088 	if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) {
   1089 		retv = B_FALSE;
   1090 
   1091 	/*
   1092 	 * Check that the packet's label is in the correct range for labeled
   1093 	 * sender, or is equal to the default label for unlabeled sender.
   1094 	 */
   1095 	} else if ((src_rhtp->tpc_tp.host_type != UNLABELED &&
   1096 	    !_blinrange(label2bslabel(plabel),
   1097 	    &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
   1098 	    !blinlset(label2bslabel(plabel),
   1099 	    src_rhtp->tpc_tp.tp_sl_set_cipso)) ||
   1100 	    (src_rhtp->tpc_tp.host_type == UNLABELED &&
   1101 	    !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) {
   1102 		retv = B_FALSE;
   1103 
   1104 	} else if (check_host) {
   1105 		retv = B_TRUE;
   1106 
   1107 	/*
   1108 	 * Until we have SL range in the Zone structure, pass it
   1109 	 * when our own address lookup returned an internal entry.
   1110 	 */
   1111 	} else switch (dst_rhtp->tpc_tp.host_type) {
   1112 	case UNLABELED:
   1113 		retv = B_TRUE;
   1114 		break;
   1115 
   1116 	case SUN_CIPSO:
   1117 		retv = _blinrange(label2bslabel(plabel),
   1118 		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) ||
   1119 		    blinlset(label2bslabel(plabel),
   1120 		    dst_rhtp->tpc_tp.tp_sl_set_cipso);
   1121 		break;
   1122 
   1123 	default:
   1124 		retv = B_FALSE;
   1125 	}
   1126 	TPC_RELE(src_rhtp);
   1127 	TPC_RELE(dst_rhtp);
   1128 	return (retv);
   1129 }
   1130 
   1131 /*
   1132  * This routine determines whether a response to a failed packet delivery or
   1133  * connection should be sent back.  By default, the policy is to allow such
   1134  * messages to be sent at all times, as these messages reveal little useful
   1135  * information and are healthy parts of TCP/IP networking.
   1136  *
   1137  * If tsol_strict_error is set, then we do strict tests: if the packet label is
   1138  * within the label range/set of this host/zone, return B_TRUE; otherwise
   1139  * return B_FALSE, which causes the packet to be dropped silently.
   1140  *
   1141  * Note that tsol_get_pkt_label will cause the packet to drop if the sender is
   1142  * marked as labeled in the remote host database, but the packet lacks a label.
   1143  * This means that we don't need to do a lookup on the source; the
   1144  * TSLF_UNLABELED flag is sufficient.
   1145  */
   1146 boolean_t
   1147 tsol_can_reply_error(const mblk_t *mp)
   1148 {
   1149 	ts_label_t	*plabel = NULL;
   1150 	tsol_tpc_t	*rhtp;
   1151 	const ipha_t	*ipha;
   1152 	const ip6_t	*ip6h;
   1153 	boolean_t	retv;
   1154 	bslabel_t	*pktbs;
   1155 	cred_t		*credp;
   1156 
   1157 	/* Caller must pull up at least the IP header */
   1158 	ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ?
   1159 	    sizeof (*ipha) : sizeof (*ip6h)));
   1160 
   1161 	if (!tsol_strict_error)
   1162 		return (B_TRUE);
   1163 
   1164 	credp = msg_getcred(mp, NULL);
   1165 	if (credp != NULL)
   1166 		plabel = crgetlabel(credp);
   1167 
   1168 	/* We are bootstrapping or the internal template was never deleted */
   1169 	if (plabel == NULL)
   1170 		return (B_TRUE);
   1171 
   1172 	if (plabel->tsl_flags & TSLF_IMPLICIT_IN) {
   1173 		DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label,
   1174 		    char *,
   1175 		    "cannot send error report for packet mp(1) with "
   1176 		    "unresolved security label sl(2)",
   1177 		    mblk_t *, mp, ts_label_t *, plabel);
   1178 		return (B_FALSE);
   1179 	}
   1180 
   1181 
   1182 	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
   1183 		ipha = (const ipha_t *)mp->b_rptr;
   1184 		rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
   1185 	} else {
   1186 		ip6h = (const ip6_t *)mp->b_rptr;
   1187 		rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE);
   1188 	}
   1189 
   1190 	if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) {
   1191 		retv = B_FALSE;
   1192 	} else {
   1193 		/*
   1194 		 * If we're in the midst of forwarding, then the destination
   1195 		 * address might not be labeled.  In that case, allow unlabeled
   1196 		 * packets through only if the default label is the same, and
   1197 		 * labeled ones if they dominate.
   1198 		 */
   1199 		pktbs = label2bslabel(plabel);
   1200 		switch (rhtp->tpc_tp.host_type) {
   1201 		case UNLABELED:
   1202 			if (plabel->tsl_flags & TSLF_UNLABELED) {
   1203 				retv = blequal(pktbs,
   1204 				    &rhtp->tpc_tp.tp_def_label);
   1205 			} else {
   1206 				retv = bldominates(pktbs,
   1207 				    &rhtp->tpc_tp.tp_def_label);
   1208 			}
   1209 			break;
   1210 
   1211 		case SUN_CIPSO:
   1212 			retv = _blinrange(pktbs,
   1213 			    &rhtp->tpc_tp.tp_sl_range_cipso) ||
   1214 			    blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso);
   1215 			break;
   1216 
   1217 		default:
   1218 			retv = B_FALSE;
   1219 			break;
   1220 		}
   1221 	}
   1222 
   1223 	if (rhtp != NULL)
   1224 		TPC_RELE(rhtp);
   1225 
   1226 	return (retv);
   1227 }
   1228 
   1229 /*
   1230  * Finds the zone associated with the given packet.  Returns GLOBAL_ZONEID if
   1231  * the zone cannot be located.
   1232  *
   1233  * This is used by the classifier when the packet matches an ALL_ZONES IRE, and
   1234  * there's no MLP defined.
   1235  *
   1236  * Note that we assume that this is only invoked in the ALL_ZONES case.
   1237  * Handling other cases would require handle exclusive stack zones where either
   1238  * this routine or the callers would have to map from
   1239  * the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc.
   1240  */
   1241 zoneid_t
   1242 tsol_packet_to_zoneid(const mblk_t *mp)
   1243 {
   1244 	cred_t *cr = msg_getcred(mp, NULL);
   1245 	zone_t *zone;
   1246 	ts_label_t *label;
   1247 
   1248 	if (cr != NULL) {
   1249 		if ((label = crgetlabel(cr)) != NULL) {
   1250 			zone = zone_find_by_label(label);
   1251 			if (zone != NULL) {
   1252 				zoneid_t zoneid = zone->zone_id;
   1253 
   1254 				zone_rele(zone);
   1255 				return (zoneid);
   1256 			}
   1257 		}
   1258 	}
   1259 	return (GLOBAL_ZONEID);
   1260 }
   1261 
   1262 int
   1263 tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl)
   1264 {
   1265 	int		error = 0;
   1266 	tsol_ire_gw_secattr_t *attrp = NULL;
   1267 	tsol_tnrhc_t	*gw_rhc = NULL;
   1268 	tsol_gcgrp_t	*gcgrp = NULL;
   1269 	tsol_gc_t	*gc = NULL;
   1270 	in_addr_t	ga_addr4;
   1271 	void		*paddr = NULL;
   1272 
   1273 	/* Not in Trusted mode or IRE is local/loopback/broadcast/interface */
   1274 	if (!is_system_labeled() ||
   1275 	    (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST |
   1276 	    IRE_INTERFACE)))
   1277 		goto done;
   1278 
   1279 	/*
   1280 	 * If we don't have a label to compare with, or the IRE does not
   1281 	 * contain any gateway security attributes, there's not much that
   1282 	 * we can do.  We let the former case pass, and the latter fail,
   1283 	 * since the IRE doesn't qualify for a match due to the lack of
   1284 	 * security attributes.
   1285 	 */
   1286 	if (tsl == NULL || ire->ire_gw_secattr == NULL) {
   1287 		if (tsl != NULL) {
   1288 			DTRACE_PROBE3(
   1289 			    tx__ip__log__drop__irematch__nogwsec, char *,
   1290 			    "ire(1) lacks ire_gw_secattr when matching "
   1291 			    "label(2)", ire_t *, ire, ts_label_t *, tsl);
   1292 			error = EACCES;
   1293 		}
   1294 		goto done;
   1295 	}
   1296 
   1297 	attrp = ire->ire_gw_secattr;
   1298 
   1299 	/*
   1300 	 * The possible lock order scenarios related to the tsol gateway
   1301 	 * attribute locks are documented at the beginning of ip.c in the
   1302 	 * lock order scenario section.
   1303 	 */
   1304 	mutex_enter(&attrp->igsa_lock);
   1305 
   1306 	/*
   1307 	 * Depending on the IRE type (prefix vs. cache), we seek the group
   1308 	 * structure which contains all security credentials of the gateway.
   1309 	 * A prefix IRE is associated with at most one gateway credential,
   1310 	 * while a cache IRE is associated with every credentials that the
   1311 	 * gateway has.
   1312 	 */
   1313 	if ((gc = attrp->igsa_gc) != NULL) {			/* prefix */
   1314 		gcgrp = gc->gc_grp;
   1315 		ASSERT(gcgrp != NULL);
   1316 		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
   1317 	} else if ((gcgrp = attrp->igsa_gcgrp) != NULL) {	/* cache */
   1318 		rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
   1319 		gc = gcgrp->gcgrp_head;
   1320 		if (gc == NULL) {
   1321 			/* gc group is empty, so the drop lock now */
   1322 			ASSERT(gcgrp->gcgrp_count == 0);
   1323 			rw_exit(&gcgrp->gcgrp_rwlock);
   1324 			gcgrp = NULL;
   1325 		}
   1326 	}
   1327 
   1328 	if (gcgrp != NULL)
   1329 		GCGRP_REFHOLD(gcgrp);
   1330 
   1331 	if ((gw_rhc = attrp->igsa_rhc) != NULL) {
   1332 		/*
   1333 		 * If our cached entry has grown stale, then discard it so we
   1334 		 * can get a new one.
   1335 		 */
   1336 		if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) {
   1337 			TNRHC_RELE(gw_rhc);
   1338 			attrp->igsa_rhc = gw_rhc = NULL;
   1339 		} else {
   1340 			TNRHC_HOLD(gw_rhc)
   1341 		}
   1342 	}
   1343 
   1344 	/* Last attempt at loading the template had failed; try again */
   1345 	if (gw_rhc == NULL) {
   1346 		if (gcgrp != NULL) {
   1347 			tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
   1348 
   1349 			if (ire->ire_ipversion == IPV4_VERSION) {
   1350 				ASSERT(ga->ga_af == AF_INET);
   1351 				IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
   1352 				paddr = &ga_addr4;
   1353 			} else {
   1354 				ASSERT(ga->ga_af == AF_INET6);
   1355 				paddr = &ga->ga_addr;
   1356 			}
   1357 		} else if (ire->ire_ipversion == IPV6_VERSION &&
   1358 		    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
   1359 			paddr = &ire->ire_gateway_addr_v6;
   1360 		} else if (ire->ire_ipversion == IPV4_VERSION &&
   1361 		    ire->ire_gateway_addr != INADDR_ANY) {
   1362 			paddr = &ire->ire_gateway_addr;
   1363 		}
   1364 
   1365 		/* We've found a gateway address to do the template lookup */
   1366 		if (paddr != NULL) {
   1367 			ASSERT(gw_rhc == NULL);
   1368 			gw_rhc = find_rhc(paddr, ire->ire_ipversion, B_FALSE);
   1369 			if (gw_rhc != NULL) {
   1370 				/*
   1371 				 * Note that if the lookup above returned an
   1372 				 * internal template, we'll use it for the
   1373 				 * time being, and do another lookup next
   1374 				 * time around.
   1375 				 */
   1376 				/* Another thread has loaded the template? */
   1377 				if (attrp->igsa_rhc != NULL) {
   1378 					TNRHC_RELE(gw_rhc)
   1379 					/* reload, it could be different */
   1380 					gw_rhc = attrp->igsa_rhc;
   1381 				} else {
   1382 					attrp->igsa_rhc = gw_rhc;
   1383 				}
   1384 				/*
   1385 				 * Hold an extra reference just like we did
   1386 				 * above prior to dropping the igsa_lock.
   1387 				 */
   1388 				TNRHC_HOLD(gw_rhc)
   1389 			}
   1390 		}
   1391 	}
   1392 
   1393 	mutex_exit(&attrp->igsa_lock);
   1394 	/* Gateway template not found */
   1395 	if (gw_rhc == NULL) {
   1396 		/*
   1397 		 * If destination address is directly reachable through an
   1398 		 * interface rather than through a learned route, pass it.
   1399 		 */
   1400 		if (paddr != NULL) {
   1401 			DTRACE_PROBE3(
   1402 			    tx__ip__log__drop__irematch__nogwtmpl, char *,
   1403 			    "ire(1), label(2) off-link with no gw_rhc",
   1404 			    ire_t *, ire, ts_label_t *, tsl);
   1405 			error = EINVAL;
   1406 		}
   1407 		goto done;
   1408 	}
   1409 
   1410 	if (gc != NULL) {
   1411 		tsol_gcdb_t *gcdb;
   1412 		/*
   1413 		 * In the case of IRE_CACHE we've got one or more gateway
   1414 		 * security credentials to compare against the passed in label.
   1415 		 * Perform label range comparison against each security
   1416 		 * credential of the gateway. In the case of a prefix ire
   1417 		 * we need to match against the security attributes of
   1418 		 * just the route itself, so the loop is executed only once.
   1419 		 */
   1420 		ASSERT(gcgrp != NULL);
   1421 		do {
   1422 			gcdb = gc->gc_db;
   1423 			if (tsl->tsl_doi == gcdb->gcdb_doi &&
   1424 			    _blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange))
   1425 				break;
   1426 			if (ire->ire_type == IRE_CACHE)
   1427 				gc = gc->gc_next;
   1428 			else
   1429 				gc = NULL;
   1430 		} while (gc != NULL);
   1431 
   1432 		if (gc == NULL) {
   1433 			DTRACE_PROBE3(
   1434 			    tx__ip__log__drop__irematch__nogcmatched,
   1435 			    char *, "ire(1), tsl(2): all gc failed match",
   1436 			    ire_t *, ire, ts_label_t *, tsl);
   1437 			error = EACCES;
   1438 		}
   1439 	} else {
   1440 		/*
   1441 		 * We didn't find any gateway credentials in the IRE
   1442 		 * attributes; fall back to the gateway's template for
   1443 		 * label range checks, if we are required to do so.
   1444 		 */
   1445 		ASSERT(gw_rhc != NULL);
   1446 		switch (gw_rhc->rhc_tpc->tpc_tp.host_type) {
   1447 		case SUN_CIPSO:
   1448 			if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
   1449 			    (!_blinrange(&tsl->tsl_label,
   1450 			    &gw_rhc->rhc_tpc->tpc_tp.tp_sl_range_cipso) &&
   1451 			    !blinlset(&tsl->tsl_label,
   1452 			    gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) {
   1453 				error = EACCES;
   1454 				DTRACE_PROBE4(
   1455 				    tx__ip__log__drop__irematch__deftmpl,
   1456 				    char *, "ire(1), tsl(2), gw_rhc(3) "
   1457 				    "failed match (cipso gw)",
   1458 				    ire_t *, ire, ts_label_t *, tsl,
   1459 				    tsol_tnrhc_t *, gw_rhc);
   1460 			}
   1461 			break;
   1462 
   1463 		case UNLABELED:
   1464 			if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
   1465 			    (!_blinrange(&tsl->tsl_label,
   1466 			    &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) &&
   1467 			    !blinlset(&tsl->tsl_label,
   1468 			    gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) {
   1469 				error = EACCES;
   1470 				DTRACE_PROBE4(
   1471 				    tx__ip__log__drop__irematch__deftmpl,
   1472 				    char *, "ire(1), tsl(2), gw_rhc(3) "
   1473 				    "failed match (unlabeled gw)",
   1474 				    ire_t *, ire, ts_label_t *, tsl,
   1475 				    tsol_tnrhc_t *, gw_rhc);
   1476 			}
   1477 			break;
   1478 		}
   1479 	}
   1480 
   1481 done:
   1482 
   1483 	if (gcgrp != NULL) {
   1484 		rw_exit(&gcgrp->gcgrp_rwlock);
   1485 		GCGRP_REFRELE(gcgrp);
   1486 	}
   1487 
   1488 	if (gw_rhc != NULL)
   1489 		TNRHC_RELE(gw_rhc)
   1490 
   1491 	return (error);
   1492 }
   1493 
   1494 /*
   1495  * Performs label accreditation checks for packet forwarding.
   1496  *
   1497  * Returns a pointer to the modified mblk if allowed for forwarding,
   1498  * or NULL if the packet must be dropped.
   1499  */
   1500 mblk_t *
   1501 tsol_ip_forward(ire_t *ire, mblk_t *mp)
   1502 {
   1503 	tsol_ire_gw_secattr_t *attrp = NULL;
   1504 	ipha_t		*ipha;
   1505 	ip6_t		*ip6h;
   1506 	const void	*pdst;
   1507 	const void	*psrc;
   1508 	boolean_t	off_link;
   1509 	tsol_tpc_t	*dst_rhtp, *gw_rhtp;
   1510 	tsol_ip_label_t label_type;
   1511 	uchar_t		*opt_ptr = NULL;
   1512 	ts_label_t	*tsl;
   1513 	uint8_t		proto;
   1514 	int		af, adjust;
   1515 	uint16_t	iplen;
   1516 	boolean_t	need_tpc_rele = B_FALSE;
   1517 	ipaddr_t	*gw;
   1518 	ip_stack_t	*ipst = ire->ire_ipst;
   1519 	cred_t		*credp;
   1520 	pid_t		pid;
   1521 
   1522 	ASSERT(ire != NULL && mp != NULL);
   1523 	ASSERT(ire->ire_stq != NULL);
   1524 
   1525 	af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6;
   1526 
   1527 	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
   1528 		ASSERT(ire->ire_ipversion == IPV4_VERSION);
   1529 		ipha = (ipha_t *)mp->b_rptr;
   1530 		psrc = &ipha->ipha_src;
   1531 		pdst = &ipha->ipha_dst;
   1532 		proto = ipha->ipha_protocol;
   1533 
   1534 		/*
   1535 		 * off_link is TRUE if destination not directly reachable.
   1536 		 * Surya note: we avoid creation of per-dst IRE_CACHE entries
   1537 		 * for forwarded packets, so we set off_link to be TRUE
   1538 		 * if the packet dst is different from the ire_addr of
   1539 		 * the ire for the nexthop.
   1540 		 */
   1541 		off_link = ((ipha->ipha_dst != ire->ire_addr) ||
   1542 		    (ire->ire_gateway_addr != INADDR_ANY));
   1543 		if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
   1544 			return (NULL);
   1545 	} else {
   1546 		ASSERT(ire->ire_ipversion == IPV6_VERSION);
   1547 		ip6h = (ip6_t *)mp->b_rptr;
   1548 		psrc = &ip6h->ip6_src;
   1549 		pdst = &ip6h->ip6_dst;
   1550 		proto = ip6h->ip6_nxt;
   1551 
   1552 		if (proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
   1553 		    proto != IPPROTO_ICMPV6) {
   1554 			uint8_t *nexthdrp;
   1555 			uint16_t hdr_len;
   1556 
   1557 			if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len,
   1558 			    &nexthdrp)) {
   1559 				/* malformed packet; drop it */
   1560 				return (NULL);
   1561 			}
   1562 			proto = *nexthdrp;
   1563 		}
   1564 
   1565 		/* destination not directly reachable? */
   1566 		off_link = !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6);
   1567 		if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
   1568 			return (NULL);
   1569 	}
   1570 
   1571 	if ((tsl = msg_getlabel(mp)) == NULL)
   1572 		return (mp);
   1573 
   1574 	if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
   1575 		DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label,
   1576 		    char *,
   1577 		    "cannot forward packet mp(1) with unresolved "
   1578 		    "security label sl(2)",
   1579 		    mblk_t *, mp, ts_label_t *, tsl);
   1580 
   1581 		return (NULL);
   1582 	}
   1583 
   1584 
   1585 	ASSERT(psrc != NULL && pdst != NULL);
   1586 	dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
   1587 
   1588 	if (dst_rhtp == NULL) {
   1589 		/*
   1590 		 * Without a template we do not know if forwarding
   1591 		 * violates MAC
   1592 		 */
   1593 		DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *,
   1594 		    "mp(1) dropped, no template for destination ip4|6(2)",
   1595 		    mblk_t *, mp, void *, pdst);
   1596 		return (NULL);
   1597 	}
   1598 
   1599 	/*
   1600 	 * Gateway template must have existed for off-link destinations,
   1601 	 * since tsol_ire_match_gwattr has ensured such condition.
   1602 	 */
   1603 	if (ire->ire_ipversion == IPV4_VERSION && off_link) {
   1604 		/*
   1605 		 * Surya note: first check if we can get the gw_rhtp from
   1606 		 * the ire_gw_secattr->igsa_rhc; if this is null, then
   1607 		 * do a lookup based on the ire_addr (address of gw)
   1608 		 */
   1609 		if (ire->ire_gw_secattr != NULL &&
   1610 		    ire->ire_gw_secattr->igsa_rhc != NULL) {
   1611 			attrp = ire->ire_gw_secattr;
   1612 			gw_rhtp = attrp->igsa_rhc->rhc_tpc;
   1613 		} else  {
   1614 			/*
   1615 			 * use the ire_addr if this is the IRE_CACHE of nexthop
   1616 			 */
   1617 			gw = (ire->ire_gateway_addr == NULL? &ire->ire_addr :
   1618 			    &ire->ire_gateway_addr);
   1619 			gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE);
   1620 			need_tpc_rele = B_TRUE;
   1621 		}
   1622 		if (gw_rhtp == NULL) {
   1623 			DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
   1624 			    "mp(1) dropped, no gateway in ire attributes(2)",
   1625 			    mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
   1626 			mp = NULL;
   1627 			goto keep_label;
   1628 		}
   1629 	}
   1630 	if (ire->ire_ipversion == IPV6_VERSION &&
   1631 	    ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL ||
   1632 	    (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) {
   1633 		DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
   1634 		    "mp(1) dropped, no gateway in ire attributes(2)",
   1635 		    mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
   1636 		mp = NULL;
   1637 		goto keep_label;
   1638 	}
   1639 
   1640 	/*
   1641 	 * Check that the label for the packet is acceptable
   1642 	 * by destination host; otherwise, drop it.
   1643 	 */
   1644 	switch (dst_rhtp->tpc_tp.host_type) {
   1645 	case SUN_CIPSO:
   1646 		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
   1647 		    (!_blinrange(&tsl->tsl_label,
   1648 		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
   1649 		    !blinlset(&tsl->tsl_label,
   1650 		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
   1651 			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
   1652 			    "labeled packet mp(1) dropped, label(2) fails "
   1653 			    "destination(3) accredation check",
   1654 			    mblk_t *, mp, ts_label_t *, tsl,
   1655 			    tsol_tpc_t *, dst_rhtp);
   1656 			mp = NULL;
   1657 			goto keep_label;
   1658 		}
   1659 		break;
   1660 
   1661 
   1662 	case UNLABELED:
   1663 		if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
   1664 		    !blequal(&dst_rhtp->tpc_tp.tp_def_label,
   1665 		    &tsl->tsl_label)) {
   1666 			DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
   1667 			    "unlabeled packet mp(1) dropped, label(2) fails "
   1668 			    "destination(3) accredation check",
   1669 			    mblk_t *, mp, ts_label_t *, tsl,
   1670 			    tsol_tpc_t *, dst_rhtp);
   1671 			mp = NULL;
   1672 			goto keep_label;
   1673 		}
   1674 		break;
   1675 	}
   1676 	if (label_type == OPT_CIPSO) {
   1677 		/*
   1678 		 * We keep the label on any of the following cases:
   1679 		 *
   1680 		 *   1. The destination is labeled (on/off-link).
   1681 		 *   2. The unlabeled destination is off-link,
   1682 		 *	and the next hop gateway is labeled.
   1683 		 */
   1684 		if (dst_rhtp->tpc_tp.host_type != UNLABELED ||
   1685 		    (off_link &&
   1686 		    gw_rhtp->tpc_tp.host_type != UNLABELED))
   1687 			goto keep_label;
   1688 
   1689 		/*
   1690 		 * Strip off the CIPSO option from the packet because: the
   1691 		 * unlabeled destination host is directly reachable through
   1692 		 * an interface (on-link); or, the unlabeled destination host
   1693 		 * is not directly reachable (off-link), and the next hop
   1694 		 * gateway is unlabeled.
   1695 		 */
   1696 		adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) :
   1697 		    tsol_remove_secopt_v6(ip6h, MBLKL(mp));
   1698 
   1699 		ASSERT(adjust <= 0);
   1700 		if (adjust != 0) {
   1701 
   1702 			/* adjust is negative */
   1703 			ASSERT((mp->b_wptr + adjust) >= mp->b_rptr);
   1704 			mp->b_wptr += adjust;
   1705 
   1706 			if (af == AF_INET) {
   1707 				ipha = (ipha_t *)mp->b_rptr;
   1708 				iplen = ntohs(ipha->ipha_length) + adjust;
   1709 				ipha->ipha_length = htons(iplen);
   1710 				ipha->ipha_hdr_checksum = 0;
   1711 				ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
   1712 			}
   1713 			DTRACE_PROBE3(tx__ip__log__info__forward__adjust,
   1714 			    char *,
   1715 			    "mp(1) adjusted(2) for CIPSO option removal",
   1716 			    mblk_t *, mp, int, adjust);
   1717 		}
   1718 		goto keep_label;
   1719 	}
   1720 
   1721 	ASSERT(label_type == OPT_NONE);
   1722 	ASSERT(dst_rhtp != NULL);
   1723 
   1724 	/*
   1725 	 * We need to add CIPSO option if the destination or the next hop
   1726 	 * gateway is labeled.  Otherwise, pass the packet as is.
   1727 	 */
   1728 	if (dst_rhtp->tpc_tp.host_type == UNLABELED &&
   1729 	    (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED))
   1730 		goto keep_label;
   1731 
   1732 
   1733 	credp = msg_getcred(mp, &pid);
   1734 	if ((af == AF_INET &&
   1735 	    tsol_check_label(credp, &mp, CONN_MAC_DEFAULT, ipst, pid) != 0) ||
   1736 	    (af == AF_INET6 &&
   1737 	    tsol_check_label_v6(credp, &mp, CONN_MAC_DEFAULT, ipst,
   1738 	    pid) != 0)) {
   1739 		mp = NULL;
   1740 		goto keep_label;
   1741 	}
   1742 
   1743 	if (af == AF_INET) {
   1744 		ipha = (ipha_t *)mp->b_rptr;
   1745 		ipha->ipha_hdr_checksum = 0;
   1746 		ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
   1747 	}
   1748 
   1749 keep_label:
   1750 	TPC_RELE(dst_rhtp);
   1751 	if (need_tpc_rele && gw_rhtp != NULL)
   1752 		TPC_RELE(gw_rhtp);
   1753 	return (mp);
   1754 }
   1755 
   1756 /*
   1757  * Name:	tsol_pmtu_adjust()
   1758  *
   1759  * Returns the adjusted mtu after removing security option.
   1760  * Removes/subtracts the option if the packet's cred indicates an unlabeled
   1761  * sender or if pkt_diff indicates this system enlarged the packet.
   1762  */
   1763 uint32_t
   1764 tsol_pmtu_adjust(mblk_t *mp, uint32_t mtu, int pkt_diff, int af)
   1765 {
   1766 	int		label_adj = 0;
   1767 	uint32_t	min_mtu = IP_MIN_MTU;
   1768 	tsol_tpc_t	*src_rhtp;
   1769 	void		*src;
   1770 
   1771 	/*
   1772 	 * Note: label_adj is non-positive, indicating the number of
   1773 	 * bytes removed by removing the security option from the
   1774 	 * header.
   1775 	 */
   1776 	if (af == AF_INET6) {
   1777 		ip6_t	*ip6h;
   1778 
   1779 		min_mtu = IPV6_MIN_MTU;
   1780 		ip6h = (ip6_t *)mp->b_rptr;
   1781 		src = &ip6h->ip6_src;
   1782 		if ((src_rhtp = find_tpc(src, IPV6_VERSION, B_FALSE)) == NULL)
   1783 			return (mtu);
   1784 		if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) {
   1785 			label_adj = tsol_remove_secopt_v6(
   1786 			    (ip6_t *)mp->b_rptr, MBLKL(mp));
   1787 		}
   1788 	} else {
   1789 		ipha_t    *ipha;
   1790 
   1791 		ASSERT(af == AF_INET);
   1792 		ipha = (ipha_t *)mp->b_rptr;
   1793 		src = &ipha->ipha_src;
   1794 		if ((src_rhtp = find_tpc(src, IPV4_VERSION, B_FALSE)) == NULL)
   1795 			return (mtu);
   1796 		if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED)
   1797 			label_adj = tsol_remove_secopt(
   1798 			    (ipha_t *)mp->b_rptr, MBLKL(mp));
   1799 	}
   1800 	/*
   1801 	 * Make pkt_diff non-negative and the larger of the bytes
   1802 	 * previously added (if any) or just removed, since label
   1803 	 * addition + subtraction may not be completely idempotent.
   1804 	 */
   1805 	if (pkt_diff < -label_adj)
   1806 		pkt_diff = -label_adj;
   1807 	if (pkt_diff > 0 && pkt_diff < mtu)
   1808 		mtu -= pkt_diff;
   1809 
   1810 	TPC_RELE(src_rhtp);
   1811 	return (MAX(mtu, min_mtu));
   1812 }
   1813 
   1814 /*
   1815  * Name:	tsol_rtsa_init()
   1816  *
   1817  * Normal:	Sanity checks on the route security attributes provided by
   1818  *		user.  Convert it into a route security parameter list to
   1819  *		be returned to caller.
   1820  *
   1821  * Output:	EINVAL if bad security attributes in the routing message
   1822  *		ENOMEM if unable to allocate data structures
   1823  *		0 otherwise.
   1824  *
   1825  * Note:	On input, cp must point to the end of any addresses in
   1826  *		the rt_msghdr_t structure.
   1827  */
   1828 int
   1829 tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp)
   1830 {
   1831 	uint_t	sacnt;
   1832 	int	err;
   1833 	caddr_t	lim;
   1834 	tsol_rtsecattr_t *tp;
   1835 
   1836 	ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL);
   1837 
   1838 	/*
   1839 	 * In theory, we could accept as many security attributes configured
   1840 	 * per route destination.  However, the current design is limited
   1841 	 * such that at most only one set security attributes is allowed to
   1842 	 * be associated with a prefix IRE.  We therefore assert for now.
   1843 	 */
   1844 	/* LINTED */
   1845 	ASSERT(TSOL_RTSA_REQUEST_MAX == 1);
   1846 
   1847 	sp->rtsa_cnt = 0;
   1848 	lim = (caddr_t)rtm + rtm->rtm_msglen;
   1849 	ASSERT(cp <= lim);
   1850 
   1851 	if ((lim - cp) < sizeof (rtm_ext_t) ||
   1852 	    ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR)
   1853 		return (0);
   1854 
   1855 	if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t))
   1856 		return (EINVAL);
   1857 
   1858 	cp += sizeof (rtm_ext_t);
   1859 
   1860 	if ((lim - cp) < sizeof (*tp) ||
   1861 	    (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) ||
   1862 	    (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt))
   1863 		return (EINVAL);
   1864 
   1865 	/*
   1866 	 * Trying to add route security attributes when system
   1867 	 * labeling service is not available, or when user supllies
   1868 	 * more than the maximum number of security attributes
   1869 	 * allowed per request.
   1870 	 */
   1871 	if ((sacnt > 0 && !is_system_labeled()) ||
   1872 	    sacnt > TSOL_RTSA_REQUEST_MAX)
   1873 		return (EINVAL);
   1874 
   1875 	/* Ensure valid credentials */
   1876 	if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)->
   1877 	    rtsa_attr[0])) != 0) {
   1878 		cp += sizeof (*sp);
   1879 		return (err);
   1880 	}
   1881 
   1882 	bcopy(cp, sp, sizeof (*sp));
   1883 	cp += sizeof (*sp);
   1884 	return (0);
   1885 }
   1886 
   1887 int
   1888 tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc,
   1889     tsol_gcgrp_t *gcgrp)
   1890 {
   1891 	tsol_ire_gw_secattr_t *attrp;
   1892 	boolean_t exists = B_FALSE;
   1893 	in_addr_t ga_addr4;
   1894 	void *paddr = NULL;
   1895 
   1896 	ASSERT(ire != NULL);
   1897 
   1898 	/*
   1899 	 * The only time that attrp can be NULL is when this routine is
   1900 	 * called for the first time during the creation/initialization
   1901 	 * of the corresponding IRE.  It will only get cleared when the
   1902 	 * IRE is deleted.
   1903 	 */
   1904 	if ((attrp = ire->ire_gw_secattr) == NULL) {
   1905 		attrp = ire_gw_secattr_alloc(KM_NOSLEEP);
   1906 		if (attrp == NULL)
   1907 			return (ENOMEM);
   1908 		ire->ire_gw_secattr = attrp;
   1909 	} else {
   1910 		exists = B_TRUE;
   1911 		mutex_enter(&attrp->igsa_lock);
   1912 
   1913 		if (attrp->igsa_rhc != NULL) {
   1914 			TNRHC_RELE(attrp->igsa_rhc);
   1915 			attrp->igsa_rhc = NULL;
   1916 		}
   1917 
   1918 		if (attrp->igsa_gc != NULL)
   1919 			GC_REFRELE(attrp->igsa_gc);
   1920 		if (attrp->igsa_gcgrp != NULL)
   1921 			GCGRP_REFRELE(attrp->igsa_gcgrp);
   1922 	}
   1923 	ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock));
   1924 
   1925 	/*
   1926 	 * References already held by caller and we keep them;
   1927 	 * note that both gc and gcgrp may be set to NULL to
   1928 	 * clear out igsa_gc and igsa_gcgrp, respectively.
   1929 	 */
   1930 	attrp->igsa_gc = gc;
   1931 	attrp->igsa_gcgrp = gcgrp;
   1932 
   1933 	if (gcgrp == NULL && gc != NULL) {
   1934 		gcgrp = gc->gc_grp;
   1935 		ASSERT(gcgrp != NULL);
   1936 	}
   1937 
   1938 	/*
   1939 	 * Intialize the template for gateway; we use the gateway's
   1940 	 * address found in either the passed in gateway credential
   1941 	 * or group pointer, or the ire_gateway_addr{_v6} field.
   1942 	 */
   1943 	if (gcgrp != NULL) {
   1944 		tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
   1945 
   1946 		/*
   1947 		 * Caller is holding a reference, and that we don't
   1948 		 * need to hold any lock to access the address.
   1949 		 */
   1950 		if (ipversion == IPV4_VERSION) {
   1951 			ASSERT(ga->ga_af == AF_INET);
   1952 			IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
   1953 			paddr = &ga_addr4;
   1954 		} else {
   1955 			ASSERT(ga->ga_af == AF_INET6);
   1956 			paddr = &ga->ga_addr;
   1957 		}
   1958 	} else if (ipversion == IPV6_VERSION &&
   1959 	    !IN6_IS_ADDR_UNSPECIFIED(&ire->ire_gateway_addr_v6)) {
   1960 		paddr = &ire->ire_gateway_addr_v6;
   1961 	} else if (ipversion == IPV4_VERSION &&
   1962 	    ire->ire_gateway_addr != INADDR_ANY) {
   1963 		paddr = &ire->ire_gateway_addr;
   1964 	}
   1965 
   1966 	/*
   1967 	 * Lookup the gateway template; note that we could get an internal
   1968 	 * template here, which we cache anyway.  During IRE matching, we'll
   1969 	 * try to update this gateway template cache and hopefully get a
   1970 	 * real one.
   1971 	 */
   1972 	if (paddr != NULL) {
   1973 		attrp->igsa_rhc = find_rhc(paddr, ipversion, B_FALSE);
   1974 	}
   1975 
   1976 	if (exists)
   1977 		mutex_exit(&attrp->igsa_lock);
   1978 
   1979 	return (0);
   1980 }
   1981 
   1982 /*
   1983  * This function figures the type of MLP that we'll be using based on the
   1984  * address that the user is binding and the zone.  If the address is
   1985  * unspecified, then we're looking at both private and shared.  If it's one
   1986  * of the zone's private addresses, then it's private only.  If it's one
   1987  * of the global addresses, then it's shared only. Multicast addresses are
   1988  * treated same as unspecified address.
   1989  *
   1990  * If we can't figure out what it is, then return mlptSingle.  That's actually
   1991  * an error case.
   1992  *
   1993  * The callers are assume to pass in zone->zone_id and not the zoneid that
   1994  * is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an
   1995  * exclusive stack zone).
   1996  */
   1997 mlp_type_t
   1998 tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr,
   1999     ip_stack_t *ipst)
   2000 {
   2001 	in_addr_t in4;
   2002 	ire_t *ire;
   2003 	ipif_t *ipif;
   2004 	zoneid_t addrzone;
   2005 	zoneid_t ip_zoneid;
   2006 
   2007 	ASSERT(addr != NULL);
   2008 
   2009 	/*
   2010 	 * For exclusive stacks we set the zoneid to zero
   2011 	 * to operate as if in the global zone for IRE and conn_t comparisons.
   2012 	 */
   2013 	if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
   2014 		ip_zoneid = GLOBAL_ZONEID;
   2015 	else
   2016 		ip_zoneid = zoneid;
   2017 
   2018 	if (version == IPV6_VERSION &&
   2019 	    IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) {
   2020 		IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4);
   2021 		addr = &in4;
   2022 		version = IPV4_VERSION;
   2023 	}
   2024 
   2025 	if (version == IPV4_VERSION) {
   2026 		in4 = *(const in_addr_t *)addr;
   2027 		if ((in4 == INADDR_ANY) || CLASSD(in4)) {
   2028 			return (mlptBoth);
   2029 		}
   2030 		ire = ire_cache_lookup(in4, ip_zoneid, NULL, ipst);
   2031 	} else {
   2032 		if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr) ||
   2033 		    IN6_IS_ADDR_MULTICAST((const in6_addr_t *)addr)) {
   2034 			return (mlptBoth);
   2035 		}
   2036 		ire = ire_cache_lookup_v6(addr, ip_zoneid, NULL, ipst);
   2037 	}
   2038 	/*
   2039 	 * If we can't find the IRE, then we have to behave exactly like
   2040 	 * ip_bind_laddr{,_v6}.  That means looking up the IPIF so that users
   2041 	 * can bind to addresses on "down" interfaces.
   2042 	 *
   2043 	 * If we can't find that either, then the bind is going to fail, so
   2044 	 * just give up.  Note that there's a miniscule chance that the address
   2045 	 * is in transition, but we don't bother handling that.
   2046 	 */
   2047 	if (ire == NULL) {
   2048 		if (version == IPV4_VERSION)
   2049 			ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL,
   2050 			    ip_zoneid, NULL, NULL, NULL, NULL, ipst);
   2051 		else
   2052 			ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr,
   2053 			    NULL, ip_zoneid, NULL, NULL, NULL, NULL, ipst);
   2054 		if (ipif == NULL) {
   2055 			return (mlptSingle);
   2056 		}
   2057 		addrzone = ipif->ipif_zoneid;
   2058 		ipif_refrele(ipif);
   2059 	} else {
   2060 		addrzone = ire->ire_zoneid;
   2061 		ire_refrele(ire);
   2062 	}
   2063 	return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate);
   2064 }
   2065 
   2066 /*
   2067  * Since we are configuring local interfaces, and we know trusted
   2068  * extension CDE requires local interfaces to be cipso host type in
   2069  * order to function correctly, we'll associate a cipso template
   2070  * to each local interface and let the interface come up.  Configuring
   2071  * a local interface to be "unlabeled" host type is a configuration error.
   2072  * We'll override that error and make the interface host type to be cipso
   2073  * here.
   2074  *
   2075  * The code is optimized for the usual "success" case and unwinds things on
   2076  * error.  We don't want to go to the trouble and expense of formatting the
   2077  * interface name for the usual case where everything is configured correctly.
   2078  */
   2079 boolean_t
   2080 tsol_check_interface_address(const ipif_t *ipif)
   2081 {
   2082 	tsol_tpc_t *tp;
   2083 	char addrbuf[INET6_ADDRSTRLEN];
   2084 	int af;
   2085 	const void *addr;
   2086 	zone_t *zone;
   2087 	ts_label_t *plabel;
   2088 	const bslabel_t *label;
   2089 	char ifbuf[LIFNAMSIZ + 10];
   2090 	const char *ifname;
   2091 	boolean_t retval;
   2092 	tsol_rhent_t rhent;
   2093 	netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack;
   2094 
   2095 	if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) {
   2096 		af = AF_INET;
   2097 		addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr);
   2098 	} else {
   2099 		af = AF_INET6;
   2100 		addr = &ipif->ipif_v6lcl_addr;
   2101 	}
   2102 
   2103 	tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE);
   2104 
   2105 	/* assumes that ALL_ZONES implies that there is no exclusive stack */
   2106 	if (ipif->ipif_zoneid == ALL_ZONES) {
   2107 		zone = NULL;
   2108 	} else if (ns->netstack_stackid == GLOBAL_NETSTACKID) {
   2109 		/* Shared stack case */
   2110 		zone = zone_find_by_id(ipif->ipif_zoneid);
   2111 	} else {
   2112 		/* Exclusive stack case */
   2113 		zone = zone_find_by_id(crgetzoneid(ipif->ipif_ill->ill_credp));
   2114 	}
   2115 	if (zone != NULL) {
   2116 		plabel = zone->zone_slabel;
   2117 		ASSERT(plabel != NULL);
   2118 		label = label2bslabel(plabel);
   2119 	}
   2120 
   2121 	/*
   2122 	 * If it's CIPSO and an all-zones address, then we're done.
   2123 	 * If it's a CIPSO zone specific address, the zone's label
   2124 	 * must be in the range or set specified in the template.
   2125 	 * When the remote host entry is missing or the template
   2126 	 * type is incorrect for this interface, we create a
   2127 	 * CIPSO host entry in kernel and allow the interface to be
   2128 	 * brought up as CIPSO type.
   2129 	 */
   2130 	if (tp != NULL && (
   2131 	    /* The all-zones case */
   2132 	    (tp->tpc_tp.host_type == SUN_CIPSO &&
   2133 	    tp->tpc_tp.tp_doi == default_doi &&
   2134 	    ipif->ipif_zoneid == ALL_ZONES) ||
   2135 	    /* The local-zone case */
   2136 	    (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi &&
   2137 	    ((tp->tpc_tp.host_type == SUN_CIPSO &&
   2138 	    (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) ||
   2139 	    blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) {
   2140 		if (zone != NULL)
   2141 			zone_rele(zone);
   2142 		TPC_RELE(tp);
   2143 		return (B_TRUE);
   2144 	}
   2145 
   2146 	ifname = ipif->ipif_ill->ill_name;
   2147 	if (ipif->ipif_id != 0) {
   2148 		(void) snprintf(ifbuf, sizeof (ifbuf), "%s:%u", ifname,
   2149 		    ipif->ipif_id);
   2150 		ifname = ifbuf;
   2151 	}
   2152 	(void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf));
   2153 
   2154 	if (tp == NULL) {
   2155 		cmn_err(CE_NOTE, "template entry for %s missing. Default to "
   2156 		    "CIPSO type for %s", ifname, addrbuf);
   2157 		retval = B_TRUE;
   2158 	} else if (tp->tpc_tp.host_type == UNLABELED) {
   2159 		cmn_err(CE_NOTE, "template type for %s incorrectly configured. "
   2160 		    "Change to CIPSO type for %s", ifname, addrbuf);
   2161 		retval = B_TRUE;
   2162 	} else if (ipif->ipif_zoneid == ALL_ZONES) {
   2163 		if (tp->tpc_tp.host_type != SUN_CIPSO) {
   2164 			cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for "
   2165 			    "all-zones. Converted to CIPSO.", ifname, addrbuf);
   2166 			retval = B_TRUE;
   2167 		} else {
   2168 			cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d "
   2169 			    "instead of %d", ifname, addrbuf,
   2170 			    tp->tpc_tp.tp_doi, default_doi);
   2171 			retval = B_FALSE;
   2172 		}
   2173 	} else if (zone == NULL) {
   2174 		cmn_err(CE_NOTE, "%s failed: zoneid %d unknown",
   2175 		    ifname, ipif->ipif_zoneid);
   2176 		retval = B_FALSE;
   2177 	} else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
   2178 		cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has "
   2179 		    "DOI %d", ifname, zone->zone_name, plabel->tsl_doi,
   2180 		    addrbuf, tp->tpc_tp.tp_doi);
   2181 		retval = B_FALSE;
   2182 	} else {
   2183 		cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with "
   2184 		    "%s", ifname, zone->zone_name, addrbuf);
   2185 		tsol_print_label(label, "zone label");
   2186 		retval = B_FALSE;
   2187 	}
   2188 
   2189 	if (zone != NULL)
   2190 		zone_rele(zone);
   2191 	if (tp != NULL)
   2192 		TPC_RELE(tp);
   2193 	if (retval) {
   2194 		/*
   2195 		 * we've corrected a config error and let the interface
   2196 		 * come up as cipso. Need to insert an rhent.
   2197 		 */
   2198 		if ((rhent.rh_address.ta_family = af) == AF_INET) {
   2199 			rhent.rh_prefix = 32;
   2200 			rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr;
   2201 		} else {
   2202 			rhent.rh_prefix = 128;
   2203 			rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr;
   2204 		}
   2205 		(void) strcpy(rhent.rh_template, "cipso");
   2206 		if (tnrh_load(&rhent) != 0) {
   2207 			cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO "
   2208 			    "template for local addr %s", ifname, addrbuf);
   2209 			retval = B_FALSE;
   2210 		}
   2211 	}
   2212 	return (retval);
   2213 }
   2214