11676Sjpk /*
21676Sjpk * CDDL HEADER START
31676Sjpk *
41676Sjpk * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
71676Sjpk *
81676Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk * or http://www.opensolaris.org/os/licensing.
101676Sjpk * See the License for the specific language governing permissions
111676Sjpk * and limitations under the License.
121676Sjpk *
131676Sjpk * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk *
191676Sjpk * CDDL HEADER END
201676Sjpk */
211676Sjpk /*
228778SErik.Nordmark@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
231676Sjpk * Use is subject to license terms.
241676Sjpk */
251676Sjpk
261676Sjpk #include <sys/types.h>
271676Sjpk #include <sys/stream.h>
281676Sjpk #include <sys/strsubr.h>
291676Sjpk #include <sys/stropts.h>
301676Sjpk #include <sys/sunddi.h>
311676Sjpk #include <sys/cred.h>
321676Sjpk #include <sys/debug.h>
331676Sjpk #include <sys/kmem.h>
341676Sjpk #include <sys/errno.h>
351676Sjpk #include <sys/disp.h>
361676Sjpk #include <netinet/in.h>
371676Sjpk #include <netinet/in_systm.h>
381676Sjpk #include <netinet/ip.h>
391676Sjpk #include <netinet/ip_icmp.h>
401676Sjpk #include <netinet/tcp.h>
411676Sjpk #include <inet/common.h>
421676Sjpk #include <inet/ipclassifier.h>
431676Sjpk #include <inet/ip.h>
441676Sjpk #include <inet/mib2.h>
451676Sjpk #include <inet/nd.h>
461676Sjpk #include <inet/tcp.h>
471676Sjpk #include <inet/ip_rts.h>
481676Sjpk #include <inet/ip_ire.h>
491676Sjpk #include <inet/ip_if.h>
501676Sjpk #include <sys/modhash.h>
511676Sjpk
521676Sjpk #include <sys/tsol/label.h>
531676Sjpk #include <sys/tsol/label_macro.h>
541676Sjpk #include <sys/tsol/tnet.h>
551676Sjpk #include <sys/tsol/tndb.h>
561676Sjpk #include <sys/strsun.h>
571676Sjpk
581676Sjpk /* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */
591676Sjpk int tsol_strict_error;
601676Sjpk
611676Sjpk /*
621676Sjpk * Some notes on the Trusted Solaris IRE gateway security attributes:
631676Sjpk *
641676Sjpk * When running in Trusted mode, the routing subsystem determines whether or
651676Sjpk * not a packet can be delivered to an off-link host (not directly reachable
661676Sjpk * through an interface) based on the accreditation checks of the packet's
671676Sjpk * security attributes against those associated with the next-hop gateway.
681676Sjpk *
691676Sjpk * The next-hop gateway's security attributes can be derived from two sources
701676Sjpk * (in order of preference): route-related and the host database. A Trusted
711676Sjpk * system must be configured with at least the host database containing an
721676Sjpk * entry for the next-hop gateway, or otherwise no accreditation checks can
731676Sjpk * be performed, which may result in the inability to send packets to any
741676Sjpk * off-link destination host.
751676Sjpk *
761676Sjpk * The major differences between the two sources are the number and type of
771676Sjpk * security attributes used for accreditation checks. A host database entry
781676Sjpk * can contain at most one set of security attributes, specific only to the
791676Sjpk * next-hop gateway. On contrast, route-related security attributes are made
801676Sjpk * up of a collection of security attributes for the distant networks, and
811676Sjpk * are grouped together per next-hop gateway used to reach those networks.
821676Sjpk * This is the preferred method, and the routing subsystem will fallback to
831676Sjpk * the host database entry only if there are no route-related attributes
841676Sjpk * associated with the next-hop gateway.
851676Sjpk *
861676Sjpk * In Trusted mode, all of the IRE entries (except LOCAL/LOOPBACK/BROADCAST/
871676Sjpk * INTERFACE type) are initialized to contain a placeholder to store this
881676Sjpk * information. The ire_gw_secattr structure gets allocated, initialized
891676Sjpk * and associated with the IRE during the time of the IRE creation. The
901676Sjpk * initialization process also includes resolving the host database entry
911676Sjpk * of the next-hop gateway for fallback purposes. It does not include any
921676Sjpk * route-related attribute setup, as that process comes separately as part
931676Sjpk * of the route requests (add/change) made to the routing subsystem.
941676Sjpk *
951676Sjpk * The underlying logic which involves associating IREs with the gateway
961676Sjpk * security attributes are represented by the following data structures:
971676Sjpk *
981676Sjpk * tsol_gcdb_t, or "gcdb"
991676Sjpk *
1001676Sjpk * - This is a system-wide collection of records containing the
1011676Sjpk * currently used route-related security attributes, which are fed
1021676Sjpk * through the routing socket interface, e.g. "route add/change".
1031676Sjpk *
1041676Sjpk * tsol_gc_t, or "gc"
1051676Sjpk *
1061676Sjpk * - This is the gateway credential structure, and it provides for the
1071676Sjpk * only mechanism to access the contents of gcdb. More than one gc
1081676Sjpk * entries may refer to the same gcdb record. gc's in the system are
1091676Sjpk * grouped according to the next-hop gateway address.
1101676Sjpk *
1111676Sjpk * tsol_gcgrp_t, or "gcgrp"
1121676Sjpk *
1131676Sjpk * - Group of gateway credentials, and is unique per next-hop gateway
1141676Sjpk * address. When the group is not empty, i.e. when gcgrp_count is
1151676Sjpk * greater than zero, it contains one or more gc's, each pointing to
1161676Sjpk * a gcdb record which indicates the gateway security attributes
1171676Sjpk * associated with the next-hop gateway.
1181676Sjpk *
1191676Sjpk * The fields of the tsol_ire_gw_secattr_t used from within the IRE are:
1201676Sjpk *
1211676Sjpk * igsa_lock
1221676Sjpk *
1231676Sjpk * - Lock that protects all fields within tsol_ire_gw_secattr_t.
1241676Sjpk *
1251676Sjpk * igsa_rhc
1261676Sjpk *
1271676Sjpk * - Remote host cache database entry of next-hop gateway. This is
1281676Sjpk * used in the case when there are no route-related attributes
1291676Sjpk * configured for the IRE.
1301676Sjpk *
1311676Sjpk * igsa_gc
1321676Sjpk *
1331676Sjpk * - A set of route-related attributes that only get set for prefix
1341676Sjpk * IREs. If this is non-NULL, the prefix IRE has been associated
1351676Sjpk * with a set of gateway security attributes by way of route add/
13611042SErik.Nordmark@Sun.COM * change functionality.
1371676Sjpk */
1381676Sjpk
1391676Sjpk static kmem_cache_t *ire_gw_secattr_cache;
1401676Sjpk
1411676Sjpk #define GCDB_HASH_SIZE 101
1421676Sjpk #define GCGRP_HASH_SIZE 101
1431676Sjpk
1441676Sjpk #define GCDB_REFRELE(p) { \
1451676Sjpk mutex_enter(&gcdb_lock); \
1461676Sjpk ASSERT((p)->gcdb_refcnt > 0); \
1471676Sjpk if (--((p)->gcdb_refcnt) == 0) \
1481676Sjpk gcdb_inactive(p); \
1491676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock)); \
1501676Sjpk mutex_exit(&gcdb_lock); \
1511676Sjpk }
1521676Sjpk
1531676Sjpk static int gcdb_hash_size = GCDB_HASH_SIZE;
1541676Sjpk static int gcgrp_hash_size = GCGRP_HASH_SIZE;
1551676Sjpk static mod_hash_t *gcdb_hash;
1561676Sjpk static mod_hash_t *gcgrp4_hash;
1571676Sjpk static mod_hash_t *gcgrp6_hash;
1581676Sjpk
1591676Sjpk static kmutex_t gcdb_lock;
1601676Sjpk kmutex_t gcgrp_lock;
1611676Sjpk
1621676Sjpk static uint_t gcdb_hash_by_secattr(void *, mod_hash_key_t);
1631676Sjpk static int gcdb_hash_cmp(mod_hash_key_t, mod_hash_key_t);
1641676Sjpk static tsol_gcdb_t *gcdb_lookup(struct rtsa_s *, boolean_t);
1651676Sjpk static void gcdb_inactive(tsol_gcdb_t *);
1661676Sjpk
1671676Sjpk static uint_t gcgrp_hash_by_addr(void *, mod_hash_key_t);
1681676Sjpk static int gcgrp_hash_cmp(mod_hash_key_t, mod_hash_key_t);
1691676Sjpk
1701676Sjpk static int ire_gw_secattr_constructor(void *, void *, int);
1711676Sjpk static void ire_gw_secattr_destructor(void *, void *);
1721676Sjpk
1731676Sjpk void
tnet_init(void)1741676Sjpk tnet_init(void)
1751676Sjpk {
1761676Sjpk ire_gw_secattr_cache = kmem_cache_create("ire_gw_secattr_cache",
1771676Sjpk sizeof (tsol_ire_gw_secattr_t), 64, ire_gw_secattr_constructor,
1781676Sjpk ire_gw_secattr_destructor, NULL, NULL, NULL, 0);
1791676Sjpk
1801676Sjpk gcdb_hash = mod_hash_create_extended("gcdb_hash",
1811676Sjpk gcdb_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
1821676Sjpk gcdb_hash_by_secattr, NULL, gcdb_hash_cmp, KM_SLEEP);
1831676Sjpk
1841676Sjpk gcgrp4_hash = mod_hash_create_extended("gcgrp4_hash",
1851676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
1861676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
1871676Sjpk
1881676Sjpk gcgrp6_hash = mod_hash_create_extended("gcgrp6_hash",
1891676Sjpk gcgrp_hash_size, mod_hash_null_keydtor, mod_hash_null_valdtor,
1901676Sjpk gcgrp_hash_by_addr, NULL, gcgrp_hash_cmp, KM_SLEEP);
1911676Sjpk
1921676Sjpk mutex_init(&gcdb_lock, NULL, MUTEX_DEFAULT, NULL);
1931676Sjpk mutex_init(&gcgrp_lock, NULL, MUTEX_DEFAULT, NULL);
1941676Sjpk }
1951676Sjpk
1961676Sjpk void
tnet_fini(void)1971676Sjpk tnet_fini(void)
1981676Sjpk {
1991676Sjpk kmem_cache_destroy(ire_gw_secattr_cache);
2001676Sjpk mod_hash_destroy_hash(gcdb_hash);
2011676Sjpk mod_hash_destroy_hash(gcgrp4_hash);
2021676Sjpk mod_hash_destroy_hash(gcgrp6_hash);
2031676Sjpk mutex_destroy(&gcdb_lock);
2041676Sjpk mutex_destroy(&gcgrp_lock);
2051676Sjpk }
2061676Sjpk
2071676Sjpk /* ARGSUSED */
2081676Sjpk static int
ire_gw_secattr_constructor(void * buf,void * cdrarg,int kmflags)2091676Sjpk ire_gw_secattr_constructor(void *buf, void *cdrarg, int kmflags)
2101676Sjpk {
2111676Sjpk tsol_ire_gw_secattr_t *attrp = buf;
2121676Sjpk
2131676Sjpk mutex_init(&attrp->igsa_lock, NULL, MUTEX_DEFAULT, NULL);
2141676Sjpk
2151676Sjpk attrp->igsa_rhc = NULL;
2161676Sjpk attrp->igsa_gc = NULL;
2171676Sjpk
2181676Sjpk return (0);
2191676Sjpk }
2201676Sjpk
2211676Sjpk /* ARGSUSED */
2221676Sjpk static void
ire_gw_secattr_destructor(void * buf,void * cdrarg)2231676Sjpk ire_gw_secattr_destructor(void *buf, void *cdrarg)
2241676Sjpk {
2251676Sjpk tsol_ire_gw_secattr_t *attrp = (tsol_ire_gw_secattr_t *)buf;
2261676Sjpk
2271676Sjpk mutex_destroy(&attrp->igsa_lock);
2281676Sjpk }
2291676Sjpk
2301676Sjpk tsol_ire_gw_secattr_t *
ire_gw_secattr_alloc(int kmflags)2311676Sjpk ire_gw_secattr_alloc(int kmflags)
2321676Sjpk {
2331676Sjpk return (kmem_cache_alloc(ire_gw_secattr_cache, kmflags));
2341676Sjpk }
2351676Sjpk
2361676Sjpk void
ire_gw_secattr_free(tsol_ire_gw_secattr_t * attrp)2371676Sjpk ire_gw_secattr_free(tsol_ire_gw_secattr_t *attrp)
2381676Sjpk {
2391676Sjpk ASSERT(MUTEX_NOT_HELD(&attrp->igsa_lock));
2401676Sjpk
2411676Sjpk if (attrp->igsa_rhc != NULL) {
2421676Sjpk TNRHC_RELE(attrp->igsa_rhc);
2431676Sjpk attrp->igsa_rhc = NULL;
2441676Sjpk }
2451676Sjpk
2461676Sjpk if (attrp->igsa_gc != NULL) {
2471676Sjpk GC_REFRELE(attrp->igsa_gc);
2481676Sjpk attrp->igsa_gc = NULL;
2491676Sjpk }
2501676Sjpk
2511676Sjpk ASSERT(attrp->igsa_rhc == NULL);
2521676Sjpk ASSERT(attrp->igsa_gc == NULL);
2531676Sjpk
2541676Sjpk kmem_cache_free(ire_gw_secattr_cache, attrp);
2551676Sjpk }
2561676Sjpk
2571676Sjpk /* ARGSUSED */
2581676Sjpk static uint_t
gcdb_hash_by_secattr(void * hash_data,mod_hash_key_t key)2591676Sjpk gcdb_hash_by_secattr(void *hash_data, mod_hash_key_t key)
2601676Sjpk {
2611676Sjpk const struct rtsa_s *rp = (struct rtsa_s *)key;
2621676Sjpk const uint32_t *up, *ue;
2631676Sjpk uint_t hash;
2641676Sjpk int i;
2651676Sjpk
2661676Sjpk ASSERT(rp != NULL);
2671676Sjpk
2681676Sjpk /* See comments in hash_bylabel in zone.c for details */
2691676Sjpk hash = rp->rtsa_doi + (rp->rtsa_doi << 1);
2701676Sjpk up = (const uint32_t *)&rp->rtsa_slrange;
2711676Sjpk ue = up + sizeof (rp->rtsa_slrange) / sizeof (*up);
2721676Sjpk i = 1;
2731676Sjpk while (up < ue) {
2741676Sjpk /* using 2^n + 1, 1 <= n <= 16 as source of many primes */
2751676Sjpk hash += *up + (*up << ((i % 16) + 1));
2761676Sjpk up++;
2771676Sjpk i++;
2781676Sjpk }
2791676Sjpk return (hash);
2801676Sjpk }
2811676Sjpk
2821676Sjpk static int
gcdb_hash_cmp(mod_hash_key_t key1,mod_hash_key_t key2)2831676Sjpk gcdb_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
2841676Sjpk {
2851676Sjpk struct rtsa_s *rp1 = (struct rtsa_s *)key1;
2861676Sjpk struct rtsa_s *rp2 = (struct rtsa_s *)key2;
2871676Sjpk
2881676Sjpk ASSERT(rp1 != NULL && rp2 != NULL);
2891676Sjpk
2901676Sjpk if (blequal(&rp1->rtsa_slrange.lower_bound,
2911676Sjpk &rp2->rtsa_slrange.lower_bound) &&
2921676Sjpk blequal(&rp1->rtsa_slrange.upper_bound,
2931676Sjpk &rp2->rtsa_slrange.upper_bound) &&
2941676Sjpk rp1->rtsa_doi == rp2->rtsa_doi)
2951676Sjpk return (0);
2961676Sjpk
2971676Sjpk /* No match; not found */
2981676Sjpk return (-1);
2991676Sjpk }
3001676Sjpk
3011676Sjpk /* ARGSUSED */
3021676Sjpk static uint_t
gcgrp_hash_by_addr(void * hash_data,mod_hash_key_t key)3031676Sjpk gcgrp_hash_by_addr(void *hash_data, mod_hash_key_t key)
3041676Sjpk {
3051676Sjpk tsol_gcgrp_addr_t *ga = (tsol_gcgrp_addr_t *)key;
3061676Sjpk uint_t idx = 0;
3071676Sjpk uint32_t *ap;
3081676Sjpk
3091676Sjpk ASSERT(ga != NULL);
3101676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
3111676Sjpk
3121676Sjpk ap = (uint32_t *)&ga->ga_addr.s6_addr32[0];
3131676Sjpk idx ^= *ap++;
3141676Sjpk idx ^= *ap++;
3151676Sjpk idx ^= *ap++;
3161676Sjpk idx ^= *ap;
3171676Sjpk
3181676Sjpk return (idx);
3191676Sjpk }
3201676Sjpk
3211676Sjpk static int
gcgrp_hash_cmp(mod_hash_key_t key1,mod_hash_key_t key2)3221676Sjpk gcgrp_hash_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
3231676Sjpk {
3241676Sjpk tsol_gcgrp_addr_t *ga1 = (tsol_gcgrp_addr_t *)key1;
3251676Sjpk tsol_gcgrp_addr_t *ga2 = (tsol_gcgrp_addr_t *)key2;
3261676Sjpk
3271676Sjpk ASSERT(ga1 != NULL && ga2 != NULL);
3281676Sjpk
3291676Sjpk /* Address family must match */
3301676Sjpk if (ga1->ga_af != ga2->ga_af)
3311676Sjpk return (-1);
3321676Sjpk
3331676Sjpk if (ga1->ga_addr.s6_addr32[0] == ga2->ga_addr.s6_addr32[0] &&
3341676Sjpk ga1->ga_addr.s6_addr32[1] == ga2->ga_addr.s6_addr32[1] &&
3351676Sjpk ga1->ga_addr.s6_addr32[2] == ga2->ga_addr.s6_addr32[2] &&
3361676Sjpk ga1->ga_addr.s6_addr32[3] == ga2->ga_addr.s6_addr32[3])
3371676Sjpk return (0);
3381676Sjpk
3391676Sjpk /* No match; not found */
3401676Sjpk return (-1);
3411676Sjpk }
3421676Sjpk
3431676Sjpk #define RTSAFLAGS "\20\11cipso\3doi\2max_sl\1min_sl"
3441676Sjpk
3451676Sjpk int
rtsa_validate(const struct rtsa_s * rp)3461676Sjpk rtsa_validate(const struct rtsa_s *rp)
3471676Sjpk {
3481676Sjpk uint32_t mask = rp->rtsa_mask;
3491676Sjpk
3501676Sjpk /* RTSA_CIPSO must be set, and DOI must not be zero */
3511676Sjpk if ((mask & RTSA_CIPSO) == 0 || rp->rtsa_doi == 0) {
3521676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
3531676Sjpk "rtsa(1) lacks flag or has 0 doi.",
3541676Sjpk rtsa_s *, rp);
3551676Sjpk return (EINVAL);
3561676Sjpk }
3571676Sjpk /*
3581676Sjpk * SL range must be specified, and it must have its
3591676Sjpk * upper bound dominating its lower bound.
3601676Sjpk */
3611676Sjpk if ((mask & RTSA_SLRANGE) != RTSA_SLRANGE ||
3621676Sjpk !bldominates(&rp->rtsa_slrange.upper_bound,
3631676Sjpk &rp->rtsa_slrange.lower_bound)) {
3641676Sjpk DTRACE_PROBE2(tx__gcdb__log__error__rtsa__validate, char *,
3651676Sjpk "rtsa(1) min_sl and max_sl not set or max_sl is "
3661676Sjpk "not dominating.", rtsa_s *, rp);
3671676Sjpk return (EINVAL);
3681676Sjpk }
3691676Sjpk return (0);
3701676Sjpk }
3711676Sjpk
3721676Sjpk /*
3731676Sjpk * A brief explanation of the reference counting scheme:
3741676Sjpk *
3751676Sjpk * Apart from dynamic references due to to reference holds done
3761676Sjpk * actively by threads, we have the following references:
3771676Sjpk *
3781676Sjpk * gcdb_refcnt:
3791676Sjpk * - Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference
3801676Sjpk * to the gcdb_refcnt.
3811676Sjpk *
3821676Sjpk * gc_refcnt:
3831676Sjpk * - A prefix IRE that points to an igsa_gc contributes a reference
3841676Sjpk * to the gc_refcnt.
3851676Sjpk *
3861676Sjpk * gcgrp_refcnt:
3871676Sjpk * - Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes
3881676Sjpk * a reference to the gcgrp_refcnt.
3891676Sjpk */
3901676Sjpk static tsol_gcdb_t *
gcdb_lookup(struct rtsa_s * rp,boolean_t alloc)3911676Sjpk gcdb_lookup(struct rtsa_s *rp, boolean_t alloc)
3921676Sjpk {
3931676Sjpk tsol_gcdb_t *gcdb = NULL;
3941676Sjpk
3951676Sjpk if (rtsa_validate(rp) != 0)
3961676Sjpk return (NULL);
3971676Sjpk
3981676Sjpk mutex_enter(&gcdb_lock);
3991676Sjpk /* Find a copy in the cache; otherwise, create one and cache it */
4001676Sjpk if (mod_hash_find(gcdb_hash, (mod_hash_key_t)rp,
4011676Sjpk (mod_hash_val_t *)&gcdb) == 0) {
4021676Sjpk gcdb->gcdb_refcnt++;
4031676Sjpk ASSERT(gcdb->gcdb_refcnt != 0);
4041676Sjpk
4051676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__lookup, char *,
4061676Sjpk "gcdb(1) is in gcdb_hash(global)", tsol_gcdb_t *, gcdb);
4071676Sjpk } else if (alloc) {
4081676Sjpk gcdb = kmem_zalloc(sizeof (*gcdb), KM_NOSLEEP);
4091676Sjpk if (gcdb != NULL) {
4101676Sjpk gcdb->gcdb_refcnt = 1;
4111676Sjpk gcdb->gcdb_mask = rp->rtsa_mask;
4121676Sjpk gcdb->gcdb_doi = rp->rtsa_doi;
4131676Sjpk gcdb->gcdb_slrange = rp->rtsa_slrange;
4141676Sjpk
4151676Sjpk if (mod_hash_insert(gcdb_hash,
4161676Sjpk (mod_hash_key_t)&gcdb->gcdb_attr,
4171676Sjpk (mod_hash_val_t)gcdb) != 0) {
4181676Sjpk mutex_exit(&gcdb_lock);
4191676Sjpk kmem_free(gcdb, sizeof (*gcdb));
4201676Sjpk return (NULL);
4211676Sjpk }
4221676Sjpk
4231676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__insert, char *,
4241676Sjpk "gcdb(1) inserted in gcdb_hash(global)",
4251676Sjpk tsol_gcdb_t *, gcdb);
4261676Sjpk }
4271676Sjpk }
4281676Sjpk mutex_exit(&gcdb_lock);
4291676Sjpk return (gcdb);
4301676Sjpk }
4311676Sjpk
4321676Sjpk static void
gcdb_inactive(tsol_gcdb_t * gcdb)4331676Sjpk gcdb_inactive(tsol_gcdb_t *gcdb)
4341676Sjpk {
4351676Sjpk ASSERT(MUTEX_HELD(&gcdb_lock));
4361676Sjpk ASSERT(gcdb != NULL && gcdb->gcdb_refcnt == 0);
4371676Sjpk
4381676Sjpk (void) mod_hash_remove(gcdb_hash, (mod_hash_key_t)&gcdb->gcdb_attr,
4391676Sjpk (mod_hash_val_t *)&gcdb);
4401676Sjpk
4411676Sjpk DTRACE_PROBE2(tx__gcdb__log__info__gcdb__remove, char *,
4421676Sjpk "gcdb(1) removed from gcdb_hash(global)",
4431676Sjpk tsol_gcdb_t *, gcdb);
4441676Sjpk kmem_free(gcdb, sizeof (*gcdb));
4451676Sjpk }
4461676Sjpk
4471676Sjpk tsol_gc_t *
gc_create(struct rtsa_s * rp,tsol_gcgrp_t * gcgrp,boolean_t * gcgrp_xtrarefp)4481676Sjpk gc_create(struct rtsa_s *rp, tsol_gcgrp_t *gcgrp, boolean_t *gcgrp_xtrarefp)
4491676Sjpk {
4501676Sjpk tsol_gc_t *gc;
4511676Sjpk tsol_gcdb_t *gcdb;
4521676Sjpk
4531676Sjpk *gcgrp_xtrarefp = B_TRUE;
4541676Sjpk
4551676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_WRITER);
4561676Sjpk if ((gcdb = gcdb_lookup(rp, B_TRUE)) == NULL) {
4571676Sjpk rw_exit(&gcgrp->gcgrp_rwlock);
4581676Sjpk return (NULL);
4591676Sjpk }
4601676Sjpk
4611676Sjpk for (gc = gcgrp->gcgrp_head; gc != NULL; gc = gc->gc_next) {
4621676Sjpk if (gc->gc_db == gcdb) {
4631676Sjpk ASSERT(gc->gc_grp == gcgrp);
4641676Sjpk
4651676Sjpk gc->gc_refcnt++;
4661676Sjpk ASSERT(gc->gc_refcnt != 0);
4671676Sjpk
4681676Sjpk GCDB_REFRELE(gcdb);
4691676Sjpk
4701676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create,
4711676Sjpk char *, "found gc(1) in gcgrp(2)",
4721676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
4731676Sjpk rw_exit(&gcgrp->gcgrp_rwlock);
4741676Sjpk return (gc);
4751676Sjpk }
4761676Sjpk }
4771676Sjpk
4781676Sjpk gc = kmem_zalloc(sizeof (*gc), KM_NOSLEEP);
4791676Sjpk if (gc != NULL) {
4801676Sjpk if (gcgrp->gcgrp_head == NULL) {
4811676Sjpk gcgrp->gcgrp_head = gcgrp->gcgrp_tail = gc;
4821676Sjpk } else {
4831676Sjpk gcgrp->gcgrp_tail->gc_next = gc;
4841676Sjpk gc->gc_prev = gcgrp->gcgrp_tail;
4851676Sjpk gcgrp->gcgrp_tail = gc;
4861676Sjpk }
4871676Sjpk gcgrp->gcgrp_count++;
4881676Sjpk ASSERT(gcgrp->gcgrp_count != 0);
4891676Sjpk
4901676Sjpk /* caller has incremented gcgrp reference for us */
4911676Sjpk gc->gc_grp = gcgrp;
4921676Sjpk
4931676Sjpk gc->gc_db = gcdb;
4941676Sjpk gc->gc_refcnt = 1;
4951676Sjpk
4961676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__create, char *,
4971676Sjpk "added gc(1) to gcgrp(2)", tsol_gc_t *, gc,
4981676Sjpk tsol_gcgrp_t *, gcgrp);
4991676Sjpk
5001676Sjpk *gcgrp_xtrarefp = B_FALSE;
5011676Sjpk }
5021676Sjpk rw_exit(&gcgrp->gcgrp_rwlock);
5031676Sjpk
5041676Sjpk return (gc);
5051676Sjpk }
5061676Sjpk
5071676Sjpk void
gc_inactive(tsol_gc_t * gc)5081676Sjpk gc_inactive(tsol_gc_t *gc)
5091676Sjpk {
5101676Sjpk tsol_gcgrp_t *gcgrp = gc->gc_grp;
5111676Sjpk
5121676Sjpk ASSERT(gcgrp != NULL);
5131676Sjpk ASSERT(RW_WRITE_HELD(&gcgrp->gcgrp_rwlock));
5141676Sjpk ASSERT(gc->gc_refcnt == 0);
5151676Sjpk
5161676Sjpk if (gc->gc_prev != NULL)
5171676Sjpk gc->gc_prev->gc_next = gc->gc_next;
5181676Sjpk else
5191676Sjpk gcgrp->gcgrp_head = gc->gc_next;
5201676Sjpk if (gc->gc_next != NULL)
5211676Sjpk gc->gc_next->gc_prev = gc->gc_prev;
5221676Sjpk else
5231676Sjpk gcgrp->gcgrp_tail = gc->gc_prev;
5241676Sjpk ASSERT(gcgrp->gcgrp_count > 0);
5251676Sjpk gcgrp->gcgrp_count--;
5261676Sjpk
5271676Sjpk /* drop lock before it's destroyed */
5281676Sjpk rw_exit(&gcgrp->gcgrp_rwlock);
5291676Sjpk
5301676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gc__remove, char *,
5311676Sjpk "removed inactive gc(1) from gcgrp(2)",
5321676Sjpk tsol_gc_t *, gc, tsol_gcgrp_t *, gcgrp);
5331676Sjpk
5341676Sjpk GCGRP_REFRELE(gcgrp);
5351676Sjpk
5361676Sjpk gc->gc_grp = NULL;
5371676Sjpk gc->gc_prev = gc->gc_next = NULL;
5381676Sjpk
5391676Sjpk if (gc->gc_db != NULL)
5401676Sjpk GCDB_REFRELE(gc->gc_db);
5411676Sjpk
5421676Sjpk kmem_free(gc, sizeof (*gc));
5431676Sjpk }
5441676Sjpk
5451676Sjpk tsol_gcgrp_t *
gcgrp_lookup(tsol_gcgrp_addr_t * ga,boolean_t alloc)5461676Sjpk gcgrp_lookup(tsol_gcgrp_addr_t *ga, boolean_t alloc)
5471676Sjpk {
5481676Sjpk tsol_gcgrp_t *gcgrp = NULL;
5491676Sjpk mod_hash_t *hashp;
5501676Sjpk
5511676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
5521676Sjpk
5531676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
5541676Sjpk
5551676Sjpk mutex_enter(&gcgrp_lock);
5561676Sjpk if (mod_hash_find(hashp, (mod_hash_key_t)ga,
5571676Sjpk (mod_hash_val_t *)&gcgrp) == 0) {
5581676Sjpk gcgrp->gcgrp_refcnt++;
5591676Sjpk ASSERT(gcgrp->gcgrp_refcnt != 0);
5601676Sjpk
5611676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__lookup, char *,
5621676Sjpk "found gcgrp(1) in hash(2)", tsol_gcgrp_t *, gcgrp,
5631676Sjpk mod_hash_t *, hashp);
5641676Sjpk
5651676Sjpk } else if (alloc) {
5661676Sjpk gcgrp = kmem_zalloc(sizeof (*gcgrp), KM_NOSLEEP);
5671676Sjpk if (gcgrp != NULL) {
5681676Sjpk gcgrp->gcgrp_refcnt = 1;
5691676Sjpk rw_init(&gcgrp->gcgrp_rwlock, NULL, RW_DEFAULT, NULL);
5701676Sjpk bcopy(ga, &gcgrp->gcgrp_addr, sizeof (*ga));
5711676Sjpk
5721676Sjpk if (mod_hash_insert(hashp,
5731676Sjpk (mod_hash_key_t)&gcgrp->gcgrp_addr,
5741676Sjpk (mod_hash_val_t)gcgrp) != 0) {
5751676Sjpk mutex_exit(&gcgrp_lock);
5761676Sjpk kmem_free(gcgrp, sizeof (*gcgrp));
5771676Sjpk return (NULL);
5781676Sjpk }
5791676Sjpk
5801676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__insert,
5811676Sjpk char *, "inserted gcgrp(1) in hash(2)",
5821676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
5831676Sjpk }
5841676Sjpk }
5851676Sjpk mutex_exit(&gcgrp_lock);
5861676Sjpk return (gcgrp);
5871676Sjpk }
5881676Sjpk
5891676Sjpk void
gcgrp_inactive(tsol_gcgrp_t * gcgrp)5901676Sjpk gcgrp_inactive(tsol_gcgrp_t *gcgrp)
5911676Sjpk {
5921676Sjpk tsol_gcgrp_addr_t *ga;
5931676Sjpk mod_hash_t *hashp;
5941676Sjpk
5951676Sjpk ASSERT(MUTEX_HELD(&gcgrp_lock));
5961676Sjpk ASSERT(gcgrp != NULL && gcgrp->gcgrp_refcnt == 0);
5971676Sjpk ASSERT(gcgrp->gcgrp_head == NULL && gcgrp->gcgrp_count == 0);
5981676Sjpk
5991676Sjpk ga = &gcgrp->gcgrp_addr;
6001676Sjpk ASSERT(ga->ga_af == AF_INET || ga->ga_af == AF_INET6);
6011676Sjpk
6021676Sjpk hashp = (ga->ga_af == AF_INET) ? gcgrp4_hash : gcgrp6_hash;
6031676Sjpk (void) mod_hash_remove(hashp, (mod_hash_key_t)ga,
6041676Sjpk (mod_hash_val_t *)&gcgrp);
6051676Sjpk rw_destroy(&gcgrp->gcgrp_rwlock);
6061676Sjpk
6071676Sjpk DTRACE_PROBE3(tx__gcdb__log__info__gcgrp__remove, char *,
6081676Sjpk "removed inactive gcgrp(1) from hash(2)",
6091676Sjpk tsol_gcgrp_t *, gcgrp, mod_hash_t *, hashp);
6101676Sjpk
6111676Sjpk kmem_free(gcgrp, sizeof (*gcgrp));
6121676Sjpk }
6131676Sjpk
61410934Ssommerfeld@sun.com
61510934Ssommerfeld@sun.com /*
61610934Ssommerfeld@sun.com * Assign a sensitivity label to inbound traffic which arrived without
61710934Ssommerfeld@sun.com * an explicit on-the-wire label.
61810934Ssommerfeld@sun.com *
61910934Ssommerfeld@sun.com * In the case of CIPSO-type hosts, we assume packets arriving without
62010934Ssommerfeld@sun.com * a label are at the most sensitive label known for the host, most
62110934Ssommerfeld@sun.com * likely involving out-of-band key management traffic (such as IKE,
62210934Ssommerfeld@sun.com * etc.,)
62310934Ssommerfeld@sun.com */
62410934Ssommerfeld@sun.com static boolean_t
tsol_find_unlabeled_label(tsol_tpc_t * rhtp,bslabel_t * sl,uint32_t * doi)62510934Ssommerfeld@sun.com tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi)
62610934Ssommerfeld@sun.com {
62710934Ssommerfeld@sun.com *doi = rhtp->tpc_tp.tp_doi;
62810934Ssommerfeld@sun.com switch (rhtp->tpc_tp.host_type) {
62910934Ssommerfeld@sun.com case UNLABELED:
63010934Ssommerfeld@sun.com *sl = rhtp->tpc_tp.tp_def_label;
63110934Ssommerfeld@sun.com break;
63210934Ssommerfeld@sun.com case SUN_CIPSO:
63310934Ssommerfeld@sun.com *sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound;
63410934Ssommerfeld@sun.com break;
63510934Ssommerfeld@sun.com default:
63610934Ssommerfeld@sun.com return (B_FALSE);
63710934Ssommerfeld@sun.com }
63810934Ssommerfeld@sun.com setbltype(sl, SUN_SL_ID);
63910934Ssommerfeld@sun.com return (B_TRUE);
64010934Ssommerfeld@sun.com }
64110934Ssommerfeld@sun.com
6421676Sjpk /*
6431676Sjpk * Converts CIPSO option to sensitivity label.
6441676Sjpk * Validity checks based on restrictions defined in
6451676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity)
6461676Sjpk */
6471676Sjpk static boolean_t
cipso_to_sl(const uchar_t * option,bslabel_t * sl)6481676Sjpk cipso_to_sl(const uchar_t *option, bslabel_t *sl)
6491676Sjpk {
6501676Sjpk const struct cipso_option *co = (const struct cipso_option *)option;
6511676Sjpk const struct cipso_tag_type_1 *tt1;
6521676Sjpk
6531676Sjpk tt1 = (struct cipso_tag_type_1 *)&co->cipso_tag_type[0];
6541676Sjpk if (tt1->tag_type != 1 ||
6551676Sjpk tt1->tag_length < TSOL_TT1_MIN_LENGTH ||
6561676Sjpk tt1->tag_length > TSOL_TT1_MAX_LENGTH ||
6571676Sjpk tt1->tag_length + TSOL_CIPSO_TAG_OFFSET > co->cipso_length)
6581676Sjpk return (B_FALSE);
6591676Sjpk
6601676Sjpk bsllow(sl); /* assumed: sets compartments to all zeroes */
6611676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, tt1->tag_sl);
6621676Sjpk bcopy(tt1->tag_cat, &((_bslabel_impl_t *)sl)->compartments,
6631676Sjpk tt1->tag_length - TSOL_TT1_MIN_LENGTH);
6641676Sjpk return (B_TRUE);
6651676Sjpk }
6661676Sjpk
6671676Sjpk /*
66811042SErik.Nordmark@Sun.COM * If present, parse the CIPSO label in the incoming packet and
66911042SErik.Nordmark@Sun.COM * construct a ts_label_t that reflects the CIPSO label and put it in
67011042SErik.Nordmark@Sun.COM * the ip_recv_attr_t. Later as the packet flows up through the stack any
67110934Ssommerfeld@sun.com * code that needs to examine the packet label can inspect the label
67211042SErik.Nordmark@Sun.COM * from the ira_tsl. This function is
67311042SErik.Nordmark@Sun.COM * called right in ip_input for all packets, i.e. locally destined and
67411042SErik.Nordmark@Sun.COM * to be forwarded packets. The forwarding path needs to examine the label
67511042SErik.Nordmark@Sun.COM * to determine how to forward the packet.
6761676Sjpk *
67710181SKen.Powell@Sun.COM * This routine pulls all message text up into the first mblk.
67810181SKen.Powell@Sun.COM * For IPv4, only the first 20 bytes of the IP header are guaranteed
67910181SKen.Powell@Sun.COM * to exist. For IPv6, only the IPv6 header is guaranteed to exist.
6801676Sjpk */
6811676Sjpk boolean_t
tsol_get_pkt_label(mblk_t * mp,int version,ip_recv_attr_t * ira)68211042SErik.Nordmark@Sun.COM tsol_get_pkt_label(mblk_t *mp, int version, ip_recv_attr_t *ira)
6831676Sjpk {
68410934Ssommerfeld@sun.com tsol_tpc_t *src_rhtp = NULL;
6851676Sjpk uchar_t *opt_ptr = NULL;
6861676Sjpk const ipha_t *ipha;
6871676Sjpk bslabel_t sl;
6881676Sjpk uint32_t doi;
6891676Sjpk tsol_ip_label_t label_type;
69010934Ssommerfeld@sun.com uint32_t label_flags = 0; /* flags to set in label */
6911676Sjpk const cipso_option_t *co;
6921676Sjpk const void *src;
6931676Sjpk const ip6_t *ip6h;
6948778SErik.Nordmark@Sun.COM cred_t *credp;
69510934Ssommerfeld@sun.com int proto;
6961676Sjpk
6971676Sjpk ASSERT(DB_TYPE(mp) == M_DATA);
6981676Sjpk
6999710SKen.Powell@Sun.COM if (mp->b_cont != NULL && !pullupmsg(mp, -1))
7009710SKen.Powell@Sun.COM return (B_FALSE);
7019710SKen.Powell@Sun.COM
7021676Sjpk if (version == IPV4_VERSION) {
70310181SKen.Powell@Sun.COM ASSERT(MBLKL(mp) >= IP_SIMPLE_HDR_LENGTH);
7041676Sjpk ipha = (const ipha_t *)mp->b_rptr;
7051676Sjpk src = &ipha->ipha_src;
70610181SKen.Powell@Sun.COM if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
70710181SKen.Powell@Sun.COM return (B_FALSE);
7081676Sjpk } else {
70910181SKen.Powell@Sun.COM ASSERT(MBLKL(mp) >= IPV6_HDR_LEN);
7101676Sjpk ip6h = (const ip6_t *)mp->b_rptr;
7111676Sjpk src = &ip6h->ip6_src;
71210181SKen.Powell@Sun.COM if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
71310181SKen.Powell@Sun.COM return (B_FALSE);
7141676Sjpk }
7151676Sjpk
7161676Sjpk switch (label_type) {
7171676Sjpk case OPT_CIPSO:
7181676Sjpk /*
7191676Sjpk * Convert the CIPSO label to the internal format
7201676Sjpk * and attach it to the dblk cred.
7211676Sjpk * Validity checks based on restrictions defined in
7221676Sjpk * COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
7231676Sjpk * (draft-ietf-cipso-ipsecurity)
7241676Sjpk */
7251676Sjpk if (version == IPV6_VERSION && ip6opt_ls == 0)
7261676Sjpk return (B_FALSE);
7271676Sjpk co = (const struct cipso_option *)opt_ptr;
7281676Sjpk if ((co->cipso_length <
7291676Sjpk TSOL_CIPSO_TAG_OFFSET + TSOL_TT1_MIN_LENGTH) ||
7301676Sjpk (co->cipso_length > IP_MAX_OPT_LENGTH))
7311676Sjpk return (B_FALSE);
7321676Sjpk bcopy(co->cipso_doi, &doi, sizeof (doi));
7331676Sjpk doi = ntohl(doi);
7341676Sjpk if (!cipso_to_sl(opt_ptr, &sl))
7351676Sjpk return (B_FALSE);
7361676Sjpk setbltype(&sl, SUN_SL_ID);
73710934Ssommerfeld@sun.com
73810934Ssommerfeld@sun.com /*
73910934Ssommerfeld@sun.com * If the source was unlabeled, then flag as such,
74010934Ssommerfeld@sun.com * (since CIPSO routers may add headers)
74110934Ssommerfeld@sun.com */
74210934Ssommerfeld@sun.com
74310934Ssommerfeld@sun.com if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
74410934Ssommerfeld@sun.com return (B_FALSE);
74510934Ssommerfeld@sun.com
74610934Ssommerfeld@sun.com if (src_rhtp->tpc_tp.host_type == UNLABELED)
74710934Ssommerfeld@sun.com label_flags = TSLF_UNLABELED;
74810934Ssommerfeld@sun.com
74910934Ssommerfeld@sun.com TPC_RELE(src_rhtp);
75010934Ssommerfeld@sun.com
7511676Sjpk break;
7521676Sjpk
7531676Sjpk case OPT_NONE:
7541676Sjpk /*
75510934Ssommerfeld@sun.com * Handle special cases that may not be labeled, even
7561676Sjpk * though the sending system may otherwise be configured as
7571676Sjpk * labeled.
7581676Sjpk * - IGMP
7591676Sjpk * - IPv4 ICMP Router Discovery
7601676Sjpk * - IPv6 Neighbor Discovery
76110934Ssommerfeld@sun.com * - IPsec ESP
7621676Sjpk */
7631676Sjpk if (version == IPV4_VERSION) {
76410934Ssommerfeld@sun.com proto = ipha->ipha_protocol;
76510934Ssommerfeld@sun.com if (proto == IPPROTO_IGMP)
7661676Sjpk return (B_TRUE);
76710934Ssommerfeld@sun.com if (proto == IPPROTO_ICMP) {
7681676Sjpk const struct icmp *icmp = (const struct icmp *)
7691676Sjpk (mp->b_rptr + IPH_HDR_LENGTH(ipha));
7701676Sjpk
77110181SKen.Powell@Sun.COM if ((uchar_t *)icmp + ICMP_MINLEN > mp->b_wptr)
77210181SKen.Powell@Sun.COM return (B_FALSE);
7731676Sjpk if (icmp->icmp_type == ICMP_ROUTERADVERT ||
7741676Sjpk icmp->icmp_type == ICMP_ROUTERSOLICIT)
7751676Sjpk return (B_TRUE);
7761676Sjpk }
7771676Sjpk } else {
77810934Ssommerfeld@sun.com proto = ip6h->ip6_nxt;
77910934Ssommerfeld@sun.com if (proto == IPPROTO_ICMPV6) {
7801676Sjpk const icmp6_t *icmp6 = (const icmp6_t *)
7811676Sjpk (mp->b_rptr + IPV6_HDR_LEN);
7821676Sjpk
7831676Sjpk if ((uchar_t *)icmp6 + ICMP6_MINLEN >
78410181SKen.Powell@Sun.COM mp->b_wptr)
78510181SKen.Powell@Sun.COM return (B_FALSE);
7861676Sjpk if (icmp6->icmp6_type >= MLD_LISTENER_QUERY &&
7871676Sjpk icmp6->icmp6_type <= ICMP6_MAX_INFO_TYPE)
7881676Sjpk return (B_TRUE);
7891676Sjpk }
7901676Sjpk }
7911676Sjpk
7921676Sjpk /*
7931676Sjpk * Look up the tnrhtp database and get the implicit label
79410934Ssommerfeld@sun.com * that is associated with the sending host and attach
7951676Sjpk * it to the packet.
7961676Sjpk */
7971676Sjpk if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
7981676Sjpk return (B_FALSE);
7991676Sjpk
80010934Ssommerfeld@sun.com /*
80110934Ssommerfeld@sun.com * If peer is label-aware, mark as "implicit" rather than
80210934Ssommerfeld@sun.com * "unlabeled" to cause appropriate mac-exempt processing
80310934Ssommerfeld@sun.com * to happen.
80410934Ssommerfeld@sun.com */
80510934Ssommerfeld@sun.com if (src_rhtp->tpc_tp.host_type == SUN_CIPSO)
80610934Ssommerfeld@sun.com label_flags = TSLF_IMPLICIT_IN;
80710934Ssommerfeld@sun.com else if (src_rhtp->tpc_tp.host_type == UNLABELED)
80810934Ssommerfeld@sun.com label_flags = TSLF_UNLABELED;
80910934Ssommerfeld@sun.com else {
81010934Ssommerfeld@sun.com DTRACE_PROBE2(tx__get__pkt__label, char *,
81110934Ssommerfeld@sun.com "template(1) has unknown hosttype",
81210934Ssommerfeld@sun.com tsol_tpc_t *, src_rhtp);
81310934Ssommerfeld@sun.com }
81410934Ssommerfeld@sun.com
81510934Ssommerfeld@sun.com
81610934Ssommerfeld@sun.com if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) {
8171676Sjpk TPC_RELE(src_rhtp);
8181676Sjpk return (B_FALSE);
8191676Sjpk }
8201676Sjpk TPC_RELE(src_rhtp);
8211676Sjpk break;
8221676Sjpk
8231676Sjpk default:
8241676Sjpk return (B_FALSE);
8251676Sjpk }
8261676Sjpk
82711042SErik.Nordmark@Sun.COM if (ira->ira_cred == NULL) {
8288778SErik.Nordmark@Sun.COM credp = newcred_from_bslabel(&sl, doi, KM_NOSLEEP);
82911042SErik.Nordmark@Sun.COM if (credp == NULL)
83011042SErik.Nordmark@Sun.COM return (B_FALSE);
8311676Sjpk } else {
83211077SErik.Nordmark@Sun.COM credp = copycred_from_bslabel(ira->ira_cred, &sl, doi,
8331676Sjpk KM_NOSLEEP);
83411077SErik.Nordmark@Sun.COM if (credp == NULL)
83511042SErik.Nordmark@Sun.COM return (B_FALSE);
83611042SErik.Nordmark@Sun.COM if (ira->ira_free_flags & IRA_FREE_CRED) {
83711042SErik.Nordmark@Sun.COM crfree(ira->ira_cred);
83811042SErik.Nordmark@Sun.COM ira->ira_free_flags &= ~IRA_FREE_CRED;
83911042SErik.Nordmark@Sun.COM ira->ira_cred = NULL;
84011042SErik.Nordmark@Sun.COM }
8411676Sjpk }
84210934Ssommerfeld@sun.com
84311042SErik.Nordmark@Sun.COM /*
84411042SErik.Nordmark@Sun.COM * Put the label in ira_tsl for convinience, while keeping
84511042SErik.Nordmark@Sun.COM * the cred in ira_cred for getpeerucred which is used to get
84611042SErik.Nordmark@Sun.COM * labels with TX.
84711042SErik.Nordmark@Sun.COM * Note: no explicit refcnt/free_flag for ira_tsl. The free_flag
84811042SErik.Nordmark@Sun.COM * for IRA_FREE_CRED is sufficient for both.
84911042SErik.Nordmark@Sun.COM */
85011042SErik.Nordmark@Sun.COM ira->ira_tsl = crgetlabel(credp);
85111042SErik.Nordmark@Sun.COM ira->ira_cred = credp;
85211042SErik.Nordmark@Sun.COM ira->ira_free_flags |= IRA_FREE_CRED;
85310934Ssommerfeld@sun.com
85411042SErik.Nordmark@Sun.COM ira->ira_tsl->tsl_flags |= label_flags;
8551676Sjpk return (B_TRUE);
8561676Sjpk }
8571676Sjpk
8581676Sjpk /*
8591676Sjpk * This routine determines whether the given packet should be accepted locally.
8601676Sjpk * It does a range/set check on the packet's label by looking up the given
8611676Sjpk * address in the remote host database.
8621676Sjpk */
8631676Sjpk boolean_t
tsol_receive_local(const mblk_t * mp,const void * addr,uchar_t version,ip_recv_attr_t * ira,const conn_t * connp)8641676Sjpk tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
86511042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, const conn_t *connp)
8661676Sjpk {
8671676Sjpk const cred_t *credp;
8681676Sjpk ts_label_t *plabel, *conn_plabel;
8691676Sjpk tsol_tpc_t *tp;
8701676Sjpk boolean_t retv;
8711676Sjpk const bslabel_t *label, *conn_label;
87211042SErik.Nordmark@Sun.COM boolean_t shared_addr = (ira->ira_flags & IRAF_TX_SHARED_ADDR);
8731676Sjpk
8741676Sjpk /*
87511042SErik.Nordmark@Sun.COM * tsol_get_pkt_label intentionally avoids the labeling process for:
87611042SErik.Nordmark@Sun.COM * - IPv6 router and neighbor discovery as well as redirects.
87711042SErik.Nordmark@Sun.COM * - MLD packets. (Anything between ICMPv6 code 130 and 138.)
87811042SErik.Nordmark@Sun.COM * - IGMP packets.
87911042SErik.Nordmark@Sun.COM * - IPv4 router discovery.
88011077SErik.Nordmark@Sun.COM * In those cases ira_cred is NULL.
8811676Sjpk */
88211042SErik.Nordmark@Sun.COM credp = ira->ira_cred;
88311042SErik.Nordmark@Sun.COM if (credp == NULL)
8841676Sjpk return (B_TRUE);
8851676Sjpk
8861676Sjpk /*
8871676Sjpk * If this packet is from the inside (not a remote host) and has the
8881676Sjpk * same zoneid as the selected destination, then no checks are
8891676Sjpk * necessary. Membership in the zone is enough proof. This is
8901676Sjpk * intended to be a hot path through this function.
89111042SErik.Nordmark@Sun.COM * Note: Using crgetzone here is ok since the peer is local.
8921676Sjpk */
8931676Sjpk if (!crisremote(credp) &&
8941676Sjpk crgetzone(credp) == crgetzone(connp->conn_cred))
8951676Sjpk return (B_TRUE);
8961676Sjpk
89711042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl;
8981676Sjpk conn_plabel = crgetlabel(connp->conn_cred);
8991676Sjpk ASSERT(plabel != NULL && conn_plabel != NULL);
9001676Sjpk
9011676Sjpk label = label2bslabel(plabel);
90211042SErik.Nordmark@Sun.COM conn_label = label2bslabel(conn_plabel);
9031676Sjpk
90410934Ssommerfeld@sun.com
90510934Ssommerfeld@sun.com /*
90610934Ssommerfeld@sun.com * Implicitly labeled packets from label-aware sources
90710934Ssommerfeld@sun.com * go only to privileged receivers
90810934Ssommerfeld@sun.com */
90910934Ssommerfeld@sun.com if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) &&
91010934Ssommerfeld@sun.com (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) {
91110934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl,
91210934Ssommerfeld@sun.com char *,
91310934Ssommerfeld@sun.com "implicitly labeled packet mp(1) for conn(2) "
91410934Ssommerfeld@sun.com "which isn't in implicit mac mode",
91510934Ssommerfeld@sun.com mblk_t *, mp, conn_t *, connp);
91610934Ssommerfeld@sun.com
91710934Ssommerfeld@sun.com return (B_FALSE);
91810934Ssommerfeld@sun.com }
91910934Ssommerfeld@sun.com
92010934Ssommerfeld@sun.com
9211676Sjpk /*
9221676Sjpk * MLPs are always validated using the range and set of the local
9231676Sjpk * address, even when the remote host is unlabeled.
9241676Sjpk */
9251676Sjpk if (connp->conn_mlp_type == mlptBoth ||
9261676Sjpk /* LINTED: no consequent */
9271676Sjpk connp->conn_mlp_type == (shared_addr ? mlptShared : mlptPrivate)) {
9281676Sjpk ;
9291676Sjpk
9301676Sjpk /*
9311676Sjpk * If this is a packet from an unlabeled sender, then we must apply
9321676Sjpk * different rules. If the label is equal to the zone's label, then
9331676Sjpk * it's allowed. If it's not equal, but the zone is either the global
9341676Sjpk * zone or the label is dominated by the zone's label, then allow it
9351676Sjpk * as long as it's in the range configured for the destination.
9361676Sjpk */
9371676Sjpk } else if (plabel->tsl_flags & TSLF_UNLABELED) {
9381676Sjpk if (plabel->tsl_doi == conn_plabel->tsl_doi &&
9391676Sjpk blequal(label, conn_label))
9401676Sjpk return (B_TRUE);
9411676Sjpk
94210934Ssommerfeld@sun.com if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
94311042SErik.Nordmark@Sun.COM (!connp->conn_zone_is_global &&
9441676Sjpk (plabel->tsl_doi != conn_plabel->tsl_doi ||
9451676Sjpk !bldominates(conn_label, label)))) {
9461676Sjpk DTRACE_PROBE3(
9471676Sjpk tx__ip__log__drop__receivelocal__mac_unl,
9481676Sjpk char *,
9491676Sjpk "unlabeled packet mp(1) fails mac for conn(2)",
9501676Sjpk mblk_t *, mp, conn_t *, connp);
9511676Sjpk return (B_FALSE);
9521676Sjpk }
9531676Sjpk
9541676Sjpk /*
9554448Skp158701 * If this is a packet from a labeled sender, verify the
9564448Skp158701 * label on the packet matches the connection label.
9571676Sjpk */
9584448Skp158701 } else {
9594448Skp158701 if (plabel->tsl_doi != conn_plabel->tsl_doi ||
9604448Skp158701 !blequal(label, conn_label)) {
9614448Skp158701 DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac__slp,
9624448Skp158701 char *,
9634448Skp158701 "packet mp(1) failed label match to SLP conn(2)",
9644448Skp158701 mblk_t *, mp, conn_t *, connp);
9654448Skp158701 return (B_FALSE);
9664448Skp158701 }
9671676Sjpk /*
9684448Skp158701 * No further checks will be needed if this is a zone-
9694448Skp158701 * specific address because (1) The process for bringing up
9704448Skp158701 * the interface ensures the zone's label is within the zone-
9714448Skp158701 * specific address's valid label range; (2) For cases where
9724448Skp158701 * the conn is bound to the unspecified addresses, ip fanout
9734448Skp158701 * logic ensures conn's zoneid equals the dest addr's zoneid;
9744448Skp158701 * (3) Mac-exempt and mlp logic above already handle all
9754448Skp158701 * cases where the zone label may not be the same as the
9764448Skp158701 * conn label.
9771676Sjpk */
9784448Skp158701 if (!shared_addr)
9791676Sjpk return (B_TRUE);
9801676Sjpk }
9811676Sjpk
9821676Sjpk tp = find_tpc(addr, version, B_FALSE);
9831676Sjpk if (tp == NULL) {
9841676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__no__tnr,
9851676Sjpk char *, "dropping mp(1), host(2) lacks entry",
9861676Sjpk mblk_t *, mp, void *, addr);
9871676Sjpk return (B_FALSE);
9881676Sjpk }
9891676Sjpk
9901676Sjpk /*
9911676Sjpk * The local host address should not be unlabeled at this point. The
9921676Sjpk * only way this can happen is that the destination isn't unicast. We
9931676Sjpk * assume that the packet should not have had a label, and thus should
9941676Sjpk * have been handled by the TSLF_UNLABELED logic above.
9951676Sjpk */
9961676Sjpk if (tp->tpc_tp.host_type == UNLABELED) {
9971676Sjpk retv = B_FALSE;
9981676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__flag, char *,
9991676Sjpk "mp(1) unlabeled source, but tp is not unlabeled.",
10001676Sjpk mblk_t *, mp, tsol_tpc_t *, tp);
10011676Sjpk
10021676Sjpk } else if (tp->tpc_tp.host_type != SUN_CIPSO) {
10031676Sjpk retv = B_FALSE;
10041676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__tptype, char *,
10051676Sjpk "delivering mp(1), found unrecognized tpc(2) type.",
10061676Sjpk mblk_t *, mp, tsol_tpc_t *, tp);
10071676Sjpk
10081676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
10091676Sjpk retv = B_FALSE;
10101676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
10111676Sjpk "mp(1) could not be delievered to tp(2), doi mismatch",
10121676Sjpk mblk_t *, mp, tsol_tpc_t *, tp);
10131676Sjpk
10141676Sjpk } else if (!_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) &&
10151676Sjpk !blinlset(label, tp->tpc_tp.tp_sl_set_cipso)) {
10161676Sjpk retv = B_FALSE;
10171676Sjpk DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac, char *,
10181676Sjpk "mp(1) could not be delievered to tp(2), bad mac",
10191676Sjpk mblk_t *, mp, tsol_tpc_t *, tp);
10201676Sjpk } else {
10211676Sjpk retv = B_TRUE;
10221676Sjpk }
10231676Sjpk
10241676Sjpk TPC_RELE(tp);
10251676Sjpk
10261676Sjpk return (retv);
10271676Sjpk }
10281676Sjpk
10291676Sjpk boolean_t
tsol_can_accept_raw(mblk_t * mp,ip_recv_attr_t * ira,boolean_t check_host)103011042SErik.Nordmark@Sun.COM tsol_can_accept_raw(mblk_t *mp, ip_recv_attr_t *ira, boolean_t check_host)
10311676Sjpk {
10321676Sjpk ts_label_t *plabel = NULL;
10331676Sjpk tsol_tpc_t *src_rhtp, *dst_rhtp;
10341676Sjpk boolean_t retv;
10351676Sjpk
103611042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl;
10371676Sjpk
10381676Sjpk /* We are bootstrapping or the internal template was never deleted */
10391676Sjpk if (plabel == NULL)
10401676Sjpk return (B_TRUE);
10411676Sjpk
10421676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
10431676Sjpk ipha_t *ipha = (ipha_t *)mp->b_rptr;
10441676Sjpk
10451676Sjpk src_rhtp = find_tpc(&ipha->ipha_src, IPV4_VERSION,
10461676Sjpk B_FALSE);
10471676Sjpk if (src_rhtp == NULL)
10481676Sjpk return (B_FALSE);
10491676Sjpk dst_rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION,
10501676Sjpk B_FALSE);
10511676Sjpk } else {
10521676Sjpk ip6_t *ip6h = (ip6_t *)mp->b_rptr;
10531676Sjpk
10541676Sjpk src_rhtp = find_tpc(&ip6h->ip6_src, IPV6_VERSION,
10551676Sjpk B_FALSE);
10561676Sjpk if (src_rhtp == NULL)
10571676Sjpk return (B_FALSE);
10581676Sjpk dst_rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION,
10591676Sjpk B_FALSE);
10601676Sjpk }
10611676Sjpk if (dst_rhtp == NULL) {
10621676Sjpk TPC_RELE(src_rhtp);
10631676Sjpk return (B_FALSE);
10641676Sjpk }
10651676Sjpk
10661676Sjpk if (label2doi(plabel) != src_rhtp->tpc_tp.tp_doi) {
10671676Sjpk retv = B_FALSE;
10681676Sjpk
10691676Sjpk /*
10701676Sjpk * Check that the packet's label is in the correct range for labeled
10711676Sjpk * sender, or is equal to the default label for unlabeled sender.
10721676Sjpk */
10731676Sjpk } else if ((src_rhtp->tpc_tp.host_type != UNLABELED &&
10741676Sjpk !_blinrange(label2bslabel(plabel),
10751676Sjpk &src_rhtp->tpc_tp.tp_sl_range_cipso) &&
10761676Sjpk !blinlset(label2bslabel(plabel),
10771676Sjpk src_rhtp->tpc_tp.tp_sl_set_cipso)) ||
10781676Sjpk (src_rhtp->tpc_tp.host_type == UNLABELED &&
10791676Sjpk !blequal(&plabel->tsl_label, &src_rhtp->tpc_tp.tp_def_label))) {
10801676Sjpk retv = B_FALSE;
10811676Sjpk
10821676Sjpk } else if (check_host) {
10831676Sjpk retv = B_TRUE;
10841676Sjpk
10851676Sjpk /*
10861676Sjpk * Until we have SL range in the Zone structure, pass it
10871676Sjpk * when our own address lookup returned an internal entry.
10881676Sjpk */
10891676Sjpk } else switch (dst_rhtp->tpc_tp.host_type) {
10901676Sjpk case UNLABELED:
10911676Sjpk retv = B_TRUE;
10921676Sjpk break;
10931676Sjpk
10941676Sjpk case SUN_CIPSO:
10951676Sjpk retv = _blinrange(label2bslabel(plabel),
10961676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) ||
10971676Sjpk blinlset(label2bslabel(plabel),
10981676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso);
10991676Sjpk break;
11001676Sjpk
11011676Sjpk default:
11021676Sjpk retv = B_FALSE;
11031676Sjpk }
11041676Sjpk TPC_RELE(src_rhtp);
11051676Sjpk TPC_RELE(dst_rhtp);
11061676Sjpk return (retv);
11071676Sjpk }
11081676Sjpk
11091676Sjpk /*
11101676Sjpk * This routine determines whether a response to a failed packet delivery or
11111676Sjpk * connection should be sent back. By default, the policy is to allow such
11121676Sjpk * messages to be sent at all times, as these messages reveal little useful
11131676Sjpk * information and are healthy parts of TCP/IP networking.
11141676Sjpk *
11151676Sjpk * If tsol_strict_error is set, then we do strict tests: if the packet label is
11161676Sjpk * within the label range/set of this host/zone, return B_TRUE; otherwise
11171676Sjpk * return B_FALSE, which causes the packet to be dropped silently.
11181676Sjpk *
11191676Sjpk * Note that tsol_get_pkt_label will cause the packet to drop if the sender is
11201676Sjpk * marked as labeled in the remote host database, but the packet lacks a label.
11211676Sjpk * This means that we don't need to do a lookup on the source; the
11221676Sjpk * TSLF_UNLABELED flag is sufficient.
11231676Sjpk */
11241676Sjpk boolean_t
tsol_can_reply_error(const mblk_t * mp,ip_recv_attr_t * ira)112511042SErik.Nordmark@Sun.COM tsol_can_reply_error(const mblk_t *mp, ip_recv_attr_t *ira)
11261676Sjpk {
11271676Sjpk ts_label_t *plabel = NULL;
11281676Sjpk tsol_tpc_t *rhtp;
11291676Sjpk const ipha_t *ipha;
11301676Sjpk const ip6_t *ip6h;
11311676Sjpk boolean_t retv;
11321676Sjpk bslabel_t *pktbs;
11331676Sjpk
11341676Sjpk /* Caller must pull up at least the IP header */
11351676Sjpk ASSERT(MBLKL(mp) >= (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ?
11361676Sjpk sizeof (*ipha) : sizeof (*ip6h)));
11371676Sjpk
11381676Sjpk if (!tsol_strict_error)
11391676Sjpk return (B_TRUE);
11401676Sjpk
114111042SErik.Nordmark@Sun.COM plabel = ira->ira_tsl;
11421676Sjpk
11431676Sjpk /* We are bootstrapping or the internal template was never deleted */
11441676Sjpk if (plabel == NULL)
11451676Sjpk return (B_TRUE);
11461676Sjpk
114710934Ssommerfeld@sun.com if (plabel->tsl_flags & TSLF_IMPLICIT_IN) {
114810934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label,
114910934Ssommerfeld@sun.com char *,
115010934Ssommerfeld@sun.com "cannot send error report for packet mp(1) with "
115110934Ssommerfeld@sun.com "unresolved security label sl(2)",
115210934Ssommerfeld@sun.com mblk_t *, mp, ts_label_t *, plabel);
115310934Ssommerfeld@sun.com return (B_FALSE);
115410934Ssommerfeld@sun.com }
115510934Ssommerfeld@sun.com
115610934Ssommerfeld@sun.com
11571676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
11581676Sjpk ipha = (const ipha_t *)mp->b_rptr;
11591676Sjpk rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
11601676Sjpk } else {
11611676Sjpk ip6h = (const ip6_t *)mp->b_rptr;
11621676Sjpk rhtp = find_tpc(&ip6h->ip6_dst, IPV6_VERSION, B_FALSE);
11631676Sjpk }
11641676Sjpk
11651676Sjpk if (rhtp == NULL || label2doi(plabel) != rhtp->tpc_tp.tp_doi) {
11661676Sjpk retv = B_FALSE;
11671676Sjpk } else {
11681676Sjpk /*
11691676Sjpk * If we're in the midst of forwarding, then the destination
11701676Sjpk * address might not be labeled. In that case, allow unlabeled
11711676Sjpk * packets through only if the default label is the same, and
11721676Sjpk * labeled ones if they dominate.
11731676Sjpk */
11741676Sjpk pktbs = label2bslabel(plabel);
11751676Sjpk switch (rhtp->tpc_tp.host_type) {
11761676Sjpk case UNLABELED:
11771676Sjpk if (plabel->tsl_flags & TSLF_UNLABELED) {
11781676Sjpk retv = blequal(pktbs,
11791676Sjpk &rhtp->tpc_tp.tp_def_label);
11801676Sjpk } else {
11811676Sjpk retv = bldominates(pktbs,
11821676Sjpk &rhtp->tpc_tp.tp_def_label);
11831676Sjpk }
11841676Sjpk break;
11851676Sjpk
11861676Sjpk case SUN_CIPSO:
11871676Sjpk retv = _blinrange(pktbs,
11881676Sjpk &rhtp->tpc_tp.tp_sl_range_cipso) ||
11891676Sjpk blinlset(pktbs, rhtp->tpc_tp.tp_sl_set_cipso);
11901676Sjpk break;
11911676Sjpk
11921676Sjpk default:
11931676Sjpk retv = B_FALSE;
11941676Sjpk break;
11951676Sjpk }
11961676Sjpk }
11971676Sjpk
11981676Sjpk if (rhtp != NULL)
11991676Sjpk TPC_RELE(rhtp);
12001676Sjpk
12011676Sjpk return (retv);
12021676Sjpk }
12031676Sjpk
12041676Sjpk /*
120511042SErik.Nordmark@Sun.COM * Finds the zone associated with the receive attributes. Returns GLOBAL_ZONEID
120611042SErik.Nordmark@Sun.COM * if the zone cannot be located.
12071676Sjpk *
12081676Sjpk * This is used by the classifier when the packet matches an ALL_ZONES IRE, and
12091676Sjpk * there's no MLP defined.
12103448Sdh155122 *
12113448Sdh155122 * Note that we assume that this is only invoked in the ALL_ZONES case.
121211042SErik.Nordmark@Sun.COM * Handling other cases would require handling exclusive IP zones where either
12133448Sdh155122 * this routine or the callers would have to map from
12143448Sdh155122 * the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc.
12151676Sjpk */
12161676Sjpk zoneid_t
tsol_attr_to_zoneid(const ip_recv_attr_t * ira)121711042SErik.Nordmark@Sun.COM tsol_attr_to_zoneid(const ip_recv_attr_t *ira)
12181676Sjpk {
12191676Sjpk zone_t *zone;
12201676Sjpk ts_label_t *label;
12211676Sjpk
122211042SErik.Nordmark@Sun.COM if ((label = ira->ira_tsl) != NULL) {
122311042SErik.Nordmark@Sun.COM zone = zone_find_by_label(label);
122411042SErik.Nordmark@Sun.COM if (zone != NULL) {
122511042SErik.Nordmark@Sun.COM zoneid_t zoneid = zone->zone_id;
12261676Sjpk
122711042SErik.Nordmark@Sun.COM zone_rele(zone);
122811042SErik.Nordmark@Sun.COM return (zoneid);
12291676Sjpk }
12301676Sjpk }
12311676Sjpk return (GLOBAL_ZONEID);
12321676Sjpk }
12331676Sjpk
12341676Sjpk int
tsol_ire_match_gwattr(ire_t * ire,const ts_label_t * tsl)12351676Sjpk tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl)
12361676Sjpk {
12371676Sjpk int error = 0;
12381676Sjpk tsol_ire_gw_secattr_t *attrp = NULL;
12391676Sjpk tsol_tnrhc_t *gw_rhc = NULL;
12401676Sjpk tsol_gcgrp_t *gcgrp = NULL;
12411676Sjpk tsol_gc_t *gc = NULL;
12421676Sjpk in_addr_t ga_addr4;
12431676Sjpk void *paddr = NULL;
12441676Sjpk
12451676Sjpk /* Not in Trusted mode or IRE is local/loopback/broadcast/interface */
12461676Sjpk if (!is_system_labeled() ||
12471676Sjpk (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST |
124811042SErik.Nordmark@Sun.COM IRE_IF_ALL | IRE_MULTICAST | IRE_NOROUTE)))
12491676Sjpk goto done;
12501676Sjpk
12511676Sjpk /*
12521676Sjpk * If we don't have a label to compare with, or the IRE does not
12531676Sjpk * contain any gateway security attributes, there's not much that
12541676Sjpk * we can do. We let the former case pass, and the latter fail,
12551676Sjpk * since the IRE doesn't qualify for a match due to the lack of
12561676Sjpk * security attributes.
12571676Sjpk */
12581676Sjpk if (tsl == NULL || ire->ire_gw_secattr == NULL) {
12591676Sjpk if (tsl != NULL) {
126010934Ssommerfeld@sun.com DTRACE_PROBE3(
126110934Ssommerfeld@sun.com tx__ip__log__drop__irematch__nogwsec, char *,
126210934Ssommerfeld@sun.com "ire(1) lacks ire_gw_secattr when matching "
126310934Ssommerfeld@sun.com "label(2)", ire_t *, ire, ts_label_t *, tsl);
12641676Sjpk error = EACCES;
12651676Sjpk }
12661676Sjpk goto done;
12671676Sjpk }
12681676Sjpk
12691676Sjpk attrp = ire->ire_gw_secattr;
12701676Sjpk
12711676Sjpk /*
12721676Sjpk * The possible lock order scenarios related to the tsol gateway
12731676Sjpk * attribute locks are documented at the beginning of ip.c in the
12741676Sjpk * lock order scenario section.
12751676Sjpk */
12761676Sjpk mutex_enter(&attrp->igsa_lock);
12771676Sjpk
12781676Sjpk /*
127911042SErik.Nordmark@Sun.COM * We seek the group
12801676Sjpk * structure which contains all security credentials of the gateway.
128111042SErik.Nordmark@Sun.COM * An offline IRE is associated with at most one gateway credential.
12821676Sjpk */
128311042SErik.Nordmark@Sun.COM if ((gc = attrp->igsa_gc) != NULL) {
12841676Sjpk gcgrp = gc->gc_grp;
12851676Sjpk ASSERT(gcgrp != NULL);
12861676Sjpk rw_enter(&gcgrp->gcgrp_rwlock, RW_READER);
128711042SErik.Nordmark@Sun.COM GCGRP_REFHOLD(gcgrp);
12881676Sjpk }
12891676Sjpk
12901676Sjpk if ((gw_rhc = attrp->igsa_rhc) != NULL) {
12911676Sjpk /*
12921676Sjpk * If our cached entry has grown stale, then discard it so we
12931676Sjpk * can get a new one.
12941676Sjpk */
12951676Sjpk if (gw_rhc->rhc_invalid || gw_rhc->rhc_tpc->tpc_invalid) {
12961676Sjpk TNRHC_RELE(gw_rhc);
12971676Sjpk attrp->igsa_rhc = gw_rhc = NULL;
12981676Sjpk } else {
12991676Sjpk TNRHC_HOLD(gw_rhc)
13001676Sjpk }
13011676Sjpk }
13021676Sjpk
13031676Sjpk /* Last attempt at loading the template had failed; try again */
13041676Sjpk if (gw_rhc == NULL) {
13051676Sjpk if (gcgrp != NULL) {
13061676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
13071676Sjpk
13081676Sjpk if (ire->ire_ipversion == IPV4_VERSION) {
13091676Sjpk ASSERT(ga->ga_af == AF_INET);
13101676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
13111676Sjpk paddr = &ga_addr4;
13121676Sjpk } else {
13131676Sjpk ASSERT(ga->ga_af == AF_INET6);
13141676Sjpk paddr = &ga->ga_addr;
13151676Sjpk }
131611042SErik.Nordmark@Sun.COM } else if (ire->ire_type & IRE_OFFLINK) {
131711042SErik.Nordmark@Sun.COM if (ire->ire_ipversion == IPV6_VERSION)
131811042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr_v6;
131911042SErik.Nordmark@Sun.COM else if (ire->ire_ipversion == IPV4_VERSION)
132011042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr;
13211676Sjpk }
13221676Sjpk
13231676Sjpk /* We've found a gateway address to do the template lookup */
13241676Sjpk if (paddr != NULL) {
13251676Sjpk ASSERT(gw_rhc == NULL);
13263292Skp158701 gw_rhc = find_rhc(paddr, ire->ire_ipversion, B_FALSE);
13271676Sjpk if (gw_rhc != NULL) {
13281676Sjpk /*
13291676Sjpk * Note that if the lookup above returned an
13301676Sjpk * internal template, we'll use it for the
13311676Sjpk * time being, and do another lookup next
13321676Sjpk * time around.
13331676Sjpk */
13341676Sjpk /* Another thread has loaded the template? */
13351676Sjpk if (attrp->igsa_rhc != NULL) {
13361676Sjpk TNRHC_RELE(gw_rhc)
13371676Sjpk /* reload, it could be different */
13381676Sjpk gw_rhc = attrp->igsa_rhc;
13391676Sjpk } else {
13401676Sjpk attrp->igsa_rhc = gw_rhc;
13411676Sjpk }
13421676Sjpk /*
13431676Sjpk * Hold an extra reference just like we did
13441676Sjpk * above prior to dropping the igsa_lock.
13451676Sjpk */
13461676Sjpk TNRHC_HOLD(gw_rhc)
13471676Sjpk }
13481676Sjpk }
13491676Sjpk }
13501676Sjpk
13511676Sjpk mutex_exit(&attrp->igsa_lock);
13521676Sjpk /* Gateway template not found */
13531676Sjpk if (gw_rhc == NULL) {
13541676Sjpk /*
13551676Sjpk * If destination address is directly reachable through an
13561676Sjpk * interface rather than through a learned route, pass it.
13571676Sjpk */
13581676Sjpk if (paddr != NULL) {
13591676Sjpk DTRACE_PROBE3(
13601676Sjpk tx__ip__log__drop__irematch__nogwtmpl, char *,
13611676Sjpk "ire(1), label(2) off-link with no gw_rhc",
13621676Sjpk ire_t *, ire, ts_label_t *, tsl);
13631676Sjpk error = EINVAL;
13641676Sjpk }
13651676Sjpk goto done;
13661676Sjpk }
13671676Sjpk
13681676Sjpk if (gc != NULL) {
136911042SErik.Nordmark@Sun.COM
13701676Sjpk tsol_gcdb_t *gcdb;
13711676Sjpk /*
13721676Sjpk * In the case of IRE_CACHE we've got one or more gateway
13731676Sjpk * security credentials to compare against the passed in label.
13741676Sjpk * Perform label range comparison against each security
13751676Sjpk * credential of the gateway. In the case of a prefix ire
13761676Sjpk * we need to match against the security attributes of
13771676Sjpk * just the route itself, so the loop is executed only once.
13781676Sjpk */
13791676Sjpk ASSERT(gcgrp != NULL);
138011042SErik.Nordmark@Sun.COM gcdb = gc->gc_db;
138111042SErik.Nordmark@Sun.COM if (tsl->tsl_doi != gcdb->gcdb_doi ||
138211042SErik.Nordmark@Sun.COM !_blinrange(&tsl->tsl_label, &gcdb->gcdb_slrange)) {
13831676Sjpk DTRACE_PROBE3(
13841676Sjpk tx__ip__log__drop__irematch__nogcmatched,
13851676Sjpk char *, "ire(1), tsl(2): all gc failed match",
13861676Sjpk ire_t *, ire, ts_label_t *, tsl);
13871676Sjpk error = EACCES;
13881676Sjpk }
13891676Sjpk } else {
13901676Sjpk /*
13911676Sjpk * We didn't find any gateway credentials in the IRE
13921676Sjpk * attributes; fall back to the gateway's template for
13931676Sjpk * label range checks, if we are required to do so.
13941676Sjpk */
13951676Sjpk ASSERT(gw_rhc != NULL);
13961676Sjpk switch (gw_rhc->rhc_tpc->tpc_tp.host_type) {
13971676Sjpk case SUN_CIPSO:
13986596Skp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
13991676Sjpk (!_blinrange(&tsl->tsl_label,
14006596Skp158701 &gw_rhc->rhc_tpc->tpc_tp.tp_sl_range_cipso) &&
14011676Sjpk !blinlset(&tsl->tsl_label,
14021676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_sl_set_cipso))) {
14031676Sjpk error = EACCES;
14041676Sjpk DTRACE_PROBE4(
14051676Sjpk tx__ip__log__drop__irematch__deftmpl,
14061676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) "
14071676Sjpk "failed match (cipso gw)",
14081676Sjpk ire_t *, ire, ts_label_t *, tsl,
14091676Sjpk tsol_tnrhc_t *, gw_rhc);
14101676Sjpk }
14111676Sjpk break;
14121676Sjpk
14131676Sjpk case UNLABELED:
14146596Skp158701 if (tsl->tsl_doi != gw_rhc->rhc_tpc->tpc_tp.tp_doi ||
14151676Sjpk (!_blinrange(&tsl->tsl_label,
14161676Sjpk &gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_range) &&
14171676Sjpk !blinlset(&tsl->tsl_label,
14181676Sjpk gw_rhc->rhc_tpc->tpc_tp.tp_gw_sl_set))) {
14191676Sjpk error = EACCES;
14201676Sjpk DTRACE_PROBE4(
14211676Sjpk tx__ip__log__drop__irematch__deftmpl,
14221676Sjpk char *, "ire(1), tsl(2), gw_rhc(3) "
14231676Sjpk "failed match (unlabeled gw)",
14241676Sjpk ire_t *, ire, ts_label_t *, tsl,
14251676Sjpk tsol_tnrhc_t *, gw_rhc);
14261676Sjpk }
14271676Sjpk break;
14281676Sjpk }
14291676Sjpk }
14301676Sjpk
14311676Sjpk done:
14321676Sjpk
14331676Sjpk if (gcgrp != NULL) {
14341676Sjpk rw_exit(&gcgrp->gcgrp_rwlock);
14351676Sjpk GCGRP_REFRELE(gcgrp);
14361676Sjpk }
14371676Sjpk
14381676Sjpk if (gw_rhc != NULL)
14391676Sjpk TNRHC_RELE(gw_rhc)
14401676Sjpk
14411676Sjpk return (error);
14421676Sjpk }
14431676Sjpk
14441676Sjpk /*
14451676Sjpk * Performs label accreditation checks for packet forwarding.
144611042SErik.Nordmark@Sun.COM * Add or remove a CIPSO option as needed.
14471676Sjpk *
14481676Sjpk * Returns a pointer to the modified mblk if allowed for forwarding,
14491676Sjpk * or NULL if the packet must be dropped.
14501676Sjpk */
14511676Sjpk mblk_t *
tsol_ip_forward(ire_t * ire,mblk_t * mp,const ip_recv_attr_t * ira)145211042SErik.Nordmark@Sun.COM tsol_ip_forward(ire_t *ire, mblk_t *mp, const ip_recv_attr_t *ira)
14531676Sjpk {
14541676Sjpk tsol_ire_gw_secattr_t *attrp = NULL;
14551676Sjpk ipha_t *ipha;
14561676Sjpk ip6_t *ip6h;
14571676Sjpk const void *pdst;
14581676Sjpk const void *psrc;
14591676Sjpk boolean_t off_link;
14601676Sjpk tsol_tpc_t *dst_rhtp, *gw_rhtp;
14611676Sjpk tsol_ip_label_t label_type;
14621676Sjpk uchar_t *opt_ptr = NULL;
14631676Sjpk ts_label_t *tsl;
14641676Sjpk uint8_t proto;
14651676Sjpk int af, adjust;
14661676Sjpk uint16_t iplen;
14672535Ssangeeta boolean_t need_tpc_rele = B_FALSE;
14682535Ssangeeta ipaddr_t *gw;
14693448Sdh155122 ip_stack_t *ipst = ire->ire_ipst;
147011042SErik.Nordmark@Sun.COM int err;
147111042SErik.Nordmark@Sun.COM ts_label_t *effective_tsl = NULL;
14721676Sjpk
14731676Sjpk ASSERT(ire != NULL && mp != NULL);
147411042SErik.Nordmark@Sun.COM /*
147511042SErik.Nordmark@Sun.COM * Note that the ire is the first one found, i.e., an IRE_OFFLINK if
147611042SErik.Nordmark@Sun.COM * the destination is offlink.
147711042SErik.Nordmark@Sun.COM */
14781676Sjpk
14791676Sjpk af = (ire->ire_ipversion == IPV4_VERSION) ? AF_INET : AF_INET6;
14801676Sjpk
14811676Sjpk if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
14821676Sjpk ASSERT(ire->ire_ipversion == IPV4_VERSION);
14831676Sjpk ipha = (ipha_t *)mp->b_rptr;
14841676Sjpk psrc = &ipha->ipha_src;
14851676Sjpk pdst = &ipha->ipha_dst;
14861676Sjpk proto = ipha->ipha_protocol;
148710181SKen.Powell@Sun.COM if (!tsol_get_option_v4(mp, &label_type, &opt_ptr))
148810181SKen.Powell@Sun.COM return (NULL);
14891676Sjpk } else {
14901676Sjpk ASSERT(ire->ire_ipversion == IPV6_VERSION);
14911676Sjpk ip6h = (ip6_t *)mp->b_rptr;
14921676Sjpk psrc = &ip6h->ip6_src;
14931676Sjpk pdst = &ip6h->ip6_dst;
14941676Sjpk proto = ip6h->ip6_nxt;
14951676Sjpk
14961676Sjpk if (proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
14971676Sjpk proto != IPPROTO_ICMPV6) {
14981676Sjpk uint8_t *nexthdrp;
14991676Sjpk uint16_t hdr_len;
15001676Sjpk
15011676Sjpk if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len,
15021676Sjpk &nexthdrp)) {
15031676Sjpk /* malformed packet; drop it */
15041676Sjpk return (NULL);
15051676Sjpk }
15061676Sjpk proto = *nexthdrp;
15071676Sjpk }
150810181SKen.Powell@Sun.COM if (!tsol_get_option_v6(mp, &label_type, &opt_ptr))
150910181SKen.Powell@Sun.COM return (NULL);
15101676Sjpk }
151111042SErik.Nordmark@Sun.COM /*
151211042SErik.Nordmark@Sun.COM * off_link is TRUE if destination not directly reachable.
151311042SErik.Nordmark@Sun.COM */
151411042SErik.Nordmark@Sun.COM off_link = (ire->ire_type & IRE_OFFLINK);
15151676Sjpk
151611042SErik.Nordmark@Sun.COM if ((tsl = ira->ira_tsl) == NULL)
15171676Sjpk return (mp);
15181676Sjpk
151910934Ssommerfeld@sun.com if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
152010934Ssommerfeld@sun.com DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label,
152110934Ssommerfeld@sun.com char *,
152210934Ssommerfeld@sun.com "cannot forward packet mp(1) with unresolved "
152310934Ssommerfeld@sun.com "security label sl(2)",
152410934Ssommerfeld@sun.com mblk_t *, mp, ts_label_t *, tsl);
152510934Ssommerfeld@sun.com
152610934Ssommerfeld@sun.com return (NULL);
152710934Ssommerfeld@sun.com }
152810934Ssommerfeld@sun.com
152910934Ssommerfeld@sun.com
15301676Sjpk ASSERT(psrc != NULL && pdst != NULL);
15311676Sjpk dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
15321676Sjpk
15331676Sjpk if (dst_rhtp == NULL) {
15341676Sjpk /*
15351676Sjpk * Without a template we do not know if forwarding
15361676Sjpk * violates MAC
15371676Sjpk */
15381676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nodst, char *,
15391676Sjpk "mp(1) dropped, no template for destination ip4|6(2)",
15401676Sjpk mblk_t *, mp, void *, pdst);
15411676Sjpk return (NULL);
15421676Sjpk }
15431676Sjpk
15441676Sjpk /*
15451676Sjpk * Gateway template must have existed for off-link destinations,
15461676Sjpk * since tsol_ire_match_gwattr has ensured such condition.
15471676Sjpk */
15482535Ssangeeta if (ire->ire_ipversion == IPV4_VERSION && off_link) {
15492535Ssangeeta /*
15502535Ssangeeta * Surya note: first check if we can get the gw_rhtp from
15512535Ssangeeta * the ire_gw_secattr->igsa_rhc; if this is null, then
15522535Ssangeeta * do a lookup based on the ire_addr (address of gw)
15532535Ssangeeta */
15542535Ssangeeta if (ire->ire_gw_secattr != NULL &&
15552535Ssangeeta ire->ire_gw_secattr->igsa_rhc != NULL) {
15562535Ssangeeta attrp = ire->ire_gw_secattr;
15572535Ssangeeta gw_rhtp = attrp->igsa_rhc->rhc_tpc;
15582535Ssangeeta } else {
155911042SErik.Nordmark@Sun.COM gw = &ire->ire_gateway_addr;
15602535Ssangeeta gw_rhtp = find_tpc(gw, ire->ire_ipversion, B_FALSE);
15612535Ssangeeta need_tpc_rele = B_TRUE;
15622535Ssangeeta }
15632535Ssangeeta if (gw_rhtp == NULL) {
15642535Ssangeeta DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
15652535Ssangeeta "mp(1) dropped, no gateway in ire attributes(2)",
15662535Ssangeeta mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
15672535Ssangeeta mp = NULL;
15682535Ssangeeta goto keep_label;
15692535Ssangeeta }
15702535Ssangeeta }
15712535Ssangeeta if (ire->ire_ipversion == IPV6_VERSION &&
15722535Ssangeeta ((attrp = ire->ire_gw_secattr) == NULL || attrp->igsa_rhc == NULL ||
15731676Sjpk (gw_rhtp = attrp->igsa_rhc->rhc_tpc) == NULL) && off_link) {
15741676Sjpk DTRACE_PROBE3(tx__ip__log__drop__forward__nogw, char *,
15751676Sjpk "mp(1) dropped, no gateway in ire attributes(2)",
15761676Sjpk mblk_t *, mp, tsol_ire_gw_secattr_t *, attrp);
15771676Sjpk mp = NULL;
15781676Sjpk goto keep_label;
15791676Sjpk }
15801676Sjpk
15811676Sjpk /*
15821676Sjpk * Check that the label for the packet is acceptable
15831676Sjpk * by destination host; otherwise, drop it.
15841676Sjpk */
15851676Sjpk switch (dst_rhtp->tpc_tp.host_type) {
15861676Sjpk case SUN_CIPSO:
15871676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
15881676Sjpk (!_blinrange(&tsl->tsl_label,
15891676Sjpk &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
15901676Sjpk !blinlset(&tsl->tsl_label,
15911676Sjpk dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
15921676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
15931676Sjpk "labeled packet mp(1) dropped, label(2) fails "
15941676Sjpk "destination(3) accredation check",
15951676Sjpk mblk_t *, mp, ts_label_t *, tsl,
15961676Sjpk tsol_tpc_t *, dst_rhtp);
15971676Sjpk mp = NULL;
15981676Sjpk goto keep_label;
15991676Sjpk }
16001676Sjpk break;
16011676Sjpk
16021676Sjpk
16031676Sjpk case UNLABELED:
16041676Sjpk if (tsl->tsl_doi != dst_rhtp->tpc_tp.tp_doi ||
16051676Sjpk !blequal(&dst_rhtp->tpc_tp.tp_def_label,
16061676Sjpk &tsl->tsl_label)) {
16071676Sjpk DTRACE_PROBE4(tx__ip__log__drop__forward__mac, char *,
16081676Sjpk "unlabeled packet mp(1) dropped, label(2) fails "
16091676Sjpk "destination(3) accredation check",
16101676Sjpk mblk_t *, mp, ts_label_t *, tsl,
16111676Sjpk tsol_tpc_t *, dst_rhtp);
16121676Sjpk mp = NULL;
16131676Sjpk goto keep_label;
16141676Sjpk }
16151676Sjpk break;
16161676Sjpk }
16171676Sjpk if (label_type == OPT_CIPSO) {
16181676Sjpk /*
16191676Sjpk * We keep the label on any of the following cases:
16201676Sjpk *
16211676Sjpk * 1. The destination is labeled (on/off-link).
16221676Sjpk * 2. The unlabeled destination is off-link,
16231676Sjpk * and the next hop gateway is labeled.
16241676Sjpk */
16251676Sjpk if (dst_rhtp->tpc_tp.host_type != UNLABELED ||
16261676Sjpk (off_link &&
16271676Sjpk gw_rhtp->tpc_tp.host_type != UNLABELED))
16281676Sjpk goto keep_label;
16291676Sjpk
16301676Sjpk /*
16311676Sjpk * Strip off the CIPSO option from the packet because: the
16321676Sjpk * unlabeled destination host is directly reachable through
16331676Sjpk * an interface (on-link); or, the unlabeled destination host
16341676Sjpk * is not directly reachable (off-link), and the next hop
16351676Sjpk * gateway is unlabeled.
16361676Sjpk */
16371676Sjpk adjust = (af == AF_INET) ? tsol_remove_secopt(ipha, MBLKL(mp)) :
16381676Sjpk tsol_remove_secopt_v6(ip6h, MBLKL(mp));
16391676Sjpk
16401676Sjpk ASSERT(adjust <= 0);
16411676Sjpk if (adjust != 0) {
16421676Sjpk
16431676Sjpk /* adjust is negative */
16441676Sjpk ASSERT((mp->b_wptr + adjust) >= mp->b_rptr);
16451676Sjpk mp->b_wptr += adjust;
164611042SErik.Nordmark@Sun.COM /*
164711042SErik.Nordmark@Sun.COM * Note that caller adjusts ira_pktlen and
164811042SErik.Nordmark@Sun.COM * ira_ip_hdr_length
164911042SErik.Nordmark@Sun.COM *
165011042SErik.Nordmark@Sun.COM * For AF_INET6 note that tsol_remove_secopt_v6
165111042SErik.Nordmark@Sun.COM * adjusted ip6_plen.
165211042SErik.Nordmark@Sun.COM */
16531676Sjpk if (af == AF_INET) {
16541676Sjpk ipha = (ipha_t *)mp->b_rptr;
16551676Sjpk iplen = ntohs(ipha->ipha_length) + adjust;
16561676Sjpk ipha->ipha_length = htons(iplen);
16571676Sjpk ipha->ipha_hdr_checksum = 0;
16581676Sjpk ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
16591676Sjpk }
16601676Sjpk DTRACE_PROBE3(tx__ip__log__info__forward__adjust,
16611676Sjpk char *,
16621676Sjpk "mp(1) adjusted(2) for CIPSO option removal",
16631676Sjpk mblk_t *, mp, int, adjust);
16641676Sjpk }
16651676Sjpk goto keep_label;
16661676Sjpk }
16671676Sjpk
16681676Sjpk ASSERT(label_type == OPT_NONE);
16691676Sjpk ASSERT(dst_rhtp != NULL);
16701676Sjpk
16711676Sjpk /*
16721676Sjpk * We need to add CIPSO option if the destination or the next hop
16731676Sjpk * gateway is labeled. Otherwise, pass the packet as is.
16741676Sjpk */
16751676Sjpk if (dst_rhtp->tpc_tp.host_type == UNLABELED &&
16761676Sjpk (!off_link || gw_rhtp->tpc_tp.host_type == UNLABELED))
16771676Sjpk goto keep_label;
16781676Sjpk
167911042SErik.Nordmark@Sun.COM /*
168011042SErik.Nordmark@Sun.COM * Since we are forwarding packets we use GLOBAL_ZONEID for
168111042SErik.Nordmark@Sun.COM * the IRE lookup in tsol_check_label.
168211042SErik.Nordmark@Sun.COM * Since mac_exempt is false the zoneid isn't used for anything
168311042SErik.Nordmark@Sun.COM * but the IRE lookup, hence we set zone_is_global to false.
168411042SErik.Nordmark@Sun.COM */
168511042SErik.Nordmark@Sun.COM if (af == AF_INET) {
168611042SErik.Nordmark@Sun.COM err = tsol_check_label_v4(tsl, GLOBAL_ZONEID, &mp,
168711042SErik.Nordmark@Sun.COM CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl);
168811042SErik.Nordmark@Sun.COM } else {
168911042SErik.Nordmark@Sun.COM err = tsol_check_label_v6(tsl, GLOBAL_ZONEID, &mp,
169011042SErik.Nordmark@Sun.COM CONN_MAC_DEFAULT, B_FALSE, ipst, &effective_tsl);
169111042SErik.Nordmark@Sun.COM }
169211042SErik.Nordmark@Sun.COM if (err != 0) {
169311042SErik.Nordmark@Sun.COM BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
169411042SErik.Nordmark@Sun.COM ip_drop_output("tsol_check_label", mp, NULL);
169511042SErik.Nordmark@Sun.COM freemsg(mp);
16961676Sjpk mp = NULL;
16971676Sjpk goto keep_label;
16981676Sjpk }
16991676Sjpk
170011042SErik.Nordmark@Sun.COM /*
170111042SErik.Nordmark@Sun.COM * The effective_tsl must never affect the routing decision, hence
170211042SErik.Nordmark@Sun.COM * we ignore it here.
170311042SErik.Nordmark@Sun.COM */
170411042SErik.Nordmark@Sun.COM if (effective_tsl != NULL)
170511042SErik.Nordmark@Sun.COM label_rele(effective_tsl);
170611042SErik.Nordmark@Sun.COM
17076596Skp158701 if (af == AF_INET) {
17086596Skp158701 ipha = (ipha_t *)mp->b_rptr;
17096596Skp158701 ipha->ipha_hdr_checksum = 0;
17106596Skp158701 ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
17111676Sjpk }
17121676Sjpk
17131676Sjpk keep_label:
17141676Sjpk TPC_RELE(dst_rhtp);
17152535Ssangeeta if (need_tpc_rele && gw_rhtp != NULL)
17162535Ssangeeta TPC_RELE(gw_rhtp);
17171676Sjpk return (mp);
17181676Sjpk }
17191676Sjpk
17201676Sjpk /*
17214564Swy83408 * Name: tsol_pmtu_adjust()
17224564Swy83408 *
17234564Swy83408 * Returns the adjusted mtu after removing security option.
17244564Swy83408 * Removes/subtracts the option if the packet's cred indicates an unlabeled
17254564Swy83408 * sender or if pkt_diff indicates this system enlarged the packet.
17264564Swy83408 */
17274564Swy83408 uint32_t
tsol_pmtu_adjust(mblk_t * mp,uint32_t mtu,int pkt_diff,int af)17284564Swy83408 tsol_pmtu_adjust(mblk_t *mp, uint32_t mtu, int pkt_diff, int af)
17294564Swy83408 {
17304564Swy83408 int label_adj = 0;
17314564Swy83408 uint32_t min_mtu = IP_MIN_MTU;
17324564Swy83408 tsol_tpc_t *src_rhtp;
17334564Swy83408 void *src;
17344564Swy83408
17354564Swy83408 /*
17364564Swy83408 * Note: label_adj is non-positive, indicating the number of
17374564Swy83408 * bytes removed by removing the security option from the
17384564Swy83408 * header.
17394564Swy83408 */
17404564Swy83408 if (af == AF_INET6) {
17414564Swy83408 ip6_t *ip6h;
17424564Swy83408
17434564Swy83408 min_mtu = IPV6_MIN_MTU;
17444564Swy83408 ip6h = (ip6_t *)mp->b_rptr;
17454564Swy83408 src = &ip6h->ip6_src;
17464564Swy83408 if ((src_rhtp = find_tpc(src, IPV6_VERSION, B_FALSE)) == NULL)
17474564Swy83408 return (mtu);
17484564Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED) {
17494564Swy83408 label_adj = tsol_remove_secopt_v6(
17504564Swy83408 (ip6_t *)mp->b_rptr, MBLKL(mp));
17514564Swy83408 }
17524564Swy83408 } else {
17534564Swy83408 ipha_t *ipha;
17544564Swy83408
17554564Swy83408 ASSERT(af == AF_INET);
17564564Swy83408 ipha = (ipha_t *)mp->b_rptr;
17574564Swy83408 src = &ipha->ipha_src;
17584564Swy83408 if ((src_rhtp = find_tpc(src, IPV4_VERSION, B_FALSE)) == NULL)
17594564Swy83408 return (mtu);
17604564Swy83408 if (pkt_diff > 0 || src_rhtp->tpc_tp.host_type == UNLABELED)
17614564Swy83408 label_adj = tsol_remove_secopt(
17624564Swy83408 (ipha_t *)mp->b_rptr, MBLKL(mp));
17634564Swy83408 }
17644564Swy83408 /*
17654564Swy83408 * Make pkt_diff non-negative and the larger of the bytes
17664564Swy83408 * previously added (if any) or just removed, since label
17674564Swy83408 * addition + subtraction may not be completely idempotent.
17684564Swy83408 */
17694564Swy83408 if (pkt_diff < -label_adj)
17704564Swy83408 pkt_diff = -label_adj;
17714564Swy83408 if (pkt_diff > 0 && pkt_diff < mtu)
17724564Swy83408 mtu -= pkt_diff;
17734564Swy83408
17744564Swy83408 TPC_RELE(src_rhtp);
17754564Swy83408 return (MAX(mtu, min_mtu));
17764564Swy83408 }
17774564Swy83408
17784564Swy83408 /*
17791676Sjpk * Name: tsol_rtsa_init()
17801676Sjpk *
17811676Sjpk * Normal: Sanity checks on the route security attributes provided by
17821676Sjpk * user. Convert it into a route security parameter list to
17831676Sjpk * be returned to caller.
17841676Sjpk *
17851676Sjpk * Output: EINVAL if bad security attributes in the routing message
17861676Sjpk * ENOMEM if unable to allocate data structures
17871676Sjpk * 0 otherwise.
17881676Sjpk *
17891676Sjpk * Note: On input, cp must point to the end of any addresses in
17901676Sjpk * the rt_msghdr_t structure.
17911676Sjpk */
17921676Sjpk int
tsol_rtsa_init(rt_msghdr_t * rtm,tsol_rtsecattr_t * sp,caddr_t cp)17931676Sjpk tsol_rtsa_init(rt_msghdr_t *rtm, tsol_rtsecattr_t *sp, caddr_t cp)
17941676Sjpk {
17951676Sjpk uint_t sacnt;
17961676Sjpk int err;
17971676Sjpk caddr_t lim;
17981676Sjpk tsol_rtsecattr_t *tp;
17991676Sjpk
18001676Sjpk ASSERT((cp >= (caddr_t)&rtm[1]) && sp != NULL);
18011676Sjpk
18021676Sjpk /*
18031676Sjpk * In theory, we could accept as many security attributes configured
18041676Sjpk * per route destination. However, the current design is limited
18051676Sjpk * such that at most only one set security attributes is allowed to
18061676Sjpk * be associated with a prefix IRE. We therefore assert for now.
18071676Sjpk */
18081676Sjpk /* LINTED */
18091676Sjpk ASSERT(TSOL_RTSA_REQUEST_MAX == 1);
18101676Sjpk
18111676Sjpk sp->rtsa_cnt = 0;
18121676Sjpk lim = (caddr_t)rtm + rtm->rtm_msglen;
18131676Sjpk ASSERT(cp <= lim);
18141676Sjpk
18151676Sjpk if ((lim - cp) < sizeof (rtm_ext_t) ||
18161676Sjpk ((rtm_ext_t *)cp)->rtmex_type != RTMEX_GATEWAY_SECATTR)
18171676Sjpk return (0);
18181676Sjpk
18191676Sjpk if (((rtm_ext_t *)cp)->rtmex_len < sizeof (tsol_rtsecattr_t))
18201676Sjpk return (EINVAL);
18211676Sjpk
18221676Sjpk cp += sizeof (rtm_ext_t);
18231676Sjpk
18241676Sjpk if ((lim - cp) < sizeof (*tp) ||
18251676Sjpk (tp = (tsol_rtsecattr_t *)cp, (sacnt = tp->rtsa_cnt) == 0) ||
18261676Sjpk (lim - cp) < TSOL_RTSECATTR_SIZE(sacnt))
18271676Sjpk return (EINVAL);
18281676Sjpk
18291676Sjpk /*
18301676Sjpk * Trying to add route security attributes when system
18311676Sjpk * labeling service is not available, or when user supllies
18321676Sjpk * more than the maximum number of security attributes
18331676Sjpk * allowed per request.
18341676Sjpk */
18351676Sjpk if ((sacnt > 0 && !is_system_labeled()) ||
18361676Sjpk sacnt > TSOL_RTSA_REQUEST_MAX)
18371676Sjpk return (EINVAL);
18381676Sjpk
18391676Sjpk /* Ensure valid credentials */
18401676Sjpk if ((err = rtsa_validate(&((tsol_rtsecattr_t *)cp)->
18411676Sjpk rtsa_attr[0])) != 0) {
18421676Sjpk cp += sizeof (*sp);
18431676Sjpk return (err);
18441676Sjpk }
18451676Sjpk
18461676Sjpk bcopy(cp, sp, sizeof (*sp));
18471676Sjpk cp += sizeof (*sp);
18481676Sjpk return (0);
18491676Sjpk }
18501676Sjpk
18511676Sjpk int
tsol_ire_init_gwattr(ire_t * ire,uchar_t ipversion,tsol_gc_t * gc)185211042SErik.Nordmark@Sun.COM tsol_ire_init_gwattr(ire_t *ire, uchar_t ipversion, tsol_gc_t *gc)
18531676Sjpk {
18541676Sjpk tsol_ire_gw_secattr_t *attrp;
18551676Sjpk boolean_t exists = B_FALSE;
18561676Sjpk in_addr_t ga_addr4;
18571676Sjpk void *paddr = NULL;
185811042SErik.Nordmark@Sun.COM tsol_gcgrp_t *gcgrp = NULL;
18591676Sjpk
18601676Sjpk ASSERT(ire != NULL);
18611676Sjpk
18621676Sjpk /*
18631676Sjpk * The only time that attrp can be NULL is when this routine is
18641676Sjpk * called for the first time during the creation/initialization
18651676Sjpk * of the corresponding IRE. It will only get cleared when the
18661676Sjpk * IRE is deleted.
18671676Sjpk */
18681676Sjpk if ((attrp = ire->ire_gw_secattr) == NULL) {
18691676Sjpk attrp = ire_gw_secattr_alloc(KM_NOSLEEP);
18701676Sjpk if (attrp == NULL)
18711676Sjpk return (ENOMEM);
18721676Sjpk ire->ire_gw_secattr = attrp;
18731676Sjpk } else {
18741676Sjpk exists = B_TRUE;
18751676Sjpk mutex_enter(&attrp->igsa_lock);
18761676Sjpk
18771676Sjpk if (attrp->igsa_rhc != NULL) {
18781676Sjpk TNRHC_RELE(attrp->igsa_rhc);
18791676Sjpk attrp->igsa_rhc = NULL;
18801676Sjpk }
18811676Sjpk
18821676Sjpk if (attrp->igsa_gc != NULL)
18831676Sjpk GC_REFRELE(attrp->igsa_gc);
18841676Sjpk }
18851676Sjpk ASSERT(!exists || MUTEX_HELD(&attrp->igsa_lock));
18861676Sjpk
18871676Sjpk /*
18881676Sjpk * References already held by caller and we keep them;
188911042SErik.Nordmark@Sun.COM * note that gc may be set to NULL to clear out igsa_gc.
18901676Sjpk */
18911676Sjpk attrp->igsa_gc = gc;
18921676Sjpk
189311042SErik.Nordmark@Sun.COM if (gc != NULL) {
18941676Sjpk gcgrp = gc->gc_grp;
18951676Sjpk ASSERT(gcgrp != NULL);
18961676Sjpk }
18971676Sjpk
18981676Sjpk /*
18991676Sjpk * Intialize the template for gateway; we use the gateway's
19001676Sjpk * address found in either the passed in gateway credential
19011676Sjpk * or group pointer, or the ire_gateway_addr{_v6} field.
19021676Sjpk */
19031676Sjpk if (gcgrp != NULL) {
19041676Sjpk tsol_gcgrp_addr_t *ga = &gcgrp->gcgrp_addr;
19051676Sjpk
19061676Sjpk /*
19071676Sjpk * Caller is holding a reference, and that we don't
19081676Sjpk * need to hold any lock to access the address.
19091676Sjpk */
19101676Sjpk if (ipversion == IPV4_VERSION) {
19111676Sjpk ASSERT(ga->ga_af == AF_INET);
19121676Sjpk IN6_V4MAPPED_TO_IPADDR(&ga->ga_addr, ga_addr4);
19131676Sjpk paddr = &ga_addr4;
19141676Sjpk } else {
19151676Sjpk ASSERT(ga->ga_af == AF_INET6);
19161676Sjpk paddr = &ga->ga_addr;
19171676Sjpk }
191811042SErik.Nordmark@Sun.COM } else if (ire->ire_type & IRE_OFFLINK) {
191911042SErik.Nordmark@Sun.COM if (ipversion == IPV6_VERSION)
192011042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr_v6;
192111042SErik.Nordmark@Sun.COM else if (ipversion == IPV4_VERSION)
192211042SErik.Nordmark@Sun.COM paddr = &ire->ire_gateway_addr;
19231676Sjpk }
19241676Sjpk
19251676Sjpk /*
19261676Sjpk * Lookup the gateway template; note that we could get an internal
19271676Sjpk * template here, which we cache anyway. During IRE matching, we'll
19281676Sjpk * try to update this gateway template cache and hopefully get a
19291676Sjpk * real one.
19301676Sjpk */
19311676Sjpk if (paddr != NULL) {
19323292Skp158701 attrp->igsa_rhc = find_rhc(paddr, ipversion, B_FALSE);
19331676Sjpk }
19341676Sjpk
19351676Sjpk if (exists)
19361676Sjpk mutex_exit(&attrp->igsa_lock);
19371676Sjpk
19381676Sjpk return (0);
19391676Sjpk }
19401676Sjpk
19411676Sjpk /*
19421676Sjpk * This function figures the type of MLP that we'll be using based on the
19431676Sjpk * address that the user is binding and the zone. If the address is
19441676Sjpk * unspecified, then we're looking at both private and shared. If it's one
19451676Sjpk * of the zone's private addresses, then it's private only. If it's one
194610493SJarrett.Lu@Sun.COM * of the global addresses, then it's shared only. Multicast addresses are
194710493SJarrett.Lu@Sun.COM * treated same as unspecified address.
19481676Sjpk *
19491676Sjpk * If we can't figure out what it is, then return mlptSingle. That's actually
19501676Sjpk * an error case.
19513448Sdh155122 *
195211042SErik.Nordmark@Sun.COM * The callers are assumed to pass in zone->zone_id and not the zoneid that
19533448Sdh155122 * is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an
19543448Sdh155122 * exclusive stack zone).
19551676Sjpk */
19561676Sjpk mlp_type_t
tsol_mlp_addr_type(zoneid_t zoneid,uchar_t version,const void * addr,ip_stack_t * ipst)19573448Sdh155122 tsol_mlp_addr_type(zoneid_t zoneid, uchar_t version, const void *addr,
19583448Sdh155122 ip_stack_t *ipst)
19591676Sjpk {
19601676Sjpk in_addr_t in4;
19611676Sjpk ire_t *ire;
19621676Sjpk ipif_t *ipif;
19631676Sjpk zoneid_t addrzone;
19643448Sdh155122 zoneid_t ip_zoneid;
19651676Sjpk
19661676Sjpk ASSERT(addr != NULL);
19671676Sjpk
19683448Sdh155122 /*
19693448Sdh155122 * For exclusive stacks we set the zoneid to zero
19703448Sdh155122 * to operate as if in the global zone for IRE and conn_t comparisons.
19713448Sdh155122 */
19723448Sdh155122 if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
19733448Sdh155122 ip_zoneid = GLOBAL_ZONEID;
19743448Sdh155122 else
19753448Sdh155122 ip_zoneid = zoneid;
19763448Sdh155122
19771676Sjpk if (version == IPV6_VERSION &&
19781676Sjpk IN6_IS_ADDR_V4MAPPED((const in6_addr_t *)addr)) {
19791676Sjpk IN6_V4MAPPED_TO_IPADDR((const in6_addr_t *)addr, in4);
19801676Sjpk addr = &in4;
19811676Sjpk version = IPV4_VERSION;
19821676Sjpk }
19831676Sjpk
198411042SErik.Nordmark@Sun.COM /* Check whether the IRE_LOCAL (or ipif) is ALL_ZONES */
19851676Sjpk if (version == IPV4_VERSION) {
19861676Sjpk in4 = *(const in_addr_t *)addr;
198710493SJarrett.Lu@Sun.COM if ((in4 == INADDR_ANY) || CLASSD(in4)) {
19881676Sjpk return (mlptBoth);
19893448Sdh155122 }
199011042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v4(in4, 0, 0, IRE_LOCAL|IRE_LOOPBACK,
199111042SErik.Nordmark@Sun.COM NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY,
199211042SErik.Nordmark@Sun.COM 0, ipst, NULL);
19931676Sjpk } else {
199410493SJarrett.Lu@Sun.COM if (IN6_IS_ADDR_UNSPECIFIED((const in6_addr_t *)addr) ||
199510493SJarrett.Lu@Sun.COM IN6_IS_ADDR_MULTICAST((const in6_addr_t *)addr)) {
19961676Sjpk return (mlptBoth);
19973448Sdh155122 }
199811042SErik.Nordmark@Sun.COM ire = ire_ftable_lookup_v6(addr, 0, 0, IRE_LOCAL|IRE_LOOPBACK,
199911042SErik.Nordmark@Sun.COM NULL, ip_zoneid, NULL, MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY,
200011042SErik.Nordmark@Sun.COM 0, ipst, NULL);
20011676Sjpk }
20021676Sjpk /*
20031676Sjpk * If we can't find the IRE, then we have to behave exactly like
200411042SErik.Nordmark@Sun.COM * ip_laddr_verify_{v4,v6}. That means looking up the IPIF so that
200511042SErik.Nordmark@Sun.COM * users can bind to addresses on "down" interfaces.
20061676Sjpk *
20071676Sjpk * If we can't find that either, then the bind is going to fail, so
20081676Sjpk * just give up. Note that there's a miniscule chance that the address
20091676Sjpk * is in transition, but we don't bother handling that.
20101676Sjpk */
20111676Sjpk if (ire == NULL) {
20121676Sjpk if (version == IPV4_VERSION)
20131676Sjpk ipif = ipif_lookup_addr(*(const in_addr_t *)addr, NULL,
201411042SErik.Nordmark@Sun.COM ip_zoneid, ipst);
20151676Sjpk else
20161676Sjpk ipif = ipif_lookup_addr_v6((const in6_addr_t *)addr,
201711042SErik.Nordmark@Sun.COM NULL, ip_zoneid, ipst);
20183448Sdh155122 if (ipif == NULL) {
20191676Sjpk return (mlptSingle);
20203448Sdh155122 }
20211676Sjpk addrzone = ipif->ipif_zoneid;
20221676Sjpk ipif_refrele(ipif);
20231676Sjpk } else {
20241676Sjpk addrzone = ire->ire_zoneid;
20251676Sjpk ire_refrele(ire);
20261676Sjpk }
20271676Sjpk return (addrzone == ALL_ZONES ? mlptShared : mlptPrivate);
20281676Sjpk }
20291676Sjpk
20301676Sjpk /*
20311676Sjpk * Since we are configuring local interfaces, and we know trusted
20321676Sjpk * extension CDE requires local interfaces to be cipso host type in
20331676Sjpk * order to function correctly, we'll associate a cipso template
20341676Sjpk * to each local interface and let the interface come up. Configuring
20351676Sjpk * a local interface to be "unlabeled" host type is a configuration error.
20361676Sjpk * We'll override that error and make the interface host type to be cipso
20371676Sjpk * here.
20381676Sjpk *
20391676Sjpk * The code is optimized for the usual "success" case and unwinds things on
20401676Sjpk * error. We don't want to go to the trouble and expense of formatting the
20411676Sjpk * interface name for the usual case where everything is configured correctly.
20421676Sjpk */
20431676Sjpk boolean_t
tsol_check_interface_address(const ipif_t * ipif)20441676Sjpk tsol_check_interface_address(const ipif_t *ipif)
20451676Sjpk {
20461676Sjpk tsol_tpc_t *tp;
20471676Sjpk char addrbuf[INET6_ADDRSTRLEN];
20481676Sjpk int af;
20491676Sjpk const void *addr;
20501676Sjpk zone_t *zone;
20511676Sjpk ts_label_t *plabel;
20521676Sjpk const bslabel_t *label;
2053*11220SGirish.Moodalbail@Sun.COM char ifname[LIFNAMSIZ];
20541676Sjpk boolean_t retval;
20551676Sjpk tsol_rhent_t rhent;
20563448Sdh155122 netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack;
20571676Sjpk
20581676Sjpk if (IN6_IS_ADDR_V4MAPPED(&ipif->ipif_v6lcl_addr)) {
20591676Sjpk af = AF_INET;
20601676Sjpk addr = &V4_PART_OF_V6(ipif->ipif_v6lcl_addr);
20611676Sjpk } else {
20621676Sjpk af = AF_INET6;
20631676Sjpk addr = &ipif->ipif_v6lcl_addr;
20641676Sjpk }
20651676Sjpk
20661676Sjpk tp = find_tpc(&ipif->ipif_v6lcl_addr, IPV6_VERSION, B_FALSE);
20673448Sdh155122
20683448Sdh155122 /* assumes that ALL_ZONES implies that there is no exclusive stack */
20693448Sdh155122 if (ipif->ipif_zoneid == ALL_ZONES) {
20703448Sdh155122 zone = NULL;
20713448Sdh155122 } else if (ns->netstack_stackid == GLOBAL_NETSTACKID) {
20723448Sdh155122 /* Shared stack case */
20733448Sdh155122 zone = zone_find_by_id(ipif->ipif_zoneid);
20743448Sdh155122 } else {
20753448Sdh155122 /* Exclusive stack case */
20763448Sdh155122 zone = zone_find_by_id(crgetzoneid(ipif->ipif_ill->ill_credp));
20773448Sdh155122 }
20781676Sjpk if (zone != NULL) {
20791676Sjpk plabel = zone->zone_slabel;
20801676Sjpk ASSERT(plabel != NULL);
20811676Sjpk label = label2bslabel(plabel);
20821676Sjpk }
20831676Sjpk
20841676Sjpk /*
20851676Sjpk * If it's CIPSO and an all-zones address, then we're done.
20861676Sjpk * If it's a CIPSO zone specific address, the zone's label
20871676Sjpk * must be in the range or set specified in the template.
20881676Sjpk * When the remote host entry is missing or the template
20891676Sjpk * type is incorrect for this interface, we create a
20901676Sjpk * CIPSO host entry in kernel and allow the interface to be
20911676Sjpk * brought up as CIPSO type.
20921676Sjpk */
20931676Sjpk if (tp != NULL && (
20941676Sjpk /* The all-zones case */
20951676Sjpk (tp->tpc_tp.host_type == SUN_CIPSO &&
20961676Sjpk tp->tpc_tp.tp_doi == default_doi &&
20971676Sjpk ipif->ipif_zoneid == ALL_ZONES) ||
20981676Sjpk /* The local-zone case */
20991676Sjpk (zone != NULL && plabel->tsl_doi == tp->tpc_tp.tp_doi &&
21001676Sjpk ((tp->tpc_tp.host_type == SUN_CIPSO &&
21011676Sjpk (_blinrange(label, &tp->tpc_tp.tp_sl_range_cipso) ||
21021676Sjpk blinlset(label, tp->tpc_tp.tp_sl_set_cipso))))))) {
21031676Sjpk if (zone != NULL)
21041676Sjpk zone_rele(zone);
21051676Sjpk TPC_RELE(tp);
21061676Sjpk return (B_TRUE);
21071676Sjpk }
21081676Sjpk
2109*11220SGirish.Moodalbail@Sun.COM ipif_get_name(ipif, ifname, sizeof (ifname));
21101676Sjpk (void) inet_ntop(af, addr, addrbuf, sizeof (addrbuf));
21111676Sjpk
21121676Sjpk if (tp == NULL) {
21131676Sjpk cmn_err(CE_NOTE, "template entry for %s missing. Default to "
21141676Sjpk "CIPSO type for %s", ifname, addrbuf);
21151676Sjpk retval = B_TRUE;
21161676Sjpk } else if (tp->tpc_tp.host_type == UNLABELED) {
21171676Sjpk cmn_err(CE_NOTE, "template type for %s incorrectly configured. "
21181676Sjpk "Change to CIPSO type for %s", ifname, addrbuf);
21191676Sjpk retval = B_TRUE;
21201676Sjpk } else if (ipif->ipif_zoneid == ALL_ZONES) {
21211676Sjpk if (tp->tpc_tp.host_type != SUN_CIPSO) {
21221676Sjpk cmn_err(CE_NOTE, "%s failed: %s isn't set to CIPSO for "
21231676Sjpk "all-zones. Converted to CIPSO.", ifname, addrbuf);
21241676Sjpk retval = B_TRUE;
21251676Sjpk } else {
21261676Sjpk cmn_err(CE_NOTE, "%s failed: %s has wrong DOI %d "
21271676Sjpk "instead of %d", ifname, addrbuf,
21281676Sjpk tp->tpc_tp.tp_doi, default_doi);
21291676Sjpk retval = B_FALSE;
21301676Sjpk }
21311676Sjpk } else if (zone == NULL) {
21321676Sjpk cmn_err(CE_NOTE, "%s failed: zoneid %d unknown",
21331676Sjpk ifname, ipif->ipif_zoneid);
21341676Sjpk retval = B_FALSE;
21351676Sjpk } else if (plabel->tsl_doi != tp->tpc_tp.tp_doi) {
21361676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s has DOI %d but %s has "
21371676Sjpk "DOI %d", ifname, zone->zone_name, plabel->tsl_doi,
21381676Sjpk addrbuf, tp->tpc_tp.tp_doi);
21391676Sjpk retval = B_FALSE;
21401676Sjpk } else {
21411676Sjpk cmn_err(CE_NOTE, "%s failed: zone %s label incompatible with "
21421676Sjpk "%s", ifname, zone->zone_name, addrbuf);
21431676Sjpk tsol_print_label(label, "zone label");
21441676Sjpk retval = B_FALSE;
21451676Sjpk }
21461676Sjpk
21471676Sjpk if (zone != NULL)
21481676Sjpk zone_rele(zone);
21491676Sjpk if (tp != NULL)
21501676Sjpk TPC_RELE(tp);
21511676Sjpk if (retval) {
21521676Sjpk /*
21531676Sjpk * we've corrected a config error and let the interface
21541676Sjpk * come up as cipso. Need to insert an rhent.
21551676Sjpk */
21561676Sjpk if ((rhent.rh_address.ta_family = af) == AF_INET) {
21571676Sjpk rhent.rh_prefix = 32;
21581676Sjpk rhent.rh_address.ta_addr_v4 = *(struct in_addr *)addr;
21591676Sjpk } else {
21601676Sjpk rhent.rh_prefix = 128;
21611676Sjpk rhent.rh_address.ta_addr_v6 = *(in6_addr_t *)addr;
21621676Sjpk }
21631676Sjpk (void) strcpy(rhent.rh_template, "cipso");
21641676Sjpk if (tnrh_load(&rhent) != 0) {
21651676Sjpk cmn_err(CE_NOTE, "%s failed: Cannot insert CIPSO "
21661676Sjpk "template for local addr %s", ifname, addrbuf);
21671676Sjpk retval = B_FALSE;
21681676Sjpk }
21691676Sjpk }
21701676Sjpk return (retval);
21711676Sjpk }
2172