Home | History | Annotate | Download | only in ip
      1      0      stevel /*
      2      0      stevel  * CDDL HEADER START
      3      0      stevel  *
      4      0      stevel  * The contents of this file are subject to the terms of the
      5   1659     markfen  * Common Development and Distribution License (the "License").
      6   1659     markfen  * You may not use this file except in compliance with the License.
      7      0      stevel  *
      8      0      stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0      stevel  * or http://www.opensolaris.org/os/licensing.
     10      0      stevel  * See the License for the specific language governing permissions
     11      0      stevel  * and limitations under the License.
     12      0      stevel  *
     13      0      stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0      stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0      stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0      stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0      stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0      stevel  *
     19      0      stevel  * CDDL HEADER END
     20      0      stevel  */
     21      0      stevel /*
     22   8704      danmcd  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0      stevel  * Use is subject to license terms.
     24      0      stevel  */
     25      0      stevel 
     26      0      stevel #include <sys/types.h>
     27      0      stevel #include <sys/stream.h>
     28      0      stevel #include <sys/stropts.h>
     29      0      stevel #include <sys/errno.h>
     30      0      stevel #include <sys/strlog.h>
     31      0      stevel #include <sys/tihdr.h>
     32      0      stevel #include <sys/socket.h>
     33      0      stevel #include <sys/ddi.h>
     34      0      stevel #include <sys/sunddi.h>
     35   7749  Thejaswini #include <sys/mkdev.h>
     36      0      stevel #include <sys/kmem.h>
     37   3448    dh155122 #include <sys/zone.h>
     38   3192      danmcd #include <sys/sysmacros.h>
     39      0      stevel #include <sys/cmn_err.h>
     40      0      stevel #include <sys/vtrace.h>
     41      0      stevel #include <sys/debug.h>
     42      0      stevel #include <sys/atomic.h>
     43      0      stevel #include <sys/strsun.h>
     44      0      stevel #include <sys/random.h>
     45      0      stevel #include <netinet/in.h>
     46      0      stevel #include <net/if.h>
     47      0      stevel #include <netinet/ip6.h>
     48      0      stevel #include <netinet/icmp6.h>
     49      0      stevel #include <net/pfkeyv2.h>
     50  10824        Mark #include <net/pfpolicy.h>
     51      0      stevel 
     52      0      stevel #include <inet/common.h>
     53      0      stevel #include <inet/mi.h>
     54      0      stevel #include <inet/ip.h>
     55      0      stevel #include <inet/ip6.h>
     56      0      stevel #include <inet/nd.h>
     57  11042        Erik #include <inet/ip_if.h>
     58  11042        Erik #include <inet/ip_ndp.h>
     59      0      stevel #include <inet/ipsec_info.h>
     60      0      stevel #include <inet/ipsec_impl.h>
     61      0      stevel #include <inet/sadb.h>
     62      0      stevel #include <inet/ipsecah.h>
     63      0      stevel #include <inet/ipsec_impl.h>
     64      0      stevel #include <inet/ipdrop.h>
     65      0      stevel #include <sys/taskq.h>
     66      0      stevel #include <sys/policy.h>
     67      0      stevel #include <sys/strsun.h>
     68      0      stevel 
     69      0      stevel #include <sys/crypto/common.h>
     70      0      stevel #include <sys/crypto/api.h>
     71      0      stevel #include <sys/kstat.h>
     72   1676         jpk #include <sys/strsubr.h>
     73      0      stevel 
     74  10934  sommerfeld #include <sys/tsol/tnet.h>
     75  10934  sommerfeld 
     76      0      stevel /*
     77      0      stevel  * Table of ND variables supported by ipsecah. These are loaded into
     78      0      stevel  * ipsecah_g_nd in ipsecah_init_nd.
     79      0      stevel  * All of these are alterable, within the min/max values given, at run time.
     80      0      stevel  */
     81   3448    dh155122 static	ipsecahparam_t	lcl_param_arr[] = {
     82      0      stevel 	/* min	max			value	name */
     83      0      stevel 	{ 0,	3,			0,	"ipsecah_debug"},
     84      0      stevel 	{ 125,	32000, SADB_AGE_INTERVAL_DEFAULT,	"ipsecah_age_interval"},
     85      0      stevel 	{ 1,	10,			1,	"ipsecah_reap_delay"},
     86      0      stevel 	{ 1,	SADB_MAX_REPLAY,	64,	"ipsecah_replay_size"},
     87      0      stevel 	{ 1,	300,			15,	"ipsecah_acquire_timeout"},
     88      0      stevel 	{ 1,	1800,			90,	"ipsecah_larval_timeout"},
     89      0      stevel 	/* Default lifetime values for ACQUIRE messages. */
     90      0      stevel 	{ 0,	0xffffffffU,		0,	"ipsecah_default_soft_bytes"},
     91      0      stevel 	{ 0,	0xffffffffU,		0,	"ipsecah_default_hard_bytes"},
     92      0      stevel 	{ 0,	0xffffffffU,		24000,	"ipsecah_default_soft_addtime"},
     93      0      stevel 	{ 0,	0xffffffffU,		28800,	"ipsecah_default_hard_addtime"},
     94      0      stevel 	{ 0,	0xffffffffU,		0,	"ipsecah_default_soft_usetime"},
     95      0      stevel 	{ 0,	0xffffffffU,		0,	"ipsecah_default_hard_usetime"},
     96      0      stevel 	{ 0,	1,			0,	"ipsecah_log_unknown_spi"},
     97      0      stevel };
     98   3448    dh155122 #define	ipsecah_debug			ipsecah_params[0].ipsecah_param_value
     99   3448    dh155122 #define	ipsecah_age_interval		ipsecah_params[1].ipsecah_param_value
    100   3448    dh155122 #define	ipsecah_age_int_max		ipsecah_params[1].ipsecah_param_max
    101   3448    dh155122 #define	ipsecah_reap_delay		ipsecah_params[2].ipsecah_param_value
    102   3448    dh155122 #define	ipsecah_replay_size		ipsecah_params[3].ipsecah_param_value
    103   3448    dh155122 #define	ipsecah_acquire_timeout		ipsecah_params[4].ipsecah_param_value
    104   3448    dh155122 #define	ipsecah_larval_timeout		ipsecah_params[5].ipsecah_param_value
    105   3448    dh155122 #define	ipsecah_default_soft_bytes	ipsecah_params[6].ipsecah_param_value
    106   3448    dh155122 #define	ipsecah_default_hard_bytes	ipsecah_params[7].ipsecah_param_value
    107   3448    dh155122 #define	ipsecah_default_soft_addtime	ipsecah_params[8].ipsecah_param_value
    108   3448    dh155122 #define	ipsecah_default_hard_addtime	ipsecah_params[9].ipsecah_param_value
    109   3448    dh155122 #define	ipsecah_default_soft_usetime	ipsecah_params[10].ipsecah_param_value
    110   3448    dh155122 #define	ipsecah_default_hard_usetime	ipsecah_params[11].ipsecah_param_value
    111   3448    dh155122 #define	ipsecah_log_unknown_spi		ipsecah_params[12].ipsecah_param_value
    112      0      stevel 
    113      0      stevel #define	ah0dbg(a)	printf a
    114      0      stevel /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
    115   3448    dh155122 #define	ah1dbg(ahstack, a)	if (ahstack->ipsecah_debug != 0) printf a
    116   3448    dh155122 #define	ah2dbg(ahstack, a)	if (ahstack->ipsecah_debug > 1) printf a
    117   3448    dh155122 #define	ah3dbg(ahstack, a)	if (ahstack->ipsecah_debug > 2) printf a
    118      0      stevel 
    119      0      stevel /*
    120      0      stevel  * XXX This is broken. Padding should be determined dynamically
    121      0      stevel  * depending on the ICV size and IP version number so that the
    122      0      stevel  * total AH header size is a multiple of 32 bits or 64 bits
    123      0      stevel  * for V4 and V6 respectively. For 96bit ICVs we have no problems.
    124      0      stevel  * Anything different from that, we need to fix our code.
    125      0      stevel  */
    126      0      stevel #define	IPV4_PADDING_ALIGN	0x04	/* Multiple of 32 bits */
    127      0      stevel #define	IPV6_PADDING_ALIGN	0x04	/* Multiple of 32 bits */
    128      0      stevel 
    129      0      stevel /*
    130      0      stevel  * Helper macro. Avoids a call to msgdsize if there is only one
    131      0      stevel  * mblk in the chain.
    132      0      stevel  */
    133      0      stevel #define	AH_MSGSIZE(mp) ((mp)->b_cont != NULL ? msgdsize(mp) : MBLKL(mp))
    134      0      stevel 
    135   3448    dh155122 
    136  11042        Erik static mblk_t *ah_auth_out_done(mblk_t *, ip_xmit_attr_t *, ipsec_crypto_t *);
    137  11042        Erik static mblk_t *ah_auth_in_done(mblk_t *, ip_recv_attr_t *, ipsec_crypto_t *);
    138      0      stevel static mblk_t *ah_process_ip_options_v4(mblk_t *, ipsa_t *, int *, uint_t,
    139   3448    dh155122     boolean_t, ipsecah_stack_t *);
    140      0      stevel static mblk_t *ah_process_ip_options_v6(mblk_t *, ipsa_t *, int *, uint_t,
    141   3448    dh155122     boolean_t, ipsecah_stack_t *);
    142   3448    dh155122 static void ah_getspi(mblk_t *, keysock_in_t *, ipsecah_stack_t *);
    143  11042        Erik static void ah_inbound_restart(mblk_t *, ip_recv_attr_t *);
    144  11042        Erik 
    145  11042        Erik static mblk_t *ah_outbound(mblk_t *, ip_xmit_attr_t *);
    146  11042        Erik static void ah_outbound_finish(mblk_t *, ip_xmit_attr_t *);
    147      0      stevel 
    148      0      stevel static int ipsecah_open(queue_t *, dev_t *, int, int, cred_t *);
    149      0      stevel static int ipsecah_close(queue_t *);
    150      0      stevel static void ipsecah_wput(queue_t *, mblk_t *);
    151   3448    dh155122 static void ah_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
    152  10934  sommerfeld static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
    153  11042        Erik     cred_t *);
    154   3448    dh155122 static void	*ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
    155   3448    dh155122 static void	ipsecah_stack_fini(netstackid_t stackid, void *arg);
    156   7749  Thejaswini 
    157   3448    dh155122 /* Setable in /etc/system */
    158   3448    dh155122 uint32_t ah_hash_size = IPSEC_DEFAULT_HASH_SIZE;
    159   3448    dh155122 
    160   3448    dh155122 static taskq_t *ah_taskq;
    161      0      stevel 
    162      0      stevel static struct module_info info = {
    163      0      stevel 	5136, "ipsecah", 0, INFPSZ, 65536, 1024
    164      0      stevel };
    165      0      stevel 
    166      0      stevel static struct qinit rinit = {
    167  11042        Erik 	(pfi_t)putnext, NULL, ipsecah_open, ipsecah_close, NULL, &info,
    168      0      stevel 	NULL
    169      0      stevel };
    170      0      stevel 
    171      0      stevel static struct qinit winit = {
    172      0      stevel 	(pfi_t)ipsecah_wput, NULL, ipsecah_open, ipsecah_close, NULL, &info,
    173      0      stevel 	NULL
    174      0      stevel };
    175      0      stevel 
    176      0      stevel struct streamtab ipsecahinfo = {
    177      0      stevel 	&rinit, &winit, NULL, NULL
    178      0      stevel };
    179      0      stevel 
    180      0      stevel static int ah_kstat_update(kstat_t *, int);
    181      0      stevel 
    182   1659     markfen uint64_t ipsacq_maxpackets = IPSACQ_MAXPACKETS;
    183   1659     markfen 
    184      0      stevel static boolean_t
    185   3448    dh155122 ah_kstat_init(ipsecah_stack_t *ahstack, netstackid_t stackid)
    186   3448    dh155122 {
    187   3448    dh155122 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
    188   3448    dh155122 
    189   3448    dh155122 	ahstack->ah_ksp = kstat_create_netstack("ipsecah", 0, "ah_stat", "net",
    190   3448    dh155122 	    KSTAT_TYPE_NAMED, sizeof (ah_kstats_t) / sizeof (kstat_named_t),
    191   3448    dh155122 	    KSTAT_FLAG_PERSISTENT, stackid);
    192   3448    dh155122 
    193   3448    dh155122 	if (ahstack->ah_ksp == NULL || ahstack->ah_ksp->ks_data == NULL)
    194      0      stevel 		return (B_FALSE);
    195      0      stevel 
    196   3448    dh155122 	ahstack->ah_kstats = ahstack->ah_ksp->ks_data;
    197   3448    dh155122 
    198   3448    dh155122 	ahstack->ah_ksp->ks_update = ah_kstat_update;
    199   3448    dh155122 	ahstack->ah_ksp->ks_private = (void *)(uintptr_t)stackid;
    200      0      stevel 
    201      0      stevel #define	K64 KSTAT_DATA_UINT64
    202   3448    dh155122 #define	KI(x) kstat_named_init(&(ahstack->ah_kstats->ah_stat_##x), #x, K64)
    203      0      stevel 
    204      0      stevel 	KI(num_aalgs);
    205      0      stevel 	KI(good_auth);
    206      0      stevel 	KI(bad_auth);
    207      0      stevel 	KI(replay_failures);
    208      0      stevel 	KI(replay_early_failures);
    209      0      stevel 	KI(keysock_in);
    210      0      stevel 	KI(out_requests);
    211      0      stevel 	KI(acquire_requests);
    212      0      stevel 	KI(bytes_expired);
    213      0      stevel 	KI(out_discards);
    214      0      stevel 	KI(crypto_sync);
    215      0      stevel 	KI(crypto_async);
    216      0      stevel 	KI(crypto_failures);
    217      0      stevel 
    218      0      stevel #undef KI
    219      0      stevel #undef K64
    220      0      stevel 
    221   3448    dh155122 	kstat_install(ahstack->ah_ksp);
    222   3448    dh155122 	IP_ACQUIRE_STAT(ipss, maxpackets, ipsacq_maxpackets);
    223      0      stevel 	return (B_TRUE);
    224      0      stevel }
    225      0      stevel 
    226      0      stevel static int
    227      0      stevel ah_kstat_update(kstat_t *kp, int rw)
    228      0      stevel {
    229   3448    dh155122 	ah_kstats_t	*ekp;
    230   3448    dh155122 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
    231   3448    dh155122 	netstack_t	*ns;
    232   3448    dh155122 	ipsec_stack_t	*ipss;
    233      0      stevel 
    234      0      stevel 	if ((kp == NULL) || (kp->ks_data == NULL))
    235      0      stevel 		return (EIO);
    236      0      stevel 
    237      0      stevel 	if (rw == KSTAT_WRITE)
    238      0      stevel 		return (EACCES);
    239      0      stevel 
    240   3448    dh155122 	ns = netstack_find_by_stackid(stackid);
    241   3448    dh155122 	if (ns == NULL)
    242   3448    dh155122 		return (-1);
    243   3448    dh155122 	ipss = ns->netstack_ipsec;
    244   3448    dh155122 	if (ipss == NULL) {
    245   3448    dh155122 		netstack_rele(ns);
    246   3448    dh155122 		return (-1);
    247   3448    dh155122 	}
    248      0      stevel 	ekp = (ah_kstats_t *)kp->ks_data;
    249   3448    dh155122 
    250   3448    dh155122 	mutex_enter(&ipss->ipsec_alg_lock);
    251   3448    dh155122 	ekp->ah_stat_num_aalgs.value.ui64 = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
    252   3448    dh155122 	mutex_exit(&ipss->ipsec_alg_lock);
    253   3448    dh155122 
    254   3448    dh155122 	netstack_rele(ns);
    255      0      stevel 	return (0);
    256      0      stevel }
    257      0      stevel 
    258      0      stevel /*
    259      0      stevel  * Don't have to lock ipsec_age_interval, as only one thread will access it at
    260      0      stevel  * a time, because I control the one function that does a qtimeout() on
    261      0      stevel  * ah_pfkey_q.
    262      0      stevel  */
    263   3448    dh155122 static void
    264   3448    dh155122 ah_ager(void *arg)
    265   3448    dh155122 {
    266   3448    dh155122 	ipsecah_stack_t *ahstack = (ipsecah_stack_t *)arg;
    267   3448    dh155122 	netstack_t	*ns = ahstack->ipsecah_netstack;
    268      0      stevel 	hrtime_t begin = gethrtime();
    269      0      stevel 
    270   3448    dh155122 	sadb_ager(&ahstack->ah_sadb.s_v4, ahstack->ah_pfkey_q,
    271  11042        Erik 	    ahstack->ipsecah_reap_delay, ns);
    272   3448    dh155122 	sadb_ager(&ahstack->ah_sadb.s_v6, ahstack->ah_pfkey_q,
    273  11042        Erik 	    ahstack->ipsecah_reap_delay, ns);
    274   3448    dh155122 
    275   3448    dh155122 	ahstack->ah_event = sadb_retimeout(begin, ahstack->ah_pfkey_q,
    276   3448    dh155122 	    ah_ager, ahstack,
    277   3448    dh155122 	    &ahstack->ipsecah_age_interval, ahstack->ipsecah_age_int_max,
    278   3448    dh155122 	    info.mi_idnum);
    279      0      stevel }
    280      0      stevel 
    281      0      stevel /*
    282      0      stevel  * Get an AH NDD parameter.
    283      0      stevel  */
    284      0      stevel /* ARGSUSED */
    285      0      stevel static int
    286      0      stevel ipsecah_param_get(q, mp, cp, cr)
    287      0      stevel 	queue_t	*q;
    288      0      stevel 	mblk_t	*mp;
    289      0      stevel 	caddr_t	cp;
    290      0      stevel 	cred_t *cr;
    291      0      stevel {
    292      0      stevel 	ipsecahparam_t	*ipsecahpa = (ipsecahparam_t *)cp;
    293      0      stevel 	uint_t value;
    294   3448    dh155122 	ipsecah_stack_t	*ahstack = (ipsecah_stack_t *)q->q_ptr;
    295   3448    dh155122 
    296   3448    dh155122 	mutex_enter(&ahstack->ipsecah_param_lock);
    297      0      stevel 	value = ipsecahpa->ipsecah_param_value;
    298   3448    dh155122 	mutex_exit(&ahstack->ipsecah_param_lock);
    299      0      stevel 
    300      0      stevel 	(void) mi_mpprintf(mp, "%u", value);
    301      0      stevel 	return (0);
    302      0      stevel }
    303      0      stevel 
    304      0      stevel /*
    305      0      stevel  * This routine sets an NDD variable in a ipsecahparam_t structure.
    306      0      stevel  */
    307      0      stevel /* ARGSUSED */
    308      0      stevel static int
    309      0      stevel ipsecah_param_set(q, mp, value, cp, cr)
    310      0      stevel 	queue_t	*q;
    311      0      stevel 	mblk_t	*mp;
    312      0      stevel 	char	*value;
    313      0      stevel 	caddr_t	cp;
    314      0      stevel 	cred_t *cr;
    315      0      stevel {
    316      0      stevel 	ulong_t	new_value;
    317      0      stevel 	ipsecahparam_t	*ipsecahpa = (ipsecahparam_t *)cp;
    318   3448    dh155122 	ipsecah_stack_t	*ahstack = (ipsecah_stack_t *)q->q_ptr;
    319      0      stevel 
    320      0      stevel 	/*
    321      0      stevel 	 * Fail the request if the new value does not lie within the
    322      0      stevel 	 * required bounds.
    323      0      stevel 	 */
    324      0      stevel 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0 ||
    325      0      stevel 	    new_value < ipsecahpa->ipsecah_param_min ||
    326      0      stevel 	    new_value > ipsecahpa->ipsecah_param_max) {
    327      0      stevel 		    return (EINVAL);
    328      0      stevel 	}
    329      0      stevel 
    330      0      stevel 	/* Set the new value */
    331   3448    dh155122 	mutex_enter(&ahstack->ipsecah_param_lock);
    332      0      stevel 	ipsecahpa->ipsecah_param_value = new_value;
    333   3448    dh155122 	mutex_exit(&ahstack->ipsecah_param_lock);
    334      0      stevel 	return (0);
    335      0      stevel }
    336      0      stevel 
    337      0      stevel /*
    338      0      stevel  * Using lifetime NDD variables, fill in an extended combination's
    339      0      stevel  * lifetime information.
    340      0      stevel  */
    341      0      stevel void
    342   3448    dh155122 ipsecah_fill_defs(sadb_x_ecomb_t *ecomb, netstack_t *ns)
    343   3448    dh155122 {
    344   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
    345   3448    dh155122 
    346   3448    dh155122 	ecomb->sadb_x_ecomb_soft_bytes = ahstack->ipsecah_default_soft_bytes;
    347   3448    dh155122 	ecomb->sadb_x_ecomb_hard_bytes = ahstack->ipsecah_default_hard_bytes;
    348   3448    dh155122 	ecomb->sadb_x_ecomb_soft_addtime =
    349   3448    dh155122 	    ahstack->ipsecah_default_soft_addtime;
    350   3448    dh155122 	ecomb->sadb_x_ecomb_hard_addtime =
    351   3448    dh155122 	    ahstack->ipsecah_default_hard_addtime;
    352   3448    dh155122 	ecomb->sadb_x_ecomb_soft_usetime =
    353   3448    dh155122 	    ahstack->ipsecah_default_soft_usetime;
    354   3448    dh155122 	ecomb->sadb_x_ecomb_hard_usetime =
    355   3448    dh155122 	    ahstack->ipsecah_default_hard_usetime;
    356      0      stevel }
    357      0      stevel 
    358      0      stevel /*
    359      0      stevel  * Initialize things for AH at module load time.
    360      0      stevel  */
    361      0      stevel boolean_t
    362      0      stevel ipsecah_ddi_init(void)
    363      0      stevel {
    364   3448    dh155122 	ah_taskq = taskq_create("ah_taskq", 1, minclsyspri,
    365   3448    dh155122 	    IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0);
    366   3448    dh155122 
    367   3448    dh155122 	/*
    368   3448    dh155122 	 * We want to be informed each time a stack is created or
    369   3448    dh155122 	 * destroyed in the kernel, so we can maintain the
    370   3448    dh155122 	 * set of ipsecah_stack_t's.
    371   3448    dh155122 	 */
    372   3448    dh155122 	netstack_register(NS_IPSECAH, ipsecah_stack_init, NULL,
    373   3448    dh155122 	    ipsecah_stack_fini);
    374   3448    dh155122 
    375   3448    dh155122 	return (B_TRUE);
    376   3448    dh155122 }
    377   3448    dh155122 
    378   3448    dh155122 /*
    379   3448    dh155122  * Walk through the param array specified registering each element with the
    380   3448    dh155122  * named dispatch handler.
    381   3448    dh155122  */
    382   3448    dh155122 static boolean_t
    383   3448    dh155122 ipsecah_param_register(IDP *ndp, ipsecahparam_t *ahp, int cnt)
    384   3448    dh155122 {
    385   3448    dh155122 	for (; cnt-- > 0; ahp++) {
    386      0      stevel 		if (ahp->ipsecah_param_name != NULL &&
    387      0      stevel 		    ahp->ipsecah_param_name[0]) {
    388   3448    dh155122 			if (!nd_load(ndp,
    389   3448    dh155122 			    ahp->ipsecah_param_name,
    390      0      stevel 			    ipsecah_param_get, ipsecah_param_set,
    391      0      stevel 			    (caddr_t)ahp)) {
    392   3448    dh155122 				nd_free(ndp);
    393      0      stevel 				return (B_FALSE);
    394      0      stevel 			}
    395      0      stevel 		}
    396      0      stevel 	}
    397      0      stevel 	return (B_TRUE);
    398      0      stevel }
    399      0      stevel 
    400      0      stevel /*
    401   3448    dh155122  * Initialize things for AH for each stack instance
    402   3448    dh155122  */
    403   3448    dh155122 static void *
    404   3448    dh155122 ipsecah_stack_init(netstackid_t stackid, netstack_t *ns)
    405   3448    dh155122 {
    406   3448    dh155122 	ipsecah_stack_t	*ahstack;
    407   3448    dh155122 	ipsecahparam_t	*ahp;
    408   3448    dh155122 
    409   3448    dh155122 	ahstack = (ipsecah_stack_t *)kmem_zalloc(sizeof (*ahstack), KM_SLEEP);
    410   3448    dh155122 	ahstack->ipsecah_netstack = ns;
    411   3448    dh155122 
    412   3448    dh155122 	ahp = (ipsecahparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
    413   3448    dh155122 	ahstack->ipsecah_params = ahp;
    414   3448    dh155122 	bcopy(lcl_param_arr, ahp, sizeof (lcl_param_arr));
    415   3448    dh155122 
    416   3448    dh155122 	(void) ipsecah_param_register(&ahstack->ipsecah_g_nd, ahp,
    417   3448    dh155122 	    A_CNT(lcl_param_arr));
    418   3448    dh155122 
    419   3448    dh155122 	(void) ah_kstat_init(ahstack, stackid);
    420   3448    dh155122 
    421   3448    dh155122 	ahstack->ah_sadb.s_acquire_timeout = &ahstack->ipsecah_acquire_timeout;
    422   3448    dh155122 	ahstack->ah_sadb.s_acqfn = ah_send_acquire;
    423   3448    dh155122 	sadbp_init("AH", &ahstack->ah_sadb, SADB_SATYPE_AH, ah_hash_size,
    424   3448    dh155122 	    ahstack->ipsecah_netstack);
    425   3448    dh155122 
    426   3448    dh155122 	mutex_init(&ahstack->ipsecah_param_lock, NULL, MUTEX_DEFAULT, 0);
    427   3448    dh155122 
    428   3448    dh155122 	ip_drop_register(&ahstack->ah_dropper, "IPsec AH");
    429   3448    dh155122 	return (ahstack);
    430   3448    dh155122 }
    431   3448    dh155122 
    432   3448    dh155122 /*
    433      0      stevel  * Destroy things for AH at module unload time.
    434      0      stevel  */
    435      0      stevel void
    436      0      stevel ipsecah_ddi_destroy(void)
    437      0      stevel {
    438   3448    dh155122 	netstack_unregister(NS_IPSECAH);
    439      0      stevel 	taskq_destroy(ah_taskq);
    440   3448    dh155122 }
    441   3448    dh155122 
    442   3448    dh155122 /*
    443   3448    dh155122  * Destroy things for AH for one stack... Never called?
    444   3448    dh155122  */
    445   3448    dh155122 static void
    446   3448    dh155122 ipsecah_stack_fini(netstackid_t stackid, void *arg)
    447   3448    dh155122 {
    448   3448    dh155122 	ipsecah_stack_t *ahstack = (ipsecah_stack_t *)arg;
    449   3448    dh155122 
    450   3448    dh155122 	if (ahstack->ah_pfkey_q != NULL) {
    451   3448    dh155122 		(void) quntimeout(ahstack->ah_pfkey_q, ahstack->ah_event);
    452   3448    dh155122 	}
    453   3448    dh155122 	ahstack->ah_sadb.s_acqfn = NULL;
    454   3448    dh155122 	ahstack->ah_sadb.s_acquire_timeout = NULL;
    455   3448    dh155122 	sadbp_destroy(&ahstack->ah_sadb, ahstack->ipsecah_netstack);
    456   3448    dh155122 	ip_drop_unregister(&ahstack->ah_dropper);
    457   3448    dh155122 	mutex_destroy(&ahstack->ipsecah_param_lock);
    458   3448    dh155122 	nd_free(&ahstack->ipsecah_g_nd);
    459   3448    dh155122 
    460   3448    dh155122 	kmem_free(ahstack->ipsecah_params, sizeof (lcl_param_arr));
    461   3448    dh155122 	ahstack->ipsecah_params = NULL;
    462   3448    dh155122 	kstat_delete_netstack(ahstack->ah_ksp, stackid);
    463   3448    dh155122 	ahstack->ah_ksp = NULL;
    464   3448    dh155122 	ahstack->ah_kstats = NULL;
    465   3448    dh155122 
    466   3448    dh155122 	kmem_free(ahstack, sizeof (*ahstack));
    467      0      stevel }
    468      0      stevel 
    469      0      stevel /*
    470  11042        Erik  * AH module open routine, which is here for keysock plumbing.
    471  11042        Erik  * Keysock is pushed over {AH,ESP} which is an artifact from the Bad Old
    472  11042        Erik  * Days of export control, and fears that ESP would not be allowed
    473  11042        Erik  * to be shipped at all by default.  Eventually, keysock should
    474  11042        Erik  * either access AH and ESP via modstubs or krtld dependencies, or
    475  11042        Erik  * perhaps be folded in with AH and ESP into a single IPsec/netsec
    476  11042        Erik  * module ("netsec" if PF_KEY provides more than AH/ESP keying tables).
    477      0      stevel  */
    478      0      stevel /* ARGSUSED */
    479      0      stevel static int
    480      0      stevel ipsecah_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
    481      0      stevel {
    482   3448    dh155122 	netstack_t	*ns;
    483   3448    dh155122 	ipsecah_stack_t	*ahstack;
    484   3448    dh155122 
    485   7118    sommerfe 	if (secpolicy_ip_config(credp, B_FALSE) != 0)
    486      0      stevel 		return (EPERM);
    487      0      stevel 
    488      0      stevel 	if (q->q_ptr != NULL)
    489      0      stevel 		return (0);  /* Re-open of an already open instance. */
    490      0      stevel 
    491      0      stevel 	if (sflag != MODOPEN)
    492      0      stevel 		return (EINVAL);
    493   3448    dh155122 
    494   3448    dh155122 	ns = netstack_find_by_cred(credp);
    495   3448    dh155122 	ASSERT(ns != NULL);
    496   3448    dh155122 	ahstack = ns->netstack_ipsecah;
    497   3448    dh155122 	ASSERT(ahstack != NULL);
    498      0      stevel 
    499   3448    dh155122 	q->q_ptr = ahstack;
    500   3448    dh155122 	WR(q)->q_ptr = q->q_ptr;
    501   3448    dh155122 
    502  11042        Erik 	qprocson(q);
    503      0      stevel 	return (0);
    504      0      stevel }
    505      0      stevel 
    506      0      stevel /*
    507      0      stevel  * AH module close routine.
    508      0      stevel  */
    509      0      stevel static int
    510      0      stevel ipsecah_close(queue_t *q)
    511      0      stevel {
    512   3448    dh155122 	ipsecah_stack_t	*ahstack = (ipsecah_stack_t *)q->q_ptr;
    513      0      stevel 
    514      0      stevel 	/*
    515      0      stevel 	 * Clean up q_ptr, if needed.
    516      0      stevel 	 */
    517      0      stevel 	qprocsoff(q);
    518      0      stevel 
    519      0      stevel 	/* Keysock queue check is safe, because of OCEXCL perimeter. */
    520      0      stevel 
    521   3448    dh155122 	if (q == ahstack->ah_pfkey_q) {
    522   3448    dh155122 		ah1dbg(ahstack,
    523   3448    dh155122 		    ("ipsecah_close:  Ummm... keysock is closing AH.\n"));
    524   3448    dh155122 		ahstack->ah_pfkey_q = NULL;
    525      0      stevel 		/* Detach qtimeouts. */
    526   3448    dh155122 		(void) quntimeout(q, ahstack->ah_event);
    527   3448    dh155122 	}
    528   3448    dh155122 
    529   3448    dh155122 	netstack_rele(ahstack->ipsecah_netstack);
    530      0      stevel 	return (0);
    531      0      stevel }
    532      0      stevel 
    533      0      stevel /*
    534      0      stevel  * Construct an SADB_REGISTER message with the current algorithms.
    535      0      stevel  */
    536      0      stevel static boolean_t
    537   3448    dh155122 ah_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
    538  11042        Erik     ipsecah_stack_t *ahstack, cred_t *cr)
    539      0      stevel {
    540      0      stevel 	mblk_t *mp;
    541      0      stevel 	boolean_t rc = B_TRUE;
    542      0      stevel 	sadb_msg_t *samsg;
    543      0      stevel 	sadb_supported_t *sasupp;
    544      0      stevel 	sadb_alg_t *saalg;
    545      0      stevel 	uint_t allocsize = sizeof (*samsg);
    546      0      stevel 	uint_t i, numalgs_snap;
    547      0      stevel 	ipsec_alginfo_t **authalgs;
    548      0      stevel 	uint_t num_aalgs;
    549   3448    dh155122 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
    550  10934  sommerfeld 	sadb_sens_t *sens;
    551  10934  sommerfeld 	size_t sens_len = 0;
    552  10934  sommerfeld 	sadb_ext_t *nextext;
    553  11042        Erik 	ts_label_t *sens_tsl = NULL;
    554      0      stevel 
    555      0      stevel 	/* Allocate the KEYSOCK_OUT. */
    556      0      stevel 	mp = sadb_keysock_out(serial);
    557      0      stevel 	if (mp == NULL) {
    558      0      stevel 		ah0dbg(("ah_register_out: couldn't allocate mblk.\n"));
    559      0      stevel 		return (B_FALSE);
    560      0      stevel 	}
    561      0      stevel 
    562  11042        Erik 	if (is_system_labeled() && (cr != NULL)) {
    563  11042        Erik 		sens_tsl = crgetlabel(cr);
    564  11042        Erik 		if (sens_tsl != NULL) {
    565  11042        Erik 			sens_len = sadb_sens_len_from_label(sens_tsl);
    566  10934  sommerfeld 			allocsize += sens_len;
    567  10934  sommerfeld 		}
    568  10934  sommerfeld 	}
    569  10934  sommerfeld 
    570      0      stevel 	/*
    571      0      stevel 	 * Allocate the PF_KEY message that follows KEYSOCK_OUT.
    572      0      stevel 	 * The alg reader lock needs to be held while allocating
    573      0      stevel 	 * the variable part (i.e. the algorithms) of the message.
    574      0      stevel 	 */
    575      0      stevel 
    576   3448    dh155122 	mutex_enter(&ipss->ipsec_alg_lock);
    577      0      stevel 
    578      0      stevel 	/*
    579      0      stevel 	 * Return only valid algorithms, so the number of algorithms
    580      0      stevel 	 * to send up may be less than the number of algorithm entries
    581      0      stevel 	 * in the table.
    582      0      stevel 	 */
    583   3448    dh155122 	authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
    584      0      stevel 	for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
    585      0      stevel 		if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
    586      0      stevel 			num_aalgs++;
    587      0      stevel 
    588      0      stevel 	/*
    589      0      stevel 	 * Fill SADB_REGISTER message's algorithm descriptors.  Hold
    590      0      stevel 	 * down the lock while filling it.
    591      0      stevel 	 */
    592      0      stevel 	if (num_aalgs != 0) {
    593      0      stevel 		allocsize += (num_aalgs * sizeof (*saalg));
    594      0      stevel 		allocsize += sizeof (*sasupp);
    595      0      stevel 	}
    596      0      stevel 	mp->b_cont = allocb(allocsize, BPRI_HI);
    597      0      stevel 	if (mp->b_cont == NULL) {
    598   3448    dh155122 		mutex_exit(&ipss->ipsec_alg_lock);
    599      0      stevel 		freemsg(mp);
    600      0      stevel 		return (B_FALSE);
    601      0      stevel 	}
    602      0      stevel 
    603      0      stevel 	mp->b_cont->b_wptr += allocsize;
    604  10934  sommerfeld 	nextext = (sadb_ext_t *)(mp->b_cont->b_rptr + sizeof (*samsg));
    605  10934  sommerfeld 
    606      0      stevel 	if (num_aalgs != 0) {
    607      0      stevel 
    608  10934  sommerfeld 		saalg = (sadb_alg_t *)(((uint8_t *)nextext) + sizeof (*sasupp));
    609      0      stevel 		ASSERT(((ulong_t)saalg & 0x7) == 0);
    610      0      stevel 
    611      0      stevel 		numalgs_snap = 0;
    612      0      stevel 		for (i = 0;
    613   3448    dh155122 		    ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs));
    614   3448    dh155122 		    i++) {
    615      0      stevel 			if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
    616      0      stevel 				continue;
    617      0      stevel 
    618      0      stevel 			saalg->sadb_alg_id = authalgs[i]->alg_id;
    619      0      stevel 			saalg->sadb_alg_ivlen = 0;
    620      0      stevel 			saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits;
    621      0      stevel 			saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits;
    622      0      stevel 			saalg->sadb_x_alg_increment =
    623      0      stevel 			    authalgs[i]->alg_increment;
    624  10824        Mark 			/* For now, salt is meaningless in AH. */
    625  10824        Mark 			ASSERT(authalgs[i]->alg_saltlen == 0);
    626  10824        Mark 			saalg->sadb_x_alg_saltbits =
    627  10824        Mark 			    SADB_8TO1(authalgs[i]->alg_saltlen);
    628      0      stevel 			numalgs_snap++;
    629      0      stevel 			saalg++;
    630      0      stevel 		}
    631      0      stevel 		ASSERT(numalgs_snap == num_aalgs);
    632      0      stevel #ifdef DEBUG
    633      0      stevel 		/*
    634      0      stevel 		 * Reality check to make sure I snagged all of the
    635      0      stevel 		 * algorithms.
    636      0      stevel 		 */
    637      0      stevel 		for (; i < IPSEC_MAX_ALGS; i++)
    638      0      stevel 			if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
    639      0      stevel 				cmn_err(CE_PANIC,
    640      0      stevel 				    "ah_register_out()!  Missed #%d.\n", i);
    641      0      stevel #endif /* DEBUG */
    642  10934  sommerfeld 		nextext = (sadb_ext_t *)saalg;
    643      0      stevel 	}
    644      0      stevel 
    645   3448    dh155122 	mutex_exit(&ipss->ipsec_alg_lock);
    646  10934  sommerfeld 
    647  11042        Erik 	if (sens_tsl != NULL) {
    648  10934  sommerfeld 		sens = (sadb_sens_t *)nextext;
    649  11042        Erik 		sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
    650  11042        Erik 		    sens_tsl, sens_len);
    651  10934  sommerfeld 
    652  10934  sommerfeld 		nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
    653  10934  sommerfeld 	}
    654      0      stevel 
    655      0      stevel 	/* Now fill the restof the SADB_REGISTER message. */
    656      0      stevel 
    657      0      stevel 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
    658      0      stevel 	samsg->sadb_msg_version = PF_KEY_V2;
    659      0      stevel 	samsg->sadb_msg_type = SADB_REGISTER;
    660      0      stevel 	samsg->sadb_msg_errno = 0;
    661      0      stevel 	samsg->sadb_msg_satype = SADB_SATYPE_AH;
    662      0      stevel 	samsg->sadb_msg_len = SADB_8TO64(allocsize);
    663      0      stevel 	samsg->sadb_msg_reserved = 0;
    664      0      stevel 	/*
    665      0      stevel 	 * Assume caller has sufficient sequence/pid number info.  If it's one
    666      0      stevel 	 * from me over a new alg., I could give two hoots about sequence.
    667      0      stevel 	 */
    668      0      stevel 	samsg->sadb_msg_seq = sequence;
    669      0      stevel 	samsg->sadb_msg_pid = pid;
    670      0      stevel 
    671  10934  sommerfeld 	if (num_aalgs != 0) {
    672      0      stevel 		sasupp = (sadb_supported_t *)(samsg + 1);
    673  10934  sommerfeld 		sasupp->sadb_supported_len = SADB_8TO64(
    674  10934  sommerfeld 		    sizeof (*sasupp) + sizeof (*saalg) * num_aalgs);
    675      0      stevel 		sasupp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
    676      0      stevel 		sasupp->sadb_supported_reserved = 0;
    677      0      stevel 	}
    678      0      stevel 
    679   3448    dh155122 	if (ahstack->ah_pfkey_q != NULL)
    680   3448    dh155122 		putnext(ahstack->ah_pfkey_q, mp);
    681      0      stevel 	else {
    682      0      stevel 		rc = B_FALSE;
    683      0      stevel 		freemsg(mp);
    684      0      stevel 	}
    685      0      stevel 
    686      0      stevel 	return (rc);
    687      0      stevel }
    688      0      stevel 
    689      0      stevel /*
    690      0      stevel  * Invoked when the algorithm table changes. Causes SADB_REGISTER
    691      0      stevel  * messages continaining the current list of algorithms to be
    692      0      stevel  * sent up to the AH listeners.
    693      0      stevel  */
    694      0      stevel void
    695   3448    dh155122 ipsecah_algs_changed(netstack_t *ns)
    696   3448    dh155122 {
    697   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
    698   3448    dh155122 
    699      0      stevel 	/*
    700      0      stevel 	 * Time to send a PF_KEY SADB_REGISTER message to AH listeners
    701      0      stevel 	 * everywhere.  (The function itself checks for NULL ah_pfkey_q.)
    702      0      stevel 	 */
    703  10934  sommerfeld 	(void) ah_register_out(0, 0, 0, ahstack, NULL);
    704      0      stevel }
    705      0      stevel 
    706      0      stevel /*
    707      0      stevel  * Stub function that taskq_dispatch() invokes to take the mblk (in arg)
    708  11042        Erik  * and send it into AH and IP again.
    709      0      stevel  */
    710      0      stevel static void
    711      0      stevel inbound_task(void *arg)
    712      0      stevel {
    713  11042        Erik 	mblk_t		*mp = (mblk_t *)arg;
    714  11042        Erik 	mblk_t		*async_mp;
    715  11042        Erik 	ip_recv_attr_t	iras;
    716  11042        Erik 
    717  11042        Erik 	async_mp = mp;
    718  11042        Erik 	mp = async_mp->b_cont;
    719  11042        Erik 	async_mp->b_cont = NULL;
    720  11042        Erik 	if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
    721  11042        Erik 		/* The ill or ip_stack_t disappeared on us */
    722  11042        Erik 		ip_drop_input("ip_recv_attr_from_mblk", mp, NULL);
    723  11042        Erik 		freemsg(mp);
    724  11042        Erik 		goto done;
    725  11042        Erik 	}
    726  11042        Erik 
    727  11042        Erik 	ah_inbound_restart(mp, &iras);
    728  11042        Erik done:
    729  11042        Erik 	ira_cleanup(&iras, B_TRUE);
    730  11042        Erik }
    731  11042        Erik 
    732  11042        Erik /*
    733  11042        Erik  * Restart ESP after the SA has been added.
    734  11042        Erik  */
    735  11042        Erik static void
    736  11042        Erik ah_inbound_restart(mblk_t *mp, ip_recv_attr_t *ira)
    737  11042        Erik {
    738  11042        Erik 	ah_t		*ah;
    739  11042        Erik 	netstack_t	*ns;
    740  11042        Erik 	ipsecah_stack_t	*ahstack;
    741  11042        Erik 
    742  11042        Erik 	ns = ira->ira_ill->ill_ipst->ips_netstack;
    743   8704      danmcd 	ahstack = ns->netstack_ipsecah;
    744   3448    dh155122 
    745   3448    dh155122 	ASSERT(ahstack != NULL);
    746  11042        Erik 	mp = ipsec_inbound_ah_sa(mp, ira, &ah);
    747  11042        Erik 	if (mp == NULL)
    748  11042        Erik 		return;
    749  11042        Erik 
    750  11042        Erik 	ASSERT(ah != NULL);
    751  11042        Erik 	ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE);
    752  11042        Erik 	ASSERT(ira->ira_ipsec_ah_sa != NULL);
    753  11042        Erik 
    754  11042        Erik 	mp = ira->ira_ipsec_ah_sa->ipsa_input_func(mp, ah, ira);
    755  11042        Erik 	if (mp == NULL) {
    756  11042        Erik 		/*
    757  11042        Erik 		 * Either it failed or is pending. In the former case
    758  11042        Erik 		 * ipIfStatsInDiscards was increased.
    759  11042        Erik 		 */
    760  11042        Erik 		return;
    761  11042        Erik 	}
    762  11042        Erik 	ip_input_post_ipsec(mp, ira);
    763   8704      danmcd }
    764      0      stevel 
    765      0      stevel /*
    766      0      stevel  * Now that weak-key passed, actually ADD the security association, and
    767      0      stevel  * send back a reply ADD message.
    768      0      stevel  */
    769      0      stevel static int
    770   3055      danmcd ah_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
    771   3448    dh155122     int *diagnostic, ipsecah_stack_t *ahstack)
    772      0      stevel {
    773  10934  sommerfeld 	isaf_t *primary = NULL, *secondary;
    774  10934  sommerfeld 	boolean_t clone = B_FALSE, is_inbound = B_FALSE;
    775      0      stevel 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
    776      0      stevel 	ipsa_t *larval;
    777      0      stevel 	ipsacq_t *acqrec;
    778      0      stevel 	iacqf_t *acq_bucket;
    779      0      stevel 	mblk_t *acq_msgs = NULL;
    780      0      stevel 	mblk_t *lpkt;
    781      0      stevel 	int rc;
    782  10934  sommerfeld 	ipsa_query_t sq;
    783  10934  sommerfeld 	int error;
    784   3448    dh155122 	netstack_t	*ns = ahstack->ipsecah_netstack;
    785   3448    dh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
    786      0      stevel 
    787      0      stevel 	/*
    788      0      stevel 	 * Locate the appropriate table(s).
    789      0      stevel 	 */
    790      0      stevel 
    791  10934  sommerfeld 	sq.spp = &ahstack->ah_sadb;
    792  10934  sommerfeld 	error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
    793  10934  sommerfeld 	    IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
    794  10934  sommerfeld 	    &sq, diagnostic);
    795  10934  sommerfeld 	if (error)
    796  10934  sommerfeld 		return (error);
    797  10934  sommerfeld 
    798   6668     markfen 	/*
    799   6668     markfen 	 * Use the direction flags provided by the KMD to determine
    800   6668     markfen 	 * if the inbound or outbound table should be the primary
    801   6668     markfen 	 * for this SA. If these flags were absent then make this
    802   6668     markfen 	 * decision based on the addresses.
    803   6668     markfen 	 */
    804   6668     markfen 	if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
    805  10934  sommerfeld 		primary = sq.inbound;
    806  10934  sommerfeld 		secondary = sq.outbound;
    807   6668     markfen 		is_inbound = B_TRUE;
    808   6668     markfen 		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
    809   6668     markfen 			clone = B_TRUE;
    810   6668     markfen 	} else {
    811   6668     markfen 		if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
    812  10934  sommerfeld 			primary = sq.outbound;
    813  10934  sommerfeld 			secondary = sq.inbound;
    814  10934  sommerfeld 		}
    815  10934  sommerfeld 	}
    816   6668     markfen 	if (primary == NULL) {
    817   6668     markfen 		/*
    818   6668     markfen 		 * The KMD did not set a direction flag, determine which
    819   6668     markfen 		 * table to insert the SA into based on addresses.
    820   6668     markfen 		 */
    821   6668     markfen 		switch (ksi->ks_in_dsttype) {
    822   6668     markfen 		case KS_IN_ADDR_MBCAST:
    823   6668     markfen 			clone = B_TRUE;	/* All mcast SAs can be bidirectional */
    824   6668     markfen 			assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
    825   6668     markfen 			/* FALLTHRU */
    826      0      stevel 		/*
    827      0      stevel 		 * If the source address is either one of mine, or unspecified
    828      0      stevel 		 * (which is best summed up by saying "not 'not mine'"),
    829      0      stevel 		 * then the association is potentially bi-directional,
    830      0      stevel 		 * in that it can be used for inbound traffic and outbound
    831      0      stevel 		 * traffic.  The best example of such and SA is a multicast
    832      0      stevel 		 * SA (which allows me to receive the outbound traffic).
    833      0      stevel 		 */
    834   6668     markfen 		case KS_IN_ADDR_ME:
    835   6668     markfen 			assoc->sadb_sa_flags |= IPSA_F_INBOUND;
    836  10934  sommerfeld 			primary = sq.inbound;
    837  10934  sommerfeld 			secondary = sq.outbound;
    838   6668     markfen 			if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
    839   6668     markfen 				clone = B_TRUE;
    840   6668     markfen 			is_inbound = B_TRUE;
    841   6668     markfen 			break;
    842  10934  sommerfeld 
    843      0      stevel 		/*
    844      0      stevel 		 * If the source address literally not mine (either
    845      0      stevel 		 * unspecified or not mine), then this SA may have an
    846      0      stevel 		 * address that WILL be mine after some configuration.
    847      0      stevel 		 * We pay the price for this by making it a bi-directional
    848      0      stevel 		 * SA.
    849      0      stevel 		 */
    850   6668     markfen 		case KS_IN_ADDR_NOTME:
    851   6668     markfen 			assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
    852  10934  sommerfeld 			primary = sq.outbound;
    853  10934  sommerfeld 			secondary = sq.inbound;
    854   6668     markfen 			if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
    855   6668     markfen 				assoc->sadb_sa_flags |= IPSA_F_INBOUND;
    856   6668     markfen 				clone = B_TRUE;
    857   6668     markfen 			}
    858   6668     markfen 			break;
    859   6668     markfen 		default:
    860   6668     markfen 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
    861   6668     markfen 			return (EINVAL);
    862   6668     markfen 		}
    863      0      stevel 	}
    864      0      stevel 
    865      0      stevel 	/*
    866      0      stevel 	 * Find a ACQUIRE list entry if possible.  If we've added an SA that
    867      0      stevel 	 * suits the needs of an ACQUIRE list entry, we can eliminate the
    868      0      stevel 	 * ACQUIRE list entry and transmit the enqueued packets.  Use the
    869      0      stevel 	 * high-bit of the sequence number to queue it.  Key off destination
    870      0      stevel 	 * addr, and change acqrec's state.
    871      0      stevel 	 */
    872      0      stevel 
    873      0      stevel 	if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
    874  10934  sommerfeld 		acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
    875      0      stevel 		mutex_enter(&acq_bucket->iacqf_lock);
    876      0      stevel 		for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
    877      0      stevel 		    acqrec = acqrec->ipsacq_next) {
    878      0      stevel 			mutex_enter(&acqrec->ipsacq_lock);
    879      0      stevel 			/*
    880      0      stevel 			 * Q:  I only check sequence.  Should I check dst?
    881      0      stevel 			 * A: Yes, check dest because those are the packets
    882      0      stevel 			 *    that are queued up.
    883      0      stevel 			 */
    884      0      stevel 			if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
    885  10934  sommerfeld 			    IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
    886   4987      danmcd 			    acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
    887      0      stevel 				break;
    888      0      stevel 			mutex_exit(&acqrec->ipsacq_lock);
    889      0      stevel 		}
    890      0      stevel 		if (acqrec != NULL) {
    891      0      stevel 			/*
    892      0      stevel 			 * AHA!  I found an ACQUIRE record for this SA.
    893      0      stevel 			 * Grab the msg list, and free the acquire record.
    894      0      stevel 			 * I already am holding the lock for this record,
    895      0      stevel 			 * so all I have to do is free it.
    896      0      stevel 			 */
    897      0      stevel 			acq_msgs = acqrec->ipsacq_mp;
    898      0      stevel 			acqrec->ipsacq_mp = NULL;
    899      0      stevel 			mutex_exit(&acqrec->ipsacq_lock);
    900   3448    dh155122 			sadb_destroy_acquire(acqrec, ns);
    901      0      stevel 		}
    902      0      stevel 		mutex_exit(&acq_bucket->iacqf_lock);
    903      0      stevel 	}
    904      0      stevel 
    905      0      stevel 	/*
    906      0      stevel 	 * Find PF_KEY message, and see if I'm an update.  If so, find entry
    907      0      stevel 	 * in larval list (if there).
    908      0      stevel 	 */
    909      0      stevel 
    910      0      stevel 	larval = NULL;
    911      0      stevel 
    912      0      stevel 	if (samsg->sadb_msg_type == SADB_UPDATE) {
    913  10934  sommerfeld 		mutex_enter(&sq.inbound->isaf_lock);
    914  10934  sommerfeld 		larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
    915  10934  sommerfeld 		    ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
    916  10934  sommerfeld 		mutex_exit(&sq.inbound->isaf_lock);
    917      0      stevel 
    918      0      stevel 		if ((larval == NULL) ||
    919      0      stevel 		    (larval->ipsa_state != IPSA_STATE_LARVAL)) {
    920   6668     markfen 			*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
    921   7110      danmcd 			if (larval != NULL) {
    922   7110      danmcd 				IPSA_REFRELE(larval);
    923   7110      danmcd 			}
    924      0      stevel 			ah0dbg(("Larval update, but larval disappeared.\n"));
    925      0      stevel 			return (ESRCH);
    926      0      stevel 		} /* Else sadb_common_add unlinks it for me! */
    927      0      stevel 	}
    928      0      stevel 
    929      0      stevel 	lpkt = NULL;
    930      0      stevel 	if (larval != NULL)
    931      0      stevel 		lpkt = sadb_clear_lpkt(larval);
    932      0      stevel 
    933  11042        Erik 	rc = sadb_common_add(ahstack->ah_pfkey_q, mp,
    934   3448    dh155122 	    samsg, ksi, primary, secondary, larval, clone, is_inbound,
    935   6668     markfen 	    diagnostic, ns, &ahstack->ah_sadb);
    936      0      stevel 
    937  11042        Erik 	if (lpkt != NULL) {
    938  11042        Erik 		if (rc == 0) {
    939  11042        Erik 			rc = !taskq_dispatch(ah_taskq, inbound_task, lpkt,
    940  11042        Erik 			    TQ_NOSLEEP);
    941  11042        Erik 		}
    942  11042        Erik 		if (rc != 0) {
    943  11042        Erik 			lpkt = ip_recv_attr_free_mblk(lpkt);
    944  11042        Erik 			ip_drop_packet(lpkt, B_TRUE, NULL,
    945  11042        Erik 			    DROPPER(ipss, ipds_sadb_inlarval_timeout),
    946  11042        Erik 			    &ahstack->ah_dropper);
    947  11042        Erik 		}
    948  11042        Erik 	}
    949  11042        Erik 
    950      0      stevel 	/*
    951      0      stevel 	 * How much more stack will I create with all of these
    952  11042        Erik 	 * ah_outbound_*() calls?
    953  11042        Erik 	 */
    954  11042        Erik 
    955  11042        Erik 	/* Handle the packets queued waiting for the SA */
    956      0      stevel 	while (acq_msgs != NULL) {
    957  11042        Erik 		mblk_t		*asyncmp;
    958  11042        Erik 		mblk_t		*data_mp;
    959  11042        Erik 		ip_xmit_attr_t	ixas;
    960  11042        Erik 		ill_t		*ill;
    961  11042        Erik 
    962  11042        Erik 		asyncmp = acq_msgs;
    963      0      stevel 		acq_msgs = acq_msgs->b_next;
    964  11042        Erik 		asyncmp->b_next = NULL;
    965  11042        Erik 
    966  11042        Erik 		/*
    967  11042        Erik 		 * Extract the ip_xmit_attr_t from the first mblk.
    968  11042        Erik 		 * Verifies that the netstack and ill is still around; could
    969  11042        Erik 		 * have vanished while iked was doing its work.
    970  11042        Erik 		 * On succesful return we have a nce_t and the ill/ipst can't
    971  11042        Erik 		 * disappear until we do the nce_refrele in ixa_cleanup.
    972  11042        Erik 		 */
    973  11042        Erik 		data_mp = asyncmp->b_cont;
    974  11042        Erik 		asyncmp->b_cont = NULL;
    975  11042        Erik 		if (!ip_xmit_attr_from_mblk(asyncmp, &ixas)) {
    976  11042        Erik 			AH_BUMP_STAT(ahstack, out_discards);
    977  11042        Erik 			ip_drop_packet(data_mp, B_FALSE, NULL,
    978  11042        Erik 			    DROPPER(ipss, ipds_sadb_acquire_timeout),
    979  11042        Erik 			    &ahstack->ah_dropper);
    980  11042        Erik 		} else if (rc != 0) {
    981  11042        Erik 			ill = ixas.ixa_nce->nce_ill;
    982  11042        Erik 			AH_BUMP_STAT(ahstack, out_discards);
    983  11042        Erik 			ip_drop_packet(data_mp, B_FALSE, ill,
    984  11042        Erik 			    DROPPER(ipss, ipds_sadb_acquire_timeout),
    985  11042        Erik 			    &ahstack->ah_dropper);
    986  11042        Erik 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
    987  11042        Erik 		} else {
    988  11042        Erik 			ah_outbound_finish(data_mp, &ixas);
    989  11042        Erik 		}
    990  11042        Erik 		ixa_cleanup(&ixas);
    991  11042        Erik 	}
    992  11042        Erik 
    993  11042        Erik 	return (rc);
    994  11042        Erik }
    995  11042        Erik 
    996  11042        Erik 
    997  11042        Erik /*
    998  11042        Erik  * Process one of the queued messages (from ipsacq_mp) once the SA
    999  11042        Erik  * has been added.
   1000  11042        Erik  */
   1001  11042        Erik static void
   1002  11042        Erik ah_outbound_finish(mblk_t *data_mp, ip_xmit_attr_t *ixa)
   1003  11042        Erik {
   1004  11042        Erik 	netstack_t	*ns = ixa->ixa_ipst->ips_netstack;
   1005  11042        Erik 	ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
   1006  11042        Erik 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
   1007  11042        Erik 	ill_t		*ill = ixa->ixa_nce->nce_ill;
   1008  11042        Erik 
   1009  11042        Erik 	if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_AH)) {
   1010   3448    dh155122 		AH_BUMP_STAT(ahstack, out_discards);
   1011  11042        Erik 		ip_drop_packet(data_mp, B_FALSE, ill,
   1012   3448    dh155122 		    DROPPER(ipss, ipds_sadb_acquire_timeout),
   1013   3448    dh155122 		    &ahstack->ah_dropper);
   1014  11042        Erik 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
   1015  11042        Erik 		return;
   1016  11042        Erik 	}
   1017  11042        Erik 
   1018  11042        Erik 	data_mp = ah_outbound(data_mp, ixa);
   1019  11042        Erik 	if (data_mp == NULL)
   1020  11042        Erik 		return;
   1021  11042        Erik 
   1022  11042        Erik 	(void) ip_output_post_ipsec(data_mp, ixa);
   1023      0      stevel }
   1024      0      stevel 
   1025      0      stevel /*
   1026      0      stevel  * Add new AH security association.  This may become a generic AH/ESP
   1027      0      stevel  * routine eventually.
   1028      0      stevel  */
   1029      0      stevel static int
   1030   3448    dh155122 ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
   1031      0      stevel {
   1032      0      stevel 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
   1033      0      stevel 	sadb_address_t *srcext =
   1034      0      stevel 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
   1035      0      stevel 	sadb_address_t *dstext =
   1036      0      stevel 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
   1037   3055      danmcd 	sadb_address_t *isrcext =
   1038   3055      danmcd 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC];
   1039   3055      danmcd 	sadb_address_t *idstext =
   1040   3055      danmcd 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST];
   1041      0      stevel 	sadb_key_t *key = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
   1042      0      stevel 	struct sockaddr_in *src, *dst;
   1043      0      stevel 	/* We don't need sockaddr_in6 for now. */
   1044      0      stevel 	sadb_lifetime_t *soft =
   1045      0      stevel 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
   1046      0      stevel 	sadb_lifetime_t *hard =
   1047      0      stevel 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
   1048   7749  Thejaswini 	sadb_lifetime_t *idle =
   1049   7749  Thejaswini 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
   1050      0      stevel 	ipsec_alginfo_t *aalg;
   1051   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   1052   3448    dh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
   1053      0      stevel 
   1054      0      stevel 	/* I need certain extensions present for an ADD message. */
   1055      0      stevel 	if (srcext == NULL) {
   1056      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
   1057      0      stevel 		return (EINVAL);
   1058      0      stevel 	}
   1059      0      stevel 	if (dstext == NULL) {
   1060      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
   1061      0      stevel 		return (EINVAL);
   1062      0      stevel 	}
   1063   3055      danmcd 	if (isrcext == NULL && idstext != NULL) {
   1064   3055      danmcd 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC;
   1065   3055      danmcd 		return (EINVAL);
   1066   3055      danmcd 	}
   1067   3055      danmcd 	if (isrcext != NULL && idstext == NULL) {
   1068   3055      danmcd 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST;
   1069   3055      danmcd 		return (EINVAL);
   1070   3055      danmcd 	}
   1071      0      stevel 	if (assoc == NULL) {
   1072      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
   1073      0      stevel 		return (EINVAL);
   1074      0      stevel 	}
   1075      0      stevel 	if (key == NULL) {
   1076      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_AKEY;
   1077      0      stevel 		return (EINVAL);
   1078      0      stevel 	}
   1079      0      stevel 
   1080      0      stevel 	src = (struct sockaddr_in *)(srcext + 1);
   1081      0      stevel 	dst = (struct sockaddr_in *)(dstext + 1);
   1082      0      stevel 
   1083      0      stevel 	/* Sundry ADD-specific reality checks. */
   1084      0      stevel 	/* XXX STATS : Logging/stats here? */
   1085      0      stevel 
   1086   7749  Thejaswini 	if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) &&
   1087   7749  Thejaswini 	    (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
   1088      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
   1089      0      stevel 		return (EINVAL);
   1090      0      stevel 	}
   1091      0      stevel 	if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) {
   1092      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_ENCR_NOTSUPP;
   1093      0      stevel 		return (EINVAL);
   1094      0      stevel 	}
   1095   7110      danmcd 	if (assoc->sadb_sa_flags & ~ahstack->ah_sadb.s_addflags) {
   1096      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
   1097      0      stevel 		return (EINVAL);
   1098      0      stevel 	}
   1099   7749  Thejaswini 	if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0)
   1100      0      stevel 		return (EINVAL);
   1101      0      stevel 
   1102   3055      danmcd 	ASSERT(src->sin_family == dst->sin_family);
   1103      0      stevel 
   1104      0      stevel 	/* Stuff I don't support, for now.  XXX Diagnostic? */
   1105  10934  sommerfeld 	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
   1106      0      stevel 		return (EOPNOTSUPP);
   1107      0      stevel 
   1108  10934  sommerfeld 	if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) {
   1109  10934  sommerfeld 		if (!is_system_labeled())
   1110  10934  sommerfeld 			return (EOPNOTSUPP);
   1111  10934  sommerfeld 	}
   1112  10934  sommerfeld 
   1113  10934  sommerfeld 	if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL) {
   1114  10934  sommerfeld 		if (!is_system_labeled())
   1115  10934  sommerfeld 			return (EOPNOTSUPP);
   1116  10934  sommerfeld 	}
   1117  10934  sommerfeld 	/*
   1118  10934  sommerfeld 	 * XXX Policy : I'm not checking identities at this time, but
   1119  10934  sommerfeld 	 * if I did, I'd do them here, before I sent the weak key
   1120  10934  sommerfeld 	 * check up to the algorithm.
   1121      0      stevel 	 */
   1122      0      stevel 
   1123      0      stevel 	/* verify that there is a mapping for the specified algorithm */
   1124   3448    dh155122 	mutex_enter(&ipss->ipsec_alg_lock);
   1125   3448    dh155122 	aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth];
   1126      0      stevel 	if (aalg == NULL || !ALG_VALID(aalg)) {
   1127   3448    dh155122 		mutex_exit(&ipss->ipsec_alg_lock);
   1128   3448    dh155122 		ah1dbg(ahstack, ("Couldn't find auth alg #%d.\n",
   1129   4987      danmcd 		    assoc->sadb_sa_auth));
   1130      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
   1131      0      stevel 		return (EINVAL);
   1132      0      stevel 	}
   1133      0      stevel 	ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
   1134      0      stevel 
   1135      0      stevel 	/* sanity check key sizes */
   1136      0      stevel 	if (!ipsec_valid_key_size(key->sadb_key_bits, aalg)) {
   1137   3448    dh155122 		mutex_exit(&ipss->ipsec_alg_lock);
   1138      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
   1139      0      stevel 		return (EINVAL);
   1140      0      stevel 	}
   1141      0      stevel 
   1142      0      stevel 	/* check key and fix parity if needed */
   1143      0      stevel 	if (ipsec_check_key(aalg->alg_mech_type, key, B_TRUE,
   1144      0      stevel 	    diagnostic) != 0) {
   1145   3448    dh155122 		mutex_exit(&ipss->ipsec_alg_lock);
   1146   3448    dh155122 		return (EINVAL);
   1147   3448    dh155122 	}
   1148   3448    dh155122 
   1149   3448    dh155122 	mutex_exit(&ipss->ipsec_alg_lock);
   1150      0      stevel 
   1151   3055      danmcd 	return (ah_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
   1152   4987      danmcd 	    diagnostic, ahstack));
   1153      0      stevel }
   1154      0      stevel 
   1155  10934  sommerfeld /* Refactor me */
   1156      0      stevel /*
   1157      0      stevel  * Update a security association.  Updates come in two varieties.  The first
   1158      0      stevel  * is an update of lifetimes on a non-larval SA.  The second is an update of
   1159      0      stevel  * a larval SA, which ends up looking a lot more like an add.
   1160      0      stevel  */
   1161      0      stevel static int
   1162   3448    dh155122 ah_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
   1163   6668     markfen     ipsecah_stack_t *ahstack, uint8_t sadb_msg_type)
   1164      0      stevel {
   1165   7749  Thejaswini 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
   1166      0      stevel 	sadb_address_t *dstext =
   1167      0      stevel 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
   1168   7749  Thejaswini 	mblk_t	*buf_pkt;
   1169   7749  Thejaswini 	int rcode;
   1170      0      stevel 
   1171      0      stevel 	if (dstext == NULL) {
   1172      0      stevel 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
   1173      0      stevel 		return (EINVAL);
   1174      0      stevel 	}
   1175   7749  Thejaswini 
   1176   7749  Thejaswini 	rcode = sadb_update_sa(mp, ksi, &buf_pkt, &ahstack->ah_sadb,
   1177   7749  Thejaswini 	    diagnostic, ahstack->ah_pfkey_q, ah_add_sa,
   1178   7749  Thejaswini 	    ahstack->ipsecah_netstack, sadb_msg_type);
   1179   7749  Thejaswini 
   1180   7749  Thejaswini 	if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) ||
   1181   7749  Thejaswini 	    (rcode != 0)) {
   1182   7749  Thejaswini 		return (rcode);
   1183   7749  Thejaswini 	}
   1184   7749  Thejaswini 
   1185   8704      danmcd 	HANDLE_BUF_PKT(ah_taskq, ahstack->ipsecah_netstack->netstack_ipsec,
   1186   8704      danmcd 	    ahstack->ah_dropper, buf_pkt);
   1187   7749  Thejaswini 
   1188   7749  Thejaswini 	return (rcode);
   1189      0      stevel }
   1190      0      stevel 
   1191  10934  sommerfeld /* Refactor me */
   1192      0      stevel /*
   1193      0      stevel  * Delete a security association.  This is REALLY likely to be code common to
   1194      0      stevel  * both AH and ESP.  Find the association, then unlink it.
   1195      0      stevel  */
   1196      0      stevel static int
   1197   3448    dh155122 ah_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
   1198   6668     markfen     ipsecah_stack_t *ahstack, uint8_t sadb_msg_type)
   1199      0      stevel {
   1200      0      stevel 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
   1201      0      stevel 	sadb_address_t *dstext =
   1202      0      stevel 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
   1203      0      stevel 	sadb_address_t *srcext =
   1204      0      stevel 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
   1205      0      stevel 	struct sockaddr_in *sin;
   1206      0      stevel 
   1207      0      stevel 	if (assoc == NULL) {
   1208      0      stevel 		if (dstext != NULL)
   1209      0      stevel 			sin = (struct sockaddr_in *)(dstext + 1);
   1210      0      stevel 		else if (srcext != NULL)
   1211      0      stevel 			sin = (struct sockaddr_in *)(srcext + 1);
   1212      0      stevel 		else {
   1213      0      stevel 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
   1214      0      stevel 			return (EINVAL);
   1215      0      stevel 		}
   1216   3055      danmcd 		return (sadb_purge_sa(mp, ksi,
   1217   3448    dh155122 		    (sin->sin_family == AF_INET6) ? &ahstack->ah_sadb.s_v6 :
   1218  11042        Erik 		    &ahstack->ah_sadb.s_v4, diagnostic, ahstack->ah_pfkey_q));
   1219   3448    dh155122 	}
   1220   3448    dh155122 
   1221   6668     markfen 	return (sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
   1222   6668     markfen 	    ahstack->ah_pfkey_q, sadb_msg_type));
   1223      0      stevel }
   1224      0      stevel 
   1225  10934  sommerfeld /* Refactor me */
   1226      0      stevel /*
   1227      0      stevel  * Convert the entire contents of all of AH's SA tables into PF_KEY SADB_DUMP
   1228      0      stevel  * messages.
   1229      0      stevel  */
   1230      0      stevel static void
   1231   3448    dh155122 ah_dump(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
   1232      0      stevel {
   1233      0      stevel 	int error;
   1234      0      stevel 	sadb_msg_t *samsg;
   1235      0      stevel 
   1236      0      stevel 	/*
   1237      0      stevel 	 * Dump each fanout, bailing if error is non-zero.
   1238      0      stevel 	 */
   1239      0      stevel 
   1240   7749  Thejaswini 	error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v4);
   1241      0      stevel 	if (error != 0)
   1242      0      stevel 		goto bail;
   1243      0      stevel 
   1244   7749  Thejaswini 	error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v6);
   1245      0      stevel bail:
   1246      0      stevel 	ASSERT(mp->b_cont != NULL);
   1247      0      stevel 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
   1248      0      stevel 	samsg->sadb_msg_errno = (uint8_t)error;
   1249   3448    dh155122 	sadb_pfkey_echo(ahstack->ah_pfkey_q, mp,
   1250   3448    dh155122 	    (sadb_msg_t *)mp->b_cont->b_rptr, ksi, NULL);
   1251      0      stevel }
   1252      0      stevel 
   1253      0      stevel /*
   1254   3055      danmcd  * First-cut reality check for an inbound PF_KEY message.
   1255   3055      danmcd  */
   1256   3055      danmcd static boolean_t
   1257   3448    dh155122 ah_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi,
   1258   3448    dh155122     ipsecah_stack_t *ahstack)
   1259   3055      danmcd {
   1260   3055      danmcd 	int diagnostic;
   1261   3055      danmcd 
   1262   3055      danmcd 	if (mp->b_cont == NULL) {
   1263   3055      danmcd 		freemsg(mp);
   1264   3055      danmcd 		return (B_TRUE);
   1265   3055      danmcd 	}
   1266   3055      danmcd 
   1267   3055      danmcd 	if (ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL) {
   1268   3055      danmcd 		diagnostic = SADB_X_DIAGNOSTIC_EKEY_PRESENT;
   1269   3055      danmcd 		goto badmsg;
   1270   3055      danmcd 	}
   1271   3055      danmcd 	if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) {
   1272   3055      danmcd 		diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT;
   1273   3055      danmcd 		goto badmsg;
   1274   3055      danmcd 	}
   1275   3055      danmcd 	if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL ||
   1276   3055      danmcd 	    ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) {
   1277   3055      danmcd 		diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT;
   1278   3055      danmcd 		goto badmsg;
   1279   3055      danmcd 	}
   1280   3055      danmcd 	return (B_FALSE);	/* False ==> no failures */
   1281   3055      danmcd 
   1282   3055      danmcd badmsg:
   1283   3448    dh155122 	sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL,
   1284   3448    dh155122 	    diagnostic, ksi->ks_in_serial);
   1285   3055      danmcd 	return (B_TRUE);	/* True ==> failures */
   1286   3055      danmcd }
   1287   3055      danmcd 
   1288   3055      danmcd /*
   1289      0      stevel  * AH parsing of PF_KEY messages.  Keysock did most of the really silly
   1290      0      stevel  * error cases.  What I receive is a fully-formed, syntactically legal
   1291      0      stevel  * PF_KEY message.  I then need to check semantics...
   1292      0      stevel  *
   1293      0      stevel  * This code may become common to AH and ESP.  Stay tuned.
   1294      0      stevel  *
   1295      0      stevel  * I also make the assumption that db_ref's are cool.  If this assumption
   1296      0      stevel  * is wrong, this means that someone other than keysock or me has been
   1297      0      stevel  * mucking with PF_KEY messages.
   1298      0      stevel  */
   1299      0      stevel static void
   1300   3448    dh155122 ah_parse_pfkey(mblk_t *mp, ipsecah_stack_t *ahstack)
   1301      0      stevel {
   1302      0      stevel 	mblk_t *msg = mp->b_cont;
   1303      0      stevel 	sadb_msg_t *samsg;
   1304      0      stevel 	keysock_in_t *ksi;
   1305      0      stevel 	int error;
   1306      0      stevel 	int diagnostic = SADB_X_DIAGNOSTIC_NONE;
   1307      0      stevel 
   1308      0      stevel 	ASSERT(msg != NULL);
   1309   3448    dh155122 
   1310      0      stevel 	samsg = (sadb_msg_t *)msg->b_rptr;
   1311      0      stevel 	ksi = (keysock_in_t *)mp->b_rptr;
   1312      0      stevel 
   1313      0      stevel 	/*
   1314      0      stevel 	 * If applicable, convert unspecified AF_INET6 to unspecified
   1315      0      stevel 	 * AF_INET.
   1316      0      stevel 	 */
   1317   3448    dh155122 	if (!sadb_addrfix(ksi, ahstack->ah_pfkey_q, mp,
   1318   3448    dh155122 	    ahstack->ipsecah_netstack) ||
   1319   3448    dh155122 	    ah_pfkey_reality_failures(mp, ksi, ahstack)) {
   1320   3055      danmcd 		return;
   1321   3055      danmcd 	}
   1322      0      stevel 
   1323      0      stevel 	switch (samsg->sadb_msg_type) {
   1324      0      stevel 	case SADB_ADD:
   1325   3448    dh155122 		error = ah_add_sa(mp, ksi, &diagnostic,
   1326   3448    dh155122 		    ahstack->ipsecah_netstack);
   1327      0      stevel 		if (error != 0) {
   1328   3448    dh155122 			sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
   1329   3448    dh155122 			    diagnostic, ksi->ks_in_serial);
   1330      0      stevel 		}
   1331      0      stevel 		/* else ah_add_sa() took care of things. */
   1332      0      stevel 		break;
   1333      0      stevel 	case SADB_DELETE:
   1334   6668     markfen 	case SADB_X_DELPAIR:
   1335   7749  Thejaswini 	case SADB_X_DELPAIR_STATE:
   1336   6668     markfen 		error = ah_del_sa(mp, ksi, &diagnostic, ahstack,
   1337   6668     markfen 		    samsg->sadb_msg_type);
   1338      0      stevel 		if (error != 0) {
   1339   3448    dh155122 			sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
   1340   3448    dh155122 			    diagnostic, ksi->ks_in_serial);
   1341      0      stevel 		}
   1342      0      stevel 		/* Else ah_del_sa() took care of things. */
   1343      0      stevel 		break;
   1344      0      stevel 	case SADB_GET:
   1345   6668     markfen 		error = sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, &diagnostic,
   1346   6668     markfen 		    ahstack->ah_pfkey_q, samsg->sadb_msg_type);
   1347      0      stevel 		if (error != 0) {
   1348   3448    dh155122 			sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
   1349   3448    dh155122 			    diagnostic, ksi->ks_in_serial);
   1350      0      stevel 		}
   1351      0      stevel 		/* Else sadb_get_sa() took care of things. */
   1352      0      stevel 		break;
   1353      0      stevel 	case SADB_FLUSH:
   1354   3448    dh155122 		sadbp_flush(&ahstack->ah_sadb, ahstack->ipsecah_netstack);
   1355   3448    dh155122 		sadb_pfkey_echo(ahstack->ah_pfkey_q, mp, samsg, ksi, NULL);
   1356      0      stevel 		break;
   1357      0      stevel 	case SADB_REGISTER:
   1358      0      stevel 		/*
   1359      0      stevel 		 * Hmmm, let's do it!  Check for extensions (there should
   1360      0      stevel 		 * be none), extract the fields, call ah_register_out(),
   1361      0      stevel 		 * then either free or report an error.
   1362      0      stevel 		 *
   1363      0      stevel 		 * Keysock takes care of the PF_KEY bookkeeping for this.
   1364      0      stevel 		 */
   1365      0      stevel 		if (ah_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
   1366  11042        Erik 		    ksi->ks_in_serial, ahstack, msg_getcred(mp, NULL))) {
   1367      0      stevel 			freemsg(mp);
   1368      0      stevel 		} else {
   1369      0      stevel 			/*
   1370      0      stevel 			 * Only way this path hits is if there is a memory
   1371      0      stevel 			 * failure.  It will not return B_FALSE because of
   1372      0      stevel 			 * lack of ah_pfkey_q if I am in wput().
   1373      0      stevel 			 */
   1374   3448    dh155122 			sadb_pfkey_error(ahstack->ah_pfkey_q, mp, ENOMEM,
   1375   3448    dh155122 			    diagnostic, ksi->ks_in_serial);
   1376      0      stevel 		}
   1377      0      stevel 		break;
   1378      0      stevel 	case SADB_UPDATE:
   1379   6668     markfen 	case SADB_X_UPDATEPAIR:
   1380      0      stevel 		/*
   1381      0      stevel 		 * Find a larval, if not there, find a full one and get
   1382      0      stevel 		 * strict.
   1383      0      stevel 		 */
   1384   6668     markfen 		error = ah_update_sa(mp, ksi, &diagnostic, ahstack,
   1385   6668     markfen 		    samsg->sadb_msg_type);
   1386      0      stevel 		if (error != 0) {
   1387   3448    dh155122 			sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
   1388   3448    dh155122 			    diagnostic, ksi->ks_in_serial);
   1389      0      stevel 		}
   1390      0      stevel 		/* else ah_update_sa() took care of things. */
   1391      0      stevel 		break;
   1392      0      stevel 	case SADB_GETSPI:
   1393      0      stevel 		/*
   1394      0      stevel 		 * Reserve a new larval entry.
   1395      0      stevel 		 */
   1396   3448    dh155122 		ah_getspi(mp, ksi, ahstack);
   1397      0      stevel 		break;
   1398      0      stevel 	case SADB_ACQUIRE:
   1399      0      stevel 		/*
   1400      0      stevel 		 * Find larval and/or ACQUIRE record and kill it (them), I'm
   1401      0      stevel 		 * most likely an error.  Inbound ACQUIRE messages should only
   1402      0      stevel 		 * have the base header.
   1403      0      stevel 		 */
   1404   3448    dh155122 		sadb_in_acquire(samsg, &ahstack->ah_sadb, ahstack->ah_pfkey_q,
   1405   3448    dh155122 		    ahstack->ipsecah_netstack);
   1406      0      stevel 		freemsg(mp);
   1407      0      stevel 		break;
   1408      0      stevel 	case SADB_DUMP:
   1409      0      stevel 		/*
   1410      0      stevel 		 * Dump all entries.
   1411      0      stevel 		 */
   1412   3448    dh155122 		ah_dump(mp, ksi, ahstack);
   1413      0      stevel 		/* ah_dump will take care of the return message, etc. */
   1414      0      stevel 		break;
   1415      0      stevel 	case SADB_EXPIRE:
   1416      0      stevel 		/* Should never reach me. */
   1417   3448    dh155122 		sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EOPNOTSUPP,
   1418   3448    dh155122 		    diagnostic, ksi->ks_in_serial);
   1419      0      stevel 		break;
   1420      0      stevel 	default:
   1421   3448    dh155122 		sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL,
   1422      0      stevel 		    SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial);
   1423      0      stevel 		break;
   1424      0      stevel 	}
   1425      0      stevel }
   1426      0      stevel 
   1427      0      stevel /*
   1428      0      stevel  * Handle case where PF_KEY says it can't find a keysock for one of my
   1429      0      stevel  * ACQUIRE messages.
   1430      0      stevel  */
   1431      0      stevel static void
   1432   3448    dh155122 ah_keysock_no_socket(mblk_t *mp, ipsecah_stack_t *ahstack)
   1433      0      stevel {
   1434      0      stevel 	sadb_msg_t *samsg;
   1435      0      stevel 	keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr;
   1436      0      stevel 
   1437      0      stevel 	if (mp->b_cont == NULL) {
   1438      0      stevel 		freemsg(mp);
   1439      0      stevel 		return;
   1440      0      stevel 	}
   1441      0      stevel 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
   1442      0      stevel 
   1443      0      stevel 	/*
   1444      0      stevel 	 * If keysock can't find any registered, delete the acquire record
   1445      0      stevel 	 * immediately, and handle errors.
   1446      0      stevel 	 */
   1447      0      stevel 	if (samsg->sadb_msg_type == SADB_ACQUIRE) {
   1448      0      stevel 		samsg->sadb_msg_errno = kse->ks_err_errno;
   1449      0      stevel 		samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
   1450      0      stevel 		/*
   1451  11042        Erik 		 * Use the write-side of the ah_pfkey_q
   1452   3448    dh155122 		 */
   1453   3448    dh155122 		sadb_in_acquire(samsg, &ahstack->ah_sadb,
   1454   3448    dh155122 		    WR(ahstack->ah_pfkey_q), ahstack->ipsecah_netstack);
   1455      0      stevel 	}
   1456      0      stevel 
   1457      0      stevel 	freemsg(mp);
   1458      0      stevel }
   1459      0      stevel 
   1460      0      stevel /*
   1461      0      stevel  * AH module write put routine.
   1462      0      stevel  */
   1463      0      stevel static void
   1464      0      stevel ipsecah_wput(queue_t *q, mblk_t *mp)
   1465      0      stevel {
   1466      0      stevel 	ipsec_info_t *ii;
   1467      0      stevel 	struct iocblk *iocp;
   1468   3448    dh155122 	ipsecah_stack_t	*ahstack = (ipsecah_stack_t *)q->q_ptr;
   1469   3448    dh155122 
   1470   3448    dh155122 	ah3dbg(ahstack, ("In ah_wput().\n"));
   1471      0      stevel 
   1472      0      stevel 	/* NOTE:  Each case must take care of freeing or passing mp. */
   1473      0      stevel 	switch (mp->b_datap->db_type) {
   1474      0      stevel 	case M_CTL:
   1475      0      stevel 		if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) {
   1476      0      stevel 			/* Not big enough message. */
   1477      0      stevel 			freemsg(mp);
   1478      0      stevel 			break;
   1479      0      stevel 		}
   1480      0      stevel 		ii = (ipsec_info_t *)mp->b_rptr;
   1481      0      stevel 
   1482      0      stevel 		switch (ii->ipsec_info_type) {
   1483      0      stevel 		case KEYSOCK_OUT_ERR:
   1484   3448    dh155122 			ah1dbg(ahstack, ("Got KEYSOCK_OUT_ERR message.\n"));
   1485   3448    dh155122 			ah_keysock_no_socket(mp, ahstack);
   1486      0      stevel 			break;
   1487      0      stevel 		case KEYSOCK_IN:
   1488   3448    dh155122 			AH_BUMP_STAT(ahstack, keysock_in);
   1489   3448    dh155122 			ah3dbg(ahstack, ("Got KEYSOCK_IN message.\n"));
   1490   3055      danmcd 
   1491   3055      danmcd 			/* Parse the message. */
   1492   3448    dh155122 			ah_parse_pfkey(mp, ahstack);
   1493      0      stevel 			break;
   1494      0      stevel 		case KEYSOCK_HELLO:
   1495   3448    dh155122 			sadb_keysock_hello(&ahstack->ah_pfkey_q, q, mp,
   1496   3448    dh155122 			    ah_ager, (void *)ahstack, &ahstack->ah_event,
   1497   3448    dh155122 			    SADB_SATYPE_AH);
   1498   3448    dh155122 			break;
   1499   3448    dh155122 		default:
   1500   3448    dh155122 			ah1dbg(ahstack, ("Got M_CTL from above of 0x%x.\n",
   1501      0      stevel 			    ii->ipsec_info_type));
   1502      0      stevel 			freemsg(mp);
   1503      0      stevel 			break;
   1504      0      stevel 		}
   1505      0      stevel 		break;
   1506      0      stevel 	case M_IOCTL:
   1507      0      stevel 		iocp = (struct iocblk *)mp->b_rptr;
   1508      0      stevel 		switch (iocp->ioc_cmd) {
   1509      0      stevel 		case ND_SET:
   1510      0      stevel 		case ND_GET:
   1511   3448    dh155122 			if (nd_getset(q, ahstack->ipsecah_g_nd, mp)) {
   1512      0      stevel 				qreply(q, mp);
   1513      0      stevel 				return;
   1514      0      stevel 			} else {
   1515      0      stevel 				iocp->ioc_error = ENOENT;
   1516      0      stevel 			}
   1517      0      stevel 			/* FALLTHRU */
   1518      0      stevel 		default:
   1519      0      stevel 			/* We really don't support any other ioctls, do we? */
   1520      0      stevel 
   1521      0      stevel 			/* Return EINVAL */
   1522      0      stevel 			if (iocp->ioc_error != ENOENT)
   1523      0      stevel 				iocp->ioc_error = EINVAL;
   1524      0      stevel 			iocp->ioc_count = 0;
   1525      0      stevel 			mp->b_datap->db_type = M_IOCACK;
   1526      0      stevel 			qreply(q, mp);
   1527      0      stevel 			return;
   1528      0      stevel 		}
   1529      0      stevel 	default:
   1530   3448    dh155122 		ah3dbg(ahstack,
   1531   3448    dh155122 		    ("Got default message, type %d, passing to IP.\n",
   1532      0      stevel 		    mp->b_datap->db_type));
   1533      0      stevel 		putnext(q, mp);
   1534      0      stevel 	}
   1535      0      stevel }
   1536      0      stevel 
   1537  10934  sommerfeld /* Refactor me */
   1538      0      stevel /*
   1539      0      stevel  * Updating use times can be tricky business if the ipsa_haspeer flag is
   1540      0      stevel  * set.  This function is called once in an SA's lifetime.
   1541      0      stevel  *
   1542      0      stevel  * Caller has to REFRELE "assoc" which is passed in.  This function has
   1543      0      stevel  * to REFRELE any peer SA that is obtained.
   1544      0      stevel  */
   1545      0      stevel static void
   1546      0      stevel ah_set_usetime(ipsa_t *assoc, boolean_t inbound)
   1547      0      stevel {
   1548      0      stevel 	ipsa_t *inassoc, *outassoc;
   1549      0      stevel 	isaf_t *bucket;
   1550      0      stevel 	sadb_t *sp;
   1551      0      stevel 	int outhash;
   1552      0      stevel 	boolean_t isv6;
   1553   3448    dh155122 	netstack_t	*ns = assoc->ipsa_netstack;
   1554   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   1555      0      stevel 
   1556      0      stevel 	/* No peer?  No problem! */
   1557      0      stevel 	if (!assoc->ipsa_haspeer) {
   1558      0      stevel 		sadb_set_usetime(assoc);
   1559      0      stevel 		return;
   1560      0      stevel 	}
   1561      0      stevel 
   1562      0      stevel 	/*
   1563      0      stevel 	 * Otherwise, we want to grab both the original assoc and its peer.
   1564      0      stevel 	 * There might be a race for this, but if it's a real race, the times
   1565      0      stevel 	 * will be out-of-synch by at most a second, and since our time
   1566      0      stevel 	 * granularity is a second, this won't be a problem.
   1567      0      stevel 	 *
   1568      0      stevel 	 * If we need tight synchronization on the peer SA, then we need to
   1569      0      stevel 	 * reconsider.
   1570      0      stevel 	 */
   1571      0      stevel 
   1572      0      stevel 	/* Use address family to select IPv6/IPv4 */
   1573      0      stevel 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
   1574      0      stevel 	if (isv6) {
   1575   3448    dh155122 		sp = &ahstack->ah_sadb.s_v6;
   1576   3448    dh155122 	} else {
   1577   3448    dh155122 		sp = &ahstack->ah_sadb.s_v4;
   1578      0      stevel 		ASSERT(assoc->ipsa_addrfam == AF_INET);
   1579      0      stevel 	}
   1580      0      stevel 	if (inbound) {
   1581      0      stevel 		inassoc = assoc;
   1582      0      stevel 		if (isv6)
   1583   4987      danmcd 			outhash = OUTBOUND_HASH_V6(sp,
   1584   4987      danmcd 			    *((in6_addr_t *)&inassoc->ipsa_dstaddr));
   1585      0      stevel 		else
   1586   4987      danmcd 			outhash = OUTBOUND_HASH_V4(sp,
   1587   4987      danmcd 			    *((ipaddr_t *)&inassoc->ipsa_dstaddr));
   1588      0      stevel 		bucket = &sp->sdb_of[outhash];
   1589      0      stevel 
   1590      0      stevel 		mutex_enter(&bucket->isaf_lock);
   1591      0      stevel 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
   1592      0      stevel 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
   1593      0      stevel 		    inassoc->ipsa_addrfam);
   1594      0      stevel 		mutex_exit(&bucket->isaf_lock);
   1595      0      stevel 		if (outassoc == NULL) {
   1596      0      stevel 			/* Q: Do we wish to set haspeer == B_FALSE? */
   1597      0      stevel 			ah0dbg(("ah_set_usetime: "
   1598      0      stevel 			    "can't find peer for inbound.\n"));
   1599      0      stevel 			sadb_set_usetime(inassoc);
   1600      0      stevel 			return;
   1601      0      stevel 		}
   1602      0      stevel 	} else {
   1603      0      stevel 		outassoc = assoc;
   1604    564    sommerfe 		bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
   1605      0      stevel 		mutex_enter(&bucket->isaf_lock);
   1606      0      stevel 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
   1607      0      stevel 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
   1608      0      stevel 		    outassoc->ipsa_addrfam);
   1609      0      stevel 		mutex_exit(&bucket->isaf_lock);
   1610      0      stevel 		if (inassoc == NULL) {
   1611      0      stevel 			/* Q: Do we wish to set haspeer == B_FALSE? */
   1612      0      stevel 			ah0dbg(("ah_set_usetime: "
   1613      0      stevel 			    "can't find peer for outbound.\n"));
   1614      0      stevel 			sadb_set_usetime(outassoc);
   1615      0      stevel 			return;
   1616      0      stevel 		}
   1617      0      stevel 	}
   1618      0      stevel 
   1619      0      stevel 	/* Update usetime on both. */
   1620      0      stevel 	sadb_set_usetime(inassoc);
   1621      0      stevel 	sadb_set_usetime(outassoc);
   1622      0      stevel 
   1623      0      stevel 	/*
   1624      0      stevel 	 * REFRELE any peer SA.
   1625      0      stevel 	 *
   1626      0      stevel 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
   1627      0      stevel 	 * them in { }.
   1628      0      stevel 	 */
   1629      0      stevel 	if (inbound) {
   1630      0      stevel 		IPSA_REFRELE(outassoc);
   1631      0      stevel 	} else {
   1632      0      stevel 		IPSA_REFRELE(inassoc);
   1633      0      stevel 	}
   1634      0      stevel }
   1635      0      stevel 
   1636  10934  sommerfeld /* Refactor me */
   1637      0      stevel /*
   1638      0      stevel  * Add a number of bytes to what the SA has protected so far.  Return
   1639      0      stevel  * B_TRUE if the SA can still protect that many bytes.
   1640      0      stevel  *
   1641      0      stevel  * Caller must REFRELE the passed-in assoc.  This function must REFRELE
   1642      0      stevel  * any obtained peer SA.
   1643      0      stevel  */
   1644      0      stevel static boolean_t
   1645      0      stevel ah_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound)
   1646      0      stevel {
   1647      0      stevel 	ipsa_t *inassoc, *outassoc;
   1648      0      stevel 	isaf_t *bucket;
   1649      0      stevel 	boolean_t inrc, outrc, isv6;
   1650      0      stevel 	sadb_t *sp;
   1651      0      stevel 	int outhash;
   1652   3448    dh155122 	netstack_t	*ns = assoc->ipsa_netstack;
   1653   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   1654      0      stevel 
   1655      0      stevel 	/* No peer?  No problem! */
   1656      0      stevel 	if (!assoc->ipsa_haspeer) {
   1657   3448    dh155122 		return (sadb_age_bytes(ahstack->ah_pfkey_q, assoc, bytes,
   1658      0      stevel 		    B_TRUE));
   1659      0      stevel 	}
   1660      0      stevel 
   1661      0      stevel 	/*
   1662      0      stevel 	 * Otherwise, we want to grab both the original assoc and its peer.
   1663      0      stevel 	 * There might be a race for this, but if it's a real race, two
   1664      0      stevel 	 * expire messages may occur.  We limit this by only sending the
   1665      0      stevel 	 * expire message on one of the peers, we'll pick the inbound
   1666      0      stevel 	 * arbitrarily.
   1667      0      stevel 	 *
   1668      0      stevel 	 * If we need tight synchronization on the peer SA, then we need to
   1669      0      stevel 	 * reconsider.
   1670      0      stevel 	 */
   1671      0      stevel 
   1672      0      stevel 	/* Pick v4/v6 bucket based on addrfam. */
   1673      0      stevel 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
   1674      0      stevel 	if (isv6) {
   1675   3448    dh155122 		sp = &ahstack->ah_sadb.s_v6;
   1676   3448    dh155122 	} else {
   1677   3448    dh155122 		sp = &ahstack->ah_sadb.s_v4;
   1678      0      stevel 		ASSERT(assoc->ipsa_addrfam == AF_INET);
   1679      0      stevel 	}
   1680      0      stevel 	if (inbound) {
   1681      0      stevel 		inassoc = assoc;
   1682      0      stevel 		if (isv6)
   1683   4987      danmcd 			outhash = OUTBOUND_HASH_V6(sp,
   1684   4987      danmcd 			    *((in6_addr_t *)&inassoc->ipsa_dstaddr));
   1685      0      stevel 		else
   1686   4987      danmcd 			outhash = OUTBOUND_HASH_V4(sp,
   1687   4987      danmcd 			    *((ipaddr_t *)&inassoc->ipsa_dstaddr));
   1688      0      stevel 		bucket = &sp->sdb_of[outhash];
   1689      0      stevel 		mutex_enter(&bucket->isaf_lock);
   1690      0      stevel 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
   1691      0      stevel 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
   1692      0      stevel 		    inassoc->ipsa_addrfam);
   1693      0      stevel 		mutex_exit(&bucket->isaf_lock);
   1694      0      stevel 		if (outassoc == NULL) {
   1695      0      stevel 			/* Q: Do we wish to set haspeer == B_FALSE? */
   1696      0      stevel 			ah0dbg(("ah_age_bytes: "
   1697      0      stevel 			    "can't find peer for inbound.\n"));
   1698   3448    dh155122 			return (sadb_age_bytes(ahstack->ah_pfkey_q, inassoc,
   1699      0      stevel 			    bytes, B_TRUE));
   1700      0      stevel 		}
   1701      0      stevel 	} else {
   1702      0      stevel 		outassoc = assoc;
   1703    564    sommerfe 		bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
   1704      0      stevel 		mutex_enter(&bucket->isaf_lock);
   1705      0      stevel 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
   1706      0      stevel 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
   1707      0      stevel 		    outassoc->ipsa_addrfam);
   1708      0      stevel 		mutex_exit(&bucket->isaf_lock);
   1709      0      stevel 		if (inassoc == NULL) {
   1710      0      stevel 			/* Q: Do we wish to set haspeer == B_FALSE? */
   1711      0      stevel 			ah0dbg(("ah_age_bytes: "
   1712      0      stevel 			    "can't find peer for outbound.\n"));
   1713   3448    dh155122 			return (sadb_age_bytes(ahstack->ah_pfkey_q, outassoc,
   1714      0      stevel 			    bytes, B_TRUE));
   1715      0      stevel 		}
   1716      0      stevel 	}
   1717      0      stevel 
   1718   3448    dh155122 	inrc = sadb_age_bytes(ahstack->ah_pfkey_q, inassoc, bytes, B_TRUE);
   1719   3448    dh155122 	outrc = sadb_age_bytes(ahstack->ah_pfkey_q, outassoc, bytes, B_FALSE);
   1720      0      stevel 
   1721      0      stevel 	/*
   1722      0      stevel 	 * REFRELE any peer SA.
   1723      0      stevel 	 *
   1724      0      stevel 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
   1725      0      stevel 	 * them in { }.
   1726      0      stevel 	 */
   1727      0      stevel 	if (inbound) {
   1728      0      stevel 		IPSA_REFRELE(outassoc);
   1729      0      stevel 	} else {
   1730      0      stevel 		IPSA_REFRELE(inassoc);
   1731      0      stevel 	}
   1732      0      stevel 
   1733      0      stevel 	return (inrc && outrc);
   1734      0      stevel }
   1735      0      stevel 
   1736      0      stevel /*
   1737      0      stevel  * Perform the really difficult work of inserting the proposed situation.
   1738      0      stevel  * Called while holding the algorithm lock.
   1739      0      stevel  */
   1740      0      stevel static void
   1741  11042        Erik ah_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
   1742  11042        Erik     netstack_t *ns)
   1743      0      stevel {
   1744      0      stevel 	sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
   1745      0      stevel 	ipsec_action_t *ap;
   1746      0      stevel 	ipsec_prot_t *prot;
   1747  11042        Erik 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   1748  11042        Erik 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
   1749  11042        Erik 
   1750   3448    dh155122 	ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
   1751      0      stevel 
   1752      0      stevel 	prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
   1753      0      stevel 	prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
   1754      0      stevel 	*(uint32_t *)(&prop->sadb_prop_replay) = 0;	/* Quick zero-out! */
   1755      0      stevel 
   1756   3448    dh155122 	prop->sadb_prop_replay = ahstack->ipsecah_replay_size;
   1757      0      stevel 
   1758      0      stevel 	/*
   1759      0      stevel 	 * Based upon algorithm properties, and what-not, prioritize a
   1760  11042        Erik 	 * proposal, based on the ordering of the AH algorithms in the
   1761  11042        Erik 	 * alternatives in the policy rule or socket that was placed
   1762  11042        Erik 	 * in the acquire record.
   1763      0      stevel 	 */
   1764      0      stevel 
   1765      0      stevel 	for (ap = acqrec->ipsacq_act; ap != NULL;
   1766      0      stevel 	    ap = ap->ipa_next) {
   1767      0      stevel 		ipsec_alginfo_t *aalg;
   1768      0      stevel 
   1769      0      stevel 		if ((ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) ||
   1770      0      stevel 		    (!ap->ipa_act.ipa_apply.ipp_use_ah))
   1771      0      stevel 			continue;
   1772      0      stevel 
   1773      0      stevel 		prot = &ap->ipa_act.ipa_apply;
   1774      0      stevel 
   1775      0      stevel 		ASSERT(prot->ipp_auth_alg > 0);
   1776      0      stevel 
   1777   3448    dh155122 		aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
   1778   3448    dh155122 		    [prot->ipp_auth_alg];
   1779      0      stevel 		if (aalg == NULL || !ALG_VALID(aalg))
   1780      0      stevel 			continue;
   1781      0      stevel 
   1782      0      stevel 		/* XXX check aalg for duplicates??.. */
   1783      0      stevel 
   1784      0      stevel 		comb->sadb_comb_flags = 0;
   1785      0      stevel 		comb->sadb_comb_reserved = 0;
   1786      0      stevel 		comb->sadb_comb_encrypt = 0;
   1787      0      stevel 		comb->sadb_comb_encrypt_minbits = 0;
   1788      0      stevel 		comb->sadb_comb_encrypt_maxbits = 0;
   1789      0      stevel 
   1790      0      stevel 		comb->sadb_comb_auth = aalg->alg_id;
   1791   2751      danmcd 		comb->sadb_comb_auth_minbits =
   1792   2751      danmcd 		    MAX(prot->ipp_ah_minbits, aalg->alg_ef_minbits);
   1793   2751      danmcd 		comb->sadb_comb_auth_maxbits =
   1794   2751      danmcd 		    MIN(prot->ipp_ah_maxbits, aalg->alg_ef_maxbits);
   1795      0      stevel 
   1796      0      stevel 		/*
   1797      0      stevel 		 * The following may be based on algorithm
   1798      0      stevel 		 * properties, but in the meantime, we just pick
   1799      0      stevel 		 * some good, sensible numbers.  Key mgmt. can
   1800      0      stevel 		 * (and perhaps should) be the place to finalize
   1801      0      stevel 		 * such decisions.
   1802      0      stevel 		 */
   1803      0      stevel 
   1804      0      stevel 		/*
   1805      0      stevel 		 * No limits on allocations, since we really don't
   1806      0      stevel 		 * support that concept currently.
   1807      0      stevel 		 */
   1808      0      stevel 		comb->sadb_comb_soft_allocations = 0;
   1809      0      stevel 		comb->sadb_comb_hard_allocations = 0;
   1810      0      stevel 
   1811      0      stevel 		/*
   1812      0      stevel 		 * These may want to come from policy rule..
   1813      0      stevel 		 */
   1814   3448    dh155122 		comb->sadb_comb_soft_bytes =
   1815   3448    dh155122 		    ahstack->ipsecah_default_soft_bytes;
   1816   3448    dh155122 		comb->sadb_comb_hard_bytes =
   1817   3448    dh155122 		    ahstack->ipsecah_default_hard_bytes;
   1818   3448    dh155122 		comb->sadb_comb_soft_addtime =
   1819   3448    dh155122 		    ahstack->ipsecah_default_soft_addtime;
   1820   3448    dh155122 		comb->sadb_comb_hard_addtime =
   1821   3448    dh155122 		    ahstack->ipsecah_default_hard_addtime;
   1822   3448    dh155122 		comb->sadb_comb_soft_usetime =
   1823   3448    dh155122 		    ahstack->ipsecah_default_soft_usetime;
   1824   3448    dh155122 		comb->sadb_comb_hard_usetime =
   1825   3448    dh155122 		    ahstack->ipsecah_default_hard_usetime;
   1826      0      stevel 
   1827      0      stevel 		prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
   1828      0      stevel 		if (--combs == 0)
   1829      0      stevel 			return;	/* out of space.. */
   1830      0      stevel 		comb++;
   1831      0      stevel 	}
   1832      0      stevel }
   1833      0      stevel 
   1834      0      stevel /*
   1835      0      stevel  * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
   1836      0      stevel  */
   1837      0      stevel static void
   1838   3448    dh155122 ah_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
   1839      0      stevel {
   1840   3055      danmcd 	uint_t combs;
   1841   3055      danmcd 	sadb_msg_t *samsg;
   1842   3055      danmcd 	sadb_prop_t *prop;
   1843      0      stevel 	mblk_t *pfkeymp, *msgmp;
   1844   3448    dh155122 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   1845   3448    dh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
   1846   3448    dh155122 
   1847   3448    dh155122 	AH_BUMP_STAT(ahstack, acquire_requests);
   1848   3448    dh155122 
   1849   7073     pwernau 	if (ahstack->ah_pfkey_q == NULL) {
   1850   7073     pwernau 		mutex_exit(&acqrec->ipsacq_lock);
   1851   7073     pwernau 		return;
   1852   7073     pwernau 	}
   1853   3055      danmcd 
   1854   3055      danmcd 	/* Set up ACQUIRE. */
   1855   3448    dh155122 	pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_AH,
   1856   3448    dh155122 	    ns->netstack_ipsec);
   1857      0      stevel 	if (pfkeymp == NULL) {
   1858   3055      danmcd 		ah0dbg(("sadb_setup_acquire failed.\n"));
   1859   7073     pwernau 		mutex_exit(&acqrec->ipsacq_lock);
   1860   3055      danmcd 		return;
   1861   3055      danmcd 	}
   1862   3448    dh155122 	ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
   1863   3448    dh155122 	combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
   1864   3055      danmcd 	msgmp = pfkeymp->b_cont;
   1865   3055      danmcd 	samsg = (sadb_msg_t *)(msgmp->b_rptr);
   1866      0      stevel 
   1867      0      stevel 	/* Insert proposal here. */
   1868      0      stevel 
   1869      0      stevel 	prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
   1870  11042        Erik 	ah_insert_prop(prop, acqrec, combs, ns);
   1871      0      stevel 	samsg->sadb_msg_len += prop->sadb_prop_len;
   1872      0      stevel 	msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
   1873      0      stevel 
   1874   3448    dh155122 	mutex_exit(&ipss->ipsec_alg_lock);
   1875      0      stevel 
   1876      0      stevel 	/*
   1877      0      stevel 	 * Must mutex_exit() before sending PF_KEY message up, in
   1878      0      stevel 	 * order to avoid recursive mutex_enter() if there are no registered
   1879      0      stevel 	 * listeners.
   1880      0      stevel 	 *
   1881      0      stevel 	 * Once I've sent the message, I'm cool anyway.
   1882      0      stevel 	 */
   1883      0      stevel 	mutex_exit(&acqrec->ipsacq_lock);
   1884   3055      danmcd 	if (extended != NULL) {
   1885   3448    dh155122 		putnext(ahstack->ah_pfkey_q, extended);
   1886   3448    dh155122 	}
   1887   3448    dh155122 	putnext(ahstack->ah_pfkey_q, pfkeymp);
   1888      0      stevel }
   1889      0      stevel 
   1890  10934  sommerfeld /* Refactor me */
   1891      0      stevel /*
   1892      0      stevel  * Handle the SADB_GETSPI message.  Create a larval SA.
   1893      0      stevel  */
   1894      0      stevel static void
   1895   3448    dh155122 ah_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
   1896      0      stevel {
   1897      0      stevel 	ipsa_t *newbie, *target;
   1898      0      stevel 	isaf_t *outbound, *inbound;
   1899      0      stevel 	int rc, diagnostic;
   1900      0      stevel 	sadb_sa_t *assoc;
   1901      0      stevel 	keysock_out_t *kso;
   1902      0      stevel 	uint32_t newspi;
   1903      0      stevel 
   1904      0      stevel 	/*
   1905      0      stevel 	 * Randomly generate a proposed SPI value.
   1906      0      stevel 	 */
   1907   7749  Thejaswini 	if (cl_inet_getspi != NULL) {
   1908   8392     Huafeng 		cl_inet_getspi(ahstack->ipsecah_netstack->netstack_stackid,
   1909   8392     Huafeng 		    IPPROTO_AH, (uint8_t *)&newspi, sizeof (uint32_t), NULL);
   1910   7749  Thejaswini 	} else {
   1911   7749  Thejaswini 		(void) random_get_pseudo_bytes((uint8_t *)&newspi,
   1912   7749  Thejaswini 		    sizeof (uint32_t));
   1913   7749  Thejaswini 	}
   1914   3448    dh155122 	newbie = sadb_getspi(ksi, newspi, &diagnostic,
   1915   7749  Thejaswini 	    ahstack->ipsecah_netstack, IPPROTO_AH);
   1916      0      stevel 
   1917      0      stevel 	if (newbie == NULL) {
   1918   3448    dh155122 		sadb_pfkey_error(ahstack->ah_pfkey_q, mp, ENOMEM, diagnostic,
   1919      0      stevel 		    ksi->ks_in_serial);
   1920      0      stevel 		return;
   1921      0      stevel 	} else if (newbie == (ipsa_t *)-1) {
   1922   3448    dh155122 		sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL, diagnostic,
   1923      0      stevel 		    ksi->ks_in_serial);
   1924      0      stevel 		return;
   1925      0      stevel 	}
   1926      0      stevel 
   1927      0      stevel 	/*
   1928      0      stevel 	 * XXX - We may randomly collide.  We really should recover from this.
   1929      0      stevel 	 *	 Unfortunately, that could require spending way-too-much-time
   1930      0      stevel 	 *	 in here.  For now, let the user retry.
   1931      0      stevel 	 */
   1932      0      stevel 
   1933      0      stevel 	if (newbie->ipsa_addrfam == AF_INET6) {
   1934   3448    dh155122 		outbound = OUTBOUND_BUCKET_V6(&ahstack->ah_sadb.s_v6,
   1935    564    sommerfe 		    *(uint32_t *)(newbie->ipsa_dstaddr));
   1936   3448    dh155122 		inbound = INBOUND_BUCKET(&ahstack->ah_sadb.s_v6,
   1937   3448    dh155122 		    newbie->ipsa_spi);
   1938   3448    dh155122 	} else {
   1939   3448    dh155122 		outbound = OUTBOUND_BUCKET_V4(&ahstack->ah_sadb.s_v4,
   1940    564    sommerfe 		    *(uint32_t *)(newbie->ipsa_dstaddr));
   1941   3448    dh155122 		inbound = INBOUND_BUCKET(&ahstack->ah_sadb.s_v4,
   1942   3448    dh155122 		    newbie->ipsa_spi);
   1943      0      stevel 	}
   1944      0      stevel 
   1945      0      stevel 	mutex_enter(&outbound->isaf_lock);
   1946      0      stevel 	mutex_enter(&inbound->isaf_lock);
   1947      0      stevel 
   1948      0      stevel 	/*
   1949      0      stevel 	 * Check for collisions (i.e. did sadb_getspi() return with something
   1950      0      stevel 	 * that already exists?).
   1951      0      stevel 	 *
   1952      0      stevel 	 * Try outbound first.  Even though SADB_GETSPI is traditionally
   1953      0      stevel 	 * for inbound SAs, you never know what a user might do.
   1954      0      stevel 	 */
   1955      0      stevel 	target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi,
   1956      0      stevel 	    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam);
   1957      0      stevel 	if (target == NULL) {
   1958      0      stevel 		target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi,
   1959      0      stevel 		    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr,
   1960      0      stevel 		    newbie->ipsa_addrfam);
   1961      0      stevel 	}
   1962      0      stevel 
   1963      0      stevel 	/*
   1964      0      stevel 	 * I don't have collisions elsewhere!
   1965      0      stevel 	 * (Nor will I because I'm still holding inbound/outbound locks.)
   1966      0      stevel 	 */
   1967      0      stevel 
   1968      0      stevel 	if (target != NULL) {
   1969      0      stevel 		rc = EEXIST;
   1970      0      stevel 		IPSA_REFRELE(target);
   1971      0      stevel 	} else {
   1972      0      stevel 		/*
   1973      0      stevel 		 * sadb_insertassoc() also checks for collisions, so
   1974      0      stevel 		 * if there's a colliding larval entry, rc will be set
   1975      0      stevel 		 * to EEXIST.
   1976      0      stevel 		 */
   1977      0      stevel 		rc = sadb_insertassoc(newbie, inbound);
   1978   4987      danmcd 		newbie->ipsa_hardexpiretime = gethrestime_sec();
   1979   3448    dh155122 		newbie->ipsa_hardexpiretime += ahstack->ipsecah_larval_timeout;
   1980      0      stevel 	}
   1981      0      stevel 
   1982      0      stevel 	/*
   1983      0      stevel 	 * Can exit outbound mutex.  Hold inbound until we're done with
   1984      0      stevel 	 * newbie.
   1985      0      stevel 	 */
   1986      0      stevel 	mutex_exit(&outbound->isaf_lock);
   1987      0      stevel 
   1988      0      stevel 	if (rc != 0) {
   1989      0      stevel 		mutex_exit(&inbound->isaf_lock);
   1990      0      stevel 		IPSA_REFRELE(newbie);
   1991   3448    dh155122 		sadb_pfkey_error(ahstack->ah_pfkey_q, mp, rc,
   1992   3448    dh155122 		    SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial);
   1993      0      stevel 		return;
   1994      0      stevel 	}
   1995      0      stevel 
   1996      0      stevel 	/* Can write here because I'm still holding the bucket lock. */
   1997      0      stevel 	newbie->ipsa_type = SADB_SATYPE_AH;
   1998      0      stevel 
   1999      0      stevel 	/*
   2000      0      stevel 	 * Construct successful return message.  We have one thing going
   2001      0      stevel 	 * for us in PF_KEY v2.  That's the fact that
   2002      0      stevel 	 *	sizeof (sadb_spirange_t) == sizeof (sadb_sa_t)
   2003      0      stevel 	 */
   2004      0      stevel 	assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE];
   2005      0      stevel 	assoc->sadb_sa_exttype = SADB_EXT_SA;
   2006      0      stevel 	assoc->sadb_sa_spi = newbie->ipsa_spi;
   2007      0      stevel 	*((uint64_t *)(&assoc->sadb_sa_replay)) = 0;
   2008      0      stevel 	mutex_exit(&inbound->isaf_lock);
   2009      0      stevel 
   2010      0      stevel 	/* Convert KEYSOCK_IN to KEYSOCK_OUT. */
   2011      0      stevel 	kso = (keysock_out_t *)ksi;
   2012      0      stevel 	kso->ks_out_len = sizeof (*kso);
   2013      0      stevel 	kso->ks_out_serial = ksi->ks_in_serial;
   2014      0      stevel 	kso->ks_out_type = KEYSOCK_OUT;
   2015      0      stevel 
   2016      0      stevel 	/*
   2017      0      stevel 	 * Can safely putnext() to ah_pfkey_q, because this is a turnaround
   2018      0      stevel 	 * from the ah_pfkey_q.
   2019      0      stevel 	 */
   2020   3448    dh155122 	putnext(ahstack->ah_pfkey_q, mp);
   2021      0      stevel }
   2022      0      stevel 
   2023      0      stevel /*
   2024      0      stevel  * IPv6 sends up the ICMP errors for validation and the removal of the AH
   2025      0      stevel  * header.
   2026  11042        Erik  * If succesful, the mp has been modified to not include the AH header so
   2027  11042        Erik  * that the caller can fanout to the ULP's icmp error handler.
   2028  11042        Erik  */
   2029  11042        Erik static mblk_t *
   2030  11042        Erik ah_icmp_error_v6(mblk_t *mp, ip_recv_attr_t *ira, ipsecah_stack_t *ahstack)
   2031  11042        Erik {
   2032      0      stevel 	ip6_t *ip6h, *oip6h;
   2033      0      stevel 	uint16_t hdr_length, ah_length;
   2034      0      stevel 	uint8_t *nexthdrp;
   2035      0      stevel 	ah_t *ah;
   2036      0      stevel 	icmp6_t *icmp6;
   2037      0      stevel 	isaf_t *isaf;
   2038      0      stevel 	ipsa_t *assoc;
   2039      0      stevel 	uint8_t *post_ah_ptr;
   2040   3448    dh155122 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
   2041      0      stevel 
   2042      0      stevel 	/*
   2043      0      stevel 	 * Eat the cost of a pullupmsg() for now.  It makes the rest of this
   2044      0      stevel 	 * code far less convoluted.
   2045      0      stevel 	 */
   2046      0      stevel 	if (!pullupmsg(mp, -1) ||
   2047      0      stevel 	    !ip_hdr_length_nexthdr_v6(mp, (ip6_t *)mp->b_rptr, &hdr_length,
   2048   4987      danmcd 	    &nexthdrp) ||
   2049      0      stevel 	    mp->b_rptr + hdr_length + sizeof (icmp6_t) + sizeof (ip6_t) +
   2050      0      stevel 	    sizeof (ah_t) > mp->b_wptr) {
   2051   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2052  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2053  11042        Erik 		    DROPPER(ipss, ipds_ah_nomem),
   2054  11042        Erik 		    &ahstack->ah_dropper);
   2055  11042        Erik 		return (NULL);
   2056      0      stevel 	}
   2057      0      stevel 
   2058      0      stevel 	oip6h = (ip6_t *)mp->b_rptr;
   2059      0      stevel 	icmp6 = (icmp6_t *)((uint8_t *)oip6h + hdr_length);
   2060      0      stevel 	ip6h = (ip6_t *)(icmp6 + 1);
   2061      0      stevel 	if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp)) {
   2062   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2063  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2064   3448    dh155122 		    DROPPER(ipss, ipds_ah_bad_v6_hdrs),
   2065   3448    dh155122 		    &ahstack->ah_dropper);
   2066  11042        Erik 		return (NULL);
   2067      0      stevel 	}
   2068      0      stevel 	ah = (ah_t *)((uint8_t *)ip6h + hdr_length);
   2069      0      stevel 
   2070   3448    dh155122 	isaf = OUTBOUND_BUCKET_V6(&ahstack->ah_sadb.s_v6, ip6h->ip6_dst);
   2071      0      stevel 	mutex_enter(&isaf->isaf_lock);
   2072      0      stevel 	assoc = ipsec_getassocbyspi(isaf, ah->ah_spi,
   2073      0      stevel 	    (uint32_t *)&ip6h->ip6_src, (uint32_t *)&ip6h->ip6_dst, AF_INET6);
   2074      0      stevel 	mutex_exit(&isaf->isaf_lock);
   2075      0      stevel 
   2076      0      stevel 	if (assoc == NULL) {
   2077   3448    dh155122 		IP_AH_BUMP_STAT(ipss, lookup_failure);
   2078   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2079   3448    dh155122 		if (ahstack->ipsecah_log_unknown_spi) {
   2080      0      stevel 			ipsec_assocfailure(info.mi_idnum, 0, 0,
   2081      0      stevel 			    SL_CONSOLE | SL_WARN | SL_ERROR,
   2082      0      stevel 			    "Bad ICMP message - No association for the "
   2083      0      stevel 			    "attached AH header whose spi is 0x%x, "
   2084      0      stevel 			    "sender is 0x%x\n",
   2085   3448    dh155122 			    ah->ah_spi, &oip6h->ip6_src, AF_INET6,
   2086   3448    dh155122 			    ahstack->ipsecah_netstack);
   2087   3448    dh155122 		}
   2088  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2089   3448    dh155122 		    DROPPER(ipss, ipds_ah_no_sa),
   2090   3448    dh155122 		    &ahstack->ah_dropper);
   2091  11042        Erik 		return (NULL);
   2092      0      stevel 	}
   2093      0      stevel 
   2094      0      stevel 	IPSA_REFRELE(assoc);
   2095      0      stevel 
   2096      0      stevel 	/*
   2097      0      stevel 	 * There seems to be a valid association. If there is enough of AH
   2098      0      stevel 	 * header remove it, otherwise bail.  One could check whether it has
   2099      0      stevel 	 * complete AH header plus 8 bytes but it does not make sense if an
   2100      0      stevel 	 * icmp error is returned for ICMP messages e.g ICMP time exceeded,
   2101      0      stevel 	 * that are being sent up. Let the caller figure out.
   2102      0      stevel 	 *
   2103      0      stevel 	 * NOTE: ah_length is the number of 32 bit words minus 2.
   2104      0      stevel 	 */
   2105      0      stevel 	ah_length = (ah->ah_length << 2) + 8;
   2106      0      stevel 	post_ah_ptr = (uint8_t *)ah + ah_length;
   2107      0      stevel 
   2108      0      stevel 	if (post_ah_ptr > mp->b_wptr) {
   2109   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2110  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2111   3448    dh155122 		    DROPPER(ipss, ipds_ah_bad_length),
   2112   3448    dh155122 		    &ahstack->ah_dropper);
   2113  11042        Erik 		return (NULL);
   2114      0      stevel 	}
   2115      0      stevel 
   2116      0      stevel 	ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - ah_length);
   2117      0      stevel 	*nexthdrp = ah->ah_nexthdr;
   2118      0      stevel 	ovbcopy(post_ah_ptr, ah,
   2119      0      stevel 	    (size_t)((uintptr_t)mp->b_wptr - (uintptr_t)post_ah_ptr));
   2120      0      stevel 	mp->b_wptr -= ah_length;
   2121  11042        Erik 
   2122  11042        Erik 	return (mp);
   2123      0      stevel }
   2124      0      stevel 
   2125      0      stevel /*
   2126      0      stevel  * IP sends up the ICMP errors for validation and the removal of
   2127      0      stevel  * the AH header.
   2128  11042        Erik  * If succesful, the mp has been modified to not include the AH header so
   2129  11042        Erik  * that the caller can fanout to the ULP's icmp error handler.
   2130  11042        Erik  */
   2131  11042        Erik static mblk_t *
   2132  11042        Erik ah_icmp_error_v4(mblk_t *mp, ip_recv_attr_t *ira, ipsecah_stack_t *ahstack)
   2133  11042        Erik {
   2134      0      stevel 	mblk_t *mp1;
   2135      0      stevel 	icmph_t *icmph;
   2136      0      stevel 	int iph_hdr_length;
   2137      0      stevel 	int hdr_length;
   2138      0      stevel 	isaf_t *hptr;
   2139      0      stevel 	ipsa_t *assoc;
   2140      0      stevel 	int ah_length;
   2141      0      stevel 	ipha_t *ipha;
   2142      0      stevel 	ipha_t *oipha;
   2143      0      stevel 	ah_t *ah;
   2144      0      stevel 	uint32_t length;
   2145      0      stevel 	int alloc_size;
   2146      0      stevel 	uint8_t nexthdr;
   2147   3448    dh155122 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
   2148      0      stevel 
   2149      0      stevel 	oipha = ipha = (ipha_t *)mp->b_rptr;
   2150      0      stevel 	iph_hdr_length = IPH_HDR_LENGTH(ipha);
   2151      0      stevel 	icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
   2152      0      stevel 
   2153      0      stevel 	ipha = (ipha_t *)&icmph[1];
   2154      0      stevel 	hdr_length = IPH_HDR_LENGTH(ipha);
   2155      0      stevel 
   2156      0      stevel 	/*
   2157      0      stevel 	 * See if we have enough to locate the SPI
   2158      0      stevel 	 */
   2159      0      stevel 	if ((uchar_t *)ipha + hdr_length + 8 > mp->b_wptr) {
   2160      0      stevel 		if (!pullupmsg(mp, (uchar_t *)ipha + hdr_length + 8 -
   2161   4987      danmcd 		    mp->b_rptr)) {
   2162   3448    dh155122 			ipsec_rl_strlog(ahstack->ipsecah_netstack,
   2163   3448    dh155122 			    info.mi_idnum, 0, 0,
   2164      0      stevel 			    SL_WARN | SL_ERROR,
   2165      0      stevel 			    "ICMP error: Small AH header\n");
   2166   3448    dh155122 			IP_AH_BUMP_STAT(ipss, in_discards);
   2167  11042        Erik 			ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2168   3448    dh155122 			    DROPPER(ipss, ipds_ah_bad_length),
   2169   3448    dh155122 			    &ahstack->ah_dropper);
   2170  11042        Erik 			return (NULL);
   2171      0      stevel 		}
   2172      0      stevel 		icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
   2173      0      stevel 		ipha = (ipha_t *)&icmph[1];
   2174      0      stevel 	}
   2175      0      stevel 
   2176      0      stevel 	ah = (ah_t *)((uint8_t *)ipha + hdr_length);
   2177      0      stevel 	nexthdr = ah->ah_nexthdr;
   2178      0      stevel 
   2179   3448    dh155122 	hptr = OUTBOUND_BUCKET_V4(&ahstack->ah_sadb.s_v4, ipha->ipha_dst);
   2180      0      stevel 	mutex_enter(&hptr->isaf_lock);
   2181      0      stevel 	assoc = ipsec_getassocbyspi(hptr, ah->ah_spi,
   2182      0      stevel 	    (uint32_t *)&ipha->ipha_src, (uint32_t *)&ipha->ipha_dst, AF_INET);
   2183      0      stevel 	mutex_exit(&hptr->isaf_lock);
   2184      0      stevel 
   2185      0      stevel 	if (assoc == NULL) {
   2186   3448    dh155122 		IP_AH_BUMP_STAT(ipss, lookup_failure);
   2187   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2188   3448    dh155122 		if (ahstack->ipsecah_log_unknown_spi) {
   2189      0      stevel 			ipsec_assocfailure(info.mi_idnum, 0, 0,
   2190      0      stevel 			    SL_CONSOLE | SL_WARN | SL_ERROR,
   2191      0      stevel 			    "Bad ICMP message - No association for the "
   2192      0      stevel 			    "attached AH header whose spi is 0x%x, "
   2193      0      stevel 			    "sender is 0x%x\n",
   2194   3448    dh155122 			    ah->ah_spi, &oipha->ipha_src, AF_INET,
   2195   3448    dh155122 			    ahstack->ipsecah_netstack);
   2196   3448    dh155122 		}
   2197  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2198   3448    dh155122 		    DROPPER(ipss, ipds_ah_no_sa),
   2199   3448    dh155122 		    &ahstack->ah_dropper);
   2200  11042        Erik 		return (NULL);
   2201      0      stevel 	}
   2202      0      stevel 
   2203      0      stevel 	IPSA_REFRELE(assoc);
   2204      0      stevel 	/*
   2205      0      stevel 	 * There seems to be a valid association. If there
   2206      0      stevel 	 * is enough of AH header remove it, otherwise remove
   2207      0      stevel 	 * as much as possible and send it back. One could check
   2208      0      stevel 	 * whether it has complete AH header plus 8 bytes but it
   2209      0      stevel 	 * does not make sense if an icmp error is returned for
   2210      0      stevel 	 * ICMP messages e.g ICMP time exceeded, that are being
   2211      0      stevel 	 * sent up. Let the caller figure out.
   2212      0      stevel 	 *
   2213      0      stevel 	 * NOTE: ah_length is the number of 32 bit words minus 2.
   2214      0      stevel 	 */
   2215      0      stevel 	ah_length = (ah->ah_length << 2) + 8;
   2216      0      stevel 
   2217      0      stevel 	if ((uchar_t *)ipha + hdr_length + ah_length > mp->b_wptr) {
   2218      0      stevel 		if (mp->b_cont == NULL) {
   2219      0      stevel 			/*
   2220      0      stevel 			 * There is nothing to pullup. Just remove as
   2221      0      stevel 			 * much as possible. This is a common case for
   2222      0      stevel 			 * IPV4.
   2223      0      stevel 			 */
   2224      0      stevel 			ah_length = (mp->b_wptr - ((uchar_t *)ipha +
   2225      0      stevel 			    hdr_length));
   2226      0      stevel 			goto done;
   2227      0      stevel 		}
   2228      0      stevel 		/* Pullup the full ah header */
   2229      0      stevel 		if (!pullupmsg(mp, (uchar_t *)ah + ah_length - mp->b_rptr)) {
   2230      0      stevel 			/*
   2231      0      stevel 			 * pullupmsg could have failed if there was not
   2232      0      stevel 			 * enough to pullup or memory allocation failed.
   2233      0      stevel 			 * We tried hard, give up now.
   2234      0      stevel 			 */
   2235   3448    dh155122 			IP_AH_BUMP_STAT(ipss, in_discards);
   2236  11042        Erik 			ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2237   3448    dh155122 			    DROPPER(ipss, ipds_ah_nomem),
   2238   3448    dh155122 			    &ahstack->ah_dropper);
   2239  11042        Erik 			return (NULL);
   2240      0      stevel 		}
   2241      0      stevel 		icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
   2242      0      stevel 		ipha = (ipha_t *)&icmph[1];
   2243      0      stevel 	}
   2244      0      stevel done:
   2245      0      stevel 	/*
   2246      0      stevel 	 * Remove the AH header and change the protocol.
   2247  11042        Erik 	 * Don't update the spi fields in the ip_recv_attr_t
   2248  11042        Erik 	 * as we are called just to validate the
   2249      0      stevel 	 * message attached to the ICMP message.
   2250      0      stevel 	 *
   2251      0      stevel 	 * If we never pulled up since all of the message
   2252      0      stevel 	 * is in one single mblk, we can't remove the AH header
   2253      0      stevel 	 * by just setting the b_wptr to the beginning of the
   2254      0      stevel 	 * AH header. We need to allocate a mblk that can hold
   2255      0      stevel 	 * up until the inner IP header and copy them.
   2256      0      stevel 	 */
   2257      0      stevel 	alloc_size = iph_hdr_length + sizeof (icmph_t) + hdr_length;
   2258      0      stevel 
   2259      0      stevel 	if ((mp1 = allocb(alloc_size, BPRI_LO)) == NULL) {
   2260   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2261  11042        Erik 		ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2262  11042        Erik 		    DROPPER(ipss, ipds_ah_nomem),
   2263  11042        Erik 		    &ahstack->ah_dropper);
   2264  11042        Erik 		return (NULL);
   2265  11042        Erik 	}
   2266      0      stevel 	bcopy(mp->b_rptr, mp1->b_rptr, alloc_size);
   2267      0      stevel 	mp1->b_wptr += alloc_size;
   2268      0      stevel 
   2269      0      stevel 	/*
   2270      0      stevel 	 * Skip whatever we have copied and as much of AH header
   2271      0      stevel 	 * possible. If we still have something left in the original
   2272      0      stevel 	 * message, tag on.
   2273      0      stevel 	 */
   2274      0      stevel 	mp->b_rptr = (uchar_t *)ipha + hdr_length + ah_length;
   2275      0      stevel 
   2276      0      stevel 	if (mp->b_rptr != mp->b_wptr) {
   2277      0      stevel 		mp1->b_cont = mp;
   2278      0      stevel 	} else {
   2279      0      stevel 		if (mp->b_cont != NULL)
   2280      0      stevel 			mp1->b_cont = mp->b_cont;
   2281      0      stevel 		freeb(mp);
   2282      0      stevel 	}
   2283      0      stevel 
   2284      0      stevel 	ipha = (ipha_t *)(mp1->b_rptr + iph_hdr_length + sizeof (icmph_t));
   2285      0      stevel 	ipha->ipha_protocol = nexthdr;
   2286      0      stevel 	length = ntohs(ipha->ipha_length);
   2287      0      stevel 	length -= ah_length;
   2288      0      stevel 	ipha->ipha_length = htons((uint16_t)length);
   2289      0      stevel 	ipha->ipha_hdr_checksum = 0;
   2290      0      stevel 	ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
   2291      0      stevel 
   2292  11042        Erik 	return (mp1);
   2293      0      stevel }
   2294      0      stevel 
   2295      0      stevel /*
   2296      0      stevel  * IP calls this to validate the ICMP errors that
   2297      0      stevel  * we got from the network.
   2298      0      stevel  */
   2299  11042        Erik mblk_t *
   2300  11042        Erik ipsecah_icmp_error(mblk_t *data_mp, ip_recv_attr_t *ira)
   2301  11042        Erik {
   2302  11042        Erik 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
   2303  11042        Erik 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   2304  11042        Erik 
   2305  11042        Erik 	if (ira->ira_flags & IRAF_IS_IPV4)
   2306  11042        Erik 		return (ah_icmp_error_v4(data_mp, ira, ahstack));
   2307      0      stevel 	else
   2308  11042        Erik 		return (ah_icmp_error_v6(data_mp, ira, ahstack));
   2309      0      stevel }
   2310      0      stevel 
   2311      0      stevel static int
   2312      0      stevel ah_fix_tlv_options_v6(uint8_t *oi_opt, uint8_t *pi_opt, uint_t ehdrlen,
   2313      0      stevel     uint8_t hdr_type, boolean_t copy_always)
   2314      0      stevel {
   2315      0      stevel 	uint8_t opt_type;
   2316      0      stevel 	uint_t optlen;
   2317      0      stevel 
   2318      0      stevel 	ASSERT(hdr_type == IPPROTO_DSTOPTS || hdr_type == IPPROTO_HOPOPTS);
   2319      0      stevel 
   2320      0      stevel 	/*
   2321      0      stevel 	 * Copy the next header and hdr ext. len of the HOP-by-HOP
   2322      0      stevel 	 * and Destination option.
   2323      0      stevel 	 */
   2324      0      stevel 	*pi_opt++ = *oi_opt++;
   2325      0      stevel 	*pi_opt++ = *oi_opt++;
   2326      0      stevel 	ehdrlen -= 2;
   2327      0      stevel 
   2328      0      stevel 	/*
   2329      0      stevel 	 * Now handle all the TLV encoded options.
   2330      0      stevel 	 */
   2331      0      stevel 	while (ehdrlen != 0) {
   2332      0      stevel 		opt_type = *oi_opt;
   2333      0      stevel 
   2334      0      stevel 		if (opt_type == IP6OPT_PAD1) {
   2335      0      stevel 			optlen = 1;
   2336      0      stevel 		} else {
   2337      0      stevel 			if (ehdrlen < 2)
   2338      0      stevel 				goto bad_opt;
   2339      0      stevel 			optlen = 2 + oi_opt[1];
   2340      0      stevel 			if (optlen > ehdrlen)
   2341      0      stevel 				goto bad_opt;
   2342      0      stevel 		}
   2343      0      stevel 		if (copy_always || !(opt_type & IP6OPT_MUTABLE)) {
   2344      0      stevel 			bcopy(oi_opt, pi_opt, optlen);
   2345      0      stevel 		} else {
   2346      0      stevel 			if (optlen == 1) {
   2347      0      stevel 				*pi_opt = 0;
   2348      0      stevel 			} else {
   2349      0      stevel 				/*
   2350      0      stevel 				 * Copy the type and data length fields.
   2351      0      stevel 				 * Zero the option data by skipping
   2352      0      stevel 				 * option type and option data len
   2353      0      stevel 				 * fields.
   2354      0      stevel 				 */
   2355      0      stevel 				*pi_opt = *oi_opt;
   2356      0      stevel 				*(pi_opt + 1) = *(oi_opt + 1);
   2357      0      stevel 				bzero(pi_opt + 2, optlen - 2);
   2358      0      stevel 			}
   2359      0      stevel 		}
   2360      0      stevel 		ehdrlen -= optlen;
   2361      0      stevel 		oi_opt += optlen;
   2362      0      stevel 		pi_opt += optlen;
   2363      0      stevel 	}
   2364      0      stevel 	return (0);
   2365      0      stevel bad_opt:
   2366      0      stevel 	return (-1);
   2367      0      stevel }
   2368      0      stevel 
   2369      0      stevel /*
   2370      0      stevel  * Construct a pseudo header for AH, processing all the options.
   2371      0      stevel  *
   2372      0      stevel  * oip6h is the IPv6 header of the incoming or outgoing packet.
   2373      0      stevel  * ip6h is the pointer to the pseudo headers IPV6 header. All
   2374      0      stevel  * the space needed for the options have been allocated including
   2375      0      stevel  * the AH header.
   2376      0      stevel  *
   2377      0      stevel  * If copy_always is set, all the options that appear before AH are copied
   2378      0      stevel  * blindly without checking for IP6OPT_MUTABLE. This is used by
   2379      0      stevel  * ah_auth_out_done().  Please refer to that function for details.
   2380      0      stevel  *
   2381      0      stevel  * NOTE :
   2382      0      stevel  *
   2383      0      stevel  * *  AH header is never copied in this function even if copy_always
   2384      0      stevel  *    is set. It just returns the ah_offset - offset of the AH header
   2385      0      stevel  *    and the caller needs to do the copying. This is done so that we
   2386      0      stevel  *    don't have pass extra arguments e.g. SA etc. and also,
   2387      0      stevel  *    it is not needed when ah_auth_out_done is calling this function.
   2388      0      stevel  */
   2389      0      stevel static uint_t
   2390      0      stevel ah_fix_phdr_v6(ip6_t *ip6h, ip6_t *oip6h, boolean_t outbound,
   2391      0      stevel     boolean_t copy_always)
   2392      0      stevel {
   2393      0      stevel 	uint8_t	*oi_opt;
   2394      0      stevel 	uint8_t	*pi_opt;
   2395      0      stevel 	uint8_t nexthdr;
   2396      0      stevel 	uint8_t *prev_nexthdr;
   2397      0      stevel 	ip6_hbh_t *hbhhdr;
   2398      0      stevel 	ip6_dest_t *dsthdr = NULL;
   2399      0      stevel 	ip6_rthdr0_t *rthdr;
   2400      0      stevel 	int ehdrlen;
   2401      0      stevel 	ah_t *ah;
   2402      0      stevel 	int ret;
   2403      0      stevel 
   2404      0      stevel 	/*
   2405      0      stevel 	 * In the outbound case for source route, ULP has already moved
   2406      0      stevel 	 * the first hop, which is now in ip6_dst. We need to re-arrange
   2407      0      stevel 	 * the header to make it look like how it would appear in the
   2408      0      stevel 	 * receiver i.e
   2409      0      stevel 	 *
   2410      0      stevel 	 * Because of ip_massage_options_v6 the header looks like
   2411      0      stevel 	 * this :
   2412      0      stevel 	 *
   2413      0      stevel 	 * ip6_src = S, ip6_dst = I1. followed by I2,I3,D.
   2414      0      stevel 	 *
   2415      0      stevel 	 * When it reaches the receiver, it would look like
   2416      0      stevel 	 *
   2417      0      stevel 	 * ip6_src = S, ip6_dst = D. followed by I1,I2,I3.
   2418      0      stevel 	 *
   2419      0      stevel 	 * NOTE : We assume that there are no problems with the options
   2420      0      stevel 	 * as IP should have already checked this.
   2421      0      stevel 	 */
   2422      0      stevel 
   2423      0      stevel 	oi_opt = (uchar_t *)&oip6h[1];
   2424      0      stevel 	pi_opt = (uchar_t *)&ip6h[1];
   2425      0      stevel 
   2426      0      stevel 	/*
   2427      0      stevel 	 * We set the prev_nexthdr properly in the pseudo header.
   2428      0      stevel 	 * After we finish authentication and come back from the
   2429      0      stevel 	 * algorithm module, pseudo header will become the real
   2430      0      stevel 	 * IP header.
   2431      0      stevel 	 */
   2432      0      stevel 	prev_nexthdr = (uint8_t *)&ip6h->ip6_nxt;
   2433      0      stevel 	nexthdr = oip6h->ip6_nxt;
   2434      0      stevel 	/* Assume IP has already stripped it */
   2435  11042        Erik 	ASSERT(nexthdr != IPPROTO_FRAGMENT);
   2436      0      stevel 	ah = NULL;
   2437      0      stevel 	dsthdr = NULL;
   2438      0      stevel 	for (;;) {
   2439      0      stevel 		switch (nexthdr) {
   2440      0      stevel 		case IPPROTO_HOPOPTS:
   2441      0      stevel 			hbhhdr = (ip6_hbh_t *)oi_opt;
   2442      0      stevel 			nexthdr = hbhhdr->ip6h_nxt;
   2443      0      stevel 			ehdrlen = 8 * (hbhhdr->ip6h_len + 1);
   2444      0      stevel 			ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen,
   2445      0      stevel 			    IPPROTO_HOPOPTS, copy_always);
   2446      0      stevel 			/*
   2447      0      stevel 			 * Return a zero offset indicating error if there
   2448      0      stevel 			 * was error.
   2449      0      stevel 			 */
   2450      0      stevel 			if (ret == -1)
   2451      0      stevel 				return (0);
   2452      0      stevel 			hbhhdr = (ip6_hbh_t *)pi_opt;
   2453      0      stevel 			prev_nexthdr = (uint8_t *)&hbhhdr->ip6h_nxt;
   2454      0      stevel 			break;
   2455      0      stevel 		case IPPROTO_ROUTING:
   2456      0      stevel 			rthdr = (ip6_rthdr0_t *)oi_opt;
   2457      0      stevel 			nexthdr = rthdr->ip6r0_nxt;
   2458      0      stevel 			ehdrlen = 8 * (rthdr->ip6r0_len + 1);
   2459      0      stevel 			if (!copy_always && outbound) {
   2460      0      stevel 				int i, left;
   2461      0      stevel 				ip6_rthdr0_t *prthdr;
   2462      0      stevel 				in6_addr_t *ap, *pap;
   2463      0      stevel 
   2464      0      stevel 				left = rthdr->ip6r0_segleft;
   2465      0      stevel 				prthdr = (ip6_rthdr0_t *)pi_opt;
   2466      0      stevel 				pap = (in6_addr_t *)(prthdr + 1);
   2467      0      stevel 				ap = (in6_addr_t *)(rthdr + 1);
   2468      0      stevel 				/*
   2469      0      stevel 				 * First eight bytes except seg_left
   2470      0      stevel 				 * does not change en route.
   2471      0      stevel 				 */
   2472      0      stevel 				bcopy(oi_opt, pi_opt, 8);
   2473      0      stevel 				prthdr->ip6r0_segleft = 0;
   2474      0      stevel 				/*
   2475      0      stevel 				 * First address has been moved to
   2476      0      stevel 				 * the destination address of the
   2477      0      stevel 				 * ip header by ip_massage_options_v6.
   2478      0      stevel 				 * And the real destination address is
   2479      0      stevel 				 * in the last address part of the
   2480      0      stevel 				 * option.
   2481      0      stevel 				 */
   2482      0      stevel 				*pap = oip6h->ip6_dst;
   2483      0      stevel 				for (i = 1; i < left - 1; i++)
   2484      0      stevel 					pap[i] = ap[i - 1];
   2485      0      stevel 				ip6h->ip6_dst = *(ap + left - 1);
   2486      0      stevel 			} else {
   2487      0      stevel 				bcopy(oi_opt, pi_opt, ehdrlen);
   2488      0      stevel 			}
   2489      0      stevel 			rthdr = (ip6_rthdr0_t *)pi_opt;
   2490      0      stevel 			prev_nexthdr = (uint8_t *)&rthdr->ip6r0_nxt;
   2491      0      stevel 			break;
   2492      0      stevel 		case IPPROTO_DSTOPTS:
   2493      0      stevel 			/*
   2494      0      stevel 			 * Destination options are tricky.  If there is
   2495      0      stevel 			 * a terminal (e.g. non-IPv6-extension) header
   2496      0      stevel 			 * following the destination options, don't
   2497      0      stevel 			 * reset prev_nexthdr or advance the AH insertion
   2498      0      stevel 			 * point and just treat this as a terminal header.
   2499      0      stevel 			 *
   2500      0      stevel 			 * If this is an inbound packet, just deal with
   2501      0      stevel 			 * it as is.
   2502      0      stevel 			 */
   2503      0      stevel 			dsthdr = (ip6_dest_t *)oi_opt;
   2504      0      stevel 			/*
   2505      0      stevel 			 * XXX I hope common-subexpression elimination
   2506      0      stevel 			 * saves us the double-evaluate.
   2507      0      stevel 			 */
   2508      0      stevel 			if (outbound && dsthdr->ip6d_nxt != IPPROTO_ROUTING &&
   2509      0      stevel 			    dsthdr->ip6d_nxt != IPPROTO_HOPOPTS)
   2510      0      stevel 				goto terminal_hdr;
   2511      0      stevel 			nexthdr = dsthdr->ip6d_nxt;
   2512      0      stevel 			ehdrlen = 8 * (dsthdr->ip6d_len + 1);
   2513      0      stevel 			ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen,
   2514      0      stevel 			    IPPROTO_DSTOPTS, copy_always);
   2515      0      stevel 			/*
   2516      0      stevel 			 * Return a zero offset indicating error if there
   2517      0      stevel 			 * was error.
   2518      0      stevel 			 */
   2519      0      stevel 			if (ret == -1)
   2520      0      stevel 				return (0);
   2521      0      stevel 			break;
   2522      0      stevel 		case IPPROTO_AH:
   2523      0      stevel 			/*
   2524      0      stevel 			 * Be conservative in what you send.  We shouldn't
   2525      0      stevel 			 * see two same-scoped AH's in one packet.
   2526      0      stevel 			 * (Inner-IP-scoped AH will be hit by terminal
   2527      0      stevel 			 * header of IP or IPv6.)
   2528      0      stevel 			 */
   2529      0      stevel 			ASSERT(!outbound);
   2530      0      stevel 			return ((uint_t)(pi_opt - (uint8_t *)ip6h));
   2531      0      stevel 		default:
   2532      0      stevel 			ASSERT(outbound);
   2533      0      stevel terminal_hdr:
   2534      0      stevel 			*prev_nexthdr = IPPROTO_AH;
   2535      0      stevel 			ah = (ah_t *)pi_opt;
   2536      0      stevel 			ah->ah_nexthdr = nexthdr;
   2537      0      stevel 			return ((uint_t)(pi_opt - (uint8_t *)ip6h));
   2538      0      stevel 		}
   2539      0      stevel 		pi_opt += ehdrlen;
   2540      0      stevel 		oi_opt += ehdrlen;
   2541      0      stevel 	}
   2542      0      stevel 	/* NOTREACHED */
   2543      0      stevel }
   2544      0      stevel 
   2545      0      stevel static boolean_t
   2546      0      stevel ah_finish_up(ah_t *phdr_ah, ah_t *inbound_ah, ipsa_t *assoc,
   2547   3448    dh155122     int ah_data_sz, int ah_align_sz, ipsecah_stack_t *ahstack)
   2548      0      stevel {
   2549      0      stevel 	int i;
   2550      0      stevel 
   2551      0      stevel 	/*
   2552      0      stevel 	 * Padding :
   2553      0      stevel 	 *
   2554      0      stevel 	 * 1) Authentication data may have to be padded
   2555      0      stevel 	 * before ICV calculation if ICV is not a multiple
   2556      0      stevel 	 * of 64 bits. This padding is arbitrary and transmitted
   2557      0      stevel 	 * with the packet at the end of the authentication data.
   2558      0      stevel 	 * Payload length should include the padding bytes.
   2559      0      stevel 	 *
   2560      0      stevel 	 * 2) Explicit padding of the whole datagram may be
   2561      0      stevel 	 * required by the algorithm which need not be
   2562      0      stevel 	 * transmitted. It is assumed that this will be taken
   2563      0      stevel 	 * care by the algorithm module.
   2564      0      stevel 	 */
   2565      0      stevel 	bzero(phdr_ah + 1, ah_data_sz);	/* Zero out ICV for pseudo-hdr. */
   2566      0      stevel 
   2567      0      stevel 	if (inbound_ah == NULL) {
   2568      0      stevel 		/* Outbound AH datagram. */
   2569      0      stevel 
   2570      0      stevel 		phdr_ah->ah_length = (ah_align_sz >> 2) + 1;
   2571      0      stevel 		phdr_ah->ah_reserved = 0;
   2572      0      stevel 		phdr_ah->ah_spi = assoc->ipsa_spi;
   2573      0      stevel 
   2574      0      stevel 		phdr_ah->ah_replay =
   2575      0      stevel 		    htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1));
   2576      0      stevel 		if (phdr_ah->ah_replay == 0 && assoc->ipsa_replay_wsize != 0) {
   2577      0      stevel 			/*
   2578      0      stevel 			 * XXX We have replay counter wrapping.  We probably
   2579      0      stevel 			 * want to nuke this SA (and its peer).
   2580      0      stevel 			 */
   2581      0      stevel 			ipsec_assocfailure(info.mi_idnum, 0, 0,
   2582      0      stevel 			    SL_ERROR | SL_CONSOLE | SL_WARN,
   2583      0      stevel 			    "Outbound AH SA (0x%x), dst %s has wrapped "
   2584      0      stevel 			    "sequence.\n", phdr_ah->ah_spi,
   2585   3448    dh155122 			    assoc->ipsa_dstaddr, assoc->ipsa_addrfam,
   2586   3448    dh155122 			    ahstack->ipsecah_netstack);
   2587      0      stevel 
   2588      0      stevel 			sadb_replay_delete(assoc);
   2589      0      stevel 			/* Caller will free phdr_mp and return NULL. */
   2590      0      stevel 			return (B_FALSE);
   2591      0      stevel 		}
   2592      0      stevel 
   2593      0      stevel 		if (ah_data_sz != ah_align_sz) {
   2594      0      stevel 			uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) +
   2595      0      stevel 			    ah_data_sz);
   2596      0      stevel 
   2597      0      stevel 			for (i = 0; i < (ah_align_sz - ah_data_sz); i++) {
   2598      0      stevel 				pad[i] = (uchar_t)i;	/* Fill the padding */
   2599      0      stevel 			}
   2600      0      stevel 		}
   2601      0      stevel 	} else {
   2602      0      stevel 		/* Inbound AH datagram. */
   2603      0      stevel 		phdr_ah->ah_nexthdr = inbound_ah->ah_nexthdr;
   2604      0      stevel 		phdr_ah->ah_length = inbound_ah->ah_length;
   2605      0      stevel 		phdr_ah->ah_reserved = 0;
   2606      0      stevel 		ASSERT(inbound_ah->ah_spi == assoc->ipsa_spi);
   2607      0      stevel 		phdr_ah->ah_spi = inbound_ah->ah_spi;
   2608      0      stevel 		phdr_ah->ah_replay = inbound_ah->ah_replay;
   2609      0      stevel 
   2610      0      stevel 		if (ah_data_sz != ah_align_sz) {
   2611   3448    dh155122 			uchar_t *opad = ((uchar_t *)inbound_ah +
   2612   3448    dh155122 			    sizeof (ah_t) + ah_data_sz);
   2613      0      stevel 			uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) +
   2614      0      stevel 			    ah_data_sz);
   2615      0      stevel 
   2616      0      stevel 			for (i = 0; i < (ah_align_sz - ah_data_sz); i++) {
   2617      0      stevel 				pad[i] = opad[i];	/* Copy the padding */
   2618      0      stevel 			}
   2619      0      stevel 		}
   2620      0      stevel 	}
   2621      0      stevel 
   2622      0      stevel 	return (B_TRUE);
   2623      0      stevel }
   2624      0      stevel 
   2625      0      stevel /*
   2626      0      stevel  * Called upon failing the inbound ICV check. The message passed as
   2627      0      stevel  * argument is freed.
   2628      0      stevel  */
   2629      0      stevel static void
   2630  11042        Erik ah_log_bad_auth(mblk_t *mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic)
   2631  11042        Erik {
   2632  11042        Erik 	boolean_t	isv4 = (ira->ira_flags & IRAF_IS_IPV4);
   2633  11042        Erik 	ipsa_t		*assoc = ira->ira_ipsec_ah_sa;
   2634  11042        Erik 	int		af;
   2635  11042        Erik 	void		*addr;
   2636  11042        Erik 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
   2637  11042        Erik 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
   2638  11042        Erik 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
   2639  11042        Erik 
   2640  11042        Erik 	ASSERT(mp->b_datap->db_type == M_DATA);
   2641  11042        Erik 
   2642  11042        Erik 	mp->b_rptr -= ic->ic_skip_len;
   2643      0      stevel 
   2644      0      stevel 	if (isv4) {
   2645      0      stevel 		ipha_t *ipha = (ipha_t *)mp->b_rptr;
   2646      0      stevel 		addr = &ipha->ipha_dst;
   2647      0      stevel 		af = AF_INET;
   2648      0      stevel 	} else {
   2649      0      stevel 		ip6_t *ip6h = (ip6_t *)mp->b_rptr;
   2650      0      stevel 		addr = &ip6h->ip6_dst;
   2651      0      stevel 		af = AF_INET6;
   2652      0      stevel 	}
   2653      0      stevel 
   2654      0      stevel 	/*
   2655      0      stevel 	 * Log the event. Don't print to the console, block
   2656      0      stevel 	 * potential denial-of-service attack.
   2657      0      stevel 	 */
   2658   3448    dh155122 	AH_BUMP_STAT(ahstack, bad_auth);
   2659      0      stevel 
   2660      0      stevel 	ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
   2661      0      stevel 	    "AH Authentication failed spi %x, dst_addr %s",
   2662   3448    dh155122 	    assoc->ipsa_spi, addr, af, ahstack->ipsecah_netstack);
   2663   3448    dh155122 
   2664   3448    dh155122 	IP_AH_BUMP_STAT(ipss, in_discards);
   2665  11042        Erik 	ip_drop_packet(mp, B_TRUE, ira->ira_ill,
   2666   3448    dh155122 	    DROPPER(ipss, ipds_ah_bad_auth),
   2667   3448    dh155122 	    &ahstack->ah_dropper);
   2668      0      stevel }
   2669      0      stevel 
   2670      0      stevel /*
   2671      0      stevel  * Kernel crypto framework callback invoked after completion of async
   2672  11042        Erik  * crypto requests for outbound packets.
   2673  11042        Erik  */
   2674  11042        Erik static void
   2675  11042        Erik ah_kcf_callback_outbound(void *arg, int status)
   2676  11042        Erik {
   2677  11042        Erik 	mblk_t		*mp = (mblk_t *)arg;
   2678  11042        Erik 	mblk_t		*async_mp;
   2679  11042        Erik 	netstack_t	*ns;
   2680   3448    dh155122 	ipsec_stack_t	*ipss;
   2681   3448    dh155122 	ipsecah_stack_t	*ahstack;
   2682  11042        Erik 	mblk_t		*data_mp;
   2683  11042        Erik 	ip_xmit_attr_t	ixas;
   2684  11042        Erik 	ipsec_crypto_t	*ic;
   2685  11042        Erik 	ill_t		*ill;
   2686  11042        Erik 
   2687  11042        Erik 	/*
   2688  11042        Erik 	 * First remove the ipsec_crypto_t mblk
   2689  11042        Erik 	 * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
   2690  11042        Erik 	 */
   2691  11042        Erik 	async_mp = ipsec_remove_crypto_data(mp, &ic);
   2692  11042        Erik 	ASSERT(async_mp != NULL);
   2693  11042        Erik 
   2694  11042        Erik 	/*
   2695  11042        Erik 	 * Extract the ip_xmit_attr_t from the first mblk.
   2696  11042        Erik 	 * Verifies that the netstack and ill is still around; could
   2697  11042        Erik 	 * have vanished while kEf was doing its work.
   2698  11042        Erik 	 * On succesful return we have a nce_t and the ill/ipst can't
   2699  11042        Erik 	 * disappear until we do the nce_refrele in ixa_cleanup.
   2700  11042        Erik 	 */
   2701  11042        Erik 	data_mp = async_mp->b_cont;
   2702  11042        Erik 	async_mp->b_cont = NULL;
   2703  11042        Erik 	if (!ip_xmit_attr_from_mblk(async_mp, &ixas)) {
   2704  11042        Erik 		/* Disappeared on us - no ill/ipst for MIB */
   2705  11042        Erik 		if (ixas.ixa_nce != NULL) {
   2706  11042        Erik 			ill = ixas.ixa_nce->nce_ill;
   2707  11042        Erik 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
   2708  11042        Erik 			ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
   2709  11042        Erik 		}
   2710  11042        Erik 		freemsg(data_mp);
   2711  11042        Erik 		goto done;
   2712  11042        Erik 	}
   2713  11042        Erik 	ns = ixas.ixa_ipst->ips_netstack;
   2714   3448    dh155122 	ahstack = ns->netstack_ipsecah;
   2715   3448    dh155122 	ipss = ns->netstack_ipsec;
   2716  11042        Erik 	ill = ixas.ixa_nce->nce_ill;
   2717      0      stevel 
   2718      0      stevel 	if (status == CRYPTO_SUCCESS) {
   2719  11042        Erik 		data_mp = ah_auth_out_done(data_mp, &ixas, ic);
   2720  11042        Erik 		if (data_mp == NULL)
   2721  11042        Erik 			goto done;
   2722  11042        Erik 
   2723  11042        Erik 		(void) ip_output_post_ipsec(data_mp, &ixas);
   2724  11042        Erik 	} else {
   2725  11042        Erik 		/* Outbound shouldn't see invalid MAC */
   2726  11042        Erik 		ASSERT(status != CRYPTO_INVALID_MAC);
   2727  11042        Erik 
   2728  11042        Erik 		ah1dbg(ahstack,
   2729  11042        Erik 		    ("ah_kcf_callback_outbound: crypto failed with 0x%x\n",
   2730   4987      danmcd 		    status));
   2731   3448    dh155122 		AH_BUMP_STAT(ahstack, crypto_failures);
   2732  11042        Erik 		AH_BUMP_STAT(ahstack, out_discards);
   2733  11042        Erik 
   2734  11042        Erik 		ip_drop_packet(data_mp, B_FALSE, ill,
   2735   3448    dh155122 		    DROPPER(ipss, ipds_ah_crypto_failed),
   2736   3448    dh155122 		    &ahstack->ah_dropper);
   2737  11042        Erik 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
   2738  11042        Erik 	}
   2739  11042        Erik done:
   2740  11042        Erik 	ixa_cleanup(&ixas);
   2741  11042        Erik 	(void) ipsec_free_crypto_data(mp);
   2742  11042        Erik }
   2743  11042        Erik 
   2744  11042        Erik /*
   2745  11042        Erik  * Kernel crypto framework callback invoked after completion of async
   2746  11042        Erik  * crypto requests for inbound packets.
   2747  11042        Erik  */
   2748  11042        Erik static void
   2749  11042        Erik ah_kcf_callback_inbound(void *arg, int status)
   2750  11042        Erik {
   2751  11042        Erik 	mblk_t		*mp = (mblk_t *)arg;
   2752  11042        Erik 	mblk_t		*async_mp;
   2753  11042        Erik 	netstack_t	*ns;
   2754  11042        Erik 	ipsec_stack_t	*ipss;
   2755  11042        Erik 	ipsecah_stack_t	*ahstack;
   2756  11042        Erik 	mblk_t		*data_mp;
   2757  11042        Erik 	ip_recv_attr_t	iras;
   2758  11042        Erik 	ipsec_crypto_t	*ic;
   2759  11042        Erik 
   2760  11042        Erik 	/*
   2761  11042        Erik 	 * First remove the ipsec_crypto_t mblk
   2762  11042        Erik 	 * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
   2763  11042        Erik 	 */
   2764  11042        Erik 	async_mp = ipsec_remove_crypto_data(mp, &ic);
   2765  11042        Erik 	ASSERT(async_mp != NULL);
   2766  11042        Erik 
   2767  11042        Erik 	/*
   2768  11042        Erik 	 * Extract the ip_xmit_attr_t from the first mblk.
   2769  11042        Erik 	 * Verifies that the netstack and ill is still around; could
   2770  11042        Erik 	 * have vanished while kEf was doing its work.
   2771  11042        Erik 	 */
   2772  11042        Erik 	data_mp = async_mp->b_cont;
   2773  11042        Erik 	async_mp->b_cont = NULL;
   2774  11042        Erik 	if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
   2775  11042        Erik 		/* The ill or ip_stack_t disappeared on us */
   2776  11042        Erik 		ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL);
   2777  11042        Erik 		freemsg(data_mp);
   2778  11042        Erik 		goto done;
   2779  11042        Erik 	}
   2780  11042        Erik 	ns = iras.ira_ill->ill_ipst->ips_netstack;
   2781  11042        Erik 	ahstack = ns->netstack_ipsecah;
   2782  11042        Erik 	ipss = ns->netstack_ipsec;
   2783  11042        Erik 
   2784  11042        Erik 	if (status == CRYPTO_SUCCESS) {
   2785  11042        Erik 		data_mp = ah_auth_in_done(data_mp, &iras, ic);
   2786  11042        Erik 		if (data_mp == NULL)
   2787  11042        Erik 			goto done;
   2788  11042        Erik 
   2789  11042        Erik 		/* finish IPsec processing */
   2790  11042        Erik 		ip_input_post_ipsec(data_mp, &iras);
   2791  11042        Erik 
   2792  11042        Erik 	} else if (status == CRYPTO_INVALID_MAC) {
   2793  11042        Erik 		ah_log_bad_auth(data_mp, &iras, ic);
   2794  11042        Erik 	} else {
   2795  11042        Erik 		ah1dbg(ahstack,
   2796  11042        Erik 		    ("ah_kcf_callback_inbound: crypto failed with 0x%x\n",
   2797  11042        Erik 		    status));
   2798  11042        Erik 		AH_BUMP_STAT(ahstack, crypto_failures);
   2799  11042        Erik 		IP_AH_BUMP_STAT(ipss, in_discards);
   2800  11042        Erik 		ip_drop_packet(data_mp, B_TRUE, iras.ira_ill,
   2801  11042        Erik 		    DROPPER(ipss, ipds_ah_crypto_failed),
   2802  11042        Erik 		    &ahstack->ah_dropper);
   2803  11042        Erik 		BUMP_MIB(iras.ira_ill->ill_ip_mib, ipIfStatsInDiscards);
   2804  11042        Erik 	}
   2805  11042        Erik done:
   2806  11042        Erik 	ira_cleanup(&iras, B_TRUE);
   2807  11042        Erik 	(void) ipsec_free_crypto_data(mp);
   2808      0      stevel }
   2809      0      stevel 
   2810      0      stevel /*
   2811      0      stevel  * Invoked on kernel crypto failure during inbound and outbound processing.
   2812      0      stevel  */
   2813      0      stevel static void
   2814  11042        Erik ah_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc,
   2815  11042        Erik     ill_t *ill, ipsecah_stack_t *ahstack)
   2816   3448    dh155122 {
   2817   3448    dh155122 	ipsec_stack_t	*ipss = ahstack->ipsecah_netstack->netstack_ipsec;
   2818   3448    dh155122 
   2819   3448    dh155122 	ah1dbg(ahstack, ("crypto failed for %s AH with 0x%x\n",
   2820      0      stevel 	    is_inbound ? "inbound" : "outbound", kef_rc));
   2821  11042        Erik 	ip_drop_packet(data_mp, is_inbound, ill,
   2822   3448    dh155122 	    DROPPER(ipss, ipds_ah_crypto_failed),
   2823   3448    dh155122 	    &ahstack->ah_dropper);
   2824   3448    dh155122 	AH_BUMP_STAT(ahstack, crypto_failures);
   2825      0      stevel 	if (is_inbound)
   2826   3448    dh155122 		IP_AH_BUMP_STAT(ipss, in_discards);
   2827      0      stevel 	else
   2828   3448    dh155122 		AH_BUMP_STAT(ahstack, out_discards);
   2829      0      stevel }
   2830      0      stevel 
   2831      0      stevel /*
   2832      0      stevel  * Helper macros for the ah_submit_req_{inbound,outbound}() functions.
   2833      0      stevel  */
   2834      0      stevel 
   2835  11042        Erik /*
   2836  11042        Erik  * A statement-equivalent macro, _cr MUST point to a modifiable
   2837  11042        Erik  * crypto_call_req_t.
   2838  11042        Erik  */
   2839  11042        Erik #define	AH_INIT_CALLREQ(_cr, _mp, _callback)		\
   2840  11042        Erik 	(_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_ALWAYS_QUEUE;	\
   2841  11042        Erik 	(_cr)->cr_callback_arg = (_mp);				\
   2842  11042        Erik 	(_cr)->cr_callback_func = (_callback)
   2843      0      stevel 
   2844      0      stevel #define	AH_INIT_CRYPTO_DATA(data, msglen, mblk) {			\
   2845      0      stevel 	(data)->cd_format = CRYPTO_DATA_MBLK;				\
   2846      0      stevel 	(data)->cd_mp = mblk;						\
   2847      0      stevel 	(data)->cd_offset = 0;						\
   2848      0      stevel 	(data)->cd_length = msglen;					\
   2849      0      stevel }
   2850      0      stevel 
   2851      0      stevel #define	AH_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) {			\
   2852      0      stevel 	(mac)->cd_format = CRYPTO_DATA_RAW;				\
   2853      0      stevel 	(mac)->cd_offset = 0;						\
   2854      0      stevel 	(mac)->cd_length = icvlen;					\
   2855      0      stevel 	(mac)->cd_raw.iov_base = icvbuf;				\
   2856      0      stevel 	(mac)->cd_raw.iov_len = icvlen;					\
   2857      0      stevel }
   2858      0      stevel 
   2859      0      stevel /*
   2860      0      stevel  * Submit an inbound packet for processing by the crypto framework.
   2861      0      stevel  */
   2862  11042        Erik static mblk_t *
   2863  11042        Erik ah_submit_req_inbound(mblk_t *phdr_mp, ip_recv_attr_t *ira,
   2864  11042        Erik     size_t skip_len, uint32_t ah_offset, ipsa_t *assoc)
   2865      0      stevel {
   2866      0      stevel 	int kef_rc;
   2867  11042        Erik 	mblk_t *mp;
   2868  11042        Erik 	crypto_call_req_t call_req, *callrp;
   2869      0      stevel 	uint_t icv_len = assoc->ipsa_mac_len;
   2870      0      stevel 	crypto_ctx_template_t ctx_tmpl;
   2871  11042        Erik 	ipsecah_stack_t	*ahstack;
   2872  11042        Erik 	ipsec_crypto_t	*ic, icstack;
   2873  11042        Erik 	boolean_t force = (assoc->ipsa_flags & IPSA_F_ASYNC);
   2874  11042        Erik 
   2875  11042        Erik 	ahstack = ira->ira_ill->ill_ipst->ips_netstack->netstack_ipsecah;
   2876  11042        Erik 
   2877      0      stevel 	ASSERT(phdr_mp != NULL);
   2878  11042        Erik 	ASSERT(phdr_mp->b_datap->db_type == M_DATA);
   2879  11042        Erik 
   2880  11042        Erik 	if (force) {
   2881  11042        Erik 		/* We are doing asynch; allocate mblks to hold state */
   2882  11042        Erik 		if ((mp = ip_recv_attr_to_mblk(ira)) == NULL ||
   2883  11042        Erik 		    (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
   2884  11042        Erik 			BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
   2885  11042        Erik 			ip_drop_input("ipIfStatsInDiscards", phdr_mp,
   2886  11042        Erik 			    ira->ira_ill);
   2887  11042        Erik 			freemsg(phdr_mp);
   2888  11042        Erik 			return (NULL);
   2889  11042        Erik 		}
   2890  11042        Erik 
   2891  11042        Erik 		linkb(mp, phdr_mp);
   2892  11042        Erik 		callrp = &call_req;
   2893  11042        Erik 		AH_INIT_CALLREQ(callrp, mp, ah_kcf_callback_inbound);
   2894  11042        Erik 	} else {
   2895  11042        Erik 		/*
   2896  11042        Erik 		 * If we know we are going to do sync then ipsec_crypto_t
   2897  11042        Erik 		 * should be on the stack.
   2898  11042        Erik 		 */
   2899  11042        Erik 		ic = &icstack;
   2900  11042        Erik 		bzero(ic, sizeof (*ic));
   2901  11042        Erik 		callrp = NULL;
   2902  11042        Erik 	}
   2903   3448    dh155122 
   2904      0      stevel 	/* init arguments for the crypto framework */
   2905  11042        Erik 	AH_INIT_CRYPTO_DATA(&ic->ic_crypto_data, AH_MSGSIZE(phdr_mp),
   2906      0      stevel 	    phdr_mp);
   2907      0      stevel 
   2908  11042        Erik 	AH_INIT_CRYPTO_MAC(&ic->ic_crypto_mac, icv_len,
   2909      0      stevel 	    (char *)phdr_mp->b_cont->b_rptr - skip_len + ah_offset +
   2910      0      stevel 	    sizeof (ah_t));
   2911      0      stevel 
   2912  11042        Erik 	ic->ic_skip_len = skip_len;
   2913      0      stevel 
   2914      0      stevel 	IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, ctx_tmpl);
   2915      0      stevel 
   2916      0      stevel 	/* call KEF to do the MAC operation */
   2917      0      stevel 	kef_rc = crypto_mac_verify(&assoc->ipsa_amech,
   2918  11042        Erik 	    &ic->ic_crypto_data, &assoc->ipsa_kcfauthkey, ctx_tmpl,
   2919  11042        Erik 	    &ic->ic_crypto_mac, callrp);
   2920      0      stevel 
   2921      0      stevel 	switch (kef_rc) {
   2922      0      stevel 	case CRYPTO_SUCCESS:
   2923   3448    dh155122 		AH_BUMP_STAT(ahstack, crypto_sync);
   2924  11042        Erik 		phdr_mp = ah_auth_in_done(phdr_mp, ira, ic);
   2925  11042        Erik 		if (force) {
   2926  11042        Erik 			/* Free mp after we are done with ic */
   2927  11042        Erik 			mp = ipsec_free_crypto_data(mp);
   2928  11042        Erik 			(void) ip_recv_attr_free_mblk(mp);
   2929  11042        Erik 		}
   2930  11042        Erik 		return (phdr_mp);
   2931      0      stevel 	case CRYPTO_QUEUED:
   2932  11042        Erik 		/* ah_kcf_callback_inbound() will be invoked on completion */
   2933   3448    dh155122 		AH_BUMP_STAT(ahstack, crypto_async);
   2934  11042        Erik 		return (NULL);
   2935      0      stevel 	case CRYPTO_INVALID_MAC:
   2936  11042        Erik 		/* Free mp after we are done with ic */
   2937   3448    dh155122 		AH_BUMP_STAT(ahstack, crypto_sync);
   2938  11042        Erik 		BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
   2939  11042        Erik 		ah_log_bad_auth(phdr_mp, ira, ic);
   2940  11042        Erik 		/* phdr_mp was passed to ip_drop_packet */
   2941  11042        Erik 		if (force) {
   2942  11042        Erik 			mp = ipsec_free_crypto_data(mp);
   2943  11042        Erik 			(void) ip_recv_attr_free_mblk(mp);
   2944  11042        Erik 		}
   2945  11042        Erik 		return (NULL);
   2946  11042        Erik 	}
   2947  11042        Erik 
   2948  11042        Erik 	if (force) {
   2949  11042        Erik 		mp = ipsec_free_crypto_data(mp);
   2950  11042        Erik 		phdr_mp = ip_recv_attr_free_mblk(mp);
   2951  11042        Erik 	}
   2952  11042        Erik 	BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
   2953  11042        Erik 	ah_crypto_failed(phdr_mp, B_TRUE, kef_rc, ira->ira_ill, ahstack);
   2954  11042        Erik 	/* phdr_mp was passed to ip_drop_packet */
   2955  11042        Erik 	return (NULL);
   2956      0      stevel }
   2957      0      stevel 
   2958      0      stevel /*
   2959      0      stevel  * Submit an outbound packet for processing by the crypto framework.
   2960      0      stevel  */
   2961  11042        Erik static mblk_t *
   2962  11042        Erik ah_submit_req_outbound(mblk_t *phdr_mp, ip_xmit_attr_t *ixa,
   2963  11042        Erik     size_t skip_len, ipsa_t *assoc)
   2964