Home | History | Annotate | Download | only in ip
      1   1676         jpk /*
      2   1676         jpk  * CDDL HEADER START
      3   1676         jpk  *
      4   1676         jpk  * The contents of this file are subject to the terms of the
      5   1676         jpk  * Common Development and Distribution License (the "License").
      6   1676         jpk  * You may not use this file except in compliance with the License.
      7   1676         jpk  *
      8   1676         jpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9   1676         jpk  * or http://www.opensolaris.org/os/licensing.
     10   1676         jpk  * See the License for the specific language governing permissions
     11   1676         jpk  * and limitations under the License.
     12   1676         jpk  *
     13   1676         jpk  * When distributing Covered Code, include this CDDL HEADER in each
     14   1676         jpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15   1676         jpk  * If applicable, add the following below this CDDL HEADER, with the
     16   1676         jpk  * fields enclosed by brackets "[]" replaced with your own identifying
     17   1676         jpk  * information: Portions Copyright [yyyy] [name of copyright owner]
     18   1676         jpk  *
     19   1676         jpk  * CDDL HEADER END
     20   1676         jpk  */
     21   1676         jpk /*
     22   8778        Erik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23   1676         jpk  * Use is subject to license terms.
     24   1676         jpk  */
     25   1676         jpk 
     26   1676         jpk #include <sys/types.h>
     27   1676         jpk #include <sys/systm.h>
     28   1676         jpk #include <sys/kmem.h>
     29   1676         jpk #include <sys/disp.h>
     30   1676         jpk #include <sys/stream.h>
     31   1676         jpk #include <sys/strsubr.h>
     32   1676         jpk #include <sys/strsun.h>
     33   1676         jpk #include <sys/policy.h>
     34   1676         jpk #include <sys/tsol/label_macro.h>
     35   1676         jpk #include <sys/tsol/tndb.h>
     36   1676         jpk #include <sys/tsol/tnet.h>
     37   1676         jpk #include <inet/ip.h>
     38   1676         jpk #include <inet/ip6.h>
     39   1676         jpk #include <inet/tcp.h>
     40   1676         jpk #include <inet/ipclassifier.h>
     41   1676         jpk #include <inet/ip_ire.h>
     42   2535    sangeeta #include <inet/ip_ftable.h>
     43   1676         jpk 
     44   1676         jpk /*
     45   1676         jpk  * This routine takes a sensitivity label as input and creates a CIPSO
     46   1676         jpk  * option in the specified buffer.  It returns the size of the CIPSO option.
     47   1676         jpk  * If the sensitivity label is too large for the CIPSO option, then 0
     48   1676         jpk  * is returned.
     49   1676         jpk  *
     50   1676         jpk  * tsol2cipso_tt1 returns 0 for failure and greater than 0 for success
     51   1676         jpk  * (more accurately, success means a return value between 10 and 40).
     52   1676         jpk  */
     53   1676         jpk 
     54   1676         jpk static int
     55   1676         jpk tsol2cipso_tt1(const bslabel_t *sl, unsigned char *cop, uint32_t doi)
     56   1676         jpk {
     57   1676         jpk 	struct cipso_tag_type_1 *tt1;
     58   1676         jpk 	const _bslabel_impl_t *bsl;
     59   1676         jpk 	const uchar_t *ucp;
     60   1676         jpk 	int i;
     61   1676         jpk 
     62   1676         jpk 	if (doi == 0)
     63   1676         jpk 		return (0);
     64   1676         jpk 
     65   1676         jpk 	/* check for Admin High sensitivity label */
     66   1676         jpk 	if (blequal(sl, label2bslabel(l_admin_high)))
     67   1676         jpk 		return (0);
     68   1676         jpk 
     69   1676         jpk 	/* check whether classification will fit in one octet */
     70   1676         jpk 	bsl = (const _bslabel_impl_t *)sl;
     71   1676         jpk 	if (LCLASS(bsl) & 0xFF00)
     72   1676         jpk 		return (0);
     73   1676         jpk 
     74   1676         jpk 	/*
     75   1676         jpk 	 * Check whether compartments will fit in 30 octets.
     76   1676         jpk 	 * Compartments 241 - 256 are not allowed.
     77   1676         jpk 	 */
     78   1676         jpk 	if (ntohl(bsl->compartments.c8) & 0x0000FFFF)
     79   1676         jpk 		return (0);
     80   1676         jpk 
     81   1676         jpk 	/*
     82   1676         jpk 	 * Compute option length and tag length.
     83   1676         jpk 	 * 'p' points to the last two bytes in the Sensitivity Label's
     84   1676         jpk 	 * compartments; these cannot be mapped into CIPSO compartments.
     85   1676         jpk 	 */
     86   1676         jpk 	ucp = (const uchar_t *)&bsl->compartments.c8 + 2;
     87   1676         jpk 	while (--ucp >= (const uchar_t *)&bsl->compartments.c1)
     88   1676         jpk 		if (*ucp != 0)
     89   1676         jpk 			break;
     90   1676         jpk 
     91   1676         jpk 	i =  ucp - (const uchar_t *)&bsl->compartments.c1 + 1;
     92   1676         jpk 
     93   1676         jpk 	if (cop == NULL)
     94   1676         jpk 		return (10 + i);
     95   1676         jpk 
     96   1676         jpk 	doi = htonl(doi);
     97   1676         jpk 	ucp = (const uchar_t *)&doi;
     98   1676         jpk 	cop[IPOPT_OPTVAL] = IPOPT_COMSEC;
     99   1676         jpk 	cop[IPOPT_OLEN] = 10 + i;
    100   1676         jpk 	cop[IPOPT_OLEN+1] = ucp[0];
    101   1676         jpk 	cop[IPOPT_OLEN+2] = ucp[1];
    102   1676         jpk 	cop[IPOPT_OLEN+3] = ucp[2];
    103   1676         jpk 	cop[IPOPT_OLEN+4] = ucp[3];
    104   1676         jpk 	tt1 = (struct cipso_tag_type_1 *)&cop[IPOPT_OLEN + 5];
    105   1676         jpk 	tt1->tag_type = 1;
    106   1676         jpk 	tt1->tag_align = 0;
    107   1676         jpk 	tt1->tag_sl = LCLASS(bsl);
    108   1676         jpk 	tt1->tag_length = 4 + i;
    109   1676         jpk 
    110   1676         jpk 	bcopy(&bsl->compartments.c1, tt1->tag_cat, i);
    111   1676         jpk 
    112   1676         jpk 	return (cop[IPOPT_OLEN]);
    113   1676         jpk }
    114   1676         jpk 
    115   1676         jpk /*
    116  10181         Ken  * The following routine searches for a security label in an IPv4 datagram.
    117  10181         Ken  * It returns label_type of:
    118  10181         Ken  *    OPT_CIPSO if a CIPSO IP option is found.
    119  10181         Ken  *    OPT_NONE if no security label is found.
    120   1676         jpk  *
    121  10181         Ken  * If OPT_CIPSO, a pointer to the CIPSO IP option will be returned in
    122  10181         Ken  * the buffer parameter.
    123  10181         Ken  *
    124  10181         Ken  * The function will return with B_FALSE if an IP format error
    125  10181         Ken  * is encountered.
    126   1676         jpk  */
    127   1676         jpk 
    128  10181         Ken boolean_t
    129  10181         Ken tsol_get_option_v4(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer)
    130   1676         jpk {
    131   1676         jpk 	ipha_t	*ipha;
    132   1676         jpk 	uchar_t	*opt;
    133   1676         jpk 	uint32_t	totallen;
    134   1676         jpk 	uint32_t	optval;
    135   1676         jpk 	uint32_t	optlen;
    136   1676         jpk 
    137  10181         Ken 	*label_type = OPT_NONE;
    138   1676         jpk 
    139   1676         jpk 	/*
    140   1676         jpk 	 * Get length (in 4 byte octets) of IP header options.
    141  10181         Ken 	 * If header doesn't contain options, then return a label_type
    142  10181         Ken 	 * of OPT_NONE.
    143   1676         jpk 	 */
    144  10181         Ken 	ipha = (ipha_t *)mp->b_rptr;
    145   1676         jpk 	totallen = ipha->ipha_version_and_hdr_length -
    146  10181         Ken 	    (uint8_t)((IP_VERSION << 4));
    147  10181         Ken 	totallen <<= 2;
    148  10181         Ken 	if (totallen < IP_SIMPLE_HDR_LENGTH || totallen > MBLKL(mp))
    149  10181         Ken 		return (B_FALSE);
    150  10181         Ken 	totallen -= IP_SIMPLE_HDR_LENGTH;
    151   1676         jpk 	if (totallen == 0)
    152  10181         Ken 		return (B_TRUE);
    153   1676         jpk 
    154   1676         jpk 	/*
    155   1676         jpk 	 * Search for CIPSO option.
    156   1676         jpk 	 * If no such option is present, then return OPT_NONE.
    157   1676         jpk 	 */
    158   1676         jpk 	opt = (uchar_t *)&ipha[1];
    159   1676         jpk 	while (totallen != 0) {
    160   1676         jpk 		switch (optval = opt[IPOPT_OPTVAL]) {
    161   1676         jpk 		case IPOPT_EOL:
    162  10181         Ken 			return (B_TRUE);
    163   1676         jpk 		case IPOPT_NOP:
    164   1676         jpk 			optlen = 1;
    165   1676         jpk 			break;
    166   1676         jpk 		default:
    167   1676         jpk 			if (totallen <= IPOPT_OLEN)
    168  10181         Ken 				return (B_FALSE);
    169   1676         jpk 			optlen = opt[IPOPT_OLEN];
    170   1676         jpk 			if (optlen < 2)
    171  10181         Ken 				return (B_FALSE);
    172   1676         jpk 		}
    173   1676         jpk 		if (optlen > totallen)
    174  10181         Ken 			return (B_FALSE);
    175   1676         jpk 		/*
    176   1676         jpk 		 * Copy pointer to option into '*buffer' and
    177   1676         jpk 		 * return the option type.
    178   1676         jpk 		 */
    179   1676         jpk 		switch (optval) {
    180   1676         jpk 		case IPOPT_COMSEC:
    181   1676         jpk 			if (TSOL_CIPSO_TAG_OFFSET < optlen &&
    182  10181         Ken 			    opt[TSOL_CIPSO_TAG_OFFSET] == 1) {
    183  10181         Ken 				*label_type = OPT_CIPSO;
    184  10181         Ken 				*buffer = opt;
    185  10181         Ken 				return (B_TRUE);
    186  10181         Ken 			}
    187  10181         Ken 			return (B_FALSE);
    188   1676         jpk 		}
    189   1676         jpk 		totallen -= optlen;
    190   1676         jpk 		opt += optlen;
    191   1676         jpk 	}
    192  10181         Ken 	return (B_TRUE);
    193  10181         Ken }
    194  10181         Ken 
    195  10181         Ken /*
    196  10181         Ken  * The following routine searches for a security label in an IPv6 datagram.
    197  10181         Ken  * It returns label_type of:
    198  10181         Ken  *    OPT_CIPSO if a CIPSO IP option is found.
    199  10181         Ken  *    OPT_NONE if no security label is found.
    200  10181         Ken  *
    201  10181         Ken  * If OPT_CIPSO, a pointer to the IPv4 portion of the CIPSO IP option will
    202  10181         Ken  * be returned in the buffer parameter.
    203  10181         Ken  *
    204  10181         Ken  * The function will return with B_FALSE if an IP format error
    205  10181         Ken  * or an unexpected label content error is encountered.
    206  10181         Ken  */
    207  10181         Ken 
    208  10181         Ken boolean_t
    209  10181         Ken tsol_get_option_v6(mblk_t *mp, tsol_ip_label_t *label_type, uchar_t **buffer)
    210  10181         Ken {
    211  10181         Ken 	uchar_t		*opt_ptr = NULL;
    212  10181         Ken 	uchar_t		*after_secopt;
    213  10181         Ken 	boolean_t	hbh_needed;
    214  10181         Ken 	const uchar_t	*ip6hbh;
    215  10181         Ken 	size_t		optlen;
    216  10181         Ken 	uint32_t	doi;
    217  10181         Ken 	const ip6_t	*ip6h;
    218  10181         Ken 
    219  10181         Ken 	*label_type = OPT_NONE;
    220  10181         Ken 	*buffer = NULL;
    221  10181         Ken 	ip6h = (const ip6_t *)mp->b_rptr;
    222  10181         Ken 	if (ip6h->ip6_nxt != IPPROTO_HOPOPTS)
    223  10181         Ken 		return (B_TRUE);
    224  10181         Ken 	ip6hbh = (const uchar_t *)&ip6h[1];
    225  10181         Ken 	if (ip6hbh + MIN_EHDR_LEN > mp->b_wptr)
    226  10181         Ken 		return (B_FALSE);
    227  10181         Ken 	optlen = (ip6hbh[1] + 1) << 3;
    228  10181         Ken 	if (ip6hbh + optlen > mp->b_wptr)
    229  10181         Ken 		return (B_FALSE);
    230  10181         Ken 	if (!tsol_find_secopt_v6(ip6hbh, optlen,
    231  10181         Ken 	    &opt_ptr, &after_secopt, &hbh_needed))
    232  10181         Ken 		return (B_FALSE);
    233  10181         Ken 	/* tsol_find_secopt_v6 guarantees some sanity */
    234  10181         Ken 	if (opt_ptr != NULL) {
    235  10181         Ken 		/*
    236  10181         Ken 		 * IPv6 Option
    237  10181         Ken 		 *   opt_ptr[0]: Option type
    238  10181         Ken 		 *   opt_ptr[1]: Length of option data in bytes
    239  10181         Ken 		 *   opt_ptr[2]: First byte of option data
    240  10181         Ken 		 */
    241  10181         Ken 		if ((optlen = opt_ptr[1]) < 8)
    242  10181         Ken 			return (B_FALSE);
    243  10181         Ken 		opt_ptr += 2;
    244  10181         Ken 		/*
    245  10181         Ken 		 * From "Generalized Labeled Security Option for IPv6" draft
    246  10181         Ken 		 *   opt_ptr[0] - opt_ptr[4]: DOI = IP6LS_DOI_V4
    247  10181         Ken 		 *   opt_ptr[4]: Tag type = IP6LS_TT_V4
    248  10181         Ken 		 *   opt_ptr[5]: Tag length in bytes starting at Tag type field
    249  10181         Ken 		 * IPv4 CIPSO Option
    250  10181         Ken 		 *   opt_ptr[6]: option type
    251  10181         Ken 		 *   opt_ptr[7]: option length in bytes starting at type field
    252  10181         Ken 		 */
    253  10181         Ken 		bcopy(opt_ptr, &doi, sizeof (doi));
    254  10181         Ken 		doi = ntohl(doi);
    255  10181         Ken 		if (doi == IP6LS_DOI_V4 &&
    256  10181         Ken 		    opt_ptr[4] == IP6LS_TT_V4 &&
    257  10181         Ken 		    opt_ptr[5] <= optlen - 4 &&
    258  10181         Ken 		    opt_ptr[7] <= optlen - 6 &&
    259  10181         Ken 		    opt_ptr[7] <= opt_ptr[5] - 2) {
    260  10181         Ken 			opt_ptr += sizeof (doi) + 2;
    261  10181         Ken 			*label_type = OPT_CIPSO;
    262  10181         Ken 			*buffer = opt_ptr;
    263  10181         Ken 			return (B_TRUE);
    264  10181         Ken 		}
    265  10181         Ken 		return (B_FALSE);
    266  10181         Ken 	}
    267  10181         Ken 	return (B_TRUE);
    268   1676         jpk }
    269   1676         jpk 
    270   1676         jpk /*
    271   9710         Ken  * tsol_check_dest()
    272   9710         Ken  *
    273   9710         Ken  * This routine verifies if a destination is allowed to recieve messages
    274  11042        Erik  * based on the security label. If any adjustments to the label are needed
    275  11042        Erik  * due to the connection's MAC mode or the destination's ability
    276  11042        Erik  * to receive labels, an "effective label" will be returned.
    277   9710         Ken  *
    278  11042        Erik  * zone_is_global is set if the actual zoneid is global. That is, it is
    279  11042        Erik  * not set for an exclusive-IP zone.
    280  11042        Erik  *
    281  11042        Erik  * On successful return, effective_tsl will point to the new label needed
    282  11042        Erik  * or will be NULL if a new label isn't needed. On error, effective_tsl will
    283  11042        Erik  * point to NULL.
    284   9710         Ken  *
    285   9710         Ken  * Returns:
    286  11042        Erik  *      0		Label (was|is now) correct
    287  11042        Erik  *	EHOSTUNREACH	The label failed the remote host accreditation
    288   9710         Ken  *      ENOMEM		Memory allocation failure
    289   9710         Ken  */
    290   9710         Ken int
    291  11042        Erik tsol_check_dest(const ts_label_t *tsl, const void *dst,
    292  11042        Erik     uchar_t version, uint_t mac_mode, boolean_t zone_is_global,
    293  11042        Erik     ts_label_t **effective_tsl)
    294   9710         Ken {
    295  11042        Erik 	ts_label_t	*newtsl = NULL;
    296   9710         Ken 	tsol_tpc_t	*dst_rhtp;
    297   9710         Ken 
    298  11042        Erik 	if (effective_tsl != NULL)
    299  11042        Erik 		*effective_tsl = NULL;
    300   9710         Ken 	ASSERT(version == IPV4_VERSION ||
    301   9710         Ken 	    (version == IPV6_VERSION &&
    302   9710         Ken 	    !IN6_IS_ADDR_V4MAPPED((in6_addr_t *)dst)));
    303   9710         Ken 
    304   9710         Ken 	/* Always pass kernel level communication (NULL label) */
    305  11042        Erik 	if (tsl == NULL) {
    306   9710         Ken 		DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allownull,
    307  11042        Erik 		    char *, "destination ip(1) with null label was passed",
    308   9710         Ken 		    ipaddr_t, dst);
    309   9710         Ken 		return (0);
    310  10934  sommerfeld 	}
    311  10934  sommerfeld 
    312  10934  sommerfeld 	if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
    313  10934  sommerfeld 		DTRACE_PROBE3(tx__tnopt__log__info__labeling__unresolved__label,
    314  10934  sommerfeld 		    char *,
    315  10934  sommerfeld 		    "implicit-in packet to ip(1) reached tsol_check_dest "
    316  10934  sommerfeld 		    "with implied security label sl(2)",
    317  10934  sommerfeld 		    ipaddr_t, dst, ts_label_t *, tsl);
    318   9710         Ken 	}
    319   9710         Ken 
    320   9710         Ken 	/* Always pass multicast */
    321   9710         Ken 	if (version == IPV4_VERSION &&
    322   9710         Ken 	    CLASSD(*(ipaddr_t *)dst)) {
    323   9710         Ken 		DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult,
    324   9710         Ken 		    char *, "destination ip(1) with multicast dest was passed",
    325   9710         Ken 		    ipaddr_t, dst);
    326   9710         Ken 		return (0);
    327   9710         Ken 	} else if (version == IPV6_VERSION &&
    328   9710         Ken 	    IN6_IS_ADDR_MULTICAST((in6_addr_t *)dst)) {
    329   9710         Ken 		DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult_v6,
    330   9710         Ken 		    char *, "destination ip(1) with multicast dest was passed",
    331   9710         Ken 		    in6_addr_t *, dst);
    332   9710         Ken 		return (0);
    333   9710         Ken 	}
    334   9710         Ken 
    335   9710         Ken 	/* Never pass an undefined destination */
    336   9710         Ken 	if ((dst_rhtp = find_tpc(dst, version, B_FALSE)) == NULL) {
    337   9710         Ken 		DTRACE_PROBE2(tx__tnopt__log__info__labeling__lookupdst,
    338   9710         Ken 		    char *, "destination ip(1) not in tn database.",
    339   9710         Ken 		    void *, dst);
    340   9710         Ken 		return (EHOSTUNREACH);
    341   9710         Ken 	}
    342   9710         Ken 
    343   9710         Ken 	switch (dst_rhtp->tpc_tp.host_type) {
    344   9710         Ken 	case UNLABELED:
    345   9710         Ken 		/*
    346   9710         Ken 		 * Can talk to unlabeled hosts if
    347   9710         Ken 		 * (1) zone's label matches the default label, or
    348  10934  sommerfeld 		 * (2) SO_MAC_EXEMPT is on and we
    349  10934  sommerfeld 		 * dominate the peer's label, or
    350  10934  sommerfeld 		 * (3) SO_MAC_EXEMPT is on and
    351  10934  sommerfeld 		 * this is the global zone
    352   9710         Ken 		 */
    353   9710         Ken 		if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi) {
    354  10181         Ken 			DTRACE_PROBE4(tx__tnopt__log__info__labeling__doi,
    355   9710         Ken 			    char *, "unlabeled dest ip(1)/tpc(2) doi does "
    356   9710         Ken 			    "not match msg label(3) doi.", void *, dst,
    357   9710         Ken 			    tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
    358   9710         Ken 			TPC_RELE(dst_rhtp);
    359   9710         Ken 			return (EHOSTUNREACH);
    360   9710         Ken 		}
    361   9710         Ken 		if (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
    362   9710         Ken 		    &tsl->tsl_label)) {
    363  10934  sommerfeld 			if (mac_mode != CONN_MAC_AWARE ||
    364  11042        Erik 			    !(zone_is_global ||
    365   9710         Ken 			    bldominates(&tsl->tsl_label,
    366   9710         Ken 			    &dst_rhtp->tpc_tp.tp_def_label))) {
    367   9710         Ken 				DTRACE_PROBE4(
    368   9710         Ken 				    tx__tnopt__log__info__labeling__mac,
    369   9710         Ken 				    char *, "unlabeled dest ip(1)/tpc(2) does "
    370   9710         Ken 				    "not match msg label(3).", void *, dst,
    371   9710         Ken 				    tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
    372   9710         Ken 				TPC_RELE(dst_rhtp);
    373   9710         Ken 				return (EHOSTUNREACH);
    374   9710         Ken 			}
    375   9710         Ken 			/*
    376   9710         Ken 			 * This is a downlabel MAC-exempt exchange.
    377   9710         Ken 			 * Use the remote destination's default label
    378   9710         Ken 			 * as the label of the message data.
    379   9710         Ken 			 */
    380   9710         Ken 			if ((newtsl = labelalloc(&dst_rhtp->tpc_tp.tp_def_label,
    381   9710         Ken 			    dst_rhtp->tpc_tp.tp_doi, KM_NOSLEEP)) == NULL) {
    382   9710         Ken 				TPC_RELE(dst_rhtp);
    383   9710         Ken 				return (ENOMEM);
    384   9710         Ken 			}
    385   9710         Ken 			newtsl->tsl_flags |= TSLF_UNLABELED;
    386   9710         Ken 
    387   9710         Ken 		} else if (!(tsl->tsl_flags & TSLF_UNLABELED)) {
    388   9710         Ken 			/*
    389   9710         Ken 			 * The security labels are the same but we need
    390   9710         Ken 			 * to flag that the remote node is unlabeled.
    391   9710         Ken 			 */
    392   9710         Ken 			if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
    393   9710         Ken 				TPC_RELE(dst_rhtp);
    394   9710         Ken 				return (ENOMEM);
    395   9710         Ken 			}
    396   9710         Ken 			newtsl->tsl_flags |= TSLF_UNLABELED;
    397   9710         Ken 		}
    398   9710         Ken 		break;
    399   9710         Ken 
    400   9710         Ken 	case SUN_CIPSO:
    401   9710         Ken 		/*
    402   9710         Ken 		 * Can talk to labeled hosts if zone's label is within target's
    403   9710         Ken 		 * label range or set.
    404   9710         Ken 		 */
    405   9710         Ken 		if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
    406   9710         Ken 		    (!_blinrange(&tsl->tsl_label,
    407   9710         Ken 		    &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
    408   9710         Ken 		    !blinlset(&tsl->tsl_label,
    409   9710         Ken 		    dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
    410   9710         Ken 			DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac,
    411   9710         Ken 			    char *, "labeled dest ip(1)/tpc(2) does not "
    412   9710         Ken 			    "match msg label(3).", void *, dst,
    413   9710         Ken 			    tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
    414   9710         Ken 			TPC_RELE(dst_rhtp);
    415   9710         Ken 			return (EHOSTUNREACH);
    416   9710         Ken 		}
    417  10934  sommerfeld 		if ((tsl->tsl_flags & TSLF_UNLABELED) ||
    418  10934  sommerfeld 		    (mac_mode == CONN_MAC_IMPLICIT)) {
    419   9710         Ken 			/*
    420  10934  sommerfeld 			 * Copy label so we can modify the flags
    421   9710         Ken 			 */
    422   9710         Ken 			if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
    423   9710         Ken 				TPC_RELE(dst_rhtp);
    424   9710         Ken 				return (ENOMEM);
    425   9710         Ken 			}
    426  10934  sommerfeld 			/*
    427  10934  sommerfeld 			 * The security label is a match but we need to
    428  10934  sommerfeld 			 * clear the unlabeled flag for this remote node.
    429  10934  sommerfeld 			 */
    430  10934  sommerfeld 			newtsl->tsl_flags &= ~TSLF_UNLABELED;
    431  10934  sommerfeld 			if (mac_mode == CONN_MAC_IMPLICIT)
    432  10934  sommerfeld 				newtsl->tsl_flags |= TSLF_IMPLICIT_OUT;
    433   9710         Ken 		}
    434   9710         Ken 		break;
    435   9710         Ken 
    436   9710         Ken 	default:
    437   9710         Ken 		TPC_RELE(dst_rhtp);
    438   9710         Ken 		return (EHOSTUNREACH);
    439   9710         Ken 	}
    440   9710         Ken 
    441   9710         Ken 	/*
    442  11042        Erik 	 * Return the new label.
    443   9710         Ken 	 */
    444   9710         Ken 	if (newtsl != NULL) {
    445  11042        Erik 		if (effective_tsl != NULL)
    446  11042        Erik 			*effective_tsl = newtsl;
    447  11042        Erik 		else
    448  11042        Erik 			label_rele(newtsl);
    449   9710         Ken 	}
    450   9710         Ken 	TPC_RELE(dst_rhtp);
    451   9710         Ken 	return (0);
    452   9710         Ken }
    453   9710         Ken 
    454   9710         Ken /*
    455  11042        Erik  * tsol_compute_label_v4()
    456   1676         jpk  *
    457   1676         jpk  * This routine computes the IP label that should be on a packet based on the
    458   1676         jpk  * connection and destination information.
    459  11042        Erik  *
    460  11042        Erik  * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones).
    461   1676         jpk  *
    462   1676         jpk  * Returns:
    463   1676         jpk  *      0		Fetched label
    464   9710         Ken  *	EHOSTUNREACH	No route to destination
    465   1676         jpk  *	EINVAL		Label cannot be computed
    466   1676         jpk  */
    467   1676         jpk int
    468  11042        Erik tsol_compute_label_v4(const ts_label_t *tsl, zoneid_t zoneid, ipaddr_t dst,
    469  11042        Erik     uchar_t *opt_storage, ip_stack_t *ipst)
    470   1676         jpk {
    471   1676         jpk 	uint_t		sec_opt_len;
    472  11042        Erik 	ire_t		*ire;
    473  11042        Erik 	tsol_ire_gw_secattr_t *attrp = NULL;
    474   1676         jpk 
    475   1676         jpk 	if (opt_storage != NULL)
    476   1676         jpk 		opt_storage[IPOPT_OLEN] = 0;
    477   1676         jpk 
    478  11042        Erik 	if (tsl == NULL)
    479   1676         jpk 		return (0);
    480   1676         jpk 
    481   1676         jpk 	/* always pass multicast */
    482   1676         jpk 	if (CLASSD(dst))
    483  10934  sommerfeld 		return (0);
    484  10934  sommerfeld 
    485  10934  sommerfeld 	if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
    486   1676         jpk 		return (0);
    487   1676         jpk 
    488   9710         Ken 	if (tsl->tsl_flags & TSLF_UNLABELED) {
    489   9710         Ken 		/*
    490   9710         Ken 		 * The destination is unlabeled. Only add a label if the
    491   9710         Ken 		 * destination is not a broadcast/local/loopback address,
    492   9710         Ken 		 * the destination is not on the same subnet, and the
    493   9710         Ken 		 * next-hop gateway is labeled.
    494   9710         Ken 		 */
    495  11042        Erik 		ire = ire_route_recursive_v4(dst, 0, NULL, zoneid, tsl,
    496  11042        Erik 		    MATCH_IRE_SECATTR, B_TRUE, 0, ipst, NULL, &attrp, NULL);
    497  11042        Erik 		ASSERT(ire != NULL);
    498  11042        Erik 		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
    499  11042        Erik 			/* no route to destination */
    500  11042        Erik 			ire_refrele(ire);
    501   9710         Ken 			DTRACE_PROBE3(
    502   1676         jpk 			    tx__tnopt__log__info__labeling__routedst__v4,
    503   9710         Ken 			    char *, "No route to unlabeled dest ip(1) with "
    504  11042        Erik 			    "with label(2).", ipaddr_t, dst, ts_label_t *, tsl);
    505   9710         Ken 			return (EHOSTUNREACH);
    506  11042        Erik 		}
    507  11042        Erik 		if (ire->ire_type & (IRE_BROADCAST | IRE_LOCAL | IRE_LOOPBACK |
    508  11042        Erik 		    IRE_INTERFACE)) {
    509  11042        Erik 			ire_refrele(ire);
    510  11042        Erik 			return (0);
    511   1676         jpk 		}
    512   1676         jpk 
    513   1676         jpk 		/*
    514  11042        Erik 		 * ire_route_recursive gives us the first attrp it finds
    515  11042        Erik 		 * in the recursive lookup.
    516   1676         jpk 		 */
    517   9710         Ken 		/*
    518   9710         Ken 		 * Return now if next hop gateway is unlabeled. There is
    519   9710         Ken 		 * no need to generate a CIPSO option for this message.
    520   9710         Ken 		 */
    521   9710         Ken 		if (attrp == NULL || attrp->igsa_rhc == NULL ||
    522   9710         Ken 		    attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) {
    523  11042        Erik 			ire_refrele(ire);
    524   9710         Ken 			return (0);
    525   1676         jpk 		}
    526  11042        Erik 		ire_refrele(ire);
    527   1676         jpk 	}
    528   1676         jpk 
    529   1676         jpk 	/* compute the CIPSO option */
    530   9710         Ken 	sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
    531   9710         Ken 	    tsl->tsl_doi);
    532   1676         jpk 
    533   1676         jpk 	if (sec_opt_len == 0) {
    534   9710         Ken 		DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v4,
    535  11042        Erik 		    char *, "options lack length for dest ip(1) with label(2).",
    536  11042        Erik 		    ipaddr_t, dst, ts_label_t *, tsl);
    537   1676         jpk 		return (EINVAL);
    538   1676         jpk 	}
    539   1676         jpk 
    540   1676         jpk 	return (0);
    541   1676         jpk }
    542   1676         jpk 
    543   1676         jpk /*
    544   1676         jpk  * Remove any existing security option (CIPSO) from the given IP
    545   1676         jpk  * header, move the 'buflen' bytes back to fill the gap, and return the number
    546   1676         jpk  * of bytes removed (as zero or negative number).  Assumes that the headers are
    547   1676         jpk  * sane.
    548  11042        Erik  *
    549  11042        Erik  * Note that tsol_remove_secopt does not adjust ipha_length but
    550  11042        Erik  * tsol_remove_secopt_v6 does adjust ip6_plen.
    551   1676         jpk  */
    552   1676         jpk int
    553   1676         jpk tsol_remove_secopt(ipha_t *ipha, int buflen)
    554   1676         jpk {
    555   1676         jpk 	int remlen, olen, oval, delta;
    556   1676         jpk 	uchar_t *fptr, *tptr;
    557   1676         jpk 	boolean_t noop_keep;
    558   1676         jpk 
    559   1676         jpk 	remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
    560   1676         jpk 	fptr = tptr = (uchar_t *)(ipha + 1);
    561   1676         jpk 	noop_keep = B_TRUE;
    562   1676         jpk 	while (remlen > 0) {
    563   1676         jpk 		oval = fptr[IPOPT_OPTVAL];
    564   1676         jpk 
    565   1676         jpk 		/* terminate on end of list */
    566   1676         jpk 		if (oval == IPOPT_EOL)
    567   1676         jpk 			break;
    568   1676         jpk 
    569   1676         jpk 		/*
    570   1676         jpk 		 * Delete any no-ops following a deleted option, at least up
    571   1676         jpk 		 * to a 4 octet alignment; copy others.
    572   1676         jpk 		 */
    573   1676         jpk 		if (oval == IPOPT_NOP) {
    574   1676         jpk 			if (((fptr - (uchar_t *)ipha) & 3) == 0)
    575   1676         jpk 				noop_keep = B_TRUE;
    576   1676         jpk 			if (noop_keep)
    577   1676         jpk 				*tptr++ = oval;
    578   1676         jpk 			fptr++;
    579   1676         jpk 			remlen--;
    580   1676         jpk 			continue;
    581   1676         jpk 		}
    582   1676         jpk 
    583   1676         jpk 		/* stop on corrupted list; just do nothing. */
    584   1676         jpk 		if (remlen < 2)
    585   1676         jpk 			return (0);
    586   1676         jpk 		olen = fptr[IPOPT_OLEN];
    587   1676         jpk 		if (olen < 2 || olen > remlen)
    588   1676         jpk 			return (0);
    589   1676         jpk 
    590   1676         jpk 		/* skip over security options to delete them */
    591   1676         jpk 		if (oval == IPOPT_COMSEC || oval == IPOPT_SECURITY) {
    592   1676         jpk 			noop_keep = B_FALSE;
    593   1676         jpk 			fptr += olen;
    594   1676         jpk 			remlen -= olen;
    595   1676         jpk 			continue;
    596   1676         jpk 		}
    597   1676         jpk 
    598   1676         jpk 		/* copy the rest */
    599   1676         jpk 		noop_keep = B_TRUE;
    600   1676         jpk 		if (tptr != fptr)
    601   1676         jpk 			ovbcopy(fptr, tptr, olen);
    602   1676         jpk 		fptr += olen;
    603   1676         jpk 		tptr += olen;
    604   1676         jpk 		remlen -= olen;
    605   1676         jpk 	}
    606   1676         jpk 
    607   1676         jpk 	fptr += remlen;
    608   1676         jpk 
    609   1676         jpk 	/* figure how much padding we'll need for header alignment */
    610   1676         jpk 	olen = (tptr - (uchar_t *)ipha) & 3;
    611   1676         jpk 	if (olen > 0) {
    612   1676         jpk 		olen = 4 - olen;
    613   1676         jpk 		/* pad with end-of-list */
    614   1676         jpk 		bzero(tptr, olen);
    615   1676         jpk 		tptr += olen;
    616   1676         jpk 	}
    617   1676         jpk 
    618   1676         jpk 	/* slide back the headers that follow and update the IP header */
    619   1676         jpk 	delta = fptr - tptr;
    620   1676         jpk 	if (delta != 0) {
    621   1676         jpk 		ovbcopy(fptr, tptr, ((uchar_t *)ipha + buflen) - fptr);
    622   1676         jpk 		ipha->ipha_version_and_hdr_length -= delta / 4;
    623   1676         jpk 	}
    624   1676         jpk 	return (-delta);
    625   1676         jpk }
    626   1676         jpk 
    627   1676         jpk /*
    628   1676         jpk  * Insert the option in 'optbuf' into the IP header pointed to by 'ipha', and
    629   1676         jpk  * move the data following the IP header (up to buflen) to accomodate the new
    630   1676         jpk  * option.  Assumes that up to IP_MAX_OPT_LENGTH bytes are available (in total)
    631   1676         jpk  * for IP options.  Returns the number of bytes actually inserted, or -1 if the
    632   1676         jpk  * option cannot be inserted.  (Note that negative return values are possible
    633   1676         jpk  * when noops must be compressed, and that only -1 indicates error.  Successful
    634   1676         jpk  * return value is always evenly divisible by 4, by definition.)
    635  11042        Erik  *
    636  11042        Erik  * Note that tsol_prepend_option does not adjust ipha_length but
    637  11042        Erik  * tsol_prepend_option_v6 does adjust ip6_plen.
    638   1676         jpk  */
    639   1676         jpk int
    640   1676         jpk tsol_prepend_option(uchar_t *optbuf, ipha_t *ipha, int buflen)
    641   1676         jpk {
    642   1676         jpk 	int remlen, padding, lastpad, totlen;
    643   1676         jpk 	int oval, olen;
    644   1676         jpk 	int delta;
    645   1676         jpk 	uchar_t *optr;
    646   1676         jpk 	uchar_t tempopt[IP_MAX_OPT_LENGTH], *toptr;
    647   1676         jpk 
    648   1676         jpk 	if (optbuf[IPOPT_OPTVAL] == IPOPT_EOL ||
    649   1676         jpk 	    optbuf[IPOPT_OPTVAL] == IPOPT_NOP ||
    650   1676         jpk 	    optbuf[IPOPT_OLEN] == 0)
    651   1676         jpk 		return (0);
    652   1676         jpk 
    653   1676         jpk 	ASSERT(optbuf[IPOPT_OLEN] >= 2 &&
    654   1676         jpk 	    optbuf[IPOPT_OLEN] <= IP_MAX_OPT_LENGTH);
    655   1676         jpk 
    656   1676         jpk 	/* first find the real (unpadded) length of the existing options */
    657   1676         jpk 	remlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
    658   1676         jpk 	padding = totlen = lastpad = 0;
    659   1676         jpk 	optr = (uchar_t *)(ipha + 1);
    660   1676         jpk 	while (remlen > 0) {
    661   1676         jpk 		oval = optr[IPOPT_OPTVAL];
    662   1676         jpk 
    663   1676         jpk 		/* stop at end of list */
    664   1676         jpk 		if (oval == IPOPT_EOL)
    665   1676         jpk 			break;
    666   1676         jpk 
    667   1676         jpk 		/* skip no-ops, noting that length byte isn't present */
    668   1676         jpk 		if (oval == IPOPT_NOP) {
    669   1676         jpk 			optr++;
    670   1676         jpk 			padding++;
    671   1676         jpk 			lastpad++;
    672   1676         jpk 			totlen++;
    673   1676         jpk 			remlen--;
    674   1676         jpk 			continue;
    675   1676         jpk 		}
    676   1676         jpk 
    677   1676         jpk 		/* give up on a corrupted list; report failure */
    678   1676         jpk 		if (remlen < 2)
    679   1676         jpk 			return (-1);
    680   1676         jpk 		olen = optr[IPOPT_OLEN];
    681   1676         jpk 		if (olen < 2 || olen > remlen)
    682   1676         jpk 			return (-1);
    683   1676         jpk 
    684   1676         jpk 		lastpad = 0;
    685   1676         jpk 		optr += olen;
    686   1676         jpk 		totlen += olen;
    687   1676         jpk 		remlen -= olen;
    688   1676         jpk 	}
    689   1676         jpk 
    690   1676         jpk 	/* completely ignore any trailing padding */
    691   1676         jpk 	totlen -= lastpad;
    692   1676         jpk 	padding -= lastpad;
    693   1676         jpk 
    694   1676         jpk 	/*
    695   1676         jpk 	 * If some sort of inter-option alignment was present, try to preserve
    696   1676         jpk 	 * that alignment.  If alignment pushes us out past the maximum, then
    697   1676         jpk 	 * discard it and try to compress to fit.  (We just "assume" that any
    698   1676         jpk 	 * padding added was attempting to get 32 bit alignment.  If that's
    699   1676         jpk 	 * wrong, that's just too bad.)
    700   1676         jpk 	 */
    701   1676         jpk 	if (padding > 0) {
    702   1676         jpk 		olen = (optbuf[IPOPT_OLEN] + 3) & ~3;
    703   1676         jpk 		if (olen + totlen > IP_MAX_OPT_LENGTH) {
    704   1676         jpk 			totlen -= padding;
    705   1676         jpk 			if (olen + totlen > IP_MAX_OPT_LENGTH)
    706   1676         jpk 				return (-1);
    707   1676         jpk 			padding = 0;
    708   1676         jpk 		}
    709   1676         jpk 	}
    710   1676         jpk 
    711   1676         jpk 	/*
    712   1676         jpk 	 * Since we may need to compress or expand the option list, we write to
    713   1676         jpk 	 * a temporary buffer and then copy the results back to the IP header.
    714   1676         jpk 	 */
    715   1676         jpk 	toptr = tempopt;
    716   1676         jpk 
    717   1676         jpk 	/* compute actual option to insert */
    718   1676         jpk 	olen = optbuf[IPOPT_OLEN];
    719   1676         jpk 	bcopy(optbuf, toptr, olen);
    720   1676         jpk 	toptr += olen;
    721   1676         jpk 	if (padding > 0) {
    722   1676         jpk 		while ((olen & 3) != 0) {
    723   1676         jpk 			*toptr++ = IPOPT_NOP;
    724   1676         jpk 			olen++;
    725   1676         jpk 		}
    726   1676         jpk 	}
    727   1676         jpk 
    728   1676         jpk 	/* copy over the existing options */
    729   1676         jpk 	optr = (uchar_t *)(ipha + 1);
    730   1676         jpk 	while (totlen > 0) {
    731   1676         jpk 		oval = optr[IPOPT_OPTVAL];
    732   1676         jpk 
    733   1676         jpk 		/* totlen doesn't include end-of-list marker */
    734   1676         jpk 		ASSERT(oval != IPOPT_EOL);
    735   1676         jpk 
    736   1676         jpk 		/* handle no-ops; copy if desired, ignore otherwise */
    737   1676         jpk 		if (oval == IPOPT_NOP) {
    738   1676         jpk 			if (padding > 0) {
    739   1676         jpk 				/* note: cannot overflow due to checks above */
    740   1676         jpk 				ASSERT(toptr < tempopt + IP_MAX_OPT_LENGTH);
    741   1676         jpk 				*toptr++ = oval;
    742   1676         jpk 			}
    743   1676         jpk 			optr++;
    744   1676         jpk 			totlen--;
    745   1676         jpk 			continue;
    746   1676         jpk 		}
    747   1676         jpk 
    748   1676         jpk 		/* list cannot be corrupt at this point */
    749   1676         jpk 		ASSERT(totlen >= 2);
    750   1676         jpk 		olen = optr[IPOPT_OLEN];
    751   1676         jpk 		ASSERT(olen >= 2 && olen <= totlen);
    752   1676         jpk 
    753   1676         jpk 		/* cannot run out of room due to tests above */
    754   1676         jpk 		ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH);
    755   1676         jpk 
    756   1676         jpk 		bcopy(optr, toptr, olen);
    757   1676         jpk 		optr += olen;
    758   1676         jpk 		toptr += olen;
    759   1676         jpk 		totlen -= olen;
    760   1676         jpk 	}
    761   1676         jpk 
    762   1676         jpk 	/* figure how much padding we'll need for header alignment */
    763   1676         jpk 	olen = (toptr - tempopt) & 3;
    764   1676         jpk 	if (olen > 0) {
    765   1676         jpk 		olen = 4 - olen;
    766   1676         jpk 		ASSERT(toptr + olen <= tempopt + IP_MAX_OPT_LENGTH);
    767   1676         jpk 		/* pad with end-of-list value */
    768   1676         jpk 		bzero(toptr, olen);
    769   1676         jpk 		toptr += olen;
    770   1676         jpk 	}
    771   1676         jpk 
    772   1676         jpk 	/* move the headers as needed and update IP header */
    773   1676         jpk 	olen = (toptr - tempopt) + IP_SIMPLE_HDR_LENGTH;
    774   1676         jpk 	remlen = IPH_HDR_LENGTH(ipha);
    775   1676         jpk 	delta = olen - remlen;
    776   1676         jpk 	if (delta != 0) {
    777   1676         jpk 		ovbcopy((uchar_t *)ipha + remlen, (uchar_t *)ipha + olen,
    778   1676         jpk 		    buflen - remlen);
    779   1676         jpk 		ipha->ipha_version_and_hdr_length += delta / 4;
    780   1676         jpk 	}
    781   1676         jpk 
    782   1676         jpk 	/* slap in the new options */
    783   1676         jpk 	bcopy(tempopt, ipha + 1, olen - IP_SIMPLE_HDR_LENGTH);
    784   1676         jpk 
    785   1676         jpk 	return (delta);
    786   1676         jpk }
    787   1676         jpk 
    788   1676         jpk /*
    789  11042        Erik  * tsol_check_label_v4()
    790   1676         jpk  *
    791   1676         jpk  * This routine computes the IP label that should be on the packet based on the
    792  11042        Erik  * connection and destination information.  It's called by the IP forwarding
    793  11042        Erik  * logic and by ip_output_simple. The ULPs generate the labels before calling
    794  11042        Erik  * conn_ip_output. If any adjustments to
    795  11042        Erik  * the label are needed due to the connection's MAC-exempt status or
    796  11042        Erik  * the destination's ability to receive labels, an "effective label"
    797  11042        Erik  * will be returned.
    798   1676         jpk  *
    799   6596    kp158701  * The packet's header is clear before entering IPsec's engine.
    800   1676         jpk  *
    801  11042        Erik  * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones).
    802  11042        Erik  * zone_is_global is set if the actual zoneid is global.
    803  11042        Erik  *
    804  11042        Erik  * On successful return, effective_tslp will point to the new label needed
    805  11042        Erik  * or will be NULL if a new label isn't needed. On error, effective_tsl will
    806  11042        Erik  * point to NULL.
    807  11042        Erik  *
    808   1676         jpk  * Returns:
    809  11077        Erik  *      0		Label (was|is now) correct
    810   1676         jpk  *      EACCES		The packet failed the remote host accreditation.
    811   1676         jpk  *      ENOMEM		Memory allocation failure.
    812   1676         jpk  *	EINVAL		Label cannot be computed
    813   1676         jpk  */
    814   1676         jpk int
    815  11042        Erik tsol_check_label_v4(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp,
    816  11042        Erik     uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst,
    817  11042        Erik     ts_label_t **effective_tslp)
    818   1676         jpk {
    819   1676         jpk 	mblk_t *mp = *mpp;
    820   1676         jpk 	ipha_t  *ipha;
    821  11042        Erik 	ts_label_t *effective_tsl = NULL;
    822   1676         jpk 	uchar_t opt_storage[IP_MAX_OPT_LENGTH];
    823   1676         jpk 	uint_t hlen;
    824   1676         jpk 	uint_t sec_opt_len;
    825   1676         jpk 	uchar_t *optr;
    826   6596    kp158701 	int delta_remove = 0, delta_add, adjust;
    827   1676         jpk 	int retv;
    828   1676         jpk 
    829  11042        Erik 	*effective_tslp = NULL;
    830   1676         jpk 	opt_storage[IPOPT_OPTVAL] = 0;
    831   1676         jpk 
    832   1676         jpk 	ipha = (ipha_t *)mp->b_rptr;
    833   1676         jpk 
    834   9710         Ken 	/*
    835   9710         Ken 	 * Verify the destination is allowed to receive packets at
    836  11042        Erik 	 * the security label of the message data. tsol_check_dest()
    837  11042        Erik 	 * may create a new effective label or label flags.
    838   9710         Ken 	 */
    839  11042        Erik 	retv = tsol_check_dest(tsl, &ipha->ipha_dst, IPV4_VERSION,
    840  11042        Erik 	    mac_mode, zone_is_global, &effective_tsl);
    841   1676         jpk 	if (retv != 0)
    842   1676         jpk 		return (retv);
    843   9710         Ken 
    844   9710         Ken 	/*
    845   9710         Ken 	 * Calculate the security label to be placed in the text
    846   9710         Ken 	 * of the message (if any).
    847   9710         Ken 	 */
    848  11042        Erik 	if (effective_tsl != NULL) {
    849  11042        Erik 		if ((retv = tsol_compute_label_v4(effective_tsl, zoneid,
    850   9710         Ken 		    ipha->ipha_dst, opt_storage, ipst)) != 0) {
    851  11042        Erik 			label_rele(effective_tsl);
    852   9710         Ken 			return (retv);
    853   9710         Ken 		}
    854  11042        Erik 		*effective_tslp = effective_tsl;
    855   9710         Ken 	} else {
    856  11042        Erik 		if ((retv = tsol_compute_label_v4(tsl, zoneid,
    857   9710         Ken 		    ipha->ipha_dst, opt_storage, ipst)) != 0) {
    858   9710         Ken 			return (retv);
    859   9710         Ken 		}
    860   9710         Ken 	}
    861   1676         jpk 
    862   1676         jpk 	optr = (uchar_t *)(ipha + 1);
    863   1676         jpk 	hlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
    864   1676         jpk 	sec_opt_len = opt_storage[IPOPT_OLEN];
    865   1676         jpk 
    866   1676         jpk 	if (hlen >= sec_opt_len) {
    867   1676         jpk 		/* If no option is supposed to be there, make sure it's not */
    868   1676         jpk 		if (sec_opt_len == 0 && hlen > 0 &&
    869   1676         jpk 		    optr[IPOPT_OPTVAL] != IPOPT_COMSEC &&
    870   1676         jpk 		    optr[IPOPT_OPTVAL] != IPOPT_SECURITY)
    871   1676         jpk 			return (0);
    872   1676         jpk 		/* if the option is there, it's always first */
    873   1676         jpk 		if (sec_opt_len != 0 &&
    874   1676         jpk 		    bcmp(opt_storage, optr, sec_opt_len) == 0)
    875   1676         jpk 			return (0);
    876   1676         jpk 	}
    877   1676         jpk 
    878   1676         jpk 	/*
    879   1676         jpk 	 * If there is an option there, then it must be the wrong one; delete.
    880   1676         jpk 	 */
    881   6596    kp158701 	if (hlen > 0) {
    882   6596    kp158701 		delta_remove = tsol_remove_secopt(ipha, MBLKL(mp));
    883   6596    kp158701 		mp->b_wptr += delta_remove;
    884   6596    kp158701 	}
    885   1676         jpk 
    886   1676         jpk 	/* Make sure we have room for the worst-case addition */
    887   1676         jpk 	hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN];
    888   1676         jpk 	hlen = (hlen + 3) & ~3;
    889   1676         jpk 	if (hlen > IP_MAX_HDR_LENGTH)
    890   1676         jpk 		hlen = IP_MAX_HDR_LENGTH;
    891   1676         jpk 	hlen -= IPH_HDR_LENGTH(ipha);
    892   1676         jpk 	if (mp->b_wptr + hlen > mp->b_datap->db_lim) {
    893   1676         jpk 		int copylen;
    894   1676         jpk 		mblk_t *new_mp;
    895   1676         jpk 
    896   1676         jpk 		/* allocate enough to be meaningful, but not *too* much */
    897   1676         jpk 		copylen = MBLKL(mp);
    898   1676         jpk 		if (copylen > 256)
    899   1676         jpk 			copylen = 256;
    900   8778        Erik 		new_mp = allocb_tmpl(hlen + copylen +
    901   8778        Erik 		    (mp->b_rptr - mp->b_datap->db_base), mp);
    902  11042        Erik 		if (new_mp == NULL) {
    903  11042        Erik 			if (effective_tsl != NULL) {
    904  11042        Erik 				label_rele(effective_tsl);
    905  11042        Erik 				*effective_tslp = NULL;
    906  11042        Erik 			}
    907   1676         jpk 			return (ENOMEM);
    908  11042        Erik 		}
    909   1676         jpk 
    910   1676         jpk 		/* keep the bias */
    911   1676         jpk 		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
    912   1676         jpk 		new_mp->b_wptr = new_mp->b_rptr + copylen;
    913   1676         jpk 		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
    914   1676         jpk 		new_mp->b_cont = mp;
    915   1676         jpk 		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
    916   1676         jpk 			new_mp->b_cont = mp->b_cont;
    917   1676         jpk 			freeb(mp);
    918   1676         jpk 		}
    919   1676         jpk 		*mpp = mp = new_mp;
    920   1676         jpk 		ipha = (ipha_t *)mp->b_rptr;
    921   1676         jpk 	}
    922   1676         jpk 
    923   6596    kp158701 	delta_add = tsol_prepend_option(opt_storage, ipha, MBLKL(mp));
    924   6596    kp158701 	if (delta_add == -1)
    925   1676         jpk 		goto param_prob;
    926   1676         jpk 
    927   6596    kp158701 	ASSERT((mp->b_wptr + delta_add) <= DB_LIM(mp));
    928   6596    kp158701 	mp->b_wptr += delta_add;
    929   1676         jpk 
    930   6596    kp158701 	adjust = delta_remove + delta_add;
    931   6596    kp158701 	adjust += ntohs(ipha->ipha_length);
    932   6596    kp158701 	ipha->ipha_length = htons(adjust);
    933   1676         jpk 
    934   1676         jpk 	return (0);
    935   1676         jpk 
    936   1676         jpk param_prob:
    937  11042        Erik 	if (effective_tsl != NULL) {
    938  11042        Erik 		label_rele(effective_tsl);
    939  11042        Erik 		*effective_tslp = NULL;
    940  11042        Erik 	}
    941   1676         jpk 	return (EINVAL);
    942   1676         jpk }
    943   1676         jpk 
    944   1676         jpk /*
    945   1676         jpk  * IPv6 HopOpt extension header for the label option layout:
    946   1676         jpk  *	- One octet giving the type of the 'next extension header'
    947   1676         jpk  *	- Header extension length in 8-byte words, not including the
    948   1676         jpk  *	  1st 8 bytes, but including any pad bytes at the end.
    949   1676         jpk  *	  Eg. A value of 2 means 16 bytes not including the 1st 8 bytes.
    950   1676         jpk  *	- Followed by TLV encoded IPv6 label option. Option layout is
    951   1676         jpk  *		* One octet, IP6OPT_LS
    952   1676         jpk  *		* One octet option length in bytes of the option data following
    953   1676         jpk  *		  the length, but not including any pad bytes at the end.
    954   1676         jpk  *		* Four-octet DOI (IP6LS_DOI_V4)
    955   1676         jpk  *		* One octet suboption, IP6LS_TT_V4
    956   1676         jpk  *		* One octet suboption length in bytes of the suboption
    957   1676         jpk  *		  following the suboption length, including the suboption
    958   1676         jpk  *		  header length, but not including any pad bytes at the end.
    959   1676         jpk  *	- Pad to make the extension header a multiple of 8 bytes.
    960   1676         jpk  *
    961   1676         jpk  * This function returns the contents of 'IPv6 option structure' in the above.
    962   1676         jpk  * i.e starting from the IP6OPT_LS but not including the pad at the end.
    963   1676         jpk  * The user must prepend two octets (either padding or next header / length)
    964   1676         jpk  * and append padding out to the next 8 octet boundary.
    965  11042        Erik  *
    966  11042        Erik  * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones).
    967   1676         jpk  */
    968   1676         jpk int
    969  11042        Erik tsol_compute_label_v6(const ts_label_t *tsl, zoneid_t zoneid,
    970  11042        Erik     const in6_addr_t *dst, uchar_t *opt_storage, ip_stack_t *ipst)
    971   1676         jpk {
    972   1676         jpk 	uint_t		sec_opt_len;
    973   1676         jpk 	uint32_t	doi;
    974  11042        Erik 	ire_t		*ire;
    975  11042        Erik 	tsol_ire_gw_secattr_t *attrp = NULL;
    976   1676         jpk 
    977   1676         jpk 	if (ip6opt_ls == 0)
    978   1676         jpk 		return (EINVAL);
    979   1676         jpk 
    980   1676         jpk 	if (opt_storage != NULL)
    981   1676         jpk 		opt_storage[IPOPT_OLEN] = 0;
    982   1676         jpk 
    983  11042        Erik 	if (tsl == NULL)
    984   1676         jpk 		return (0);
    985   1676         jpk 
    986   1676         jpk 	/* Always pass multicast */
    987   1676         jpk 	if (IN6_IS_ADDR_MULTICAST(dst))
    988   1676         jpk 		return (0);
    989   3448    dh155122 
    990   3448    dh155122 	/*
    991   1676         jpk 	 * Fill in a V6 label.  If a new format is added here, make certain
    992   1676         jpk 	 * that the maximum size of this label is reflected in sys/tsol/tnet.h
    993   1676         jpk 	 * as TSOL_MAX_IPV6_OPTION.
    994   1676         jpk 	 */
    995  10934  sommerfeld 	if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
    996  10934  sommerfeld 		return (0);
    997  10934  sommerfeld 
    998   9710         Ken 	if (tsl->tsl_flags & TSLF_UNLABELED) {
    999   1676         jpk 		/*
   1000   9710         Ken 		 * The destination is unlabeled. Only add a label if the
   1001  11042        Erik 		 * destination is not a broadcast/local/loopback address,
   1002   9710         Ken 		 * the destination is not on the same subnet, and the
   1003   9710         Ken 		 * next-hop gateway is labeled.
   1004   1676         jpk 		 */
   1005  11042        Erik 		ire = ire_route_recursive_v6(dst, 0, NULL, zoneid, tsl,
   1006  11042        Erik 		    MATCH_IRE_SECATTR, B_TRUE, 0, ipst, NULL, &attrp, NULL);
   1007  11042        Erik 		ASSERT(ire != NULL);
   1008  11042        Erik 		if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
   1009  11042        Erik 			/* no route to destination */
   1010  11042        Erik 			ire_refrele(ire);
   1011   9710         Ken 			DTRACE_PROBE3(
   1012   1676         jpk 			    tx__tnopt__log__info__labeling__routedst__v6,
   1013   9710         Ken 			    char *, "No route to unlabeled dest ip6(1) with "
   1014  11042        Erik 			    "label(2).", in6_addr_t *, dst, ts_label_t *, tsl);
   1015   9710         Ken 			return (EHOSTUNREACH);
   1016   1676         jpk 		}
   1017  11042        Erik 		if (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK |
   1018  11042        Erik 		    IRE_INTERFACE)) {
   1019  11042        Erik 			ire_refrele(ire);
   1020  11042        Erik 			return (0);
   1021  11042        Erik 		}
   1022   1676         jpk 		/*
   1023  11042        Erik 		 * ire_route_recursive gives us the first attrp it finds
   1024  11042        Erik 		 * in the recursive lookup.
   1025   1676         jpk 		 */
   1026   9710         Ken 		/*
   1027   9710         Ken 		 * Return now if next hop gateway is unlabeled. There is
   1028   9710         Ken 		 * no need to generate a CIPSO option for this message.
   1029   9710         Ken 		 */
   1030   9710         Ken 		if (attrp == NULL || attrp->igsa_rhc == NULL ||
   1031   9710         Ken 		    attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) {
   1032  11042        Erik 			ire_refrele(ire);
   1033   9710         Ken 			return (0);
   1034   1676         jpk 		}
   1035  11042        Erik 		ire_refrele(ire);
   1036   1676         jpk 	}
   1037   1676         jpk 
   1038   1676         jpk 	/* compute the CIPSO option */
   1039   1676         jpk 	if (opt_storage != NULL)
   1040   1676         jpk 		opt_storage += 8;
   1041   9710         Ken 	sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
   1042   9710         Ken 	    tsl->tsl_doi);
   1043   1676         jpk 
   1044   1676         jpk 	if (sec_opt_len == 0) {
   1045   9710         Ken 		DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v6,
   1046   9710         Ken 		    char *, "options lack length for dest ip6(1) with "
   1047  11042        Erik 		    "label(2).", in6_addr_t *, dst, ts_label_t *, tsl);
   1048   1676         jpk 		return (EINVAL);
   1049   1676         jpk 	}
   1050   1676         jpk 
   1051   1676         jpk 	if (opt_storage == NULL)
   1052   1676         jpk 		return (0);
   1053   1676         jpk 
   1054   1676         jpk 	if (sec_opt_len < IP_MAX_OPT_LENGTH)
   1055   1676         jpk 		opt_storage[sec_opt_len] = IPOPT_EOL;
   1056   1676         jpk 
   1057   1676         jpk 	/*
   1058   1676         jpk 	 * Just in case the option length is odd, round it up to the next even
   1059   1676         jpk 	 * multiple.  The IPv6 option definition doesn't like odd numbers for
   1060   1676         jpk 	 * some reason.
   1061   1676         jpk 	 *
   1062   1676         jpk 	 * Length in the overall option header (IP6OPT_LS) does not include the
   1063   1676         jpk 	 * option header itself, but the length in the suboption does include
   1064   1676         jpk 	 * the suboption header.  Thus, when there's just one suboption, the
   1065   1676         jpk 	 * length in the option header is the suboption length plus 4 (for the
   1066   1676         jpk 	 * DOI value).
   1067   1676         jpk 	 */
   1068   1676         jpk 	opt_storage[-2] = IP6LS_TT_V4;
   1069   1676         jpk 	opt_storage[-1] = (sec_opt_len + 2 + 1) & ~1;
   1070   1676         jpk 	opt_storage[-8] = ip6opt_ls;
   1071   1676         jpk 	opt_storage[-7] = opt_storage[-1] + 4;
   1072   1676         jpk 	doi = htons(IP6LS_DOI_V4);
   1073   1676         jpk 	bcopy(&doi, opt_storage - 6, 4);
   1074   1676         jpk 
   1075   1676         jpk 	return (0);
   1076   1676         jpk }
   1077   1676         jpk 
   1078   1676         jpk /*
   1079   1676         jpk  * Locate the start of the IP6OPT_LS label option and return it.
   1080   1676         jpk  * Also return the start of the next non-pad option in after_secoptp.
   1081   1676         jpk  * Usually the label option is the first option at least when packets
   1082   1676         jpk  * are generated, but for generality we don't assume that on received packets.
   1083  10181         Ken  *
   1084  10181         Ken  * The function will return with B_FALSE if an IP format error
   1085  10181         Ken  * or an unexpected label content error is encountered.
   1086   1676         jpk  */
   1087  10181         Ken boolean_t
   1088   1676         jpk tsol_find_secopt_v6(
   1089   1676         jpk     const uchar_t *ip6hbh,	/* Start of the hop-by-hop extension header */
   1090   1676         jpk     uint_t hbhlen,		/* Length of the hop-by-hop extension header */
   1091  10181         Ken     uchar_t **secoptp,		/* Location of IP6OPT_LS label option */
   1092   1676         jpk     uchar_t **after_secoptp,	/* Non-pad option following the label option */
   1093   1676         jpk     boolean_t *hbh_needed)	/* Is hop-by-hop hdr needed w/o label */
   1094   1676         jpk {
   1095   1676         jpk 	uint_t	optlen;
   1096   1676         jpk 	uint_t	optused;
   1097   1676         jpk 	const uchar_t *optptr;
   1098   1676         jpk 	uchar_t	opt_type;
   1099   1676         jpk 
   1100  10181         Ken 	*secoptp = NULL;
   1101   1676         jpk 	*hbh_needed = B_FALSE;
   1102   1676         jpk 	*after_secoptp = NULL;
   1103   1676         jpk 	optlen = hbhlen - 2;
   1104   1676         jpk 	optptr = ip6hbh + 2;
   1105   1676         jpk 	while (optlen != 0) {
   1106   1676         jpk 		opt_type = *optptr;
   1107   1676         jpk 		if (opt_type == IP6OPT_PAD1) {
   1108   1676         jpk 			optptr++;
   1109   1676         jpk 			optlen--;
   1110   1676         jpk 			continue;
   1111   1676         jpk 		}
   1112   1676         jpk 		if (optlen == 1)
   1113  10181         Ken 			return (B_FALSE);
   1114   1676         jpk 		optused = 2 + optptr[1];
   1115   1676         jpk 		if (optused > optlen)
   1116  10181         Ken 			return (B_FALSE);
   1117   1676         jpk 		/*
   1118   1676         jpk 		 * if we get here, ip6opt_ls can
   1119   1676         jpk 		 * not be 0 because it will always
   1120   1676         jpk 		 * match the IP6OPT_PAD1 above.
   1121   1676         jpk 		 * Therefore ip6opt_ls == 0 forces
   1122   1676         jpk 		 * this test to always fail here.
   1123   1676         jpk 		 */
   1124  10181         Ken 		if (opt_type == ip6opt_ls) {
   1125  10181         Ken 			if (*secoptp != NULL)
   1126  10181         Ken 				/* More than one security option found */
   1127  10181         Ken 				return (B_FALSE);
   1128  10181         Ken 			*secoptp = (uchar_t *)optptr;
   1129  10181         Ken 		} else switch (opt_type) {
   1130   1676         jpk 		case IP6OPT_PADN:
   1131   1676         jpk 			break;
   1132   1676         jpk 		default:
   1133   1676         jpk 			/*
   1134   1676         jpk 			 * There is at least 1 option other than
   1135   1676         jpk 			 * the label option. So the hop-by-hop header is needed
   1136   1676         jpk 			 */
   1137   1676         jpk 			*hbh_needed = B_TRUE;
   1138  10181         Ken 			if (*secoptp != NULL) {
   1139   1676         jpk 				*after_secoptp = (uchar_t *)optptr;
   1140  10181         Ken 				return (B_TRUE);
   1141   1676         jpk 			}
   1142   1676         jpk 			break;
   1143   1676         jpk 		}
   1144   1676         jpk 		optlen -= optused;
   1145   1676         jpk 		optptr += optused;
   1146   1676         jpk 	}
   1147  10181         Ken 	return (B_TRUE);
   1148   1676         jpk }
   1149   1676         jpk 
   1150   1676         jpk /*
   1151   1676         jpk  * Remove the label option from the hop-by-hop options header if it exists.
   1152   1676         jpk  * 'buflen' is the total length of the packet typically b_wptr - b_rptr.
   1153   1676         jpk  * Header and data following the label option that is deleted are copied
   1154   4564     wy83408  * (i.e. slid backward) to the right position, and returns the number
   1155   4564     wy83408  * of bytes removed (as zero or negative number.)
   1156  11042        Erik  *
   1157  11042        Erik  * Note that tsol_remove_secopt does not adjust ipha_length but
   1158  11042        Erik  * tsol_remove_secopt_v6 does adjust ip6_plen.
   1159   1676         jpk  */
   1160   1676         jpk int
   1161   1676         jpk tsol_remove_secopt_v6(ip6_t *ip6h, int buflen)
   1162   1676         jpk {
   1163   1676         jpk 	uchar_t	*ip6hbh;	/* hop-by-hop header */
   1164   1676         jpk 	uint_t	hbhlen;		/* hop-by-hop extension header length */
   1165   1676         jpk 	uchar_t *secopt = NULL;
   1166   1676         jpk 	uchar_t *after_secopt;
   1167   1676         jpk 	uint_t	pad;
   1168   1676         jpk 	uint_t	delta;
   1169   1676         jpk 	boolean_t hbh_needed;
   1170   1676         jpk 
   1171   1676         jpk 	/*
   1172   1676         jpk 	 * hop-by-hop extension header must appear first, if it does not
   1173   1676         jpk 	 * exist, there is no label option.
   1174   1676         jpk 	 */
   1175   1676         jpk 	if (ip6h->ip6_nxt != IPPROTO_HOPOPTS)
   1176   1676         jpk 		return (0);
   1177   1676         jpk 
   1178   1676         jpk 	ip6hbh = (uchar_t *)&ip6h[1];
   1179   1676         jpk 	hbhlen = (ip6hbh[1] + 1) << 3;
   1180   1676         jpk 	/*
   1181   1676         jpk 	 * Locate the start of the label option if it exists and the end
   1182   1676         jpk 	 * of the label option including pads if any.
   1183   1676         jpk 	 */
   1184  10181         Ken 	if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt, &after_secopt,
   1185  10181         Ken 	    &hbh_needed)) {
   1186  10181         Ken 		/*
   1187  10181         Ken 		 * This function should not see invalid messages.
   1188  10181         Ken 		 * If one occurs, it would indicate either an
   1189  10181         Ken 		 * option previously verified in the forwarding
   1190  10181         Ken 		 * path has been corrupted or an option was
   1191  10181         Ken 		 * incorrectly generated locally.
   1192  10181         Ken 		 */
   1193  10181         Ken 		ASSERT(0);
   1194  10181         Ken 		return (0);
   1195  10181         Ken 	}
   1196   1676         jpk 	if (secopt == NULL)
   1197   1676         jpk 		return (0);
   1198   1676         jpk 	if (!hbh_needed) {
   1199   1676         jpk 		uchar_t	next_hdr;
   1200   1676         jpk 		/*
   1201   1676         jpk 		 * The label option was the only option in the hop-by-hop
   1202   1676         jpk 		 * header. We don't need the hop-by-hop header itself any
   1203   1676         jpk 		 * longer.
   1204   1676         jpk 		 */
   1205   1676         jpk 		next_hdr = ip6hbh[0];
   1206   1676         jpk 		ovbcopy(ip6hbh + hbhlen, ip6hbh,
   1207   1676         jpk 		    buflen - (IPV6_HDR_LEN + hbhlen));
   1208   2776    kp158701 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - hbhlen);
   1209   1676         jpk 		ip6h->ip6_nxt = next_hdr;
   1210   4564     wy83408 		return (-hbhlen);
   1211   1676         jpk 	}
   1212   1676         jpk 
   1213   1676         jpk 	if (after_secopt == NULL) {
   1214   1676         jpk 		/* There is no option following the label option */
   1215   1676         jpk 		after_secopt = ip6hbh + hbhlen;
   1216   1676         jpk 	}
   1217   1676         jpk 
   1218   1676         jpk 	/*
   1219   1676         jpk 	 * After deleting the label option, we need to slide the headers
   1220   1676         jpk 	 * and data back, while still maintaining the same alignment (module 8)
   1221   1676         jpk 	 * for the other options. So we slide the headers and data back only
   1222   1676         jpk 	 * by an integral multiple of 8 bytes, and fill the remaining bytes
   1223   1676         jpk 	 * with pads.
   1224   1676         jpk 	 */
   1225   1676         jpk 	delta = after_secopt - secopt;
   1226   1676         jpk 	pad = delta % 8;
   1227   1676         jpk 	if (pad == 1) {
   1228   1676         jpk 		secopt[0] = IP6OPT_PAD1;
   1229   1676         jpk 	} else if (pad > 1) {
   1230   1676         jpk 		secopt[0] = IP6OPT_PADN;
   1231   1676         jpk 		secopt[1] = pad - 2;
   1232   1676         jpk 		if (pad > 2)
   1233   1676         jpk 			bzero(&secopt[2], pad - 2);
   1234   1676         jpk 	}
   1235   1676         jpk 	secopt += pad;
   1236   1676         jpk 	delta -= pad;
   1237   1676         jpk 	ovbcopy(after_secopt, secopt,
   1238   1676         jpk 	    (uchar_t *)ip6h + buflen - after_secopt);
   1239   1676         jpk 	ip6hbh[1] -= delta/8;
   1240   2776    kp158701 	ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - delta);
   1241   1676         jpk 
   1242   4564     wy83408 	return (-delta);
   1243   1676         jpk }
   1244   1676         jpk 
   1245   1676         jpk /*
   1246   1676         jpk  * 'optbuf' contains a CIPSO label embedded in an IPv6 hop-by-hop option,
   1247   1676         jpk  * starting with the IP6OPT_LS option type. The format of this hop-by-hop
   1248   1676         jpk  * option is described in the block comment above tsol_compute_label_v6.
   1249   1676         jpk  * This function prepends this hop-by-hop option before any other hop-by-hop
   1250   1676         jpk  * options in the hop-by-hop header if one already exists, else a new
   1251   1676         jpk  * hop-by-hop header is created and stuffed into the packet following
   1252   1676         jpk  * the IPv6 header. 'buflen' is the total length of the packet i.e.
   1253   1676         jpk  * b_wptr - b_rptr. The caller ensures that there is enough space for the
   1254   1676         jpk  * extra option being added. Header and data following the position where
   1255   1676         jpk  * the label option is inserted are copied (i.e. slid forward) to the right
   1256   1676         jpk  * position.
   1257  11042        Erik  *
   1258  11042        Erik  * Note that tsol_prepend_option does not adjust ipha_length but
   1259  11042        Erik  * tsol_prepend_option_v6 does adjust ip6_plen.
   1260   1676         jpk  */
   1261   1676         jpk int
   1262   1676         jpk tsol_prepend_option_v6(uchar_t *optbuf, ip6_t *ip6h, int buflen)
   1263   1676         jpk {
   1264   1676         jpk 	/*
   1265   1676         jpk 	 * rawlen is the length of the label option in bytes, not including
   1266   1676         jpk 	 * any pads, starting from the IP6OPT_LS (option type) byte.
   1267   1676         jpk 	 */
   1268   1676         jpk 	uint_t	rawlen;
   1269   1676         jpk 
   1270   1676         jpk 	uint_t	optlen;		/* rawlen rounded to an 8 byte multiple */
   1271   1676         jpk 	uchar_t	*ip6hbh;	/* start of the hop-by-hop extension header */
   1272   1676         jpk 	uint_t	hbhlen;		/* Length of the hop-by-hop extension header */
   1273   1676         jpk 	uint_t	pad_len;
   1274   1676         jpk 	uchar_t	*pad_position;
   1275   1676         jpk 	int	delta;		/* Actual number of bytes inserted */
   1276   1676         jpk 
   1277   1676         jpk 	rawlen = optbuf[1] + 2;	/* Add 2 for the option type, option length */
   1278   1676         jpk 	ip6hbh = (uchar_t *)&ip6h[1];
   1279   1676         jpk 	if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
   1280   1676         jpk 		/*
   1281   1676         jpk 		 * There is a hop-by-hop header present already. In order to
   1282   1676         jpk 		 * preserve the alignment of the other options at the existing
   1283   1676         jpk 		 * value (modulo 8) we need to pad the label option to a
   1284   1676         jpk 		 * multiple of 8 bytes before prepending it to the other
   1285   1676         jpk 		 * options. Slide the extension headers and data forward to
   1286   1676         jpk 		 * accomodate the label option at the start of the hop-by-hop
   1287   1676         jpk 		 * header
   1288   1676         jpk 		 */
   1289   1676         jpk 		delta = optlen = (rawlen + 7) & ~7;
   1290   1676         jpk 		pad_len = optlen - rawlen;
   1291   1676         jpk 		pad_position = ip6hbh + 2 + rawlen;
   1292   1676         jpk 		ovbcopy(ip6hbh + 2, ip6hbh + 2 + optlen,
   1293   1676         jpk 		    buflen - (IPV6_HDR_LEN + 2));
   1294   1676         jpk 		/*
   1295   1676         jpk 		 * Bump up the hop-by-hop extension header length by
   1296   1676         jpk 		 * the number of 8-byte words added
   1297   1676         jpk 		 */
   1298   1676         jpk 		optlen >>= 3;
   1299   1676         jpk 		if (ip6hbh[1] + optlen > 255)
   1300   1676         jpk 			return (-1);
   1301   1676         jpk 		ip6hbh[1] += optlen;
   1302   1676         jpk 	} else {
   1303   1676         jpk 		/*
   1304   1676         jpk 		 * There is no hop-by-hop header in the packet. Construct a
   1305   1676         jpk 		 * new Hop-by-hop extension header (a multiple of 8 bytes).
   1306   1676         jpk 		 * Slide any other extension headers and data forward to
   1307   1676         jpk 		 * accomodate this hop-by-hop header
   1308   1676         jpk 		 */
   1309   1676         jpk 		delta = hbhlen = (2 + rawlen + 7) & ~7; /* +2 for nxthdr, len */
   1310   1676         jpk 		pad_len = hbhlen - (2 + rawlen);
   1311   1676         jpk 		pad_position = ip6hbh + 2 + rawlen;
   1312   1676         jpk 		ovbcopy(ip6hbh, ip6hbh + hbhlen, buflen - IPV6_HDR_LEN);
   1313   1676         jpk 		ip6hbh[0] = ip6h->ip6_nxt;
   1314   1676         jpk 		/*
   1315   1676         jpk 		 * hop-by-hop extension header length in 8-byte words, not
   1316   1676         jpk 		 * including the 1st 8 bytes of the hop-by-hop header.
   1317   1676         jpk 		 */
   1318   1676         jpk 		ip6hbh[1] = (hbhlen >> 3) - 1;
   1319   1676         jpk 		ip6h->ip6_nxt = IPPROTO_HOPOPTS;
   1320   1676         jpk 	}
   1321   1676         jpk 	/*
   1322   1676         jpk 	 * Copy the label option into the hop-by-hop header and insert any
   1323   1676         jpk 	 * needed pads
   1324   1676         jpk 	 */
   1325   1676         jpk 	bcopy(optbuf, ip6hbh + 2, rawlen);
   1326   1676         jpk 	if (pad_len == 1) {
   1327   1676         jpk 		pad_position[0] = IP6OPT_PAD1;
   1328   1676         jpk 	} else if (pad_len > 1) {
   1329   1676         jpk 		pad_position[0] = IP6OPT_PADN;
   1330   1676         jpk 		pad_position[1] = pad_len - 2;
   1331   1676         jpk 		if (pad_len > 2)
   1332   1676         jpk 			bzero(pad_position + 2, pad_len - 2);
   1333   1676         jpk 	}
   1334   2776    kp158701 	ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + delta);
   1335   1676         jpk 	return (delta);
   1336   1676         jpk }
   1337   1676         jpk 
   1338   1676         jpk /*
   1339   1676         jpk  * tsol_check_label_v6()
   1340   1676         jpk  *
   1341   1676         jpk  * This routine computes the IP label that should be on the packet based on the
   1342  11042        Erik  * connection and destination information.  It's called by the IP forwarding
   1343  11042        Erik  * logic and by ip_output_simple. The ULPs generate the labels before calling
   1344  11042        Erik  * conn_ip_output. If any adjustments to
   1345  11042        Erik  * the label are needed due to the connection's MAC-exempt status or
   1346  11042        Erik  * the destination's ability to receive labels, an "effective label"
   1347  11042        Erik  * will be returned.
   1348  11042        Erik  *
   1349  11042        Erik  * The packet's header is clear before entering IPsec's engine.
   1350  11042        Erik  *
   1351  11042        Erik  * The zoneid is the IP zoneid (i.e., GLOBAL_ZONEID for exlusive-IP zones).
   1352  11042        Erik  * zone_is_global is set if the actual zoneid is global.
   1353  11042        Erik  *
   1354  11042        Erik  * On successful return, effective_tslp will point to the new label needed
   1355  11042        Erik  * or will be NULL if a new label isn't needed. On error, effective_tsl will
   1356  11042        Erik  * point to NULL.
   1357   1676         jpk  *
   1358   1676         jpk  * Returns:
   1359  11077        Erik  *      0		Label (was|is now) correct
   1360   9710         Ken  *      EACCES		The packet failed the remote host accreditation.
   1361   1676         jpk  *      ENOMEM		Memory allocation failure.
   1362  11042        Erik  *	EINVAL		Label cannot be computed
   1363   1676         jpk  */
   1364   1676         jpk int
   1365  11042        Erik tsol_check_label_v6(const ts_label_t *tsl, zoneid_t zoneid, mblk_t **mpp,
   1366  11042        Erik     uint_t mac_mode, boolean_t zone_is_global, ip_stack_t *ipst,
   1367  11042        Erik     ts_label_t **effective_tslp)
   1368   1676         jpk {
   1369   1676         jpk 	mblk_t *mp = *mpp;
   1370   1676         jpk 	ip6_t  *ip6h;
   1371  11042        Erik 	ts_label_t *effective_tsl = NULL;
   1372   1676         jpk 	/*
   1373   1676         jpk 	 * Label option length is limited to IP_MAX_OPT_LENGTH for
   1374   1676         jpk 	 * symmetry with IPv4. Can be relaxed if needed
   1375   1676         jpk 	 */
   1376   1676         jpk 	uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
   1377   1676         jpk 	uint_t hlen;
   1378   1676         jpk 	uint_t sec_opt_len; /* label option length not including type, len */
   1379   6596    kp158701 	int delta_remove = 0, delta_add;
   1380   1676         jpk 	int retv;
   1381   1676         jpk 	uchar_t	*after_secopt;
   1382   1676         jpk 	uchar_t	*secopt = NULL;
   1383   1676         jpk 	uchar_t	*ip6hbh;
   1384   1676         jpk 	uint_t	hbhlen;
   1385   1676         jpk 	boolean_t hbh_needed;
   1386   1676         jpk 
   1387  11042        Erik 	*effective_tslp = NULL;
   1388  11042        Erik 
   1389   9710         Ken 	/*
   1390   9710         Ken 	 * Verify the destination is allowed to receive packets at
   1391  11042        Erik 	 * the security label of the message data. tsol_check_dest()
   1392  11042        Erik 	 * may create a new effective label or label flags.
   1393   9710         Ken 	 */
   1394   1676         jpk 	ip6h = (ip6_t *)mp->b_rptr;
   1395  11042        Erik 	retv = tsol_check_dest(tsl, &ip6h->ip6_dst, IPV6_VERSION,
   1396  11042        Erik 	    mac_mode, zone_is_global, &effective_tsl);
   1397   1676         jpk 	if (retv != 0)
   1398   1676         jpk 		return (retv);
   1399   9710         Ken 
   1400   9710         Ken 	/*
   1401   9710         Ken 	 * Calculate the security label to be placed in the text
   1402   9710         Ken 	 * of the message (if any).
   1403   9710         Ken 	 */
   1404  11042        Erik 	if (effective_tsl != NULL) {
   1405  11042        Erik 		if ((retv = tsol_compute_label_v6(effective_tsl, zoneid,
   1406   9710         Ken 		    &ip6h->ip6_dst, opt_storage, ipst)) != 0) {
   1407  11042        Erik 			label_rele(effective_tsl);
   1408   9710         Ken 			return (retv);
   1409   9710         Ken 		}
   1410  11042        Erik 		*effective_tslp = effective_tsl;
   1411   9710         Ken 	} else {
   1412  11042        Erik 		if ((retv = tsol_compute_label_v6(tsl, zoneid,
   1413   9710         Ken 		    &ip6h->ip6_dst, opt_storage, ipst)) != 0)
   1414   9710         Ken 			return (retv);
   1415   9710         Ken 	}
   1416   1676         jpk 
   1417   1676         jpk 	sec_opt_len = opt_storage[1];
   1418   1676         jpk 
   1419   1676         jpk 	if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
   1420   1676         jpk 		ip6hbh = (uchar_t *)&ip6h[1];
   1421   1676         jpk 		hbhlen = (ip6hbh[1] + 1) << 3;
   1422  10181         Ken 		if (!tsol_find_secopt_v6(ip6hbh, hbhlen, &secopt,
   1423  10181         Ken 		    &after_secopt, &hbh_needed)) {
   1424  10181         Ken 			/*
   1425  10181         Ken 			 * This function should not see invalid messages.
   1426  10181         Ken 			 * If one occurs, it would indicate either an
   1427  10181         Ken 			 * option previously verified in the forwarding
   1428  10181         Ken 			 * path has been corrupted or an option was
   1429  10181         Ken 			 * incorrectly generated locally.
   1430  10181         Ken 			 */
   1431  10181         Ken 			ASSERT(0);
   1432  10181         Ken 			return (EACCES);
   1433  10181         Ken 		}
   1434   1676         jpk 	}
   1435   1676         jpk 
   1436   1676         jpk 	if (sec_opt_len == 0 && secopt == NULL) {
   1437   1676         jpk 		/*
   1438   1676         jpk 		 * The packet is not supposed to have a label, and it
   1439   1676         jpk 		 * does not have one currently
   1440   1676         jpk 		 */
   1441   1676         jpk 		return (0);
   1442  10934  sommerfeld 	}
   1443  10934  sommerfeld 
   1444   1676         jpk 	if (secopt != NULL && sec_opt_len != 0 &&
   1445   1676         jpk 	    (bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) {
   1446   1676         jpk 		/* The packet has the correct label already */
   1447   1676         jpk 		return (0);
   1448   1676         jpk 	}
   1449   1676         jpk 
   1450   1676         jpk 	/*
   1451   1676         jpk 	 * If there is an option there, then it must be the wrong one; delete.
   1452   1676         jpk 	 */
   1453   6596    kp158701 	if (secopt != NULL) {
   1454   6596    kp158701 		delta_remove = tsol_remove_secopt_v6(ip6h, MBLKL(mp));
   1455   6596    kp158701 		mp->b_wptr += delta_remove;
   1456   6596    kp158701 	}
   1457   1676         jpk 
   1458   1676         jpk 	/*
   1459   1676         jpk 	 * Make sure we have room for the worst-case addition. Add 2 bytes for
   1460   1676         jpk 	 * the hop-by-hop ext header's next header and length fields. Add
   1461   1676         jpk 	 * another 2 bytes for the label option type, len and then round
   1462   1676         jpk 	 * up to the next 8-byte multiple.
   1463   1676         jpk 	 */
   1464   1676         jpk 	hlen = (4 + sec_opt_len + 7) & ~7;
   1465   1676         jpk 	if (mp->b_wptr + hlen > mp->b_datap->db_lim) {
   1466   1676         jpk 		int copylen;
   1467   1676         jpk 		mblk_t *new_mp;
   1468   1676         jpk 		uint16_t hdr_len;
   1469   1676         jpk 
   1470   1676         jpk 		hdr_len = ip_hdr_length_v6(mp, ip6h);
   1471   1676         jpk 		/*
   1472   1676         jpk 		 * Allocate enough to be meaningful, but not *too* much.
   1473   1676         jpk 		 * Also all the IPv6 extension headers must be in the same mblk
   1474   1676         jpk 		 */
   1475   1676         jpk 		copylen = MBLKL(mp);
   1476   1676         jpk 		if (copylen > 256)
   1477   1676         jpk 			copylen = 256;
   1478   1676         jpk 		if (copylen < hdr_len)
   1479   1676         jpk 			copylen = hdr_len;
   1480   8778        Erik 		new_mp = allocb_tmpl(hlen + copylen +
   1481   8778        Erik 		    (mp->b_rptr - mp->b_datap->db_base), mp);
   1482  11042        Erik 		if (new_mp == NULL) {
   1483  11042        Erik 			if (effective_tsl != NULL) {
   1484  11042        Erik 				label_rele(effective_tsl);
   1485  11042        Erik 				*effective_tslp = NULL;
   1486  11042        Erik 			}
   1487   1676         jpk 			return (ENOMEM);
   1488  11042        Erik 		}
   1489   1676         jpk 
   1490   1676         jpk 		/* keep the bias */
   1491   1676         jpk 		new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
   1492   1676         jpk 		new_mp->b_wptr = new_mp->b_rptr + copylen;
   1493   1676         jpk 		bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
   1494   1676         jpk 		new_mp->b_cont = mp;
   1495   1676         jpk 		if ((mp->b_rptr += copylen) >= mp->b_wptr) {
   1496   1676         jpk 			new_mp->b_cont = mp->b_cont;
   1497   1676         jpk 			freeb(mp);
   1498   1676         jpk 		}
   1499   1676         jpk 		*mpp = mp = new_mp;
   1500   1676         jpk 		ip6h = (ip6_t *)mp->b_rptr;
   1501   1676         jpk 	}
   1502   1676         jpk 
   1503   6596    kp158701 	delta_add = tsol_prepend_option_v6(opt_storage, ip6h, MBLKL(mp));
   1504   6596    kp158701 	if (delta_add == -1)
   1505   1676         jpk 		goto param_prob;
   1506   1676         jpk 
   1507   6596    kp158701 	ASSERT(mp->b_wptr + delta_add <= DB_LIM(mp));
   1508   6596    kp158701 	mp->b_wptr += delta_add;
   1509   1676         jpk 
   1510  11042        Erik 	/* tsol_prepend_option_v6 has adjusted ip6_plen */
   1511   1676         jpk 	return (0);
   1512   1676         jpk 
   1513   1676         jpk param_prob:
   1514  11042        Erik 	if (effective_tsl != NULL) {
   1515  11042        Erik 		label_rele(effective_tsl);
   1516  11042        Erik 		*effective_tslp = NULL;
   1517  11042        Erik 	}
   1518   1676         jpk 	return (EINVAL);
   1519   1676         jpk }
   1520