xref: /titanic_44/usr/src/uts/common/inet/ip/ipsecesp.c (revision 1a5e258f5471356ca102c7176637cdce45bac147)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57845d282Sdanmcd  * Common Development and Distribution License (the "License").
67845d282Sdanmcd  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22930af642SDan McDonald  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/stream.h>
287c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
297c478bd9Sstevel@tonic-gate #include <sys/errno.h>
307c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
317c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
327c478bd9Sstevel@tonic-gate #include <sys/socket.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
36f4b3ec61Sdh155122 #include <sys/zone.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
397c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
407c478bd9Sstevel@tonic-gate #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
427c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
437c478bd9Sstevel@tonic-gate #include <sys/random.h>
447c478bd9Sstevel@tonic-gate #include <netinet/in.h>
457c478bd9Sstevel@tonic-gate #include <net/if.h>
467c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
477c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
48628b0c67SMark Fenwick #include <net/pfpolicy.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <inet/common.h>
517c478bd9Sstevel@tonic-gate #include <inet/mi.h>
527c478bd9Sstevel@tonic-gate #include <inet/nd.h>
537c478bd9Sstevel@tonic-gate #include <inet/ip.h>
54437220cdSdanmcd #include <inet/ip_impl.h>
557c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
56bd670b35SErik Nordmark #include <inet/ip_if.h>
57bd670b35SErik Nordmark #include <inet/ip_ndp.h>
587c478bd9Sstevel@tonic-gate #include <inet/sadb.h>
597c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h>
607c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
617c478bd9Sstevel@tonic-gate #include <inet/ipsecesp.h>
627c478bd9Sstevel@tonic-gate #include <inet/ipdrop.h>
637c478bd9Sstevel@tonic-gate #include <inet/tcp.h>
647c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
657c478bd9Sstevel@tonic-gate #include <sys/policy.h>
667c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
675d3b8cb7SBill Sommerfeld #include <sys/strsubr.h>
687c478bd9Sstevel@tonic-gate #include <inet/udp_impl.h>
697c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
70f4b3ec61Sdh155122 #include <sys/note.h>
717c478bd9Sstevel@tonic-gate 
725d3b8cb7SBill Sommerfeld #include <sys/tsol/tnet.h>
735d3b8cb7SBill Sommerfeld 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Table of ND variables supported by ipsecesp. These are loaded into
767c478bd9Sstevel@tonic-gate  * ipsecesp_g_nd in ipsecesp_init_nd.
777c478bd9Sstevel@tonic-gate  * All of these are alterable, within the min/max values given, at run time.
787c478bd9Sstevel@tonic-gate  */
79f4b3ec61Sdh155122 static	ipsecespparam_t	lcl_param_arr[] = {
807c478bd9Sstevel@tonic-gate 	/* min	max			value	name */
817c478bd9Sstevel@tonic-gate 	{ 0,	3,			0,	"ipsecesp_debug"},
827c478bd9Sstevel@tonic-gate 	{ 125,	32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"},
837c478bd9Sstevel@tonic-gate 	{ 1,	10,			1,	"ipsecesp_reap_delay"},
847c478bd9Sstevel@tonic-gate 	{ 1,	SADB_MAX_REPLAY,	64,	"ipsecesp_replay_size"},
857c478bd9Sstevel@tonic-gate 	{ 1,	300,			15,	"ipsecesp_acquire_timeout"},
867c478bd9Sstevel@tonic-gate 	{ 1,	1800,			90,	"ipsecesp_larval_timeout"},
877c478bd9Sstevel@tonic-gate 	/* Default lifetime values for ACQUIRE messages. */
887c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_soft_bytes"},
897c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_hard_bytes"},
907c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	24000,	"ipsecesp_default_soft_addtime"},
917c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	28800,	"ipsecesp_default_hard_addtime"},
927c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_soft_usetime"},
937c478bd9Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_hard_usetime"},
947c478bd9Sstevel@tonic-gate 	{ 0,	1,		0,	"ipsecesp_log_unknown_spi"},
957c478bd9Sstevel@tonic-gate 	{ 0,	2,		1,	"ipsecesp_padding_check"},
96437220cdSdanmcd 	{ 0,	600,		20,	"ipsecesp_nat_keepalive_interval"},
977c478bd9Sstevel@tonic-gate };
98f4b3ec61Sdh155122 #define	ipsecesp_debug	ipsecesp_params[0].ipsecesp_param_value
99f4b3ec61Sdh155122 #define	ipsecesp_age_interval ipsecesp_params[1].ipsecesp_param_value
100f4b3ec61Sdh155122 #define	ipsecesp_age_int_max	ipsecesp_params[1].ipsecesp_param_max
101f4b3ec61Sdh155122 #define	ipsecesp_reap_delay	ipsecesp_params[2].ipsecesp_param_value
102f4b3ec61Sdh155122 #define	ipsecesp_replay_size	ipsecesp_params[3].ipsecesp_param_value
103f4b3ec61Sdh155122 #define	ipsecesp_acquire_timeout	\
104f4b3ec61Sdh155122 	ipsecesp_params[4].ipsecesp_param_value
105f4b3ec61Sdh155122 #define	ipsecesp_larval_timeout	\
106f4b3ec61Sdh155122 	ipsecesp_params[5].ipsecesp_param_value
1077c478bd9Sstevel@tonic-gate #define	ipsecesp_default_soft_bytes	\
108f4b3ec61Sdh155122 	ipsecesp_params[6].ipsecesp_param_value
1097c478bd9Sstevel@tonic-gate #define	ipsecesp_default_hard_bytes	\
110f4b3ec61Sdh155122 	ipsecesp_params[7].ipsecesp_param_value
1117c478bd9Sstevel@tonic-gate #define	ipsecesp_default_soft_addtime	\
112f4b3ec61Sdh155122 	ipsecesp_params[8].ipsecesp_param_value
1137c478bd9Sstevel@tonic-gate #define	ipsecesp_default_hard_addtime	\
114f4b3ec61Sdh155122 	ipsecesp_params[9].ipsecesp_param_value
1157c478bd9Sstevel@tonic-gate #define	ipsecesp_default_soft_usetime	\
116f4b3ec61Sdh155122 	ipsecesp_params[10].ipsecesp_param_value
1177c478bd9Sstevel@tonic-gate #define	ipsecesp_default_hard_usetime	\
118f4b3ec61Sdh155122 	ipsecesp_params[11].ipsecesp_param_value
1197c478bd9Sstevel@tonic-gate #define	ipsecesp_log_unknown_spi	\
120f4b3ec61Sdh155122 	ipsecesp_params[12].ipsecesp_param_value
1217c478bd9Sstevel@tonic-gate #define	ipsecesp_padding_check	\
122f4b3ec61Sdh155122 	ipsecesp_params[13].ipsecesp_param_value
123437220cdSdanmcd /* For ipsecesp_nat_keepalive_interval, see ipsecesp.h. */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate #define	esp0dbg(a)	printf a
1267c478bd9Sstevel@tonic-gate /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
127f4b3ec61Sdh155122 #define	esp1dbg(espstack, a)	if (espstack->ipsecesp_debug != 0) printf a
128f4b3ec61Sdh155122 #define	esp2dbg(espstack, a)	if (espstack->ipsecesp_debug > 1) printf a
129f4b3ec61Sdh155122 #define	esp3dbg(espstack, a)	if (espstack->ipsecesp_debug > 2) printf a
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *);
1327c478bd9Sstevel@tonic-gate static int ipsecesp_close(queue_t *);
1337c478bd9Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *);
134f4b3ec61Sdh155122 static void	*ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns);
135f4b3ec61Sdh155122 static void	ipsecesp_stack_fini(netstackid_t stackid, void *arg);
136f4b3ec61Sdh155122 static void esp_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
1377c478bd9Sstevel@tonic-gate 
138437220cdSdanmcd static void esp_prepare_udp(netstack_t *, mblk_t *, ipha_t *);
139bd670b35SErik Nordmark static void esp_outbound_finish(mblk_t *, ip_xmit_attr_t *);
140bd670b35SErik Nordmark static void esp_inbound_restart(mblk_t *, ip_recv_attr_t *);
1417c478bd9Sstevel@tonic-gate 
142f4b3ec61Sdh155122 static boolean_t esp_register_out(uint32_t, uint32_t, uint_t,
143bd670b35SErik Nordmark     ipsecesp_stack_t *, cred_t *);
1447c478bd9Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
145f4b3ec61Sdh155122     kstat_named_t **, ipsecesp_stack_t *);
146bd670b35SErik Nordmark static mblk_t *esp_submit_req_inbound(mblk_t *, ip_recv_attr_t *,
147bd670b35SErik Nordmark     ipsa_t *, uint_t);
148bd670b35SErik Nordmark static mblk_t *esp_submit_req_outbound(mblk_t *, ip_xmit_attr_t *,
149bd670b35SErik Nordmark     ipsa_t *, uchar_t *, uint_t);
1509c2c14abSThejaswini Singarajipura 
151f4b3ec61Sdh155122 /* Setable in /etc/system */
152f4b3ec61Sdh155122 uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE;
153f4b3ec61Sdh155122 
1547c478bd9Sstevel@tonic-gate static struct module_info info = {
1557c478bd9Sstevel@tonic-gate 	5137, "ipsecesp", 0, INFPSZ, 65536, 1024
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static struct qinit rinit = {
159bd670b35SErik Nordmark 	(pfi_t)putnext, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
1607c478bd9Sstevel@tonic-gate 	NULL
1617c478bd9Sstevel@tonic-gate };
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static struct qinit winit = {
1647c478bd9Sstevel@tonic-gate 	(pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
1657c478bd9Sstevel@tonic-gate 	NULL
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate struct streamtab ipsecespinfo = {
1697c478bd9Sstevel@tonic-gate 	&rinit, &winit, NULL, NULL
1707c478bd9Sstevel@tonic-gate };
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static taskq_t *esp_taskq;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now.
1767c478bd9Sstevel@tonic-gate  *
1777c478bd9Sstevel@tonic-gate  * Question:	Do I need this, given that all instance's esps->esps_wq point
1787c478bd9Sstevel@tonic-gate  *		to IP?
1797c478bd9Sstevel@tonic-gate  *
1807c478bd9Sstevel@tonic-gate  * Answer:	Yes, because I need to know which queue is BOUND to
1817c478bd9Sstevel@tonic-gate  *		IPPROTO_ESP
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * Stats.  This may eventually become a full-blown SNMP MIB once that spec
1867c478bd9Sstevel@tonic-gate  * stabilizes.
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate 
189f4b3ec61Sdh155122 typedef struct esp_kstats_s {
1907c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_num_aalgs;
1917c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_good_auth;
1927c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_auth;
1937c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_padding;
1947c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_replay_failures;
1957c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_replay_early_failures;
1967c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_keysock_in;
1977c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_out_requests;
1987c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_acquire_requests;
1997c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_bytes_expired;
2007c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_out_discards;
2017c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_sync;
2027c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_async;
2037c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_failures;
2047c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_num_ealgs;
2057c478bd9Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_decrypt;
2064a179720Sdanmcd 	kstat_named_t esp_stat_sa_port_renumbers;
2077c478bd9Sstevel@tonic-gate } esp_kstats_t;
2087c478bd9Sstevel@tonic-gate 
209f4b3ec61Sdh155122 /*
210f4b3ec61Sdh155122  * espstack->esp_kstats is equal to espstack->esp_ksp->ks_data if
211f4b3ec61Sdh155122  * kstat_create_netstack for espstack->esp_ksp succeeds, but when it
212f4b3ec61Sdh155122  * fails, it will be NULL. Note this is done for all stack instances,
213f4b3ec61Sdh155122  * so it *could* fail. hence a non-NULL checking is done for
214f4b3ec61Sdh155122  * ESP_BUMP_STAT and ESP_DEBUMP_STAT
215f4b3ec61Sdh155122  */
216f4b3ec61Sdh155122 #define	ESP_BUMP_STAT(espstack, x)					\
217f4b3ec61Sdh155122 do {									\
218f4b3ec61Sdh155122 	if (espstack->esp_kstats != NULL)				\
219f4b3ec61Sdh155122 		(espstack->esp_kstats->esp_stat_ ## x).value.ui64++;	\
220f4b3ec61Sdh155122 _NOTE(CONSTCOND)							\
221f4b3ec61Sdh155122 } while (0)
2227c478bd9Sstevel@tonic-gate 
223f4b3ec61Sdh155122 #define	ESP_DEBUMP_STAT(espstack, x)					\
224f4b3ec61Sdh155122 do {									\
225f4b3ec61Sdh155122 	if (espstack->esp_kstats != NULL)				\
226f4b3ec61Sdh155122 		(espstack->esp_kstats->esp_stat_ ## x).value.ui64--;	\
227f4b3ec61Sdh155122 _NOTE(CONSTCOND)							\
228f4b3ec61Sdh155122 } while (0)
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static int	esp_kstat_update(kstat_t *, int);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate static boolean_t
esp_kstat_init(ipsecesp_stack_t * espstack,netstackid_t stackid)233f4b3ec61Sdh155122 esp_kstat_init(ipsecesp_stack_t *espstack, netstackid_t stackid)
2347c478bd9Sstevel@tonic-gate {
235f4b3ec61Sdh155122 	espstack->esp_ksp = kstat_create_netstack("ipsecesp", 0, "esp_stat",
236f4b3ec61Sdh155122 	    "net", KSTAT_TYPE_NAMED,
237f4b3ec61Sdh155122 	    sizeof (esp_kstats_t) / sizeof (kstat_named_t),
238f4b3ec61Sdh155122 	    KSTAT_FLAG_PERSISTENT, stackid);
2397c478bd9Sstevel@tonic-gate 
240f4b3ec61Sdh155122 	if (espstack->esp_ksp == NULL || espstack->esp_ksp->ks_data == NULL)
2417c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2427c478bd9Sstevel@tonic-gate 
243f4b3ec61Sdh155122 	espstack->esp_kstats = espstack->esp_ksp->ks_data;
2447c478bd9Sstevel@tonic-gate 
245f4b3ec61Sdh155122 	espstack->esp_ksp->ks_update = esp_kstat_update;
246f4b3ec61Sdh155122 	espstack->esp_ksp->ks_private = (void *)(uintptr_t)stackid;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate #define	K64 KSTAT_DATA_UINT64
249f4b3ec61Sdh155122 #define	KI(x) kstat_named_init(&(espstack->esp_kstats->esp_stat_##x), #x, K64)
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	KI(num_aalgs);
2527c478bd9Sstevel@tonic-gate 	KI(num_ealgs);
2537c478bd9Sstevel@tonic-gate 	KI(good_auth);
2547c478bd9Sstevel@tonic-gate 	KI(bad_auth);
2557c478bd9Sstevel@tonic-gate 	KI(bad_padding);
2567c478bd9Sstevel@tonic-gate 	KI(replay_failures);
2577c478bd9Sstevel@tonic-gate 	KI(replay_early_failures);
2587c478bd9Sstevel@tonic-gate 	KI(keysock_in);
2597c478bd9Sstevel@tonic-gate 	KI(out_requests);
2607c478bd9Sstevel@tonic-gate 	KI(acquire_requests);
2617c478bd9Sstevel@tonic-gate 	KI(bytes_expired);
2627c478bd9Sstevel@tonic-gate 	KI(out_discards);
2637c478bd9Sstevel@tonic-gate 	KI(crypto_sync);
2647c478bd9Sstevel@tonic-gate 	KI(crypto_async);
2657c478bd9Sstevel@tonic-gate 	KI(crypto_failures);
2667c478bd9Sstevel@tonic-gate 	KI(bad_decrypt);
2674a179720Sdanmcd 	KI(sa_port_renumbers);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate #undef KI
2707c478bd9Sstevel@tonic-gate #undef K64
2717c478bd9Sstevel@tonic-gate 
272f4b3ec61Sdh155122 	kstat_install(espstack->esp_ksp);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	return (B_TRUE);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate static int
esp_kstat_update(kstat_t * kp,int rw)2787c478bd9Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	esp_kstats_t *ekp;
281f4b3ec61Sdh155122 	netstackid_t	stackid = (zoneid_t)(uintptr_t)kp->ks_private;
282f4b3ec61Sdh155122 	netstack_t	*ns;
283f4b3ec61Sdh155122 	ipsec_stack_t	*ipss;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if ((kp == NULL) || (kp->ks_data == NULL))
2867c478bd9Sstevel@tonic-gate 		return (EIO);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
2897c478bd9Sstevel@tonic-gate 		return (EACCES);
2907c478bd9Sstevel@tonic-gate 
291f4b3ec61Sdh155122 	ns = netstack_find_by_stackid(stackid);
292f4b3ec61Sdh155122 	if (ns == NULL)
293f4b3ec61Sdh155122 		return (-1);
294f4b3ec61Sdh155122 	ipss = ns->netstack_ipsec;
295f4b3ec61Sdh155122 	if (ipss == NULL) {
296f4b3ec61Sdh155122 		netstack_rele(ns);
297f4b3ec61Sdh155122 		return (-1);
298f4b3ec61Sdh155122 	}
2997c478bd9Sstevel@tonic-gate 	ekp = (esp_kstats_t *)kp->ks_data;
3007c478bd9Sstevel@tonic-gate 
301f4b3ec61Sdh155122 	mutex_enter(&ipss->ipsec_alg_lock);
302f4b3ec61Sdh155122 	ekp->esp_stat_num_aalgs.value.ui64 =
303f4b3ec61Sdh155122 	    ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
304f4b3ec61Sdh155122 	ekp->esp_stat_num_ealgs.value.ui64 =
305f4b3ec61Sdh155122 	    ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
306f4b3ec61Sdh155122 	mutex_exit(&ipss->ipsec_alg_lock);
3077c478bd9Sstevel@tonic-gate 
308f4b3ec61Sdh155122 	netstack_rele(ns);
3097c478bd9Sstevel@tonic-gate 	return (0);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate #ifdef DEBUG
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Debug routine, useful to see pre-encryption data.
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate static char *
dump_msg(mblk_t * mp)3177c478bd9Sstevel@tonic-gate dump_msg(mblk_t *mp)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	char tmp_str[3], tmp_line[256];
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	while (mp != NULL) {
3227c478bd9Sstevel@tonic-gate 		unsigned char *ptr;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		printf("mblk address 0x%p, length %ld, db_ref %d "
3257c478bd9Sstevel@tonic-gate 		    "type %d, base 0x%p, lim 0x%p\n",
3267c478bd9Sstevel@tonic-gate 		    (void *) mp, (long)(mp->b_wptr - mp->b_rptr),
3277c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_ref, mp->b_datap->db_type,
3287c478bd9Sstevel@tonic-gate 		    (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim);
3297c478bd9Sstevel@tonic-gate 		ptr = mp->b_rptr;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		tmp_line[0] = '\0';
3327c478bd9Sstevel@tonic-gate 		while (ptr < mp->b_wptr) {
3337c478bd9Sstevel@tonic-gate 			uint_t diff;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 			diff = (ptr - mp->b_rptr);
3367c478bd9Sstevel@tonic-gate 			if (!(diff & 0x1f)) {
3377c478bd9Sstevel@tonic-gate 				if (strlen(tmp_line) > 0) {
3387c478bd9Sstevel@tonic-gate 					printf("bytes: %s\n", tmp_line);
3397c478bd9Sstevel@tonic-gate 					tmp_line[0] = '\0';
3407c478bd9Sstevel@tonic-gate 				}
3417c478bd9Sstevel@tonic-gate 			}
3427c478bd9Sstevel@tonic-gate 			if (!(diff & 0x3))
3437c478bd9Sstevel@tonic-gate 				(void) strcat(tmp_line, " ");
3447c478bd9Sstevel@tonic-gate 			(void) sprintf(tmp_str, "%02x", *ptr);
3457c478bd9Sstevel@tonic-gate 			(void) strcat(tmp_line, tmp_str);
3467c478bd9Sstevel@tonic-gate 			ptr++;
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 		if (strlen(tmp_line) > 0)
3497c478bd9Sstevel@tonic-gate 			printf("bytes: %s\n", tmp_line);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	return ("\n");
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate #else /* DEBUG */
3587c478bd9Sstevel@tonic-gate static char *
dump_msg(mblk_t * mp)3597c478bd9Sstevel@tonic-gate dump_msg(mblk_t *mp)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	printf("Find value of mp %p.\n", mp);
3627c478bd9Sstevel@tonic-gate 	return ("\n");
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * Don't have to lock age_interval, as only one thread will access it at
3687c478bd9Sstevel@tonic-gate  * a time, because I control the one function that does with timeout().
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate static void
esp_ager(void * arg)371f4b3ec61Sdh155122 esp_ager(void *arg)
3727c478bd9Sstevel@tonic-gate {
373f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg;
374f4b3ec61Sdh155122 	netstack_t	*ns = espstack->ipsecesp_netstack;
3757c478bd9Sstevel@tonic-gate 	hrtime_t begin = gethrtime();
3767c478bd9Sstevel@tonic-gate 
377f4b3ec61Sdh155122 	sadb_ager(&espstack->esp_sadb.s_v4, espstack->esp_pfkey_q,
378bd670b35SErik Nordmark 	    espstack->ipsecesp_reap_delay, ns);
379f4b3ec61Sdh155122 	sadb_ager(&espstack->esp_sadb.s_v6, espstack->esp_pfkey_q,
380bd670b35SErik Nordmark 	    espstack->ipsecesp_reap_delay, ns);
3817c478bd9Sstevel@tonic-gate 
382f4b3ec61Sdh155122 	espstack->esp_event = sadb_retimeout(begin, espstack->esp_pfkey_q,
383f4b3ec61Sdh155122 	    esp_ager, espstack,
384f4b3ec61Sdh155122 	    &espstack->ipsecesp_age_interval, espstack->ipsecesp_age_int_max,
385f4b3ec61Sdh155122 	    info.mi_idnum);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Get an ESP NDD parameter.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate /* ARGSUSED */
3927c478bd9Sstevel@tonic-gate static int
ipsecesp_param_get(q,mp,cp,cr)3937c478bd9Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr)
3947c478bd9Sstevel@tonic-gate 	queue_t	*q;
3957c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
3967c478bd9Sstevel@tonic-gate 	caddr_t	cp;
3977c478bd9Sstevel@tonic-gate 	cred_t *cr;
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	ipsecespparam_t	*ipsecesppa = (ipsecespparam_t *)cp;
4007c478bd9Sstevel@tonic-gate 	uint_t value;
401f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = (ipsecesp_stack_t *)q->q_ptr;
4027c478bd9Sstevel@tonic-gate 
403f4b3ec61Sdh155122 	mutex_enter(&espstack->ipsecesp_param_lock);
4047c478bd9Sstevel@tonic-gate 	value = ipsecesppa->ipsecesp_param_value;
405f4b3ec61Sdh155122 	mutex_exit(&espstack->ipsecesp_param_lock);
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%u", value);
4087c478bd9Sstevel@tonic-gate 	return (0);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate  * This routine sets an NDD variable in a ipsecespparam_t structure.
4137c478bd9Sstevel@tonic-gate  */
4147c478bd9Sstevel@tonic-gate /* ARGSUSED */
4157c478bd9Sstevel@tonic-gate static int
ipsecesp_param_set(q,mp,value,cp,cr)4167c478bd9Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr)
4177c478bd9Sstevel@tonic-gate 	queue_t	*q;
4187c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
4197c478bd9Sstevel@tonic-gate 	char	*value;
4207c478bd9Sstevel@tonic-gate 	caddr_t	cp;
4217c478bd9Sstevel@tonic-gate 	cred_t *cr;
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	ulong_t	new_value;
4247c478bd9Sstevel@tonic-gate 	ipsecespparam_t	*ipsecesppa = (ipsecespparam_t *)cp;
425f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = (ipsecesp_stack_t *)q->q_ptr;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	/*
4287c478bd9Sstevel@tonic-gate 	 * Fail the request if the new value does not lie within the
4297c478bd9Sstevel@tonic-gate 	 * required bounds.
4307c478bd9Sstevel@tonic-gate 	 */
4317c478bd9Sstevel@tonic-gate 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0 ||
4327c478bd9Sstevel@tonic-gate 	    new_value < ipsecesppa->ipsecesp_param_min ||
4337c478bd9Sstevel@tonic-gate 	    new_value > ipsecesppa->ipsecesp_param_max) {
4347c478bd9Sstevel@tonic-gate 		return (EINVAL);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/* Set the new value */
438f4b3ec61Sdh155122 	mutex_enter(&espstack->ipsecesp_param_lock);
4397c478bd9Sstevel@tonic-gate 	ipsecesppa->ipsecesp_param_value = new_value;
440f4b3ec61Sdh155122 	mutex_exit(&espstack->ipsecesp_param_lock);
4417c478bd9Sstevel@tonic-gate 	return (0);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate /*
4457c478bd9Sstevel@tonic-gate  * Using lifetime NDD variables, fill in an extended combination's
4467c478bd9Sstevel@tonic-gate  * lifetime information.
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate void
ipsecesp_fill_defs(sadb_x_ecomb_t * ecomb,netstack_t * ns)449f4b3ec61Sdh155122 ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb, netstack_t *ns)
4507c478bd9Sstevel@tonic-gate {
451f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = ns->netstack_ipsecesp;
452f4b3ec61Sdh155122 
453f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_soft_bytes = espstack->ipsecesp_default_soft_bytes;
454f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_hard_bytes = espstack->ipsecesp_default_hard_bytes;
455f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_soft_addtime =
456f4b3ec61Sdh155122 	    espstack->ipsecesp_default_soft_addtime;
457f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_hard_addtime =
458f4b3ec61Sdh155122 	    espstack->ipsecesp_default_hard_addtime;
459f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_soft_usetime =
460f4b3ec61Sdh155122 	    espstack->ipsecesp_default_soft_usetime;
461f4b3ec61Sdh155122 	ecomb->sadb_x_ecomb_hard_usetime =
462f4b3ec61Sdh155122 	    espstack->ipsecesp_default_hard_usetime;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate  * Initialize things for ESP at module load time.
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate boolean_t
ipsecesp_ddi_init(void)4697c478bd9Sstevel@tonic-gate ipsecesp_ddi_init(void)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	esp_taskq = taskq_create("esp_taskq", 1, minclsyspri,
4727c478bd9Sstevel@tonic-gate 	    IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0);
4737c478bd9Sstevel@tonic-gate 
474f4b3ec61Sdh155122 	/*
475f4b3ec61Sdh155122 	 * We want to be informed each time a stack is created or
476f4b3ec61Sdh155122 	 * destroyed in the kernel, so we can maintain the
477f4b3ec61Sdh155122 	 * set of ipsecesp_stack_t's.
478f4b3ec61Sdh155122 	 */
479f4b3ec61Sdh155122 	netstack_register(NS_IPSECESP, ipsecesp_stack_init, NULL,
480f4b3ec61Sdh155122 	    ipsecesp_stack_fini);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	return (B_TRUE);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
486f4b3ec61Sdh155122  * Walk through the param array specified registering each element with the
487f4b3ec61Sdh155122  * named dispatch handler.
488f4b3ec61Sdh155122  */
489f4b3ec61Sdh155122 static boolean_t
ipsecesp_param_register(IDP * ndp,ipsecespparam_t * espp,int cnt)490f4b3ec61Sdh155122 ipsecesp_param_register(IDP *ndp, ipsecespparam_t *espp, int cnt)
491f4b3ec61Sdh155122 {
492f4b3ec61Sdh155122 	for (; cnt-- > 0; espp++) {
493f4b3ec61Sdh155122 		if (espp->ipsecesp_param_name != NULL &&
494f4b3ec61Sdh155122 		    espp->ipsecesp_param_name[0]) {
495f4b3ec61Sdh155122 			if (!nd_load(ndp,
496f4b3ec61Sdh155122 			    espp->ipsecesp_param_name,
497f4b3ec61Sdh155122 			    ipsecesp_param_get, ipsecesp_param_set,
498f4b3ec61Sdh155122 			    (caddr_t)espp)) {
499f4b3ec61Sdh155122 				nd_free(ndp);
500f4b3ec61Sdh155122 				return (B_FALSE);
501f4b3ec61Sdh155122 			}
502f4b3ec61Sdh155122 		}
503f4b3ec61Sdh155122 	}
504f4b3ec61Sdh155122 	return (B_TRUE);
505f4b3ec61Sdh155122 }
506f4b3ec61Sdh155122 /*
507f4b3ec61Sdh155122  * Initialize things for ESP for each stack instance
508f4b3ec61Sdh155122  */
509f4b3ec61Sdh155122 static void *
ipsecesp_stack_init(netstackid_t stackid,netstack_t * ns)510f4b3ec61Sdh155122 ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns)
511f4b3ec61Sdh155122 {
512f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack;
513f4b3ec61Sdh155122 	ipsecespparam_t		*espp;
514f4b3ec61Sdh155122 
515f4b3ec61Sdh155122 	espstack = (ipsecesp_stack_t *)kmem_zalloc(sizeof (*espstack),
516f4b3ec61Sdh155122 	    KM_SLEEP);
517f4b3ec61Sdh155122 	espstack->ipsecesp_netstack = ns;
518f4b3ec61Sdh155122 
519f4b3ec61Sdh155122 	espp = (ipsecespparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
520f4b3ec61Sdh155122 	espstack->ipsecesp_params = espp;
521f4b3ec61Sdh155122 	bcopy(lcl_param_arr, espp, sizeof (lcl_param_arr));
522f4b3ec61Sdh155122 
523f4b3ec61Sdh155122 	(void) ipsecesp_param_register(&espstack->ipsecesp_g_nd, espp,
524f4b3ec61Sdh155122 	    A_CNT(lcl_param_arr));
525f4b3ec61Sdh155122 
526f4b3ec61Sdh155122 	(void) esp_kstat_init(espstack, stackid);
527f4b3ec61Sdh155122 
528f4b3ec61Sdh155122 	espstack->esp_sadb.s_acquire_timeout =
529f4b3ec61Sdh155122 	    &espstack->ipsecesp_acquire_timeout;
530f4b3ec61Sdh155122 	espstack->esp_sadb.s_acqfn = esp_send_acquire;
531f4b3ec61Sdh155122 	sadbp_init("ESP", &espstack->esp_sadb, SADB_SATYPE_ESP, esp_hash_size,
532f4b3ec61Sdh155122 	    espstack->ipsecesp_netstack);
533f4b3ec61Sdh155122 
534f4b3ec61Sdh155122 	mutex_init(&espstack->ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0);
535f4b3ec61Sdh155122 
536f4b3ec61Sdh155122 	ip_drop_register(&espstack->esp_dropper, "IPsec ESP");
537f4b3ec61Sdh155122 	return (espstack);
538f4b3ec61Sdh155122 }
539f4b3ec61Sdh155122 
540f4b3ec61Sdh155122 /*
5417c478bd9Sstevel@tonic-gate  * Destroy things for ESP at module unload time.
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate void
ipsecesp_ddi_destroy(void)5447c478bd9Sstevel@tonic-gate ipsecesp_ddi_destroy(void)
5457c478bd9Sstevel@tonic-gate {
546f4b3ec61Sdh155122 	netstack_unregister(NS_IPSECESP);
5477c478bd9Sstevel@tonic-gate 	taskq_destroy(esp_taskq);
548f4b3ec61Sdh155122 }
549f4b3ec61Sdh155122 
550f4b3ec61Sdh155122 /*
551f4b3ec61Sdh155122  * Destroy things for ESP for one stack instance
552f4b3ec61Sdh155122  */
553f4b3ec61Sdh155122 static void
ipsecesp_stack_fini(netstackid_t stackid,void * arg)554f4b3ec61Sdh155122 ipsecesp_stack_fini(netstackid_t stackid, void *arg)
555f4b3ec61Sdh155122 {
556f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg;
557f4b3ec61Sdh155122 
558f4b3ec61Sdh155122 	if (espstack->esp_pfkey_q != NULL) {
559f4b3ec61Sdh155122 		(void) quntimeout(espstack->esp_pfkey_q, espstack->esp_event);
560f4b3ec61Sdh155122 	}
561f4b3ec61Sdh155122 	espstack->esp_sadb.s_acqfn = NULL;
562f4b3ec61Sdh155122 	espstack->esp_sadb.s_acquire_timeout = NULL;
563f4b3ec61Sdh155122 	sadbp_destroy(&espstack->esp_sadb, espstack->ipsecesp_netstack);
564f4b3ec61Sdh155122 	ip_drop_unregister(&espstack->esp_dropper);
565f4b3ec61Sdh155122 	mutex_destroy(&espstack->ipsecesp_param_lock);
566f4b3ec61Sdh155122 	nd_free(&espstack->ipsecesp_g_nd);
567f4b3ec61Sdh155122 
568f4b3ec61Sdh155122 	kmem_free(espstack->ipsecesp_params, sizeof (lcl_param_arr));
569f4b3ec61Sdh155122 	espstack->ipsecesp_params = NULL;
570f4b3ec61Sdh155122 	kstat_delete_netstack(espstack->esp_ksp, stackid);
571f4b3ec61Sdh155122 	espstack->esp_ksp = NULL;
572f4b3ec61Sdh155122 	espstack->esp_kstats = NULL;
573f4b3ec61Sdh155122 	kmem_free(espstack, sizeof (*espstack));
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
577bd670b35SErik Nordmark  * ESP module open routine, which is here for keysock plumbing.
578bd670b35SErik Nordmark  * Keysock is pushed over {AH,ESP} which is an artifact from the Bad Old
579bd670b35SErik Nordmark  * Days of export control, and fears that ESP would not be allowed
580bd670b35SErik Nordmark  * to be shipped at all by default.  Eventually, keysock should
581bd670b35SErik Nordmark  * either access AH and ESP via modstubs or krtld dependencies, or
582bd670b35SErik Nordmark  * perhaps be folded in with AH and ESP into a single IPsec/netsec
583bd670b35SErik Nordmark  * module ("netsec" if PF_KEY provides more than AH/ESP keying tables).
5847c478bd9Sstevel@tonic-gate  */
5857c478bd9Sstevel@tonic-gate /* ARGSUSED */
5867c478bd9Sstevel@tonic-gate static int
ipsecesp_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)5877c478bd9Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
5887c478bd9Sstevel@tonic-gate {
589f4b3ec61Sdh155122 	netstack_t		*ns;
590f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack;
591f4b3ec61Sdh155122 
592d2370ffeSsommerfe 	if (secpolicy_ip_config(credp, B_FALSE) != 0)
5937c478bd9Sstevel@tonic-gate 		return (EPERM);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
5967c478bd9Sstevel@tonic-gate 		return (0);  /* Re-open of an already open instance. */
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN)
5997c478bd9Sstevel@tonic-gate 		return (EINVAL);
6007c478bd9Sstevel@tonic-gate 
601f4b3ec61Sdh155122 	ns = netstack_find_by_cred(credp);
602f4b3ec61Sdh155122 	ASSERT(ns != NULL);
603f4b3ec61Sdh155122 	espstack = ns->netstack_ipsecesp;
604f4b3ec61Sdh155122 	ASSERT(espstack != NULL);
605f4b3ec61Sdh155122 
606f4b3ec61Sdh155122 	q->q_ptr = espstack;
607f4b3ec61Sdh155122 	WR(q)->q_ptr = q->q_ptr;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	qprocson(q);
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate /*
6147c478bd9Sstevel@tonic-gate  * ESP module close routine.
6157c478bd9Sstevel@tonic-gate  */
6167c478bd9Sstevel@tonic-gate static int
ipsecesp_close(queue_t * q)6177c478bd9Sstevel@tonic-gate ipsecesp_close(queue_t *q)
6187c478bd9Sstevel@tonic-gate {
619f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = (ipsecesp_stack_t *)q->q_ptr;
620f4b3ec61Sdh155122 
6217c478bd9Sstevel@tonic-gate 	/*
6227c478bd9Sstevel@tonic-gate 	 * Clean up q_ptr, if needed.
6237c478bd9Sstevel@tonic-gate 	 */
6247c478bd9Sstevel@tonic-gate 	qprocsoff(q);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/* Keysock queue check is safe, because of OCEXCL perimeter. */
6277c478bd9Sstevel@tonic-gate 
628f4b3ec61Sdh155122 	if (q == espstack->esp_pfkey_q) {
629f4b3ec61Sdh155122 		esp1dbg(espstack,
630f4b3ec61Sdh155122 		    ("ipsecesp_close:  Ummm... keysock is closing ESP.\n"));
631f4b3ec61Sdh155122 		espstack->esp_pfkey_q = NULL;
6327c478bd9Sstevel@tonic-gate 		/* Detach qtimeouts. */
633f4b3ec61Sdh155122 		(void) quntimeout(q, espstack->esp_event);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
636f4b3ec61Sdh155122 	netstack_rele(espstack->ipsecesp_netstack);
6377c478bd9Sstevel@tonic-gate 	return (0);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * Add a number of bytes to what the SA has protected so far.  Return
6427c478bd9Sstevel@tonic-gate  * B_TRUE if the SA can still protect that many bytes.
6437c478bd9Sstevel@tonic-gate  *
6447c478bd9Sstevel@tonic-gate  * Caller must REFRELE the passed-in assoc.  This function must REFRELE
6457c478bd9Sstevel@tonic-gate  * any obtained peer SA.
6467c478bd9Sstevel@tonic-gate  */
6477c478bd9Sstevel@tonic-gate static boolean_t
esp_age_bytes(ipsa_t * assoc,uint64_t bytes,boolean_t inbound)6487c478bd9Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate 	ipsa_t *inassoc, *outassoc;
6517c478bd9Sstevel@tonic-gate 	isaf_t *bucket;
6527c478bd9Sstevel@tonic-gate 	boolean_t inrc, outrc, isv6;
6537c478bd9Sstevel@tonic-gate 	sadb_t *sp;
6547c478bd9Sstevel@tonic-gate 	int outhash;
655f4b3ec61Sdh155122 	netstack_t		*ns = assoc->ipsa_netstack;
656f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = ns->netstack_ipsecesp;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	/* No peer?  No problem! */
6597c478bd9Sstevel@tonic-gate 	if (!assoc->ipsa_haspeer) {
660f4b3ec61Sdh155122 		return (sadb_age_bytes(espstack->esp_pfkey_q, assoc, bytes,
6617c478bd9Sstevel@tonic-gate 		    B_TRUE));
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/*
6657c478bd9Sstevel@tonic-gate 	 * Otherwise, we want to grab both the original assoc and its peer.
6667c478bd9Sstevel@tonic-gate 	 * There might be a race for this, but if it's a real race, two
6677c478bd9Sstevel@tonic-gate 	 * expire messages may occur.  We limit this by only sending the
6687c478bd9Sstevel@tonic-gate 	 * expire message on one of the peers, we'll pick the inbound
6697c478bd9Sstevel@tonic-gate 	 * arbitrarily.
6707c478bd9Sstevel@tonic-gate 	 *
6717c478bd9Sstevel@tonic-gate 	 * If we need tight synchronization on the peer SA, then we need to
6727c478bd9Sstevel@tonic-gate 	 * reconsider.
6737c478bd9Sstevel@tonic-gate 	 */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* Use address length to select IPv6/IPv4 */
6767c478bd9Sstevel@tonic-gate 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
677f4b3ec61Sdh155122 	sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	if (inbound) {
6807c478bd9Sstevel@tonic-gate 		inassoc = assoc;
6817c478bd9Sstevel@tonic-gate 		if (isv6) {
682fb87b5d2Ssommerfe 			outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *)
6837c478bd9Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
6847c478bd9Sstevel@tonic-gate 		} else {
685fb87b5d2Ssommerfe 			outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *)
6867c478bd9Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 		bucket = &sp->sdb_of[outhash];
6897c478bd9Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
6907c478bd9Sstevel@tonic-gate 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
6917c478bd9Sstevel@tonic-gate 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
6927c478bd9Sstevel@tonic-gate 		    inassoc->ipsa_addrfam);
6937c478bd9Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
6947c478bd9Sstevel@tonic-gate 		if (outassoc == NULL) {
6957c478bd9Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
6967c478bd9Sstevel@tonic-gate 			esp0dbg(("esp_age_bytes: "
6977c478bd9Sstevel@tonic-gate 			    "can't find peer for inbound.\n"));
698f4b3ec61Sdh155122 			return (sadb_age_bytes(espstack->esp_pfkey_q, inassoc,
6997c478bd9Sstevel@tonic-gate 			    bytes, B_TRUE));
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 	} else {
7027c478bd9Sstevel@tonic-gate 		outassoc = assoc;
703fb87b5d2Ssommerfe 		bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
7047c478bd9Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
7057c478bd9Sstevel@tonic-gate 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
7067c478bd9Sstevel@tonic-gate 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
7077c478bd9Sstevel@tonic-gate 		    outassoc->ipsa_addrfam);
7087c478bd9Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
7097c478bd9Sstevel@tonic-gate 		if (inassoc == NULL) {
7107c478bd9Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
7117c478bd9Sstevel@tonic-gate 			esp0dbg(("esp_age_bytes: "
7127c478bd9Sstevel@tonic-gate 			    "can't find peer for outbound.\n"));
713f4b3ec61Sdh155122 			return (sadb_age_bytes(espstack->esp_pfkey_q, outassoc,
7147c478bd9Sstevel@tonic-gate 			    bytes, B_TRUE));
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
718f4b3ec61Sdh155122 	inrc = sadb_age_bytes(espstack->esp_pfkey_q, inassoc, bytes, B_TRUE);
719f4b3ec61Sdh155122 	outrc = sadb_age_bytes(espstack->esp_pfkey_q, outassoc, bytes, B_FALSE);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	/*
7227c478bd9Sstevel@tonic-gate 	 * REFRELE any peer SA.
7237c478bd9Sstevel@tonic-gate 	 *
7247c478bd9Sstevel@tonic-gate 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
7257c478bd9Sstevel@tonic-gate 	 * them in { }.
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	if (inbound) {
7287c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(outassoc);
7297c478bd9Sstevel@tonic-gate 	} else {
7307c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(inassoc);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	return (inrc && outrc);
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate  * Do incoming NAT-T manipulations for packet.
738bd670b35SErik Nordmark  * Returns NULL if the mblk chain is consumed.
7397c478bd9Sstevel@tonic-gate  */
740bd670b35SErik Nordmark static mblk_t *
esp_fix_natt_checksums(mblk_t * data_mp,ipsa_t * assoc)7417c478bd9Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
744bd670b35SErik Nordmark 	tcpha_t *tcpha;
7457c478bd9Sstevel@tonic-gate 	udpha_t *udpha;
7467c478bd9Sstevel@tonic-gate 	/* Initialize to our inbound cksum adjustment... */
7477c478bd9Sstevel@tonic-gate 	uint32_t sum = assoc->ipsa_inbound_cksum;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	switch (ipha->ipha_protocol) {
7507c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
751bd670b35SErik Nordmark 		tcpha = (tcpha_t *)(data_mp->b_rptr +
7527c478bd9Sstevel@tonic-gate 		    IPH_HDR_LENGTH(ipha));
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate #define	DOWN_SUM(x) (x) = ((x) & 0xFFFF) +	 ((x) >> 16)
755bd670b35SErik Nordmark 		sum += ~ntohs(tcpha->tha_sum) & 0xFFFF;
7567c478bd9Sstevel@tonic-gate 		DOWN_SUM(sum);
7577c478bd9Sstevel@tonic-gate 		DOWN_SUM(sum);
758bd670b35SErik Nordmark 		tcpha->tha_sum = ~htons(sum);
7597c478bd9Sstevel@tonic-gate 		break;
7607c478bd9Sstevel@tonic-gate 	case IPPROTO_UDP:
7617c478bd9Sstevel@tonic-gate 		udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha));
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		if (udpha->uha_checksum != 0) {
7647c478bd9Sstevel@tonic-gate 			/* Adujst if the inbound one was not zero. */
7657c478bd9Sstevel@tonic-gate 			sum += ~ntohs(udpha->uha_checksum) & 0xFFFF;
7667c478bd9Sstevel@tonic-gate 			DOWN_SUM(sum);
7677c478bd9Sstevel@tonic-gate 			DOWN_SUM(sum);
7687c478bd9Sstevel@tonic-gate 			udpha->uha_checksum = ~htons(sum);
7697c478bd9Sstevel@tonic-gate 			if (udpha->uha_checksum == 0)
7707c478bd9Sstevel@tonic-gate 				udpha->uha_checksum = 0xFFFF;
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate #undef DOWN_SUM
7737c478bd9Sstevel@tonic-gate 		break;
7747c478bd9Sstevel@tonic-gate 	case IPPROTO_IP:
7757c478bd9Sstevel@tonic-gate 		/*
7767c478bd9Sstevel@tonic-gate 		 * This case is only an issue for self-encapsulated
7777c478bd9Sstevel@tonic-gate 		 * packets.  So for now, fall through.
7787c478bd9Sstevel@tonic-gate 		 */
7797c478bd9Sstevel@tonic-gate 		break;
7807c478bd9Sstevel@tonic-gate 	}
781bd670b35SErik Nordmark 	return (data_mp);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate /*
78632350c00Sdanmcd  * Strip ESP header, check padding, and fix IP header.
7877c478bd9Sstevel@tonic-gate  * Returns B_TRUE on success, B_FALSE if an error occured.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate static boolean_t
esp_strip_header(mblk_t * data_mp,boolean_t isv4,uint32_t ivlen,kstat_named_t ** counter,ipsecesp_stack_t * espstack)7907c478bd9Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen,
791f4b3ec61Sdh155122     kstat_named_t **counter, ipsecesp_stack_t *espstack)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 	ipha_t *ipha;
7947c478bd9Sstevel@tonic-gate 	ip6_t *ip6h;
7957c478bd9Sstevel@tonic-gate 	uint_t divpoint;
7967c478bd9Sstevel@tonic-gate 	mblk_t *scratch;
7977c478bd9Sstevel@tonic-gate 	uint8_t nexthdr, padlen;
7987c478bd9Sstevel@tonic-gate 	uint8_t lastpad;
799f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
80032350c00Sdanmcd 	uint8_t *lastbyte;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	/*
8037c478bd9Sstevel@tonic-gate 	 * Strip ESP data and fix IP header.
8047c478bd9Sstevel@tonic-gate 	 *
8057c478bd9Sstevel@tonic-gate 	 * XXX In case the beginning of esp_inbound() changes to not do a
8067c478bd9Sstevel@tonic-gate 	 * pullup, this part of the code can remain unchanged.
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 	if (isv4) {
8097c478bd9Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t));
8107c478bd9Sstevel@tonic-gate 		ipha = (ipha_t *)data_mp->b_rptr;
8117c478bd9Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) +
8127c478bd9Sstevel@tonic-gate 		    IPH_HDR_LENGTH(ipha));
8137c478bd9Sstevel@tonic-gate 		divpoint = IPH_HDR_LENGTH(ipha);
8147c478bd9Sstevel@tonic-gate 	} else {
8157c478bd9Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t));
8167c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)data_mp->b_rptr;
8177c478bd9Sstevel@tonic-gate 		divpoint = ip_hdr_length_v6(data_mp, ip6h);
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	scratch = data_mp;
8217c478bd9Sstevel@tonic-gate 	while (scratch->b_cont != NULL)
8227c478bd9Sstevel@tonic-gate 		scratch = scratch->b_cont;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3);
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	/*
8277c478bd9Sstevel@tonic-gate 	 * "Next header" and padding length are the last two bytes in the
8287c478bd9Sstevel@tonic-gate 	 * ESP-protected datagram, thus the explicit - 1 and - 2.
8297c478bd9Sstevel@tonic-gate 	 * lastpad is the last byte of the padding, which can be used for
8307c478bd9Sstevel@tonic-gate 	 * a quick check to see if the padding is correct.
8317c478bd9Sstevel@tonic-gate 	 */
83232350c00Sdanmcd 	lastbyte = scratch->b_wptr - 1;
83332350c00Sdanmcd 	nexthdr = *lastbyte--;
83432350c00Sdanmcd 	padlen = *lastbyte--;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	if (isv4) {
8377c478bd9Sstevel@tonic-gate 		/* Fix part of the IP header. */
8387c478bd9Sstevel@tonic-gate 		ipha->ipha_protocol = nexthdr;
8397c478bd9Sstevel@tonic-gate 		/*
8407c478bd9Sstevel@tonic-gate 		 * Reality check the padlen.  The explicit - 2 is for the
8417c478bd9Sstevel@tonic-gate 		 * padding length and the next-header bytes.
8427c478bd9Sstevel@tonic-gate 		 */
8437c478bd9Sstevel@tonic-gate 		if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 -
8447c478bd9Sstevel@tonic-gate 		    sizeof (esph_t) - ivlen) {
845f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, bad_decrypt);
846f4b3ec61Sdh155122 			ipsec_rl_strlog(espstack->ipsecesp_netstack,
847f4b3ec61Sdh155122 			    info.mi_idnum, 0, 0,
848f4b3ec61Sdh155122 			    SL_ERROR | SL_WARN,
84932350c00Sdanmcd 			    "Corrupt ESP packet (padlen too big).\n");
850f4b3ec61Sdh155122 			esp1dbg(espstack, ("padlen (%d) is greater than:\n",
851f4b3ec61Sdh155122 			    padlen));
852f4b3ec61Sdh155122 			esp1dbg(espstack, ("pkt len(%d) - ip hdr - esp "
853f4b3ec61Sdh155122 			    "hdr - ivlen(%d) = %d.\n",
854f4b3ec61Sdh155122 			    ntohs(ipha->ipha_length), ivlen,
8557c478bd9Sstevel@tonic-gate 			    (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) -
8567c478bd9Sstevel@tonic-gate 			    2 - sizeof (esph_t) - ivlen)));
857f4b3ec61Sdh155122 			*counter = DROPPER(ipss, ipds_esp_bad_padlen);
8587c478bd9Sstevel@tonic-gate 			return (B_FALSE);
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		/*
8627c478bd9Sstevel@tonic-gate 		 * Fix the rest of the header.  The explicit - 2 is for the
8637c478bd9Sstevel@tonic-gate 		 * padding length and the next-header bytes.
8647c478bd9Sstevel@tonic-gate 		 */
8657c478bd9Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen -
8667c478bd9Sstevel@tonic-gate 		    2 - sizeof (esph_t) - ivlen);
8677c478bd9Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = 0;
8687c478bd9Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
8697c478bd9Sstevel@tonic-gate 	} else {
8707c478bd9Sstevel@tonic-gate 		if (ip6h->ip6_nxt == IPPROTO_ESP) {
8717c478bd9Sstevel@tonic-gate 			ip6h->ip6_nxt = nexthdr;
8727c478bd9Sstevel@tonic-gate 		} else {
873bd670b35SErik Nordmark 			ip_pkt_t ipp;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 			bzero(&ipp, sizeof (ipp));
876bd670b35SErik Nordmark 			(void) ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp,
877bd670b35SErik Nordmark 			    NULL);
8787c478bd9Sstevel@tonic-gate 			if (ipp.ipp_dstopts != NULL) {
8797c478bd9Sstevel@tonic-gate 				ipp.ipp_dstopts->ip6d_nxt = nexthdr;
8807c478bd9Sstevel@tonic-gate 			} else if (ipp.ipp_rthdr != NULL) {
8817c478bd9Sstevel@tonic-gate 				ipp.ipp_rthdr->ip6r_nxt = nexthdr;
8827c478bd9Sstevel@tonic-gate 			} else if (ipp.ipp_hopopts != NULL) {
8837c478bd9Sstevel@tonic-gate 				ipp.ipp_hopopts->ip6h_nxt = nexthdr;
8847c478bd9Sstevel@tonic-gate 			} else {
8857c478bd9Sstevel@tonic-gate 				/* Panic a DEBUG kernel. */
8867c478bd9Sstevel@tonic-gate 				ASSERT(ipp.ipp_hopopts != NULL);
8877c478bd9Sstevel@tonic-gate 				/* Otherwise, pretend it's IP + ESP. */
8887c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n");
8897c478bd9Sstevel@tonic-gate 				ip6h->ip6_nxt = nexthdr;
8907c478bd9Sstevel@tonic-gate 			}
8917c478bd9Sstevel@tonic-gate 		}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 		if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) -
8947c478bd9Sstevel@tonic-gate 		    ivlen) {
895f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, bad_decrypt);
896f4b3ec61Sdh155122 			ipsec_rl_strlog(espstack->ipsecesp_netstack,
897f4b3ec61Sdh155122 			    info.mi_idnum, 0, 0,
898f4b3ec61Sdh155122 			    SL_ERROR | SL_WARN,
89932350c00Sdanmcd 			    "Corrupt ESP packet (v6 padlen too big).\n");
900f4b3ec61Sdh155122 			esp1dbg(espstack, ("padlen (%d) is greater than:\n",
901f4b3ec61Sdh155122 			    padlen));
902437220cdSdanmcd 			esp1dbg(espstack,
903437220cdSdanmcd 			    ("pkt len(%u) - ip hdr - esp hdr - ivlen(%d) = "
904437220cdSdanmcd 			    "%u.\n", (unsigned)(ntohs(ip6h->ip6_plen)
9057c478bd9Sstevel@tonic-gate 			    + sizeof (ip6_t)), ivlen,
9067c478bd9Sstevel@tonic-gate 			    (unsigned)(ntohs(ip6h->ip6_plen) - 2 -
9077c478bd9Sstevel@tonic-gate 			    sizeof (esph_t) - ivlen)));
908f4b3ec61Sdh155122 			*counter = DROPPER(ipss, ipds_esp_bad_padlen);
9097c478bd9Sstevel@tonic-gate 			return (B_FALSE);
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 		/*
9147c478bd9Sstevel@tonic-gate 		 * Fix the rest of the header.  The explicit - 2 is for the
9157c478bd9Sstevel@tonic-gate 		 * padding length and the next-header bytes.  IPv6 is nice,
9167c478bd9Sstevel@tonic-gate 		 * because there's no hdr checksum!
9177c478bd9Sstevel@tonic-gate 		 */
9187c478bd9Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen -
9197c478bd9Sstevel@tonic-gate 		    2 - sizeof (esph_t) - ivlen);
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
922f4b3ec61Sdh155122 	if (espstack->ipsecesp_padding_check > 0 && padlen > 0) {
92332350c00Sdanmcd 		/*
92432350c00Sdanmcd 		 * Weak padding check: compare last-byte to length, they
92532350c00Sdanmcd 		 * should be equal.
92632350c00Sdanmcd 		 */
92732350c00Sdanmcd 		lastpad = *lastbyte--;
92832350c00Sdanmcd 
92932350c00Sdanmcd 		if (padlen != lastpad) {
930f4b3ec61Sdh155122 			ipsec_rl_strlog(espstack->ipsecesp_netstack,
931f4b3ec61Sdh155122 			    info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
93232350c00Sdanmcd 			    "Corrupt ESP packet (lastpad != padlen).\n");
933f4b3ec61Sdh155122 			esp1dbg(espstack,
934f4b3ec61Sdh155122 			    ("lastpad (%d) not equal to padlen (%d):\n",
9357c478bd9Sstevel@tonic-gate 			    lastpad, padlen));
936f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, bad_padding);
937f4b3ec61Sdh155122 			*counter = DROPPER(ipss, ipds_esp_bad_padding);
9387c478bd9Sstevel@tonic-gate 			return (B_FALSE);
9397c478bd9Sstevel@tonic-gate 		}
9407c478bd9Sstevel@tonic-gate 
94132350c00Sdanmcd 		/*
94232350c00Sdanmcd 		 * Strong padding check: Check all pad bytes to see that
94332350c00Sdanmcd 		 * they're ascending.  Go backwards using a descending counter
94432350c00Sdanmcd 		 * to verify.  padlen == 1 is checked by previous block, so
94532350c00Sdanmcd 		 * only bother if we've more than 1 byte of padding.
94632350c00Sdanmcd 		 * Consequently, start the check one byte before the location
94732350c00Sdanmcd 		 * of "lastpad".
94832350c00Sdanmcd 		 */
949f4b3ec61Sdh155122 		if (espstack->ipsecesp_padding_check > 1) {
95032350c00Sdanmcd 			/*
95132350c00Sdanmcd 			 * This assert may have to become an if and a pullup
95232350c00Sdanmcd 			 * if we start accepting multi-dblk mblks. For now,
95332350c00Sdanmcd 			 * though, any packet here will have been pulled up in
95432350c00Sdanmcd 			 * esp_inbound.
95532350c00Sdanmcd 			 */
95632350c00Sdanmcd 			ASSERT(MBLKL(scratch) >= lastpad + 3);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 			/*
95932350c00Sdanmcd 			 * Use "--lastpad" because we already checked the very
96032350c00Sdanmcd 			 * last pad byte previously.
9617c478bd9Sstevel@tonic-gate 			 */
96232350c00Sdanmcd 			while (--lastpad != 0) {
96332350c00Sdanmcd 				if (lastpad != *lastbyte) {
964f4b3ec61Sdh155122 					ipsec_rl_strlog(
965f4b3ec61Sdh155122 					    espstack->ipsecesp_netstack,
966f4b3ec61Sdh155122 					    info.mi_idnum, 0, 0,
96732350c00Sdanmcd 					    SL_ERROR | SL_WARN, "Corrupt ESP "
96832350c00Sdanmcd 					    "packet (bad padding).\n");
969f4b3ec61Sdh155122 					esp1dbg(espstack,
970f4b3ec61Sdh155122 					    ("padding not in correct"
9717c478bd9Sstevel@tonic-gate 					    " format:\n"));
972f4b3ec61Sdh155122 					ESP_BUMP_STAT(espstack, bad_padding);
973f4b3ec61Sdh155122 					*counter = DROPPER(ipss,
974f4b3ec61Sdh155122 					    ipds_esp_bad_padding);
9757c478bd9Sstevel@tonic-gate 					return (B_FALSE);
9767c478bd9Sstevel@tonic-gate 				}
97732350c00Sdanmcd 				lastbyte--;
97832350c00Sdanmcd 			}
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	/* Trim off the padding. */
9837c478bd9Sstevel@tonic-gate 	ASSERT(data_mp->b_cont == NULL);
9847c478bd9Sstevel@tonic-gate 	data_mp->b_wptr -= (padlen + 2);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	/*
9877c478bd9Sstevel@tonic-gate 	 * Remove the ESP header.
9887c478bd9Sstevel@tonic-gate 	 *
9897c478bd9Sstevel@tonic-gate 	 * The above assertions about data_mp's size will make this work.
9907c478bd9Sstevel@tonic-gate 	 *
9917c478bd9Sstevel@tonic-gate 	 * XXX  Question:  If I send up and get back a contiguous mblk,
9927c478bd9Sstevel@tonic-gate 	 * would it be quicker to bcopy over, or keep doing the dupb stuff?
9937c478bd9Sstevel@tonic-gate 	 * I go with copying for now.
9947c478bd9Sstevel@tonic-gate 	 */
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) &&
9977c478bd9Sstevel@tonic-gate 	    IS_P2ALIGNED(ivlen, sizeof (uint32_t))) {
9987c478bd9Sstevel@tonic-gate 		uint8_t *start = data_mp->b_rptr;
9997c478bd9Sstevel@tonic-gate 		uint32_t *src, *dst;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		src = (uint32_t *)(start + divpoint);
10027c478bd9Sstevel@tonic-gate 		dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) &&
10057c478bd9Sstevel@tonic-gate 		    IS_P2ALIGNED(src, sizeof (uint32_t)));
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 		do {
10087c478bd9Sstevel@tonic-gate 			src--;
10097c478bd9Sstevel@tonic-gate 			dst--;
10107c478bd9Sstevel@tonic-gate 			*dst = *src;
10117c478bd9Sstevel@tonic-gate 		} while (src != (uint32_t *)start);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		data_mp->b_rptr = (uchar_t *)dst;
10147c478bd9Sstevel@tonic-gate 	} else {
10157c478bd9Sstevel@tonic-gate 		uint8_t *start = data_mp->b_rptr;
10167c478bd9Sstevel@tonic-gate 		uint8_t *src, *dst;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		src = start + divpoint;
10197c478bd9Sstevel@tonic-gate 		dst = src + sizeof (esph_t) + ivlen;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		do {
10227c478bd9Sstevel@tonic-gate 			src--;
10237c478bd9Sstevel@tonic-gate 			dst--;
10247c478bd9Sstevel@tonic-gate 			*dst = *src;
10257c478bd9Sstevel@tonic-gate 		} while (src != start);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		data_mp->b_rptr = dst;
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 
1030f4b3ec61Sdh155122 	esp2dbg(espstack, ("data_mp after inbound ESP adjustment:\n"));
1031f4b3ec61Sdh155122 	esp2dbg(espstack, (dump_msg(data_mp)));
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	return (B_TRUE);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * Updating use times can be tricky business if the ipsa_haspeer flag is
10387c478bd9Sstevel@tonic-gate  * set.  This function is called once in an SA's lifetime.
10397c478bd9Sstevel@tonic-gate  *
10407c478bd9Sstevel@tonic-gate  * Caller has to REFRELE "assoc" which is passed in.  This function has
10417c478bd9Sstevel@tonic-gate  * to REFRELE any peer SA that is obtained.
10427c478bd9Sstevel@tonic-gate  */
10437c478bd9Sstevel@tonic-gate static void
esp_set_usetime(ipsa_t * assoc,boolean_t inbound)10447c478bd9Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound)
10457c478bd9Sstevel@tonic-gate {
10467c478bd9Sstevel@tonic-gate 	ipsa_t *inassoc, *outassoc;
10477c478bd9Sstevel@tonic-gate 	isaf_t *bucket;
10487c478bd9Sstevel@tonic-gate 	sadb_t *sp;
10497c478bd9Sstevel@tonic-gate 	int outhash;
10507c478bd9Sstevel@tonic-gate 	boolean_t isv6;
1051f4b3ec61Sdh155122 	netstack_t		*ns = assoc->ipsa_netstack;
1052f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = ns->netstack_ipsecesp;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	/* No peer?  No problem! */
10557c478bd9Sstevel@tonic-gate 	if (!assoc->ipsa_haspeer) {
10567c478bd9Sstevel@tonic-gate 		sadb_set_usetime(assoc);
10577c478bd9Sstevel@tonic-gate 		return;
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	/*
10617c478bd9Sstevel@tonic-gate 	 * Otherwise, we want to grab both the original assoc and its peer.
10627c478bd9Sstevel@tonic-gate 	 * There might be a race for this, but if it's a real race, the times
10637c478bd9Sstevel@tonic-gate 	 * will be out-of-synch by at most a second, and since our time
10647c478bd9Sstevel@tonic-gate 	 * granularity is a second, this won't be a problem.
10657c478bd9Sstevel@tonic-gate 	 *
10667c478bd9Sstevel@tonic-gate 	 * If we need tight synchronization on the peer SA, then we need to
10677c478bd9Sstevel@tonic-gate 	 * reconsider.
10687c478bd9Sstevel@tonic-gate 	 */
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	/* Use address length to select IPv6/IPv4 */
10717c478bd9Sstevel@tonic-gate 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
1072f4b3ec61Sdh155122 	sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if (inbound) {
10757c478bd9Sstevel@tonic-gate 		inassoc = assoc;
10767c478bd9Sstevel@tonic-gate 		if (isv6) {
1077fb87b5d2Ssommerfe 			outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *)
10787c478bd9Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
10797c478bd9Sstevel@tonic-gate 		} else {
1080fb87b5d2Ssommerfe 			outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *)
10817c478bd9Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
10827c478bd9Sstevel@tonic-gate 		}
10837c478bd9Sstevel@tonic-gate 		bucket = &sp->sdb_of[outhash];
10847c478bd9Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
10857c478bd9Sstevel@tonic-gate 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
10867c478bd9Sstevel@tonic-gate 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
10877c478bd9Sstevel@tonic-gate 		    inassoc->ipsa_addrfam);
10887c478bd9Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
10897c478bd9Sstevel@tonic-gate 		if (outassoc == NULL) {
10907c478bd9Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
10917c478bd9Sstevel@tonic-gate 			esp0dbg(("esp_set_usetime: "
10927c478bd9Sstevel@tonic-gate 			    "can't find peer for inbound.\n"));
10937c478bd9Sstevel@tonic-gate 			sadb_set_usetime(inassoc);
10947c478bd9Sstevel@tonic-gate 			return;
10957c478bd9Sstevel@tonic-gate 		}
10967c478bd9Sstevel@tonic-gate 	} else {
10977c478bd9Sstevel@tonic-gate 		outassoc = assoc;
1098fb87b5d2Ssommerfe 		bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
10997c478bd9Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
11007c478bd9Sstevel@tonic-gate 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
11017c478bd9Sstevel@tonic-gate 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
11027c478bd9Sstevel@tonic-gate 		    outassoc->ipsa_addrfam);
11037c478bd9Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
11047c478bd9Sstevel@tonic-gate 		if (inassoc == NULL) {
11057c478bd9Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
11067c478bd9Sstevel@tonic-gate 			esp0dbg(("esp_set_usetime: "
11077c478bd9Sstevel@tonic-gate 			    "can't find peer for outbound.\n"));
11087c478bd9Sstevel@tonic-gate 			sadb_set_usetime(outassoc);
11097c478bd9Sstevel@tonic-gate 			return;
11107c478bd9Sstevel@tonic-gate 		}
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	/* Update usetime on both. */
11147c478bd9Sstevel@tonic-gate 	sadb_set_usetime(inassoc);
11157c478bd9Sstevel@tonic-gate 	sadb_set_usetime(outassoc);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/*
11187c478bd9Sstevel@tonic-gate 	 * REFRELE any peer SA.
11197c478bd9Sstevel@tonic-gate 	 *
11207c478bd9Sstevel@tonic-gate 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
11217c478bd9Sstevel@tonic-gate 	 * them in { }.
11227c478bd9Sstevel@tonic-gate 	 */
11237c478bd9Sstevel@tonic-gate 	if (inbound) {
11247c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(outassoc);
11257c478bd9Sstevel@tonic-gate 	} else {
11267c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(inassoc);
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate /*
11317c478bd9Sstevel@tonic-gate  * Handle ESP inbound data for IPv4 and IPv6.
11327c478bd9Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
1133bd670b35SErik Nordmark  * mblk chain data_mp.
11347c478bd9Sstevel@tonic-gate  */
1135bd670b35SErik Nordmark mblk_t *
esp_inbound(mblk_t * data_mp,void * arg,ip_recv_attr_t * ira)1136bd670b35SErik Nordmark esp_inbound(mblk_t *data_mp, void *arg, ip_recv_attr_t *ira)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate 	esph_t *esph = (esph_t *)arg;
1139bd670b35SErik Nordmark 	ipsa_t *ipsa = ira->ira_ipsec_esp_sa;
1140bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
1141f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1142f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/*
11457c478bd9Sstevel@tonic-gate 	 * We may wish to check replay in-range-only here as an optimization.
11467c478bd9Sstevel@tonic-gate 	 * Include the reality check of ipsa->ipsa_replay >
11477c478bd9Sstevel@tonic-gate 	 * ipsa->ipsa_replay_wsize for times when it's the first N packets,
11487c478bd9Sstevel@tonic-gate 	 * where N == ipsa->ipsa_replay_wsize.
11497c478bd9Sstevel@tonic-gate 	 *
11507c478bd9Sstevel@tonic-gate 	 * Another check that may come here later is the "collision" check.
11517c478bd9Sstevel@tonic-gate 	 * If legitimate packets flow quickly enough, this won't be a problem,
11527c478bd9Sstevel@tonic-gate 	 * but collisions may cause authentication algorithm crunching to
11537c478bd9Sstevel@tonic-gate 	 * take place when it doesn't need to.
11547c478bd9Sstevel@tonic-gate 	 */
11557c478bd9Sstevel@tonic-gate 	if (!sadb_replay_peek(ipsa, esph->esph_replay)) {
1156f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, replay_early_failures);
1157f4b3ec61Sdh155122 		IP_ESP_BUMP_STAT(ipss, in_discards);
1158bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
1159f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_early_replay),
1160f4b3ec61Sdh155122 		    &espstack->esp_dropper);
1161bd670b35SErik Nordmark 		BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
1162bd670b35SErik Nordmark 		return (NULL);
11637c478bd9Sstevel@tonic-gate 	}
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	/*
11667c478bd9Sstevel@tonic-gate 	 * Adjust the IP header's payload length to reflect the removal
11677c478bd9Sstevel@tonic-gate 	 * of the ICV.
11687c478bd9Sstevel@tonic-gate 	 */
1169bd670b35SErik Nordmark 	if (!(ira->ira_flags & IRAF_IS_IPV4)) {
11707c478bd9Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
11717c478bd9Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) -
11727c478bd9Sstevel@tonic-gate 		    ipsa->ipsa_mac_len);
11737c478bd9Sstevel@tonic-gate 	} else {
11747c478bd9Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
11757c478bd9Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) -
11767c478bd9Sstevel@tonic-gate 		    ipsa->ipsa_mac_len);
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	/* submit the request to the crypto framework */
1180bd670b35SErik Nordmark 	return (esp_submit_req_inbound(data_mp, ira, ipsa,
11817c478bd9Sstevel@tonic-gate 	    (uint8_t *)esph - data_mp->b_rptr));
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate /*
11857c478bd9Sstevel@tonic-gate  * Perform the really difficult work of inserting the proposed situation.
11867c478bd9Sstevel@tonic-gate  * Called while holding the algorithm lock.
11877c478bd9Sstevel@tonic-gate  */
11887c478bd9Sstevel@tonic-gate static void
esp_insert_prop(sadb_prop_t * prop,ipsacq_t * acqrec,uint_t combs,netstack_t * ns)1189bd670b35SErik Nordmark esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
1190bd670b35SErik Nordmark     netstack_t *ns)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate 	sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
11937c478bd9Sstevel@tonic-gate 	ipsec_action_t *ap;
11947c478bd9Sstevel@tonic-gate 	ipsec_prot_t *prot;
1195bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1196bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
11977c478bd9Sstevel@tonic-gate 
1198f4b3ec61Sdh155122 	ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
12017c478bd9Sstevel@tonic-gate 	prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
12027c478bd9Sstevel@tonic-gate 	*(uint32_t *)(&prop->sadb_prop_replay) = 0;	/* Quick zero-out! */
12037c478bd9Sstevel@tonic-gate 
1204f4b3ec61Sdh155122 	prop->sadb_prop_replay = espstack->ipsecesp_replay_size;
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	/*
1207bd670b35SErik Nordmark 	 * Based upon algorithm properties, and what-not, prioritize a
1208bd670b35SErik Nordmark 	 * proposal, based on the ordering of the ESP algorithms in the
1209bd670b35SErik Nordmark 	 * alternatives in the policy rule or socket that was placed
1210bd670b35SErik Nordmark 	 * in the acquire record.
12117c478bd9Sstevel@tonic-gate 	 *
12127c478bd9Sstevel@tonic-gate 	 * For each action in policy list
12137c478bd9Sstevel@tonic-gate 	 *   Add combination.  If I've hit limit, return.
12147c478bd9Sstevel@tonic-gate 	 */
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	for (ap = acqrec->ipsacq_act; ap != NULL;
12177c478bd9Sstevel@tonic-gate 	    ap = ap->ipa_next) {
12187c478bd9Sstevel@tonic-gate 		ipsec_alginfo_t *ealg = NULL;
12197c478bd9Sstevel@tonic-gate 		ipsec_alginfo_t *aalg = NULL;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY)
12227c478bd9Sstevel@tonic-gate 			continue;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 		prot = &ap->ipa_act.ipa_apply;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		if (!(prot->ipp_use_esp))
12277c478bd9Sstevel@tonic-gate 			continue;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 		if (prot->ipp_esp_auth_alg != 0) {
1230f4b3ec61Sdh155122 			aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
12317c478bd9Sstevel@tonic-gate 			    [prot->ipp_esp_auth_alg];
12327c478bd9Sstevel@tonic-gate 			if (aalg == NULL || !ALG_VALID(aalg))
12337c478bd9Sstevel@tonic-gate 				continue;
12347c478bd9Sstevel@tonic-gate 		}
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 		ASSERT(prot->ipp_encr_alg > 0);
1237f4b3ec61Sdh155122 		ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
1238f4b3ec61Sdh155122 		    [prot->ipp_encr_alg];
12397c478bd9Sstevel@tonic-gate 		if (ealg == NULL || !ALG_VALID(ealg))
12407c478bd9Sstevel@tonic-gate 			continue;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 		comb->sadb_comb_flags = 0;
12437c478bd9Sstevel@tonic-gate 		comb->sadb_comb_reserved = 0;
12447c478bd9Sstevel@tonic-gate 		comb->sadb_comb_encrypt = ealg->alg_id;
12457845d282Sdanmcd 		comb->sadb_comb_encrypt_minbits =
12467845d282Sdanmcd 		    MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits);
12477845d282Sdanmcd 		comb->sadb_comb_encrypt_maxbits =
12487845d282Sdanmcd 		    MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits);
1249628b0c67SMark Fenwick 
12507c478bd9Sstevel@tonic-gate 		if (aalg == NULL) {
12517c478bd9Sstevel@tonic-gate 			comb->sadb_comb_auth = 0;
12527c478bd9Sstevel@tonic-gate 			comb->sadb_comb_auth_minbits = 0;
12537c478bd9Sstevel@tonic-gate 			comb->sadb_comb_auth_maxbits = 0;
12547c478bd9Sstevel@tonic-gate 		} else {
12557c478bd9Sstevel@tonic-gate 			comb->sadb_comb_auth = aalg->alg_id;
12567845d282Sdanmcd 			comb->sadb_comb_auth_minbits =
12577845d282Sdanmcd 			    MAX(prot->ipp_espa_minbits, aalg->alg_ef_minbits);
12587845d282Sdanmcd 			comb->sadb_comb_auth_maxbits =
12597845d282Sdanmcd 			    MIN(prot->ipp_espa_maxbits, aalg->alg_ef_maxbits);
12607c478bd9Sstevel@tonic-gate 		}
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		/*
12637c478bd9Sstevel@tonic-gate 		 * The following may be based on algorithm
12647c478bd9Sstevel@tonic-gate 		 * properties, but in the meantime, we just pick
12657c478bd9Sstevel@tonic-gate 		 * some good, sensible numbers.  Key mgmt. can
12667c478bd9Sstevel@tonic-gate 		 * (and perhaps should) be the place to finalize
12677c478bd9Sstevel@tonic-gate 		 * such decisions.
12687c478bd9Sstevel@tonic-gate 		 */
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		/*
12717c478bd9Sstevel@tonic-gate 		 * No limits on allocations, since we really don't
12727c478bd9Sstevel@tonic-gate 		 * support that concept currently.
12737c478bd9Sstevel@tonic-gate 		 */
12747c478bd9Sstevel@tonic-gate 		comb->sadb_comb_soft_allocations = 0;
12757c478bd9Sstevel@tonic-gate 		comb->sadb_comb_hard_allocations = 0;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		/*
12787c478bd9Sstevel@tonic-gate 		 * These may want to come from policy rule..
12797c478bd9Sstevel@tonic-gate 		 */
1280f4b3ec61Sdh155122 		comb->sadb_comb_soft_bytes =
1281f4b3ec61Sdh155122 		    espstack->ipsecesp_default_soft_bytes;
1282f4b3ec61Sdh155122 		comb->sadb_comb_hard_bytes =
1283f4b3ec61Sdh155122 		    espstack->ipsecesp_default_hard_bytes;
1284f4b3ec61Sdh155122 		comb->sadb_comb_soft_addtime =
1285f4b3ec61Sdh155122 		    espstack->ipsecesp_default_soft_addtime;
1286f4b3ec61Sdh155122 		comb->sadb_comb_hard_addtime =
1287f4b3ec61Sdh155122 		    espstack->ipsecesp_default_hard_addtime;
1288f4b3ec61Sdh155122 		comb->sadb_comb_soft_usetime =
1289f4b3ec61Sdh155122 		    espstack->ipsecesp_default_soft_usetime;
1290f4b3ec61Sdh155122 		comb->sadb_comb_hard_usetime =
1291f4b3ec61Sdh155122 		    espstack->ipsecesp_default_hard_usetime;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 		prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
12947c478bd9Sstevel@tonic-gate 		if (--combs == 0)
12957c478bd9Sstevel@tonic-gate 			break;	/* out of space.. */
12967c478bd9Sstevel@tonic-gate 		comb++;
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate /*
13017c478bd9Sstevel@tonic-gate  * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
13027c478bd9Sstevel@tonic-gate  */
13037c478bd9Sstevel@tonic-gate static void
esp_send_acquire(ipsacq_t * acqrec,mblk_t * extended,netstack_t * ns)1304f4b3ec61Sdh155122 esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
13057c478bd9Sstevel@tonic-gate {
13068810c16bSdanmcd 	uint_t combs;
13077c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
13087c478bd9Sstevel@tonic-gate 	sadb_prop_t *prop;
13098810c16bSdanmcd 	mblk_t *pfkeymp, *msgmp;
1310f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1311f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
13127c478bd9Sstevel@tonic-gate 
1313f4b3ec61Sdh155122 	ESP_BUMP_STAT(espstack, acquire_requests);
13147c478bd9Sstevel@tonic-gate 
13157ba9381bSpwernau 	if (espstack->esp_pfkey_q == NULL) {
13167ba9381bSpwernau 		mutex_exit(&acqrec->ipsacq_lock);
13178810c16bSdanmcd 		return;
13187ba9381bSpwernau 	}
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	/* Set up ACQUIRE. */
1321f4b3ec61Sdh155122 	pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP,
1322f4b3ec61Sdh155122 	    ns->netstack_ipsec);
13238810c16bSdanmcd 	if (pfkeymp == NULL) {
13247c478bd9Sstevel@tonic-gate 		esp0dbg(("sadb_setup_acquire failed.\n"));
13257ba9381bSpwernau 		mutex_exit(&acqrec->ipsacq_lock);
13268810c16bSdanmcd 		return;
13277c478bd9Sstevel@tonic-gate 	}
1328f4b3ec61Sdh155122 	ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1329f4b3ec61Sdh155122 	combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
1330f4b3ec61Sdh155122 	    ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
13318810c16bSdanmcd 	msgmp = pfkeymp->b_cont;
13328810c16bSdanmcd 	samsg = (sadb_msg_t *)(msgmp->b_rptr);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/* Insert proposal here. */
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1337bd670b35SErik Nordmark 	esp_insert_prop(prop, acqrec, combs, ns);
13387c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_len += prop->sadb_prop_len;
13397c478bd9Sstevel@tonic-gate 	msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
13407c478bd9Sstevel@tonic-gate 
1341f4b3ec61Sdh155122 	mutex_exit(&ipss->ipsec_alg_lock);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	/*
13447c478bd9Sstevel@tonic-gate 	 * Must mutex_exit() before sending PF_KEY message up, in
13457c478bd9Sstevel@tonic-gate 	 * order to avoid recursive mutex_enter() if there are no registered
13467c478bd9Sstevel@tonic-gate 	 * listeners.
13477c478bd9Sstevel@tonic-gate 	 *
13487c478bd9Sstevel@tonic-gate 	 * Once I've sent the message, I'm cool anyway.
13497c478bd9Sstevel@tonic-gate 	 */
13507c478bd9Sstevel@tonic-gate 	mutex_exit(&acqrec->ipsacq_lock);
13517c478bd9Sstevel@tonic-gate 	if (extended != NULL) {
1352f4b3ec61Sdh155122 		putnext(espstack->esp_pfkey_q, extended);
13537c478bd9Sstevel@tonic-gate 	}
1354f4b3ec61Sdh155122 	putnext(espstack->esp_pfkey_q, pfkeymp);
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate 
13575d3b8cb7SBill Sommerfeld /* XXX refactor me */
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate  * Handle the SADB_GETSPI message.  Create a larval SA.
13607c478bd9Sstevel@tonic-gate  */
13617c478bd9Sstevel@tonic-gate static void
esp_getspi(mblk_t * mp,keysock_in_t * ksi,ipsecesp_stack_t * espstack)1362f4b3ec61Sdh155122 esp_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack)
13637c478bd9Sstevel@tonic-gate {
13647c478bd9Sstevel@tonic-gate 	ipsa_t *newbie, *target;
13657c478bd9Sstevel@tonic-gate 	isaf_t *outbound, *inbound;
13667c478bd9Sstevel@tonic-gate 	int rc, diagnostic;
13677c478bd9Sstevel@tonic-gate 	sadb_sa_t *assoc;
13687c478bd9Sstevel@tonic-gate 	keysock_out_t *kso;
13697c478bd9Sstevel@tonic-gate 	uint32_t newspi;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	/*
13727c478bd9Sstevel@tonic-gate 	 * Randomly generate a proposed SPI value
13737c478bd9Sstevel@tonic-gate 	 */
13749c2c14abSThejaswini Singarajipura 	if (cl_inet_getspi != NULL) {
13758e4b770fSLu Huafeng 		cl_inet_getspi(espstack->ipsecesp_netstack->netstack_stackid,
13768e4b770fSLu Huafeng 		    IPPROTO_ESP, (uint8_t *)&newspi, sizeof (uint32_t), NULL);
13779c2c14abSThejaswini Singarajipura 	} else {
13789c2c14abSThejaswini Singarajipura 		(void) random_get_pseudo_bytes((uint8_t *)&newspi,
13799c2c14abSThejaswini Singarajipura 		    sizeof (uint32_t));
13809c2c14abSThejaswini Singarajipura 	}
1381f4b3ec61Sdh155122 	newbie = sadb_getspi(ksi, newspi, &diagnostic,
13829c2c14abSThejaswini Singarajipura 	    espstack->ipsecesp_netstack, IPPROTO_ESP);
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if (newbie == NULL) {
1385f4b3ec61Sdh155122 		sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, diagnostic,
13867c478bd9Sstevel@tonic-gate 		    ksi->ks_in_serial);
13877c478bd9Sstevel@tonic-gate 		return;
13887c478bd9Sstevel@tonic-gate 	} else if (newbie == (ipsa_t *)-1) {
1389f4b3ec61Sdh155122 		sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic,
13907c478bd9Sstevel@tonic-gate 		    ksi->ks_in_serial);
13917c478bd9Sstevel@tonic-gate 		return;
13927c478bd9Sstevel@tonic-gate 	}
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	/*
13957c478bd9Sstevel@tonic-gate 	 * XXX - We may randomly collide.  We really should recover from this.
13967c478bd9Sstevel@tonic-gate 	 *	 Unfortunately, that could require spending way-too-much-time
13977c478bd9Sstevel@tonic-gate 	 *	 in here.  For now, let the user retry.
13987c478bd9Sstevel@tonic-gate 	 */
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	if (newbie->ipsa_addrfam == AF_INET6) {
1401f4b3ec61Sdh155122 		outbound = OUTBOUND_BUCKET_V6(&espstack->esp_sadb.s_v6,
1402fb87b5d2Ssommerfe 		    *(uint32_t *)(newbie->ipsa_dstaddr));
1403f4b3ec61Sdh155122 		inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v6,
1404f4b3ec61Sdh155122 		    newbie->ipsa_spi);
14057c478bd9Sstevel@tonic-gate 	} else {
14067c478bd9Sstevel@tonic-gate 		ASSERT(newbie->ipsa_addrfam == AF_INET);
1407f4b3ec61Sdh155122 		outbound = OUTBOUND_BUCKET_V4(&espstack->esp_sadb.s_v4,
1408fb87b5d2Ssommerfe 		    *(uint32_t *)(newbie->ipsa_dstaddr));
1409f4b3ec61Sdh155122 		inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v4,
1410f4b3ec61Sdh155122 		    newbie->ipsa_spi);
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	mutex_enter(&outbound->isaf_lock);
14147c478bd9Sstevel@tonic-gate 	mutex_enter(&inbound->isaf_lock);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	/*
14177c478bd9Sstevel@tonic-gate 	 * Check for collisions (i.e. did sadb_getspi() return with something
14187c478bd9Sstevel@tonic-gate 	 * that already exists?).
14197c478bd9Sstevel@tonic-gate 	 *
14207c478bd9Sstevel@tonic-gate 	 * Try outbound first.  Even though SADB_GETSPI is traditionally
14217c478bd9Sstevel@tonic-gate 	 * for inbound SAs, you never know what a user might do.
14227c478bd9Sstevel@tonic-gate 	 */
14237c478bd9Sstevel@tonic-gate 	target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi,
14247c478bd9Sstevel@tonic-gate 	    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam);
14257c478bd9Sstevel@tonic-gate 	if (target == NULL) {
14267c478bd9Sstevel@tonic-gate 		target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi,
14277c478bd9Sstevel@tonic-gate 		    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr,
14287c478bd9Sstevel@tonic-gate 		    newbie->ipsa_addrfam);
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	/*
14327c478bd9Sstevel@tonic-gate 	 * I don't have collisions elsewhere!
14337c478bd9Sstevel@tonic-gate 	 * (Nor will I because I'm still holding inbound/outbound locks.)
14347c478bd9Sstevel@tonic-gate 	 */
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	if (target != NULL) {
14377c478bd9Sstevel@tonic-gate 		rc = EEXIST;
14387c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(target);
14397c478bd9Sstevel@tonic-gate 	} else {
14407c478bd9Sstevel@tonic-gate 		/*
14417c478bd9Sstevel@tonic-gate 		 * sadb_insertassoc() also checks for collisions, so
14427c478bd9Sstevel@tonic-gate 		 * if there's a colliding entry, rc will be set
14437c478bd9Sstevel@tonic-gate 		 * to EEXIST.
14447c478bd9Sstevel@tonic-gate 		 */
14457c478bd9Sstevel@tonic-gate 		rc = sadb_insertassoc(newbie, inbound);
1446437220cdSdanmcd 		newbie->ipsa_hardexpiretime = gethrestime_sec();
1447f4b3ec61Sdh155122 		newbie->ipsa_hardexpiretime +=
1448f4b3ec61Sdh155122 		    espstack->ipsecesp_larval_timeout;
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	/*
14527c478bd9Sstevel@tonic-gate 	 * Can exit outbound mutex.  Hold inbound until we're done
14537c478bd9Sstevel@tonic-gate 	 * with newbie.
14547c478bd9Sstevel@tonic-gate 	 */
14557c478bd9Sstevel@tonic-gate 	mutex_exit(&outbound->isaf_lock);
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	if (rc != 0) {
14587c478bd9Sstevel@tonic-gate 		mutex_exit(&inbound->isaf_lock);
14597c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(newbie);
1460f4b3ec61Sdh155122 		sadb_pfkey_error(espstack->esp_pfkey_q, mp, rc,
1461f4b3ec61Sdh155122 		    SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial);
14627c478bd9Sstevel@tonic-gate 		return;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	/* Can write here because I'm still holding the bucket lock. */
14677c478bd9Sstevel@tonic-gate 	newbie->ipsa_type = SADB_SATYPE_ESP;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	/*
14707c478bd9Sstevel@tonic-gate 	 * Construct successful return message. We have one thing going
14717c478bd9Sstevel@tonic-gate 	 * for us in PF_KEY v2.  That's the fact that
14727c478bd9Sstevel@tonic-gate 	 *	sizeof (sadb_spirange_t) == sizeof (sadb_sa_t)
14737c478bd9Sstevel@tonic-gate 	 */
14747c478bd9Sstevel@tonic-gate 	assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE];
14757c478bd9Sstevel@tonic-gate 	assoc->sadb_sa_exttype = SADB_EXT_SA;
14767c478bd9Sstevel@tonic-gate 	assoc->sadb_sa_spi = newbie->ipsa_spi;
14777c478bd9Sstevel@tonic-gate 	*((uint64_t *)(&assoc->sadb_sa_replay)) = 0;
14787c478bd9Sstevel@tonic-gate 	mutex_exit(&inbound->isaf_lock);
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	/* Convert KEYSOCK_IN to KEYSOCK_OUT. */
14817c478bd9Sstevel@tonic-gate 	kso = (keysock_out_t *)ksi;
14827c478bd9Sstevel@tonic-gate 	kso->ks_out_len = sizeof (*kso);
14837c478bd9Sstevel@tonic-gate 	kso->ks_out_serial = ksi->ks_in_serial;
14847c478bd9Sstevel@tonic-gate 	kso->ks_out_type = KEYSOCK_OUT;
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	/*
14877c478bd9Sstevel@tonic-gate 	 * Can safely putnext() to esp_pfkey_q, because this is a turnaround
14887c478bd9Sstevel@tonic-gate 	 * from the esp_pfkey_q.
14897c478bd9Sstevel@tonic-gate 	 */
1490f4b3ec61Sdh155122 	putnext(espstack->esp_pfkey_q, mp);
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate  * Insert the ESP header into a packet.  Duplicate an mblk, and insert a newly
14957c478bd9Sstevel@tonic-gate  * allocated mblk with the ESP header in between the two.
14967c478bd9Sstevel@tonic-gate  */
14977c478bd9Sstevel@tonic-gate static boolean_t
esp_insert_esp(mblk_t * mp,mblk_t * esp_mp,uint_t divpoint,ipsecesp_stack_t * espstack)1498f4b3ec61Sdh155122 esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint,
1499f4b3ec61Sdh155122     ipsecesp_stack_t *espstack)
15007c478bd9Sstevel@tonic-gate {
15017c478bd9Sstevel@tonic-gate 	mblk_t *split_mp = mp;
15027c478bd9Sstevel@tonic-gate 	uint_t wheretodiv = divpoint;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) {
15057c478bd9Sstevel@tonic-gate 		wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr);
15067c478bd9Sstevel@tonic-gate 		split_mp = split_mp->b_cont;
15077c478bd9Sstevel@tonic-gate 		ASSERT(split_mp != NULL);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) {
15117c478bd9Sstevel@tonic-gate 		mblk_t *scratch;
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 		/* "scratch" is the 2nd half, split_mp is the first. */
15147c478bd9Sstevel@tonic-gate 		scratch = dupb(split_mp);
15157c478bd9Sstevel@tonic-gate 		if (scratch == NULL) {
1516f4b3ec61Sdh155122 			esp1dbg(espstack,
1517f4b3ec61Sdh155122 			    ("esp_insert_esp: can't allocate scratch.\n"));
15187c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15197c478bd9Sstevel@tonic-gate 		}
15207c478bd9Sstevel@tonic-gate 		/* NOTE:  dupb() doesn't set b_cont appropriately. */
15217c478bd9Sstevel@tonic-gate 		scratch->b_cont = split_mp->b_cont;
15227c478bd9Sstevel@tonic-gate 		scratch->b_rptr += wheretodiv;
15237c478bd9Sstevel@tonic-gate 		split_mp->b_wptr = split_mp->b_rptr + wheretodiv;
15247c478bd9Sstevel@tonic-gate 		split_mp->b_cont = scratch;
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 	/*
15277c478bd9Sstevel@tonic-gate 	 * At this point, split_mp is exactly "wheretodiv" bytes long, and
15287c478bd9Sstevel@tonic-gate 	 * holds the end of the pre-ESP part of the datagram.
15297c478bd9Sstevel@tonic-gate 	 */
15307c478bd9Sstevel@tonic-gate 	esp_mp->b_cont = split_mp->b_cont;
15317c478bd9Sstevel@tonic-gate 	split_mp->b_cont = esp_mp;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	return (B_TRUE);
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate /*
15374a179720Sdanmcd  * Section 7 of RFC 3947 says:
15384a179720Sdanmcd  *
15394a179720Sdanmcd  * 7.  Recovering from the Expiring NAT Mappings
15404a179720Sdanmcd  *
15414a179720Sdanmcd  *    There are cases where NAT box decides to remove mappings that are still
15424a179720Sdanmcd  *    alive (for example, when the keepalive interval is too long, or when the
15434a179720Sdanmcd  *    NAT box is rebooted).  To recover from this, ends that are NOT behind
15444a179720Sdanmcd  *    NAT SHOULD use the last valid UDP encapsulated IKE or IPsec packet from
15454a179720Sdanmcd  *    the other end to determine which IP and port addresses should be used.
15464a179720Sdanmcd  *    The host behind dynamic NAT MUST NOT do this, as otherwise it opens a
15474a179720Sdanmcd  *    DoS attack possibility because the IP address or port of the other host
15484a179720Sdanmcd  *    will not change (it is not behind NAT).
15494a179720Sdanmcd  *
15504a179720Sdanmcd  *    Keepalives cannot be used for these purposes, as they are not
15514a179720Sdanmcd  *    authenticated, but any IKE authenticated IKE packet or ESP packet can be
15524a179720Sdanmcd  *    used to detect whether the IP address or the port has changed.
15534a179720Sdanmcd  *
15544a179720Sdanmcd  * The following function will check an SA and its explicitly-set pair to see
15554a179720Sdanmcd  * if the NAT-T remote port matches the received packet (which must have
15564a179720Sdanmcd  * passed ESP authentication, see esp_in_done() for the caller context).  If
15574a179720Sdanmcd  * there is a mismatch, the SAs are updated.  It is not important if we race
15584a179720Sdanmcd  * with a transmitting thread, as if there is a transmitting thread, it will
15594a179720Sdanmcd  * merely emit a packet that will most-likely be dropped.
15604a179720Sdanmcd  *
15614a179720Sdanmcd  * "ports" are ordered src,dst, and assoc is an inbound SA, where src should
15624a179720Sdanmcd  * match ipsa_remote_nat_port and dst should match ipsa_local_nat_port.
15634a179720Sdanmcd  */
15644a179720Sdanmcd #ifdef _LITTLE_ENDIAN
15654a179720Sdanmcd #define	FIRST_16(x) ((x) & 0xFFFF)
15664a179720Sdanmcd #define	NEXT_16(x) (((x) >> 16) & 0xFFFF)
15674a179720Sdanmcd #else
15684a179720Sdanmcd #define	FIRST_16(x) (((x) >> 16) & 0xFFFF)
15694a179720Sdanmcd #define	NEXT_16(x) ((x) & 0xFFFF)
15704a179720Sdanmcd #endif
15714a179720Sdanmcd static void
esp_port_freshness(uint32_t ports,ipsa_t * assoc)15724a179720Sdanmcd esp_port_freshness(uint32_t ports, ipsa_t *assoc)
15734a179720Sdanmcd {
15744a179720Sdanmcd 	uint16_t remote = FIRST_16(ports);
15754a179720Sdanmcd 	uint16_t local = NEXT_16(ports);
15764a179720Sdanmcd 	ipsa_t *outbound_peer;
15774a179720Sdanmcd 	isaf_t *bucket;
15784a179720Sdanmcd 	ipsecesp_stack_t *espstack = assoc->ipsa_netstack->netstack_ipsecesp;
15794a179720Sdanmcd 
15804a179720Sdanmcd 	/* We found a conn_t, therefore local != 0. */
15814a179720Sdanmcd 	ASSERT(local != 0);
15824a179720Sdanmcd 	/* Assume an IPv4 SA. */
15834a179720Sdanmcd 	ASSERT(assoc->ipsa_addrfam == AF_INET);
15844a179720Sdanmcd 
15854a179720Sdanmcd 	/*
15864a179720Sdanmcd 	 * On-the-wire rport == 0 means something's very wrong.
15874a179720Sdanmcd 	 * An unpaired SA is also useless to us.
15884a179720Sdanmcd 	 * If we are behind the NAT, don't bother.
15894a179720Sdanmcd 	 * A zero local NAT port defaults to 4500, so check that too.
15904a179720Sdanmcd 	 * And, of course, if the ports already match, we don't need to
15914a179720Sdanmcd 	 * bother.
15924a179720Sdanmcd 	 */
15934a179720Sdanmcd 	if (remote == 0 || assoc->ipsa_otherspi == 0 ||
15944a179720Sdanmcd 	    (assoc->ipsa_flags & IPSA_F_BEHIND_NAT) ||
15954a179720Sdanmcd 	    (assoc->ipsa_remote_nat_port == 0 &&
15964a179720Sdanmcd 	    remote == htons(IPPORT_IKE_NATT)) ||
15974a179720Sdanmcd 	    remote == assoc->ipsa_remote_nat_port)
15984a179720Sdanmcd 		return;
15994a179720Sdanmcd 
16004a179720Sdanmcd 	/* Try and snag the peer.   NOTE:  Assume IPv4 for now. */
16014a179720Sdanmcd 	bucket = OUTBOUND_BUCKET_V4(&(espstack->esp_sadb.s_v4),
16024a179720Sdanmcd 	    assoc->ipsa_srcaddr[0]);
16034a179720Sdanmcd 	mutex_enter(&bucket->isaf_lock);
16044a179720Sdanmcd 	outbound_peer = ipsec_getassocbyspi(bucket, assoc->ipsa_otherspi,
16054a179720Sdanmcd 	    assoc->ipsa_dstaddr, assoc->ipsa_srcaddr, AF_INET);
16064a179720Sdanmcd 	mutex_exit(&bucket->isaf_lock);
16074a179720Sdanmcd 
16084a179720Sdanmcd 	/* We probably lost a race to a deleting or expiring thread. */
16094a179720Sdanmcd 	if (outbound_peer == NULL)
16104a179720Sdanmcd 		return;
16114a179720Sdanmcd 
16124a179720Sdanmcd 	/*
16134a179720Sdanmcd 	 * Hold the mutexes for both SAs so we don't race another inbound
16144a179720Sdanmcd 	 * thread.  A lock-entry order shouldn't matter, since all other
16154a179720Sdanmcd 	 * per-ipsa locks are individually held-then-released.
16164a179720Sdanmcd 	 *
16174a179720Sdanmcd 	 * Luckily, this has nothing to do with the remote-NAT address,
16184a179720Sdanmcd 	 * so we don't have to re-scribble the cached-checksum differential.
16194a179720Sdanmcd 	 */
16204a179720Sdanmcd 	mutex_enter(&outbound_peer->ipsa_lock);
16214a179720Sdanmcd 	mutex_enter(&assoc->ipsa_lock);
16224a179720Sdanmcd 	outbound_peer->ipsa_remote_nat_port = assoc->ipsa_remote_nat_port =
16234a179720Sdanmcd 	    remote;
16244a179720Sdanmcd 	mutex_exit(&assoc->ipsa_lock);
16254a179720Sdanmcd 	mutex_exit(&outbound_peer->ipsa_lock);
16264a179720Sdanmcd 	IPSA_REFRELE(outbound_peer);
16274a179720Sdanmcd 	ESP_BUMP_STAT(espstack, sa_port_renumbers);
16284a179720Sdanmcd }
16294a179720Sdanmcd /*
16307c478bd9Sstevel@tonic-gate  * Finish processing of an inbound ESP packet after processing by the
16317c478bd9Sstevel@tonic-gate  * crypto framework.
16327c478bd9Sstevel@tonic-gate  * - Remove the ESP header.
16337c478bd9Sstevel@tonic-gate  * - Send packet back to IP.
16347c478bd9Sstevel@tonic-gate  * If authentication was performed on the packet, this function is called
16357c478bd9Sstevel@tonic-gate  * only if the authentication succeeded.
16367c478bd9Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
1637bd670b35SErik Nordmark  * mblk chain data_mp.
16387c478bd9Sstevel@tonic-gate  */
1639bd670b35SErik Nordmark static mblk_t *
esp_in_done(mblk_t * data_mp,ip_recv_attr_t * ira,ipsec_crypto_t * ic)1640bd670b35SErik Nordmark esp_in_done(mblk_t *data_mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate 	ipsa_t *assoc;
16437c478bd9Sstevel@tonic-gate 	uint_t espstart;
16447c478bd9Sstevel@tonic-gate 	uint32_t ivlen = 0;
16457c478bd9Sstevel@tonic-gate 	uint_t processed_len;
16467c478bd9Sstevel@tonic-gate 	esph_t *esph;
16477c478bd9Sstevel@tonic-gate 	kstat_named_t *counter;
16487c478bd9Sstevel@tonic-gate 	boolean_t is_natt;
1649bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
1650f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1651f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
16527c478bd9Sstevel@tonic-gate 
1653bd670b35SErik Nordmark 	assoc = ira->ira_ipsec_esp_sa;
16547c478bd9Sstevel@tonic-gate 	ASSERT(assoc != NULL);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	/* get the pointer to the ESP header */
16597c478bd9Sstevel@tonic-gate 	if (assoc->ipsa_encr_alg == SADB_EALG_NULL) {
16607c478bd9Sstevel@tonic-gate 		/* authentication-only ESP */
1661bd670b35SErik Nordmark 		espstart = ic->ic_crypto_data.cd_offset;
1662bd670b35SErik Nordmark 		processed_len = ic->ic_crypto_data.cd_length;
16637c478bd9Sstevel@tonic-gate 	} else {
16647c478bd9Sstevel@tonic-gate 		/* encryption present */
16657c478bd9Sstevel@tonic-gate 		ivlen = assoc->ipsa_iv_len;
16667c478bd9Sstevel@tonic-gate 		if (assoc->ipsa_auth_alg == SADB_AALG_NONE) {
16677c478bd9Sstevel@tonic-gate 			/* encryption-only ESP */
1668bd670b35SErik Nordmark 			espstart = ic->ic_crypto_data.cd_offset -
16697c478bd9Sstevel@tonic-gate 			    sizeof (esph_t) - assoc->ipsa_iv_len;
1670bd670b35SErik Nordmark 			processed_len = ic->ic_crypto_data.cd_length +
16717c478bd9Sstevel@tonic-gate 			    ivlen;
16727c478bd9Sstevel@tonic-gate 		} else {
16737c478bd9Sstevel@tonic-gate 			/* encryption with authentication */
1674bd670b35SErik Nordmark 			espstart = ic->ic_crypto_dual_data.dd_offset1;
1675bd670b35SErik Nordmark 			processed_len = ic->ic_crypto_dual_data.dd_len2 +
16767c478bd9Sstevel@tonic-gate 			    ivlen;
16777c478bd9Sstevel@tonic-gate 		}
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	esph = (esph_t *)(data_mp->b_rptr + espstart);
16817c478bd9Sstevel@tonic-gate 
1682628b0c67SMark Fenwick 	if (assoc->ipsa_auth_alg != IPSA_AALG_NONE ||
1683628b0c67SMark Fenwick 	    (assoc->ipsa_flags & IPSA_F_COMBINED)) {
1684628b0c67SMark Fenwick 		/*
1685628b0c67SMark Fenwick 		 * Authentication passed if we reach this point.
1686628b0c67SMark Fenwick 		 * Packets with authentication will have the ICV
1687628b0c67SMark Fenwick 		 * after the crypto data. Adjust b_wptr before
1688628b0c67SMark Fenwick 		 * making padlen checks.
1689628b0c67SMark Fenwick 		 */
1690f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, good_auth);
16917c478bd9Sstevel@tonic-gate 		data_mp->b_wptr -= assoc->ipsa_mac_len;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 		/*
16947c478bd9Sstevel@tonic-gate 		 * Check replay window here!
16957c478bd9Sstevel@tonic-gate 		 * For right now, assume keysock will set the replay window
16967c478bd9Sstevel@tonic-gate 		 * size to zero for SAs that have an unspecified sender.
16977c478bd9Sstevel@tonic-gate 		 * This may change...
16987c478bd9Sstevel@tonic-gate 		 */
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 		if (!sadb_replay_check(assoc, esph->esph_replay)) {
17017c478bd9Sstevel@tonic-gate 			/*
17027c478bd9Sstevel@tonic-gate 			 * Log the event. As of now we print out an event.
17037c478bd9Sstevel@tonic-gate 			 * Do not print the replay failure number, or else
17047c478bd9Sstevel@tonic-gate 			 * syslog cannot collate the error messages.  Printing
17057c478bd9Sstevel@tonic-gate 			 * the replay number that failed opens a denial-of-
17067c478bd9Sstevel@tonic-gate 			 * service attack.
17077c478bd9Sstevel@tonic-gate 			 */
17087c478bd9Sstevel@tonic-gate 			ipsec_assocfailure(info.mi_idnum, 0, 0,
17097c478bd9Sstevel@tonic-gate 			    SL_ERROR | SL_WARN,
17107c478bd9Sstevel@tonic-gate 			    "Replay failed for ESP spi 0x%x, dst %s.\n",
17117c478bd9Sstevel@tonic-gate 			    assoc->ipsa_spi, assoc->ipsa_dstaddr,
1712f4b3ec61Sdh155122 			    assoc->ipsa_addrfam, espstack->ipsecesp_netstack);
1713f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, replay_failures);
1714f4b3ec61Sdh155122 			counter = DROPPER(ipss, ipds_esp_replay);
17157c478bd9Sstevel@tonic-gate 			goto drop_and_bail;
17167c478bd9Sstevel@tonic-gate 		}
17174a179720Sdanmcd 
1718bd670b35SErik Nordmark 		if (is_natt) {
1719bd670b35SErik Nordmark 			ASSERT(ira->ira_flags & IRAF_ESP_UDP_PORTS);
1720bd670b35SErik Nordmark 			ASSERT(ira->ira_esp_udp_ports != 0);
1721bd670b35SErik Nordmark 			esp_port_freshness(ira->ira_esp_udp_ports, assoc);
1722bd670b35SErik Nordmark 		}
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 
1725437220cdSdanmcd 	esp_set_usetime(assoc, B_TRUE);
1726437220cdSdanmcd 
17277c478bd9Sstevel@tonic-gate 	if (!esp_age_bytes(assoc, processed_len, B_TRUE)) {
17287c478bd9Sstevel@tonic-gate 		/* The ipsa has hit hard expiration, LOG and AUDIT. */
17297c478bd9Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0,
17307c478bd9Sstevel@tonic-gate 		    SL_ERROR | SL_WARN,
17317c478bd9Sstevel@tonic-gate 		    "ESP association 0x%x, dst %s had bytes expire.\n",
1732f4b3ec61Sdh155122 		    assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam,
1733f4b3ec61Sdh155122 		    espstack->ipsecesp_netstack);
1734f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, bytes_expired);
1735f4b3ec61Sdh155122 		counter = DROPPER(ipss, ipds_esp_bytes_expire);
17367c478bd9Sstevel@tonic-gate 		goto drop_and_bail;
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	/*
17407c478bd9Sstevel@tonic-gate 	 * Remove ESP header and padding from packet.  I hope the compiler
17417c478bd9Sstevel@tonic-gate 	 * spews "branch, predict taken" code for this.
17427c478bd9Sstevel@tonic-gate 	 */
17437c478bd9Sstevel@tonic-gate 
1744bd670b35SErik Nordmark 	if (esp_strip_header(data_mp, (ira->ira_flags & IRAF_IS_IPV4),
1745bd670b35SErik Nordmark 	    ivlen, &counter, espstack)) {
17465d3b8cb7SBill Sommerfeld 
1747bd670b35SErik Nordmark 		if (is_system_labeled() && assoc->ipsa_tsl != NULL) {
1748bd670b35SErik Nordmark 			if (!ip_recv_attr_replace_label(ira, assoc->ipsa_tsl)) {
1749bd670b35SErik Nordmark 				ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
1750bd670b35SErik Nordmark 				    DROPPER(ipss, ipds_ah_nomem),
1751bd670b35SErik Nordmark 				    &espstack->esp_dropper);
1752bd670b35SErik Nordmark 				BUMP_MIB(ira->ira_ill->ill_ip_mib,
1753bd670b35SErik Nordmark 				    ipIfStatsInDiscards);
1754bd670b35SErik Nordmark 				return (NULL);
17555d3b8cb7SBill Sommerfeld 			}
17565d3b8cb7SBill Sommerfeld 		}
17577c478bd9Sstevel@tonic-gate 		if (is_natt)
17587c478bd9Sstevel@tonic-gate 			return (esp_fix_natt_checksums(data_mp, assoc));
1759d74f5ecaSDan McDonald 
1760d74f5ecaSDan McDonald 		if (assoc->ipsa_state == IPSA_STATE_IDLE) {
1761d74f5ecaSDan McDonald 			/*
1762d74f5ecaSDan McDonald 			 * Cluster buffering case.  Tell caller that we're
1763d74f5ecaSDan McDonald 			 * handling the packet.
1764d74f5ecaSDan McDonald 			 */
1765bd670b35SErik Nordmark 			sadb_buf_pkt(assoc, data_mp, ira);
1766bd670b35SErik Nordmark 			return (NULL);
1767d74f5ecaSDan McDonald 		}
1768d74f5ecaSDan McDonald 
1769bd670b35SErik Nordmark 		return (data_mp);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 
1772f4b3ec61Sdh155122 	esp1dbg(espstack, ("esp_in_done: esp_strip_header() failed\n"));
17737c478bd9Sstevel@tonic-gate drop_and_bail:
1774f4b3ec61Sdh155122 	IP_ESP_BUMP_STAT(ipss, in_discards);
1775bd670b35SErik Nordmark 	ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, counter,
1776f4b3ec61Sdh155122 	    &espstack->esp_dropper);
1777bd670b35SErik Nordmark 	BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
1778bd670b35SErik Nordmark 	return (NULL);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate /*
17827c478bd9Sstevel@tonic-gate  * Called upon failing the inbound ICV check. The message passed as
17837c478bd9Sstevel@tonic-gate  * argument is freed.
17847c478bd9Sstevel@tonic-gate  */
17857c478bd9Sstevel@tonic-gate static void
esp_log_bad_auth(mblk_t * mp,ip_recv_attr_t * ira)1786bd670b35SErik Nordmark esp_log_bad_auth(mblk_t *mp, ip_recv_attr_t *ira)
17877c478bd9Sstevel@tonic-gate {
1788bd670b35SErik Nordmark 	ipsa_t		*assoc = ira->ira_ipsec_esp_sa;
1789bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
1790f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1791f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	/*
17947c478bd9Sstevel@tonic-gate 	 * Log the event. Don't print to the console, block
17957c478bd9Sstevel@tonic-gate 	 * potential denial-of-service attack.
17967c478bd9Sstevel@tonic-gate 	 */
1797f4b3ec61Sdh155122 	ESP_BUMP_STAT(espstack, bad_auth);
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
18007c478bd9Sstevel@tonic-gate 	    "ESP Authentication failed for spi 0x%x, dst %s.\n",
1801f4b3ec61Sdh155122 	    assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam,
1802f4b3ec61Sdh155122 	    espstack->ipsecesp_netstack);
18037c478bd9Sstevel@tonic-gate 
1804f4b3ec61Sdh155122 	IP_ESP_BUMP_STAT(ipss, in_discards);
1805bd670b35SErik Nordmark 	ip_drop_packet(mp, B_TRUE, ira->ira_ill,
1806f4b3ec61Sdh155122 	    DROPPER(ipss, ipds_esp_bad_auth),
1807f4b3ec61Sdh155122 	    &espstack->esp_dropper);
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate /*
18127c478bd9Sstevel@tonic-gate  * Invoked for outbound packets after ESP processing. If the packet
18137c478bd9Sstevel@tonic-gate  * also requires AH, performs the AH SA selection and AH processing.
18147c478bd9Sstevel@tonic-gate  * Returns B_TRUE if the AH processing was not needed or if it was
18157c478bd9Sstevel@tonic-gate  * performed successfully. Returns B_FALSE and consumes the passed mblk
18167c478bd9Sstevel@tonic-gate  * if AH processing was required but could not be performed.
1817bd670b35SErik Nordmark  *
1818bd670b35SErik Nordmark  * Returns data_mp unless data_mp was consumed/queued.
18197c478bd9Sstevel@tonic-gate  */
1820bd670b35SErik Nordmark static mblk_t *
esp_do_outbound_ah(mblk_t * data_mp,ip_xmit_attr_t * ixa)1821bd670b35SErik Nordmark esp_do_outbound_ah(mblk_t *data_mp, ip_xmit_attr_t *ixa)
18227c478bd9Sstevel@tonic-gate {
18237c478bd9Sstevel@tonic-gate 	ipsec_action_t *ap;
18247c478bd9Sstevel@tonic-gate 
1825bd670b35SErik Nordmark 	ap = ixa->ixa_ipsec_action;
18267c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
1827bd670b35SErik Nordmark 		ipsec_policy_t *pp = ixa->ixa_ipsec_policy;
18287c478bd9Sstevel@tonic-gate 		ap = pp->ipsp_act;
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if (!ap->ipa_want_ah)
1832bd670b35SErik Nordmark 		return (data_mp);
18337c478bd9Sstevel@tonic-gate 
1834bd670b35SErik Nordmark 	/*
1835bd670b35SErik Nordmark 	 * Normally the AH SA would have already been put in place
1836bd670b35SErik Nordmark 	 * but it could have been flushed so we need to look for it.
1837bd670b35SErik Nordmark 	 */
1838bd670b35SErik Nordmark 	if (ixa->ixa_ipsec_ah_sa == NULL) {
1839bd670b35SErik Nordmark 		if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_AH)) {
1840bd670b35SErik Nordmark 			sadb_acquire(data_mp, ixa, B_TRUE, B_FALSE);
1841bd670b35SErik Nordmark 			return (NULL);
18427c478bd9Sstevel@tonic-gate 		}
18437c478bd9Sstevel@tonic-gate 	}
1844bd670b35SErik Nordmark 	ASSERT(ixa->ixa_ipsec_ah_sa != NULL);
18457c478bd9Sstevel@tonic-gate 
1846bd670b35SErik Nordmark 	data_mp = ixa->ixa_ipsec_ah_sa->ipsa_output_func(data_mp, ixa);
1847bd670b35SErik Nordmark 	return (data_mp);
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate  * Kernel crypto framework callback invoked after completion of async
1853bd670b35SErik Nordmark  * crypto requests for outbound packets.
18547c478bd9Sstevel@tonic-gate  */
18557c478bd9Sstevel@tonic-gate static void
esp_kcf_callback_outbound(void * arg,int status)1856bd670b35SErik Nordmark esp_kcf_callback_outbound(void *arg, int status)
18577c478bd9Sstevel@tonic-gate {
1858bd670b35SErik Nordmark 	mblk_t		*mp = (mblk_t *)arg;
1859bd670b35SErik Nordmark 	mblk_t		*async_mp;
1860bd670b35SErik Nordmark 	netstack_t	*ns;
1861f4b3ec61Sdh155122 	ipsec_stack_t	*ipss;
1862bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack;
1863bd670b35SErik Nordmark 	mblk_t		*data_mp;
1864bd670b35SErik Nordmark 	ip_xmit_attr_t	ixas;
1865bd670b35SErik Nordmark 	ipsec_crypto_t	*ic;
1866bd670b35SErik Nordmark 	ill_t		*ill;
1867f4b3ec61Sdh155122 
1868f4b3ec61Sdh155122 	/*
1869bd670b35SErik Nordmark 	 * First remove the ipsec_crypto_t mblk
1870bd670b35SErik Nordmark 	 * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
1871f4b3ec61Sdh155122 	 */
1872bd670b35SErik Nordmark 	async_mp = ipsec_remove_crypto_data(mp, &ic);
1873bd670b35SErik Nordmark 	ASSERT(async_mp != NULL);
1874f4b3ec61Sdh155122 
1875bd670b35SErik Nordmark 	/*
1876bd670b35SErik Nordmark 	 * Extract the ip_xmit_attr_t from the first mblk.
1877bd670b35SErik Nordmark 	 * Verifies that the netstack and ill is still around; could
1878bd670b35SErik Nordmark 	 * have vanished while kEf was doing its work.
1879bd670b35SErik Nordmark 	 * On succesful return we have a nce_t and the ill/ipst can't
1880bd670b35SErik Nordmark 	 * disappear until we do the nce_refrele in ixa_cleanup.
1881bd670b35SErik Nordmark 	 */
1882bd670b35SErik Nordmark 	data_mp = async_mp->b_cont;
1883bd670b35SErik Nordmark 	async_mp->b_cont = NULL;
1884bd670b35SErik Nordmark 	if (!ip_xmit_attr_from_mblk(async_mp, &ixas)) {
1885bd670b35SErik Nordmark 		/* Disappeared on us - no ill/ipst for MIB */
1886bd670b35SErik Nordmark 		/* We have nowhere to do stats since ixa_ipst could be NULL */
1887bd670b35SErik Nordmark 		if (ixas.ixa_nce != NULL) {
1888bd670b35SErik Nordmark 			ill = ixas.ixa_nce->nce_ill;
1889bd670b35SErik Nordmark 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
1890bd670b35SErik Nordmark 			ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
1891bd670b35SErik Nordmark 		}
1892bd670b35SErik Nordmark 		freemsg(data_mp);
1893bd670b35SErik Nordmark 		goto done;
1894bd670b35SErik Nordmark 	}
1895bd670b35SErik Nordmark 	ns = ixas.ixa_ipst->ips_netstack;
1896f4b3ec61Sdh155122 	espstack = ns->netstack_ipsecesp;
1897f4b3ec61Sdh155122 	ipss = ns->netstack_ipsec;
1898bd670b35SErik Nordmark 	ill = ixas.ixa_nce->nce_ill;
1899f4b3ec61Sdh155122 
19007c478bd9Sstevel@tonic-gate 	if (status == CRYPTO_SUCCESS) {
19017c478bd9Sstevel@tonic-gate 		/*
19027c478bd9Sstevel@tonic-gate 		 * If a ICV was computed, it was stored by the
19037c478bd9Sstevel@tonic-gate 		 * crypto framework at the end of the packet.
19047c478bd9Sstevel@tonic-gate 		 */
1905bd670b35SErik Nordmark 		ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
19067c478bd9Sstevel@tonic-gate 
1907bd670b35SErik Nordmark 		esp_set_usetime(ixas.ixa_ipsec_esp_sa, B_FALSE);
1908437220cdSdanmcd 		/* NAT-T packet. */
1909bd670b35SErik Nordmark 		if (IPH_HDR_VERSION(ipha) == IP_VERSION &&
1910bd670b35SErik Nordmark 		    ipha->ipha_protocol == IPPROTO_UDP)
1911bd670b35SErik Nordmark 			esp_prepare_udp(ns, data_mp, ipha);
1912437220cdSdanmcd 
19137c478bd9Sstevel@tonic-gate 		/* do AH processing if needed */
1914bd670b35SErik Nordmark 		data_mp = esp_do_outbound_ah(data_mp, &ixas);
1915bd670b35SErik Nordmark 		if (data_mp == NULL)
1916bd670b35SErik Nordmark 			goto done;
1917bd670b35SErik Nordmark 
1918bd670b35SErik Nordmark 		(void) ip_output_post_ipsec(data_mp, &ixas);
19197c478bd9Sstevel@tonic-gate 	} else {
1920bd670b35SErik Nordmark 		/* Outbound shouldn't see invalid MAC */
1921bd670b35SErik Nordmark 		ASSERT(status != CRYPTO_INVALID_MAC);
1922bd670b35SErik Nordmark 
1923bd670b35SErik Nordmark 		esp1dbg(espstack,
1924bd670b35SErik Nordmark 		    ("esp_kcf_callback_outbound: crypto failed with 0x%x\n",
1925bd670b35SErik Nordmark 		    status));
1926bd670b35SErik Nordmark 		ESP_BUMP_STAT(espstack, crypto_failures);
1927bd670b35SErik Nordmark 		ESP_BUMP_STAT(espstack, out_discards);
1928bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
1929bd670b35SErik Nordmark 		    DROPPER(ipss, ipds_esp_crypto_failed),
1930bd670b35SErik Nordmark 		    &espstack->esp_dropper);
1931bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
19327c478bd9Sstevel@tonic-gate 	}
1933bd670b35SErik Nordmark done:
1934bd670b35SErik Nordmark 	ixa_cleanup(&ixas);
1935bd670b35SErik Nordmark 	(void) ipsec_free_crypto_data(mp);
19367c478bd9Sstevel@tonic-gate }
19377c478bd9Sstevel@tonic-gate 
1938bd670b35SErik Nordmark /*
1939bd670b35SErik Nordmark  * Kernel crypto framework callback invoked after completion of async
1940bd670b35SErik Nordmark  * crypto requests for inbound packets.
1941bd670b35SErik Nordmark  */
1942bd670b35SErik Nordmark static void
esp_kcf_callback_inbound(void * arg,int status)1943bd670b35SErik Nordmark esp_kcf_callback_inbound(void *arg, int status)
1944bd670b35SErik Nordmark {
1945bd670b35SErik Nordmark 	mblk_t		*mp = (mblk_t *)arg;
1946bd670b35SErik Nordmark 	mblk_t		*async_mp;
1947bd670b35SErik Nordmark 	netstack_t	*ns;
1948bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack;
1949bd670b35SErik Nordmark 	ipsec_stack_t	*ipss;
1950bd670b35SErik Nordmark 	mblk_t		*data_mp;
1951bd670b35SErik Nordmark 	ip_recv_attr_t	iras;
1952bd670b35SErik Nordmark 	ipsec_crypto_t	*ic;
1953bd670b35SErik Nordmark 
1954bd670b35SErik Nordmark 	/*
1955bd670b35SErik Nordmark 	 * First remove the ipsec_crypto_t mblk
1956bd670b35SErik Nordmark 	 * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
1957bd670b35SErik Nordmark 	 */
1958bd670b35SErik Nordmark 	async_mp = ipsec_remove_crypto_data(mp, &ic);
1959bd670b35SErik Nordmark 	ASSERT(async_mp != NULL);
1960bd670b35SErik Nordmark 
1961bd670b35SErik Nordmark 	/*
1962bd670b35SErik Nordmark 	 * Extract the ip_recv_attr_t from the first mblk.
1963bd670b35SErik Nordmark 	 * Verifies that the netstack and ill is still around; could
1964bd670b35SErik Nordmark 	 * have vanished while kEf was doing its work.
1965bd670b35SErik Nordmark 	 */
1966bd670b35SErik Nordmark 	data_mp = async_mp->b_cont;
1967bd670b35SErik Nordmark 	async_mp->b_cont = NULL;
1968bd670b35SErik Nordmark 	if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
1969bd670b35SErik Nordmark 		/* The ill or ip_stack_t disappeared on us */
1970bd670b35SErik Nordmark 		ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL);
1971bd670b35SErik Nordmark 		freemsg(data_mp);
1972bd670b35SErik Nordmark 		goto done;
1973bd670b35SErik Nordmark 	}
1974bd670b35SErik Nordmark 
1975bd670b35SErik Nordmark 	ns = iras.ira_ill->ill_ipst->ips_netstack;
1976bd670b35SErik Nordmark 	espstack = ns->netstack_ipsecesp;
1977bd670b35SErik Nordmark 	ipss = ns->netstack_ipsec;
1978bd670b35SErik Nordmark 
1979bd670b35SErik Nordmark 	if (status == CRYPTO_SUCCESS) {
1980bd670b35SErik Nordmark 		data_mp = esp_in_done(data_mp, &iras, ic);
1981bd670b35SErik Nordmark 		if (data_mp == NULL)
1982bd670b35SErik Nordmark 			goto done;
1983bd670b35SErik Nordmark 
1984bd670b35SErik Nordmark 		/* finish IPsec processing */
1985bd670b35SErik Nordmark 		ip_input_post_ipsec(data_mp, &iras);
19867c478bd9Sstevel@tonic-gate 	} else if (status == CRYPTO_INVALID_MAC) {
1987bd670b35SErik Nordmark 		esp_log_bad_auth(data_mp, &iras);
19887c478bd9Sstevel@tonic-gate 	} else {
1989f4b3ec61Sdh155122 		esp1dbg(espstack,
1990f4b3ec61Sdh155122 		    ("esp_kcf_callback: crypto failed with 0x%x\n",
19917c478bd9Sstevel@tonic-gate 		    status));
1992f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_failures);
1993f4b3ec61Sdh155122 		IP_ESP_BUMP_STAT(ipss, in_discards);
1994bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_TRUE, iras.ira_ill,
1995f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_crypto_failed),
1996f4b3ec61Sdh155122 		    &espstack->esp_dropper);
1997bd670b35SErik Nordmark 		BUMP_MIB(iras.ira_ill->ill_ip_mib, ipIfStatsInDiscards);
19987c478bd9Sstevel@tonic-gate 	}
1999bd670b35SErik Nordmark done:
2000bd670b35SErik Nordmark 	ira_cleanup(&iras, B_TRUE);
2001bd670b35SErik Nordmark 	(void) ipsec_free_crypto_data(mp);
20027c478bd9Sstevel@tonic-gate }
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate /*
20057c478bd9Sstevel@tonic-gate  * Invoked on crypto framework failure during inbound and outbound processing.
20067c478bd9Sstevel@tonic-gate  */
20077c478bd9Sstevel@tonic-gate static void
esp_crypto_failed(mblk_t * data_mp,boolean_t is_inbound,int kef_rc,ill_t * ill,ipsecesp_stack_t * espstack)2008bd670b35SErik Nordmark esp_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc,
2009bd670b35SErik Nordmark     ill_t *ill, ipsecesp_stack_t *espstack)
20107c478bd9Sstevel@tonic-gate {
2011f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
2012f4b3ec61Sdh155122 
2013f4b3ec61Sdh155122 	esp1dbg(espstack, ("crypto failed for %s ESP with 0x%x\n",
20147c478bd9Sstevel@tonic-gate 	    is_inbound ? "inbound" : "outbound", kef_rc));
2015bd670b35SErik Nordmark 	ip_drop_packet(data_mp, is_inbound, ill,
2016f4b3ec61Sdh155122 	    DROPPER(ipss, ipds_esp_crypto_failed),
2017f4b3ec61Sdh155122 	    &espstack->esp_dropper);
2018f4b3ec61Sdh155122 	ESP_BUMP_STAT(espstack, crypto_failures);
20197c478bd9Sstevel@tonic-gate 	if (is_inbound)
2020f4b3ec61Sdh155122 		IP_ESP_BUMP_STAT(ipss, in_discards);
20217c478bd9Sstevel@tonic-gate 	else
2022f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, out_discards);
20237c478bd9Sstevel@tonic-gate }
20247c478bd9Sstevel@tonic-gate 
2025bd670b35SErik Nordmark /*
2026bd670b35SErik Nordmark  * A statement-equivalent macro, _cr MUST point to a modifiable
2027bd670b35SErik Nordmark  * crypto_call_req_t.
2028bd670b35SErik Nordmark  */
2029bd670b35SErik Nordmark #define	ESP_INIT_CALLREQ(_cr, _mp, _callback)				\
2030bd670b35SErik Nordmark 	(_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_ALWAYS_QUEUE;	\
2031bd670b35SErik Nordmark 	(_cr)->cr_callback_arg = (_mp);				\
2032bd670b35SErik Nordmark 	(_cr)->cr_callback_func = (_callback)
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) {			\
20357c478bd9Sstevel@tonic-gate 	(mac)->cd_format = CRYPTO_DATA_RAW;				\
20367c478bd9Sstevel@tonic-gate 	(mac)->cd_offset = 0;						\
20377c478bd9Sstevel@tonic-gate 	(mac)->cd_length = icvlen;					\
20387c478bd9Sstevel@tonic-gate 	(mac)->cd_raw.iov_base = (char *)icvbuf;			\
20397c478bd9Sstevel@tonic-gate 	(mac)->cd_raw.iov_len = icvlen;					\
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_DATA(data, mp, off, len) {			\
20437c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) >= (len) + (off)) {				\
20447c478bd9Sstevel@tonic-gate 		(data)->cd_format = CRYPTO_DATA_RAW;			\
20457c478bd9Sstevel@tonic-gate 		(data)->cd_raw.iov_base = (char *)(mp)->b_rptr;		\
20467c478bd9Sstevel@tonic-gate 		(data)->cd_raw.iov_len = MBLKL(mp);			\
20477c478bd9Sstevel@tonic-gate 		(data)->cd_offset = off;				\
20487c478bd9Sstevel@tonic-gate 	} else {							\
20497c478bd9Sstevel@tonic-gate 		(data)->cd_format = CRYPTO_DATA_MBLK;			\
20507c478bd9Sstevel@tonic-gate 		(data)->cd_mp = mp;			       		\
20517c478bd9Sstevel@tonic-gate 		(data)->cd_offset = off;				\
20527c478bd9Sstevel@tonic-gate 	}								\
20537c478bd9Sstevel@tonic-gate 	(data)->cd_length = len;					\
20547c478bd9Sstevel@tonic-gate }
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) {	\
20577c478bd9Sstevel@tonic-gate 	(data)->dd_format = CRYPTO_DATA_MBLK;				\
20587c478bd9Sstevel@tonic-gate 	(data)->dd_mp = mp;						\
20597c478bd9Sstevel@tonic-gate 	(data)->dd_len1 = len1;						\
20607c478bd9Sstevel@tonic-gate 	(data)->dd_offset1 = off1;					\
20617c478bd9Sstevel@tonic-gate 	(data)->dd_len2 = len2;						\
20627c478bd9Sstevel@tonic-gate 	(data)->dd_offset2 = off2;					\
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate 
2065bd670b35SErik Nordmark /*
2066bd670b35SErik Nordmark  * Returns data_mp if successfully completed the request. Returns
2067bd670b35SErik Nordmark  * NULL if it failed (and increments InDiscards) or if it is pending.
2068bd670b35SErik Nordmark  */
2069bd670b35SErik Nordmark static mblk_t *
esp_submit_req_inbound(mblk_t * esp_mp,ip_recv_attr_t * ira,ipsa_t * assoc,uint_t esph_offset)2070bd670b35SErik Nordmark esp_submit_req_inbound(mblk_t *esp_mp, ip_recv_attr_t *ira,
2071bd670b35SErik Nordmark     ipsa_t *assoc, uint_t esph_offset)
20727c478bd9Sstevel@tonic-gate {
20737c478bd9Sstevel@tonic-gate 	uint_t auth_offset, msg_len, auth_len;
2074bd670b35SErik Nordmark 	crypto_call_req_t call_req, *callrp;
2075bd670b35SErik Nordmark 	mblk_t *mp;
2076628b0c67SMark Fenwick 	esph_t *esph_ptr;
2077bd670b35SErik Nordmark 	int kef_rc;
20787c478bd9Sstevel@tonic-gate 	uint_t icv_len = assoc->ipsa_mac_len;
20797c478bd9Sstevel@tonic-gate 	crypto_ctx_template_t auth_ctx_tmpl;
2080bd670b35SErik Nordmark 	boolean_t do_auth, do_encr, force;
20817c478bd9Sstevel@tonic-gate 	uint_t encr_offset, encr_len;
20827c478bd9Sstevel@tonic-gate 	uint_t iv_len = assoc->ipsa_iv_len;
20837c478bd9Sstevel@tonic-gate 	crypto_ctx_template_t encr_ctx_tmpl;
2084bd670b35SErik Nordmark 	ipsec_crypto_t	*ic, icstack;
2085628b0c67SMark Fenwick 	uchar_t *iv_ptr;
2086bd670b35SErik Nordmark 	netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
2087bd670b35SErik Nordmark 	ipsec_stack_t *ipss = ns->netstack_ipsec;
2088bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
2089f4b3ec61Sdh155122 
20907c478bd9Sstevel@tonic-gate 	do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
20917c478bd9Sstevel@tonic-gate 	do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
2092bd670b35SErik Nordmark 	force = (assoc->ipsa_flags & IPSA_F_ASYNC);
2093bd670b35SErik Nordmark 
2094bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST
2095bd670b35SErik Nordmark 	kef_rc = CRYPTO_SUCCESS;
2096bd670b35SErik Nordmark #else
2097bd670b35SErik Nordmark 	kef_rc = CRYPTO_FAILED;
2098bd670b35SErik Nordmark #endif
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	/*
21017c478bd9Sstevel@tonic-gate 	 * An inbound packet is of the form:
2102bd670b35SErik Nordmark 	 * [IP,options,ESP,IV,data,ICV,pad]
21037c478bd9Sstevel@tonic-gate 	 */
2104628b0c67SMark Fenwick 	esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset);
2105628b0c67SMark Fenwick 	iv_ptr = (uchar_t *)(esph_ptr + 1);
2106628b0c67SMark Fenwick 	/* Packet length starting at IP header ending after ESP ICV. */
21077c478bd9Sstevel@tonic-gate 	msg_len = MBLKL(esp_mp);
21087c478bd9Sstevel@tonic-gate 
2109628b0c67SMark Fenwick 	encr_offset = esph_offset + sizeof (esph_t) + iv_len;
2110628b0c67SMark Fenwick 	encr_len = msg_len - encr_offset;
2111628b0c67SMark Fenwick 
2112628b0c67SMark Fenwick 	/*
2113628b0c67SMark Fenwick 	 * Counter mode algs need a nonce. This is setup in sadb_common_add().
2114628b0c67SMark Fenwick 	 * If for some reason we are using a SA which does not have a nonce
2115628b0c67SMark Fenwick 	 * then we must fail here.
2116628b0c67SMark Fenwick 	 */
2117628b0c67SMark Fenwick 	if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) &&
2118628b0c67SMark Fenwick 	    (assoc->ipsa_nonce == NULL)) {
2119bd670b35SErik Nordmark 		ip_drop_packet(esp_mp, B_TRUE, ira->ira_ill,
2120628b0c67SMark Fenwick 		    DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
2121bd670b35SErik Nordmark 		return (NULL);
2122bd670b35SErik Nordmark 	}
2123bd670b35SErik Nordmark 
2124bd670b35SErik Nordmark 	if (force) {
2125bd670b35SErik Nordmark 		/* We are doing asynch; allocate mblks to hold state */
2126bd670b35SErik Nordmark 		if ((mp = ip_recv_attr_to_mblk(ira)) == NULL ||
2127bd670b35SErik Nordmark 		    (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
2128bd670b35SErik Nordmark 			BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2129bd670b35SErik Nordmark 			ip_drop_input("ipIfStatsInDiscards", esp_mp,
2130bd670b35SErik Nordmark 			    ira->ira_ill);
2131bd670b35SErik Nordmark 			return (NULL);
2132bd670b35SErik Nordmark 		}
2133bd670b35SErik Nordmark 		linkb(mp, esp_mp);
2134bd670b35SErik Nordmark 		callrp = &call_req;
2135bd670b35SErik Nordmark 		ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_inbound);
2136bd670b35SErik Nordmark 	} else {
2137bd670b35SErik Nordmark 		/*
2138bd670b35SErik Nordmark 		 * If we know we are going to do sync then ipsec_crypto_t
2139bd670b35SErik Nordmark 		 * should be on the stack.
2140bd670b35SErik Nordmark 		 */
2141bd670b35SErik Nordmark 		ic = &icstack;
2142bd670b35SErik Nordmark 		bzero(ic, sizeof (*ic));
2143bd670b35SErik Nordmark 		callrp = NULL;
2144628b0c67SMark Fenwick 	}
2145628b0c67SMark Fenwick 
21467c478bd9Sstevel@tonic-gate 	if (do_auth) {
21477c478bd9Sstevel@tonic-gate 		/* authentication context template */
21487c478bd9Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
21497c478bd9Sstevel@tonic-gate 		    auth_ctx_tmpl);
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 		/* ICV to be verified */
2152bd670b35SErik Nordmark 		ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac,
21537c478bd9Sstevel@tonic-gate 		    icv_len, esp_mp->b_wptr - icv_len);
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 		/* authentication starts at the ESP header */
21567c478bd9Sstevel@tonic-gate 		auth_offset = esph_offset;
21577c478bd9Sstevel@tonic-gate 		auth_len = msg_len - auth_offset - icv_len;
21587c478bd9Sstevel@tonic-gate 		if (!do_encr) {
21597c478bd9Sstevel@tonic-gate 			/* authentication only */
21607c478bd9Sstevel@tonic-gate 			/* initialize input data argument */
2161bd670b35SErik Nordmark 			ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
21627c478bd9Sstevel@tonic-gate 			    esp_mp, auth_offset, auth_len);
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 			/* call the crypto framework */
21657c478bd9Sstevel@tonic-gate 			kef_rc = crypto_mac_verify(&assoc->ipsa_amech,
2166bd670b35SErik Nordmark 			    &ic->ic_crypto_data,
21677c478bd9Sstevel@tonic-gate 			    &assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
2168bd670b35SErik Nordmark 			    &ic->ic_crypto_mac, callrp);
21697c478bd9Sstevel@tonic-gate 		}
21707c478bd9Sstevel@tonic-gate 	}
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (do_encr) {
21737c478bd9Sstevel@tonic-gate 		/* encryption template */
21747c478bd9Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
21757c478bd9Sstevel@tonic-gate 		    encr_ctx_tmpl);
21767c478bd9Sstevel@tonic-gate 
2177628b0c67SMark Fenwick 		/* Call the nonce update function. Also passes in IV */
2178628b0c67SMark Fenwick 		(assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, encr_len,
2179bd670b35SErik Nordmark 		    iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data);
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 		if (!do_auth) {
21827c478bd9Sstevel@tonic-gate 			/* decryption only */
21837c478bd9Sstevel@tonic-gate 			/* initialize input data argument */
2184bd670b35SErik Nordmark 			ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
21857c478bd9Sstevel@tonic-gate 			    esp_mp, encr_offset, encr_len);
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 			/* call the crypto framework */
2188628b0c67SMark Fenwick 			kef_rc = crypto_decrypt((crypto_mechanism_t *)
2189bd670b35SErik Nordmark 			    &ic->ic_cmm, &ic->ic_crypto_data,
21907c478bd9Sstevel@tonic-gate 			    &assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
2191bd670b35SErik Nordmark 			    NULL, callrp);
21927c478bd9Sstevel@tonic-gate 		}
21937c478bd9Sstevel@tonic-gate 	}
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	if (do_auth && do_encr) {
21967c478bd9Sstevel@tonic-gate 		/* dual operation */
21977c478bd9Sstevel@tonic-gate 		/* initialize input data argument */
2198bd670b35SErik Nordmark 		ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data,
21997c478bd9Sstevel@tonic-gate 		    esp_mp, auth_offset, auth_len,
22007c478bd9Sstevel@tonic-gate 		    encr_offset, encr_len - icv_len);
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 		/* specify IV */
2203bd670b35SErik Nordmark 		ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 		/* call the framework */
22067c478bd9Sstevel@tonic-gate 		kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech,
2207bd670b35SErik Nordmark 		    &assoc->ipsa_emech, &ic->ic_crypto_dual_data,
22087c478bd9Sstevel@tonic-gate 		    &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey,
2209bd670b35SErik Nordmark 		    auth_ctx_tmpl, encr_ctx_tmpl, &ic->ic_crypto_mac,
2210bd670b35SErik Nordmark 		    NULL, callrp);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	switch (kef_rc) {
22147c478bd9Sstevel@tonic-gate 	case CRYPTO_SUCCESS:
2215f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_sync);
2216bd670b35SErik Nordmark 		esp_mp = esp_in_done(esp_mp, ira, ic);
2217bd670b35SErik Nordmark 		if (force) {
2218bd670b35SErik Nordmark 			/* Free mp after we are done with ic */
2219bd670b35SErik Nordmark 			mp = ipsec_free_crypto_data(mp);
2220bd670b35SErik Nordmark 			(void) ip_recv_attr_free_mblk(mp);
2221bd670b35SErik Nordmark 		}
2222bd670b35SErik Nordmark 		return (esp_mp);
22237c478bd9Sstevel@tonic-gate 	case CRYPTO_QUEUED:
2224bd670b35SErik Nordmark 		/* esp_kcf_callback_inbound() will be invoked on completion */
2225f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_async);
2226bd670b35SErik Nordmark 		return (NULL);
22277c478bd9Sstevel@tonic-gate 	case CRYPTO_INVALID_MAC:
2228bd670b35SErik Nordmark 		if (force) {
2229bd670b35SErik Nordmark 			mp = ipsec_free_crypto_data(mp);
2230bd670b35SErik Nordmark 			esp_mp = ip_recv_attr_free_mblk(mp);
2231bd670b35SErik Nordmark 		}
2232f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_sync);
2233bd670b35SErik Nordmark 		BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2234bd670b35SErik Nordmark 		esp_log_bad_auth(esp_mp, ira);
2235bd670b35SErik Nordmark 		/* esp_mp was passed to ip_drop_packet */
2236bd670b35SErik Nordmark 		return (NULL);
22377c478bd9Sstevel@tonic-gate 	}
22387c478bd9Sstevel@tonic-gate 
2239bd984e57SDan McDonald 	if (force) {
2240bd670b35SErik Nordmark 		mp = ipsec_free_crypto_data(mp);
2241bd670b35SErik Nordmark 		esp_mp = ip_recv_attr_free_mblk(mp);
2242bd984e57SDan McDonald 	}
2243bd670b35SErik Nordmark 	BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2244bd670b35SErik Nordmark 	esp_crypto_failed(esp_mp, B_TRUE, kef_rc, ira->ira_ill, espstack);
2245bd670b35SErik Nordmark 	/* esp_mp was passed to ip_drop_packet */
2246bd670b35SErik Nordmark 	return (NULL);
22477c478bd9Sstevel@tonic-gate }
22487c478bd9Sstevel@tonic-gate 
2249437220cdSdanmcd /*
2250437220cdSdanmcd  * Compute the IP and UDP checksums -- common code for both keepalives and
2251437220cdSdanmcd  * actual ESP-in-UDP packets.  Be flexible with multiple mblks because ESP
2252437220cdSdanmcd  * uses mblk-insertion to insert the UDP header.
2253437220cdSdanmcd  * TODO - If there is an easy way to prep a packet for HW checksums, make
2254437220cdSdanmcd  * it happen here.
2255bd670b35SErik Nordmark  * Note that this is used before both before calling ip_output_simple and
2256bd670b35SErik Nordmark  * in the esp datapath. The former could use IXAF_SET_ULP_CKSUM but not the
2257bd670b35SErik Nordmark  * latter.
2258437220cdSdanmcd  */
2259437220cdSdanmcd static void
esp_prepare_udp(netstack_t * ns,mblk_t * mp,ipha_t * ipha)2260437220cdSdanmcd esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha)
2261437220cdSdanmcd {
2262437220cdSdanmcd 	int offset;
2263437220cdSdanmcd 	uint32_t cksum;
2264437220cdSdanmcd 	uint16_t *arr;
2265437220cdSdanmcd 	mblk_t *udpmp = mp;
226687e10ffaSwy83408 	uint_t hlen = IPH_HDR_LENGTH(ipha);
2267437220cdSdanmcd 
2268437220cdSdanmcd 	ASSERT(MBLKL(mp) >= sizeof (ipha_t));
2269437220cdSdanmcd 
2270437220cdSdanmcd 	ipha->ipha_hdr_checksum = 0;
2271437220cdSdanmcd 	ipha->ipha_hdr_checksum = ip_csum_hdr(ipha);
2272437220cdSdanmcd 
2273437220cdSdanmcd 	if (ns->netstack_udp->us_do_checksum) {
2274437220cdSdanmcd 		ASSERT(MBLKL(udpmp) >= sizeof (udpha_t));
2275437220cdSdanmcd 		/* arr points to the IP header. */
2276437220cdSdanmcd 		arr = (uint16_t *)ipha;
2277437220cdSdanmcd 		IP_STAT(ns->netstack_ip, ip_out_sw_cksum);
2278bd670b35SErik Nordmark 		IP_STAT_UPDATE(ns->netstack_ip, ip_out_sw_cksum_bytes,
227987e10ffaSwy83408 		    ntohs(htons(ipha->ipha_length) - hlen));
2280437220cdSdanmcd 		/* arr[6-9] are the IP addresses. */
2281437220cdSdanmcd 		cksum = IP_UDP_CSUM_COMP + arr[6] + arr[7] + arr[8] + arr[9] +
228287e10ffaSwy83408 		    ntohs(htons(ipha->ipha_length) - hlen);
228387e10ffaSwy83408 		cksum = IP_CSUM(mp, hlen, cksum);
228487e10ffaSwy83408 		offset = hlen + UDP_CHECKSUM_OFFSET;
2285437220cdSdanmcd 		while (offset >= MBLKL(udpmp)) {
2286437220cdSdanmcd 			offset -= MBLKL(udpmp);
2287437220cdSdanmcd 			udpmp = udpmp->b_cont;
2288437220cdSdanmcd 		}
2289437220cdSdanmcd 		/* arr points to the UDP header's checksum field. */
2290437220cdSdanmcd 		arr = (uint16_t *)(udpmp->b_rptr + offset);
2291437220cdSdanmcd 		*arr = cksum;
2292437220cdSdanmcd 	}
2293437220cdSdanmcd }
2294437220cdSdanmcd 
2295437220cdSdanmcd /*
229673184bc7SDan McDonald  * taskq handler so we can send the NAT-T keepalive on a separate thread.
229773184bc7SDan McDonald  */
229873184bc7SDan McDonald static void
actually_send_keepalive(void * arg)229973184bc7SDan McDonald actually_send_keepalive(void *arg)
230073184bc7SDan McDonald {
2301bd670b35SErik Nordmark 	mblk_t *mp = (mblk_t *)arg;
2302bd670b35SErik Nordmark 	ip_xmit_attr_t ixas;
230373184bc7SDan McDonald 	netstack_t	*ns;
2304bd670b35SErik Nordmark 	netstackid_t	stackid;
230573184bc7SDan McDonald 
2306bd670b35SErik Nordmark 	stackid = (netstackid_t)(uintptr_t)mp->b_prev;
2307bd670b35SErik Nordmark 	mp->b_prev = NULL;
2308bd670b35SErik Nordmark 	ns = netstack_find_by_stackid(stackid);
2309bd670b35SErik Nordmark 	if (ns == NULL) {
2310bd670b35SErik Nordmark 		/* Disappeared */
2311bd670b35SErik Nordmark 		ip_drop_output("ipIfStatsOutDiscards", mp, NULL);
2312bd670b35SErik Nordmark 		freemsg(mp);
231373184bc7SDan McDonald 		return;
231473184bc7SDan McDonald 	}
231573184bc7SDan McDonald 
2316bd670b35SErik Nordmark 	bzero(&ixas, sizeof (ixas));
2317bd670b35SErik Nordmark 	ixas.ixa_zoneid = ALL_ZONES;
2318bd670b35SErik Nordmark 	ixas.ixa_cred = kcred;
2319bd670b35SErik Nordmark 	ixas.ixa_cpid = NOPID;
2320bd670b35SErik Nordmark 	ixas.ixa_tsl = NULL;
2321bd670b35SErik Nordmark 	ixas.ixa_ipst = ns->netstack_ip;
2322bd670b35SErik Nordmark 	/* No ULP checksum; done by esp_prepare_udp */
232344b099c4SSowmini Varadhan 	ixas.ixa_flags = (IXAF_IS_IPV4 | IXAF_NO_IPSEC | IXAF_VERIFY_SOURCE);
2324bd670b35SErik Nordmark 
2325bd670b35SErik Nordmark 	(void) ip_output_simple(mp, &ixas);
2326bd670b35SErik Nordmark 	ixa_cleanup(&ixas);
232773184bc7SDan McDonald 	netstack_rele(ns);
232873184bc7SDan McDonald }
232973184bc7SDan McDonald 
233073184bc7SDan McDonald /*
2331bd670b35SErik Nordmark  * Send a one-byte UDP NAT-T keepalive.
2332437220cdSdanmcd  */
2333437220cdSdanmcd void
ipsecesp_send_keepalive(ipsa_t * assoc)2334437220cdSdanmcd ipsecesp_send_keepalive(ipsa_t *assoc)
2335437220cdSdanmcd {
2336bd670b35SErik Nordmark 	mblk_t		*mp;
2337437220cdSdanmcd 	ipha_t		*ipha;
2338437220cdSdanmcd 	udpha_t		*udpha;
2339bd670b35SErik Nordmark 	netstack_t	*ns = assoc->ipsa_netstack;
2340437220cdSdanmcd 
23410c0328cdSBill Sommerfeld 	ASSERT(MUTEX_NOT_HELD(&assoc->ipsa_lock));
2342437220cdSdanmcd 
2343437220cdSdanmcd 	mp = allocb(sizeof (ipha_t) + sizeof (udpha_t) + 1, BPRI_HI);
2344437220cdSdanmcd 	if (mp == NULL)
2345437220cdSdanmcd 		return;
2346437220cdSdanmcd 	ipha = (ipha_t *)mp->b_rptr;
2347437220cdSdanmcd 	ipha->ipha_version_and_hdr_length = IP_SIMPLE_HDR_VERSION;
2348437220cdSdanmcd 	ipha->ipha_type_of_service = 0;
2349437220cdSdanmcd 	ipha->ipha_length = htons(sizeof (ipha_t) + sizeof (udpha_t) + 1);
2350437220cdSdanmcd 	/* Use the low-16 of the SPI so we have some clue where it came from. */
2351437220cdSdanmcd 	ipha->ipha_ident = *(((uint16_t *)(&assoc->ipsa_spi)) + 1);
2352437220cdSdanmcd 	ipha->ipha_fragment_offset_and_flags = 0;  /* Too small to fragment! */
2353437220cdSdanmcd 	ipha->ipha_ttl = 0xFF;
2354437220cdSdanmcd 	ipha->ipha_protocol = IPPROTO_UDP;
2355437220cdSdanmcd 	ipha->ipha_hdr_checksum = 0;
2356437220cdSdanmcd 	ipha->ipha_src = assoc->ipsa_srcaddr[0];
2357437220cdSdanmcd 	ipha->ipha_dst = assoc->ipsa_dstaddr[0];
2358437220cdSdanmcd 	udpha = (udpha_t *)(ipha + 1);
2359437220cdSdanmcd 	udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ?
2360437220cdSdanmcd 	    assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT);
2361437220cdSdanmcd 	udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ?
2362437220cdSdanmcd 	    assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT);
2363437220cdSdanmcd 	udpha->uha_length = htons(sizeof (udpha_t) + 1);
2364437220cdSdanmcd 	udpha->uha_checksum = 0;
2365437220cdSdanmcd 	mp->b_wptr = (uint8_t *)(udpha + 1);
2366437220cdSdanmcd 	*(mp->b_wptr++) = 0xFF;
2367437220cdSdanmcd 
2368bd670b35SErik Nordmark 	esp_prepare_udp(ns, mp, ipha);
2369437220cdSdanmcd 
237073184bc7SDan McDonald 	/*
237173184bc7SDan McDonald 	 * We're holding an isaf_t bucket lock, so pawn off the actual
237273184bc7SDan McDonald 	 * packet transmission to another thread.  Just in case syncq
237373184bc7SDan McDonald 	 * processing causes a same-bucket packet to be processed.
237473184bc7SDan McDonald 	 */
2375bd670b35SErik Nordmark 	mp->b_prev = (mblk_t *)(uintptr_t)ns->netstack_stackid;
2376bd670b35SErik Nordmark 
2377bd670b35SErik Nordmark 	if (taskq_dispatch(esp_taskq, actually_send_keepalive, mp,
237873184bc7SDan McDonald 	    TQ_NOSLEEP) == 0) {
237973184bc7SDan McDonald 		/* Assume no memory if taskq_dispatch() fails. */
2380bd670b35SErik Nordmark 		mp->b_prev = NULL;
2381bd670b35SErik Nordmark 		ip_drop_packet(mp, B_FALSE, NULL,
2382bd670b35SErik Nordmark 		    DROPPER(ns->netstack_ipsec, ipds_esp_nomem),
2383bd670b35SErik Nordmark 		    &ns->netstack_ipsecesp->esp_dropper);
238473184bc7SDan McDonald 	}
2385437220cdSdanmcd }
2386437220cdSdanmcd 
2387bd670b35SErik Nordmark /*
2388bd670b35SErik Nordmark  * Returns mp if successfully completed the request. Returns
2389bd670b35SErik Nordmark  * NULL if it failed (and increments InDiscards) or if it is pending.
2390bd670b35SErik Nordmark  */
2391bd670b35SErik Nordmark static mblk_t *
esp_submit_req_outbound(mblk_t * data_mp,ip_xmit_attr_t * ixa,ipsa_t * assoc,uchar_t * icv_buf,uint_t payload_len)2392bd670b35SErik Nordmark esp_submit_req_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa, ipsa_t *assoc,
2393bd670b35SErik Nordmark     uchar_t *icv_buf, uint_t payload_len)
23947c478bd9Sstevel@tonic-gate {
23957c478bd9Sstevel@tonic-gate 	uint_t auth_len;
2396bd670b35SErik Nordmark 	crypto_call_req_t call_req, *callrp;
2397bd670b35SErik Nordmark 	mblk_t *esp_mp;
2398628b0c67SMark Fenwick 	esph_t *esph_ptr;
2399bd670b35SErik Nordmark 	mblk_t *mp;
24007c478bd9Sstevel@tonic-gate 	int kef_rc = CRYPTO_FAILED;
24017c478bd9Sstevel@tonic-gate 	uint_t icv_len = assoc->ipsa_mac_len;
24027c478bd9Sstevel@tonic-gate 	crypto_ctx_template_t auth_ctx_tmpl;
2403bd670b35SErik Nordmark 	boolean_t do_auth, do_encr, force;
24047c478bd9Sstevel@tonic-gate 	uint_t iv_len = assoc->ipsa_iv_len;
24057c478bd9Sstevel@tonic-gate 	crypto_ctx_template_t encr_ctx_tmpl;
24067c478bd9Sstevel@tonic-gate 	boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
24077c478bd9Sstevel@tonic-gate 	size_t esph_offset = (is_natt ? UDPH_SIZE : 0);
2408bd670b35SErik Nordmark 	netstack_t	*ns = ixa->ixa_ipst->ips_netstack;
2409f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
2410bd670b35SErik Nordmark 	ipsec_crypto_t	*ic, icstack;
2411628b0c67SMark Fenwick 	uchar_t		*iv_ptr;
2412628b0c67SMark Fenwick 	crypto_data_t	*cd_ptr = NULL;
2413bd670b35SErik Nordmark 	ill_t		*ill = ixa->ixa_nce->nce_ill;
2414bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
24157c478bd9Sstevel@tonic-gate 
2416f4b3ec61Sdh155122 	esp3dbg(espstack, ("esp_submit_req_outbound:%s",
2417f4b3ec61Sdh155122 	    is_natt ? "natt" : "not natt"));
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 	do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
24207c478bd9Sstevel@tonic-gate 	do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
2421bd670b35SErik Nordmark 	force = (assoc->ipsa_flags & IPSA_F_ASYNC);
2422bd670b35SErik Nordmark 
2423bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST
2424bd670b35SErik Nordmark 	kef_rc = CRYPTO_SUCCESS;
2425bd670b35SErik Nordmark #else
2426bd670b35SErik Nordmark 	kef_rc = CRYPTO_FAILED;
2427bd670b35SErik Nordmark #endif
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	/*
24307c478bd9Sstevel@tonic-gate 	 * Outbound IPsec packets are of the form:
2431bd670b35SErik Nordmark 	 * [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV]
24327c478bd9Sstevel@tonic-gate 	 * unless it's NATT, then it's
2433bd670b35SErik Nordmark 	 * [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV]
24347c478bd9Sstevel@tonic-gate 	 * Get a pointer to the mblk containing the ESP header.
24357c478bd9Sstevel@tonic-gate 	 */
2436bd670b35SErik Nordmark 	ASSERT(data_mp->b_cont != NULL);
2437bd670b35SErik Nordmark 	esp_mp = data_mp->b_cont;
2438628b0c67SMark Fenwick 	esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset);
2439628b0c67SMark Fenwick 	iv_ptr = (uchar_t *)(esph_ptr + 1);
2440628b0c67SMark Fenwick 
2441628b0c67SMark Fenwick 	/*
2442628b0c67SMark Fenwick 	 * Combined mode algs need a nonce. This is setup in sadb_common_add().
2443628b0c67SMark Fenwick 	 * If for some reason we are using a SA which does not have a nonce
2444628b0c67SMark Fenwick 	 * then we must fail here.
2445628b0c67SMark Fenwick 	 */
2446628b0c67SMark Fenwick 	if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) &&
2447628b0c67SMark Fenwick 	    (assoc->ipsa_nonce == NULL)) {
2448bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, NULL,
2449628b0c67SMark Fenwick 		    DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
2450bd670b35SErik Nordmark 		return (NULL);
2451628b0c67SMark Fenwick 	}
24527c478bd9Sstevel@tonic-gate 
2453bd670b35SErik Nordmark 	if (force) {
2454bd670b35SErik Nordmark 		/* We are doing asynch; allocate mblks to hold state */
2455bd670b35SErik Nordmark 		if ((mp = ip_xmit_attr_to_mblk(ixa)) == NULL ||
2456bd670b35SErik Nordmark 		    (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
2457bd670b35SErik Nordmark 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2458bd670b35SErik Nordmark 			ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
2459bd670b35SErik Nordmark 			freemsg(data_mp);
2460bd670b35SErik Nordmark 			return (NULL);
2461bd670b35SErik Nordmark 		}
2462bd670b35SErik Nordmark 
2463bd670b35SErik Nordmark 		linkb(mp, data_mp);
2464bd670b35SErik Nordmark 		callrp = &call_req;
2465bd670b35SErik Nordmark 		ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_outbound);
2466bd670b35SErik Nordmark 	} else {
2467bd670b35SErik Nordmark 		/*
2468bd670b35SErik Nordmark 		 * If we know we are going to do sync then ipsec_crypto_t
2469bd670b35SErik Nordmark 		 * should be on the stack.
2470bd670b35SErik Nordmark 		 */
2471bd670b35SErik Nordmark 		ic = &icstack;
2472bd670b35SErik Nordmark 		bzero(ic, sizeof (*ic));
2473bd670b35SErik Nordmark 		callrp = NULL;
2474bd670b35SErik Nordmark 	}
2475bd670b35SErik Nordmark 
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	if (do_auth) {
24787c478bd9Sstevel@tonic-gate 		/* authentication context template */
24797c478bd9Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
24807c478bd9Sstevel@tonic-gate 		    auth_ctx_tmpl);
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 		/* where to store the computed mac */
2483bd670b35SErik Nordmark 		ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac,
24847c478bd9Sstevel@tonic-gate 		    icv_len, icv_buf);
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 		/* authentication starts at the ESP header */
2487a86080f9Sdanmcd 		auth_len = payload_len + iv_len + sizeof (esph_t);
24887c478bd9Sstevel@tonic-gate 		if (!do_encr) {
24897c478bd9Sstevel@tonic-gate 			/* authentication only */
24907c478bd9Sstevel@tonic-gate 			/* initialize input data argument */
2491bd670b35SErik Nordmark 			ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
24927c478bd9Sstevel@tonic-gate 			    esp_mp, esph_offset, auth_len);
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 			/* call the crypto framework */
24957c478bd9Sstevel@tonic-gate 			kef_rc = crypto_mac(&assoc->ipsa_amech,
2496bd670b35SErik Nordmark 			    &ic->ic_crypto_data,
24977c478bd9Sstevel@tonic-gate 			    &assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
2498bd670b35SErik Nordmark 			    &ic->ic_crypto_mac, callrp);
24997c478bd9Sstevel@tonic-gate 		}
25007c478bd9Sstevel@tonic-gate 	}
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	if (do_encr) {
25037c478bd9Sstevel@tonic-gate 		/* encryption context template */
25047c478bd9Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
25057c478bd9Sstevel@tonic-gate 		    encr_ctx_tmpl);
2506628b0c67SMark Fenwick 		/* Call the nonce update function. */
2507628b0c67SMark Fenwick 		(assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, payload_len,
2508bd670b35SErik Nordmark 		    iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data);
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 		if (!do_auth) {
25117c478bd9Sstevel@tonic-gate 			/* encryption only, skip mblk that contains ESP hdr */
25127c478bd9Sstevel@tonic-gate 			/* initialize input data argument */
2513bd670b35SErik Nordmark 			ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
2514bd670b35SErik Nordmark 			    esp_mp->b_cont, 0, payload_len);
25157c478bd9Sstevel@tonic-gate 
2516628b0c67SMark Fenwick 			/*
2517628b0c67SMark Fenwick 			 * For combined mode ciphers, the ciphertext is the same
2518628b0c67SMark Fenwick 			 * size as the clear text, the ICV should follow the
2519628b0c67SMark Fenwick 			 * ciphertext. To convince the kcf to allow in-line
2520628b0c67SMark Fenwick 			 * encryption, with an ICV, use ipsec_out_crypto_mac
2521628b0c67SMark Fenwick 			 * to point to the same buffer as the data. The calling
2522628b0c67SMark Fenwick 			 * function need to ensure the buffer is large enough to
2523628b0c67SMark Fenwick 			 * include the ICV.
2524628b0c67SMark Fenwick 			 *
2525628b0c67SMark Fenwick 			 * The IV is already written to the packet buffer, the
2526628b0c67SMark Fenwick 			 * nonce setup function copied it to the params struct
2527628b0c67SMark Fenwick 			 * for the cipher to use.
2528628b0c67SMark Fenwick 			 */
2529628b0c67SMark Fenwick 			if (assoc->ipsa_flags & IPSA_F_COMBINED) {
2530bd670b35SErik Nordmark 				bcopy(&ic->ic_crypto_data,
2531bd670b35SErik Nordmark 				    &ic->ic_crypto_mac,
2532628b0c67SMark Fenwick 				    sizeof (crypto_data_t));
2533bd670b35SErik Nordmark 				ic->ic_crypto_mac.cd_length =
2534628b0c67SMark Fenwick 				    payload_len + icv_len;
2535bd670b35SErik Nordmark 				cd_ptr = &ic->ic_crypto_mac;
2536628b0c67SMark Fenwick 			}
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 			/* call the crypto framework */
2539628b0c67SMark Fenwick 			kef_rc = crypto_encrypt((crypto_mechanism_t *)
2540bd670b35SErik Nordmark 			    &ic->ic_cmm, &ic->ic_crypto_data,
25417c478bd9Sstevel@tonic-gate 			    &assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
2542bd670b35SErik Nordmark 			    cd_ptr, callrp);
2543628b0c67SMark Fenwick 
25447c478bd9Sstevel@tonic-gate 		}
25457c478bd9Sstevel@tonic-gate 	}
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	if (do_auth && do_encr) {
25487c478bd9Sstevel@tonic-gate 		/*
25497c478bd9Sstevel@tonic-gate 		 * Encryption and authentication:
25507c478bd9Sstevel@tonic-gate 		 * Pass the pointer to the mblk chain starting at the ESP
25517c478bd9Sstevel@tonic-gate 		 * header to the framework. Skip the ESP header mblk
25527c478bd9Sstevel@tonic-gate 		 * for encryption, which is reflected by an encryption
25537c478bd9Sstevel@tonic-gate 		 * offset equal to the length of that mblk. Start
25547c478bd9Sstevel@tonic-gate 		 * the authentication at the ESP header, i.e. use an
25557c478bd9Sstevel@tonic-gate 		 * authentication offset of zero.
25567c478bd9Sstevel@tonic-gate 		 */
2557bd670b35SErik Nordmark 		ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data,
25587c478bd9Sstevel@tonic-gate 		    esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len);
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 		/* specify IV */
2561bd670b35SErik Nordmark 		ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 		/* call the framework */
25647c478bd9Sstevel@tonic-gate 		kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech,
25657c478bd9Sstevel@tonic-gate 		    &assoc->ipsa_amech, NULL,
25667c478bd9Sstevel@tonic-gate 		    &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey,
25677c478bd9Sstevel@tonic-gate 		    encr_ctx_tmpl, auth_ctx_tmpl,
2568bd670b35SErik Nordmark 		    &ic->ic_crypto_dual_data,
2569bd670b35SErik Nordmark 		    &ic->ic_crypto_mac, callrp);
25707c478bd9Sstevel@tonic-gate 	}
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	switch (kef_rc) {
25737c478bd9Sstevel@tonic-gate 	case CRYPTO_SUCCESS:
2574f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_sync);
2575437220cdSdanmcd 		esp_set_usetime(assoc, B_FALSE);
2576bd670b35SErik Nordmark 		if (force) {
2577bd670b35SErik Nordmark 			mp = ipsec_free_crypto_data(mp);
2578bd670b35SErik Nordmark 			data_mp = ip_xmit_attr_free_mblk(mp);
2579bd670b35SErik Nordmark 		}
2580437220cdSdanmcd 		if (is_natt)
2581bd670b35SErik Nordmark 			esp_prepare_udp(ns, data_mp, (ipha_t *)data_mp->b_rptr);
2582bd670b35SErik Nordmark 		return (data_mp);
25837c478bd9Sstevel@tonic-gate 	case CRYPTO_QUEUED:
2584bd670b35SErik Nordmark 		/* esp_kcf_callback_outbound() will be invoked on completion */
2585f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, crypto_async);
2586bd670b35SErik Nordmark 		return (NULL);
25877c478bd9Sstevel@tonic-gate 	}
25887c478bd9Sstevel@tonic-gate 
2589bd670b35SErik Nordmark 	if (force) {
2590bd670b35SErik Nordmark 		mp = ipsec_free_crypto_data(mp);
2591bd670b35SErik Nordmark 		data_mp = ip_xmit_attr_free_mblk(mp);
2592bd670b35SErik Nordmark 	}
2593bd670b35SErik Nordmark 	BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2594bd670b35SErik Nordmark 	esp_crypto_failed(data_mp, B_FALSE, kef_rc, NULL, espstack);
2595bd670b35SErik Nordmark 	/* data_mp was passed to ip_drop_packet */
2596bd670b35SErik Nordmark 	return (NULL);
25977c478bd9Sstevel@tonic-gate }
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate /*
26007c478bd9Sstevel@tonic-gate  * Handle outbound IPsec processing for IPv4 and IPv6
2601bd670b35SErik Nordmark  *
2602bd670b35SErik Nordmark  * Returns data_mp if successfully completed the request. Returns
2603bd670b35SErik Nordmark  * NULL if it failed (and increments InDiscards) or if it is pending.
26047c478bd9Sstevel@tonic-gate  */
2605bd670b35SErik Nordmark static mblk_t *
esp_outbound(mblk_t * data_mp,ip_xmit_attr_t * ixa)2606bd670b35SErik Nordmark esp_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa)
26077c478bd9Sstevel@tonic-gate {
2608bd670b35SErik Nordmark 	mblk_t *espmp, *tailmp;
26097c478bd9Sstevel@tonic-gate 	ipha_t *ipha;
26107c478bd9Sstevel@tonic-gate 	ip6_t *ip6h;
2611628b0c67SMark Fenwick 	esph_t *esph_ptr, *iv_ptr;
26127c478bd9Sstevel@tonic-gate 	uint_t af;
26137c478bd9Sstevel@tonic-gate 	uint8_t *nhp;
26147c478bd9Sstevel@tonic-gate 	uintptr_t divpoint, datalen, adj, padlen, i, alloclen;
26157c478bd9Sstevel@tonic-gate 	uintptr_t esplen = sizeof (esph_t);
26167c478bd9Sstevel@tonic-gate 	uint8_t protocol;
26177c478bd9Sstevel@tonic-gate 	ipsa_t *assoc;
2618628b0c67SMark Fenwick 	uint_t iv_len, block_size, mac_len = 0;
26197c478bd9Sstevel@tonic-gate 	uchar_t *icv_buf;
26207c478bd9Sstevel@tonic-gate 	udpha_t *udpha;
26217c478bd9Sstevel@tonic-gate 	boolean_t is_natt = B_FALSE;
2622bd670b35SErik Nordmark 	netstack_t	*ns = ixa->ixa_ipst->ips_netstack;
2623bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
2624bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
2625bd670b35SErik Nordmark 	ill_t		*ill = ixa->ixa_nce->nce_ill;
2626bd670b35SErik Nordmark 	boolean_t	need_refrele = B_FALSE;
2627f4b3ec61Sdh155122 
2628f4b3ec61Sdh155122 	ESP_BUMP_STAT(espstack, out_requests);
2629f4b3ec61Sdh155122 
26307c478bd9Sstevel@tonic-gate 	/*
26317c478bd9Sstevel@tonic-gate 	 * <sigh> We have to copy the message here, because TCP (for example)
26327c478bd9Sstevel@tonic-gate 	 * keeps a dupb() of the message lying around for retransmission.
26337c478bd9Sstevel@tonic-gate 	 * Since ESP changes the whole of the datagram, we have to create our
26347c478bd9Sstevel@tonic-gate 	 * own copy lest we clobber TCP's data.  Since we have to copy anyway,
26357c478bd9Sstevel@tonic-gate 	 * we might as well make use of msgpullup() and get the mblk into one
26367c478bd9Sstevel@tonic-gate 	 * contiguous piece!
26377c478bd9Sstevel@tonic-gate 	 */
2638bd670b35SErik Nordmark 	tailmp = msgpullup(data_mp, -1);
2639bd670b35SErik Nordmark 	if (tailmp == NULL) {
26407c478bd9Sstevel@tonic-gate 		esp0dbg(("esp_outbound: msgpullup() failed, "
26417c478bd9Sstevel@tonic-gate 		    "dropping packet.\n"));
2642bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2643f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_nomem),
2644f4b3ec61Sdh155122 		    &espstack->esp_dropper);
2645bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2646bd670b35SErik Nordmark 		return (NULL);
26477c478bd9Sstevel@tonic-gate 	}
2648bd670b35SErik Nordmark 	freemsg(data_mp);
2649bd670b35SErik Nordmark 	data_mp = tailmp;
26507c478bd9Sstevel@tonic-gate 
2651bd670b35SErik Nordmark 	assoc = ixa->ixa_ipsec_esp_sa;
26525d3b8cb7SBill Sommerfeld 	ASSERT(assoc != NULL);
26535d3b8cb7SBill Sommerfeld 
26545d3b8cb7SBill Sommerfeld 	/*
26555d3b8cb7SBill Sommerfeld 	 * Get the outer IP header in shape to escape this system..
26565d3b8cb7SBill Sommerfeld 	 */
2657bd670b35SErik Nordmark 	if (is_system_labeled() && (assoc->ipsa_otsl != NULL)) {
2658bd670b35SErik Nordmark 		/*
2659bd670b35SErik Nordmark 		 * Need to update packet with any CIPSO option and update
2660bd670b35SErik Nordmark 		 * ixa_tsl to capture the new label.
2661bd670b35SErik Nordmark 		 * We allocate a separate ixa for that purpose.
2662bd670b35SErik Nordmark 		 */
2663bd670b35SErik Nordmark 		ixa = ip_xmit_attr_duplicate(ixa);
2664bd670b35SErik Nordmark 		if (ixa == NULL) {
2665bd670b35SErik Nordmark 			ip_drop_packet(data_mp, B_FALSE, ill,
2666bd670b35SErik Nordmark 			    DROPPER(ipss, ipds_esp_nomem),
26675d3b8cb7SBill Sommerfeld 			    &espstack->esp_dropper);
2668bd670b35SErik Nordmark 			return (NULL);
26695d3b8cb7SBill Sommerfeld 		}
2670bd670b35SErik Nordmark 		need_refrele = B_TRUE;
26715d3b8cb7SBill Sommerfeld 
2672bd670b35SErik Nordmark 		label_hold(assoc->ipsa_otsl);
2673bd670b35SErik Nordmark 		ip_xmit_attr_replace_tsl(ixa, assoc->ipsa_otsl);
2674bd670b35SErik Nordmark 
2675bd670b35SErik Nordmark 		data_mp = sadb_whack_label(data_mp, assoc, ixa,
2676bd670b35SErik Nordmark 		    DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
2677bd670b35SErik Nordmark 		if (data_mp == NULL) {
2678bd670b35SErik Nordmark 			/* Packet dropped by sadb_whack_label */
2679bd670b35SErik Nordmark 			ixa_refrele(ixa);
2680bd670b35SErik Nordmark 			return (NULL);
2681bd670b35SErik Nordmark 		}
2682bd670b35SErik Nordmark 	}
26835d3b8cb7SBill Sommerfeld 
26847c478bd9Sstevel@tonic-gate 	/*
26857c478bd9Sstevel@tonic-gate 	 * Reality check....
26867c478bd9Sstevel@tonic-gate 	 */
26877c478bd9Sstevel@tonic-gate 	ipha = (ipha_t *)data_mp->b_rptr;  /* So we can call esp_acquire(). */
26887c478bd9Sstevel@tonic-gate 
2689bd670b35SErik Nordmark 	if (ixa->ixa_flags & IXAF_IS_IPV4) {
2690bd670b35SErik Nordmark 		ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
2691bd670b35SErik Nordmark 
26927c478bd9Sstevel@tonic-gate 		af = AF_INET;
26937c478bd9Sstevel@tonic-gate 		divpoint = IPH_HDR_LENGTH(ipha);
26947c478bd9Sstevel@tonic-gate 		datalen = ntohs(ipha->ipha_length) - divpoint;
26957c478bd9Sstevel@tonic-gate 		nhp = (uint8_t *)&ipha->ipha_protocol;
26967c478bd9Sstevel@tonic-gate 	} else {
2697bd670b35SErik Nordmark 		ip_pkt_t ipp;
2698bd670b35SErik Nordmark 
2699bd670b35SErik Nordmark 		ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 		af = AF_INET6;
27027c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)ipha;
27037c478bd9Sstevel@tonic-gate 		bzero(&ipp, sizeof (ipp));
2704bd670b35SErik Nordmark 		divpoint = ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp, NULL);
27057c478bd9Sstevel@tonic-gate 		if (ipp.ipp_dstopts != NULL &&
27067c478bd9Sstevel@tonic-gate 		    ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) {
27077c478bd9Sstevel@tonic-gate 			/*
27087c478bd9Sstevel@tonic-gate 			 * Destination options are tricky.  If we get in here,
27097c478bd9Sstevel@tonic-gate 			 * then we have a terminal header following the
27107c478bd9Sstevel@tonic-gate 			 * destination options.  We need to adjust backwards
27117c478bd9Sstevel@tonic-gate 			 * so we insert ESP BEFORE the destination options
27127c478bd9Sstevel@tonic-gate 			 * bag.  (So that the dstopts get encrypted!)
27137c478bd9Sstevel@tonic-gate 			 *
27147c478bd9Sstevel@tonic-gate 			 * Since this is for outbound packets only, we know
27157c478bd9Sstevel@tonic-gate 			 * that non-terminal destination options only precede
27167c478bd9Sstevel@tonic-gate 			 * routing headers.
27177c478bd9Sstevel@tonic-gate 			 */
27187c478bd9Sstevel@tonic-gate 			divpoint -= ipp.ipp_dstoptslen;
27197c478bd9Sstevel@tonic-gate 		}
27207c478bd9Sstevel@tonic-gate 		datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint;
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 		if (ipp.ipp_rthdr != NULL) {
27237c478bd9Sstevel@tonic-gate 			nhp = &ipp.ipp_rthdr->ip6r_nxt;
27247c478bd9Sstevel@tonic-gate 		} else if (ipp.ipp_hopopts != NULL) {
27257c478bd9Sstevel@tonic-gate 			nhp = &ipp.ipp_hopopts->ip6h_nxt;
27267c478bd9Sstevel@tonic-gate 		} else {
27277c478bd9Sstevel@tonic-gate 			ASSERT(divpoint == sizeof (ip6_t));
27287c478bd9Sstevel@tonic-gate 			/* It's probably IP + ESP. */
27297c478bd9Sstevel@tonic-gate 			nhp = &ip6h->ip6_nxt;
27307c478bd9Sstevel@tonic-gate 		}
27317c478bd9Sstevel@tonic-gate 	}
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	mac_len = assoc->ipsa_mac_len;
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	if (assoc->ipsa_flags & IPSA_F_NATT) {
27365d3b8cb7SBill Sommerfeld 		/* wedge in UDP header */
27377c478bd9Sstevel@tonic-gate 		is_natt = B_TRUE;
27387c478bd9Sstevel@tonic-gate 		esplen += UDPH_SIZE;
27397c478bd9Sstevel@tonic-gate 	}
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate 	/*
27427c478bd9Sstevel@tonic-gate 	 * Set up ESP header and encryption padding for ENCR PI request.
27437c478bd9Sstevel@tonic-gate 	 */
27447c478bd9Sstevel@tonic-gate 
274532350c00Sdanmcd 	/* Determine the padding length.  Pad to 4-bytes for no-encryption. */
27467c478bd9Sstevel@tonic-gate 	if (assoc->ipsa_encr_alg != SADB_EALG_NULL) {
274732350c00Sdanmcd 		iv_len = assoc->ipsa_iv_len;
2748628b0c67SMark Fenwick 		block_size = assoc->ipsa_datalen;
274932350c00Sdanmcd 
275032350c00Sdanmcd 		/*
2751628b0c67SMark Fenwick 		 * Pad the data to the length of the cipher block size.
275232350c00Sdanmcd 		 * Include the two additional bytes (hence the - 2) for the
275332350c00Sdanmcd 		 * padding length and the next header.  Take this into account
275432350c00Sdanmcd 		 * when calculating the actual length of the padding.
275532350c00Sdanmcd 		 */
275632350c00Sdanmcd 		ASSERT(ISP2(iv_len));
2757628b0c67SMark Fenwick 		padlen = ((unsigned)(block_size - datalen - 2)) &
2758628b0c67SMark Fenwick 		    (block_size - 1);
27597c478bd9Sstevel@tonic-gate 	} else {
276032350c00Sdanmcd 		iv_len = 0;
276132350c00Sdanmcd 		padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) &
276232350c00Sdanmcd 		    (sizeof (uint32_t) - 1);
27637c478bd9Sstevel@tonic-gate 	}
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	/* Allocate ESP header and IV. */
27667c478bd9Sstevel@tonic-gate 	esplen += iv_len;
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 	/*
27697c478bd9Sstevel@tonic-gate 	 * Update association byte-count lifetimes.  Don't forget to take
27707c478bd9Sstevel@tonic-gate 	 * into account the padding length and next-header (hence the + 2).
2771a86080f9Sdanmcd 	 *
27727c478bd9Sstevel@tonic-gate 	 * Use the amount of data fed into the "encryption algorithm".  This
27737c478bd9Sstevel@tonic-gate 	 * is the IV, the data length, the padding length, and the final two
27747c478bd9Sstevel@tonic-gate 	 * bytes (padlen, and next-header).
27757c478bd9Sstevel@tonic-gate 	 *
27767c478bd9Sstevel@tonic-gate 	 */
27777c478bd9Sstevel@tonic-gate 
2778a86080f9Sdanmcd 	if (!esp_age_bytes(assoc, datalen + padlen + iv_len + 2, B_FALSE)) {
2779bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2780f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_bytes_expire),
2781f4b3ec61Sdh155122 		    &espstack->esp_dropper);
2782bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2783bd670b35SErik Nordmark 		if (need_refrele)
2784bd670b35SErik Nordmark 			ixa_refrele(ixa);
2785bd670b35SErik Nordmark 		return (NULL);
27867c478bd9Sstevel@tonic-gate 	}
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate 	espmp = allocb(esplen, BPRI_HI);
27897c478bd9Sstevel@tonic-gate 	if (espmp == NULL) {
2790f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, out_discards);
2791f4b3ec61Sdh155122 		esp1dbg(espstack, ("esp_outbound: can't allocate espmp.\n"));
2792bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2793f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_nomem),
2794f4b3ec61Sdh155122 		    &espstack->esp_dropper);
2795bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2796bd670b35SErik Nordmark 		if (need_refrele)
2797bd670b35SErik Nordmark 			ixa_refrele(ixa);
2798bd670b35SErik Nordmark 		return (NULL);
27997c478bd9Sstevel@tonic-gate 	}
28007c478bd9Sstevel@tonic-gate 	espmp->b_wptr += esplen;
2801628b0c67SMark Fenwick 	esph_ptr = (esph_t *)espmp->b_rptr;
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 	if (is_natt) {
2804f4b3ec61Sdh155122 		esp3dbg(espstack, ("esp_outbound: NATT"));
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 		udpha = (udpha_t *)espmp->b_rptr;
2807437220cdSdanmcd 		udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ?
2808437220cdSdanmcd 		    assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT);
2809437220cdSdanmcd 		udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ?
2810437220cdSdanmcd 		    assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT);
28117c478bd9Sstevel@tonic-gate 		/*
2812437220cdSdanmcd 		 * Set the checksum to 0, so that the esp_prepare_udp() call
28137c478bd9Sstevel@tonic-gate 		 * can do the right thing.
28147c478bd9Sstevel@tonic-gate 		 */
28157c478bd9Sstevel@tonic-gate 		udpha->uha_checksum = 0;
2816628b0c67SMark Fenwick 		esph_ptr = (esph_t *)(udpha + 1);
28177c478bd9Sstevel@tonic-gate 	}
28187c478bd9Sstevel@tonic-gate 
2819628b0c67SMark Fenwick 	esph_ptr->esph_spi = assoc->ipsa_spi;
28207c478bd9Sstevel@tonic-gate 
2821*1a5e258fSJosef 'Jeff' Sipek 	esph_ptr->esph_replay = htonl(atomic_inc_32_nv(&assoc->ipsa_replay));
2822628b0c67SMark Fenwick 	if (esph_ptr->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) {
28237c478bd9Sstevel@tonic-gate 		/*
28247c478bd9Sstevel@tonic-gate 		 * XXX We have replay counter wrapping.
28257c478bd9Sstevel@tonic-gate 		 * We probably want to nuke this SA (and its peer).
28267c478bd9Sstevel@tonic-gate 		 */
28277c478bd9Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0,
28287c478bd9Sstevel@tonic-gate 		    SL_ERROR | SL_CONSOLE | SL_WARN,
28297c478bd9Sstevel@tonic-gate 		    "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n",
2830628b0c67SMark Fenwick 		    esph_ptr->esph_spi, assoc->ipsa_dstaddr, af,
2831f4b3ec61Sdh155122 		    espstack->ipsecesp_netstack);
28327c478bd9Sstevel@tonic-gate 
2833f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, out_discards);
28347c478bd9Sstevel@tonic-gate 		sadb_replay_delete(assoc);
2835bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2836f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_replay),
2837f4b3ec61Sdh155122 		    &espstack->esp_dropper);
2838bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2839bd670b35SErik Nordmark 		if (need_refrele)
2840bd670b35SErik Nordmark 			ixa_refrele(ixa);
2841bd670b35SErik Nordmark 		return (NULL);
28427c478bd9Sstevel@tonic-gate 	}
28437c478bd9Sstevel@tonic-gate 
2844628b0c67SMark Fenwick 	iv_ptr = (esph_ptr + 1);
28457c478bd9Sstevel@tonic-gate 	/*
2846628b0c67SMark Fenwick 	 * iv_ptr points to the mblk which will contain the IV once we have
2847628b0c67SMark Fenwick 	 * written it there. This mblk will be part of a mblk chain that
2848628b0c67SMark Fenwick 	 * will make up the packet.
2849628b0c67SMark Fenwick 	 *
2850628b0c67SMark Fenwick 	 * For counter mode algorithms, the IV is a 64 bit quantity, it
2851628b0c67SMark Fenwick 	 * must NEVER repeat in the lifetime of the SA, otherwise an
2852628b0c67SMark Fenwick 	 * attacker who had recorded enough packets might be able to
2853628b0c67SMark Fenwick 	 * determine some clear text.
2854628b0c67SMark Fenwick 	 *
2855628b0c67SMark Fenwick 	 * To ensure this does not happen, the IV is stored in the SA and
2856628b0c67SMark Fenwick 	 * incremented for each packet, the IV is then copied into the
2857628b0c67SMark Fenwick 	 * "packet" for transmission to the receiving system. The IV will
2858628b0c67SMark Fenwick 	 * also be copied into the nonce, when the packet is encrypted.
2859628b0c67SMark Fenwick 	 *
2860628b0c67SMark Fenwick 	 * CBC mode algorithms use a random IV for each packet. We do not
2861628b0c67SMark Fenwick 	 * require the highest quality random bits, but for best security
2862628b0c67SMark Fenwick 	 * with CBC mode ciphers, the value must be unlikely to repeat and
2863628b0c67SMark Fenwick 	 * must not be known in advance to an adversary capable of influencing
2864628b0c67SMark Fenwick 	 * the clear text.
28657c478bd9Sstevel@tonic-gate 	 */
2866628b0c67SMark Fenwick 	if (!update_iv((uint8_t *)iv_ptr, espstack->esp_pfkey_q, assoc,
2867628b0c67SMark Fenwick 	    espstack)) {
2868bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2869628b0c67SMark Fenwick 		    DROPPER(ipss, ipds_esp_iv_wrap), &espstack->esp_dropper);
2870bd670b35SErik Nordmark 		if (need_refrele)
2871bd670b35SErik Nordmark 			ixa_refrele(ixa);
2872bd670b35SErik Nordmark 		return (NULL);
2873628b0c67SMark Fenwick 	}
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 	/* Fix the IP header. */
28767c478bd9Sstevel@tonic-gate 	alloclen = padlen + 2 + mac_len;
28777c478bd9Sstevel@tonic-gate 	adj = alloclen + (espmp->b_wptr - espmp->b_rptr);
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	protocol = *nhp;
28807c478bd9Sstevel@tonic-gate 
2881bd670b35SErik Nordmark 	if (ixa->ixa_flags & IXAF_IS_IPV4) {
28827c478bd9Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj);
28837c478bd9Sstevel@tonic-gate 		if (is_natt) {
28847c478bd9Sstevel@tonic-gate 			*nhp = IPPROTO_UDP;
28857c478bd9Sstevel@tonic-gate 			udpha->uha_length = htons(ntohs(ipha->ipha_length) -
28867c478bd9Sstevel@tonic-gate 			    IPH_HDR_LENGTH(ipha));
28877c478bd9Sstevel@tonic-gate 		} else {
28887c478bd9Sstevel@tonic-gate 			*nhp = IPPROTO_ESP;
28897c478bd9Sstevel@tonic-gate 		}
28907c478bd9Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = 0;
28917c478bd9Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
28927c478bd9Sstevel@tonic-gate 	} else {
28937c478bd9Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj);
28947c478bd9Sstevel@tonic-gate 		*nhp = IPPROTO_ESP;
28957c478bd9Sstevel@tonic-gate 	}
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 	/* I've got the two ESP mblks, now insert them. */
28987c478bd9Sstevel@tonic-gate 
2899f4b3ec61Sdh155122 	esp2dbg(espstack, ("data_mp before outbound ESP adjustment:\n"));
2900f4b3ec61Sdh155122 	esp2dbg(espstack, (dump_msg(data_mp)));
29017c478bd9Sstevel@tonic-gate 
2902f4b3ec61Sdh155122 	if (!esp_insert_esp(data_mp, espmp, divpoint, espstack)) {
2903f4b3ec61Sdh155122 		ESP_BUMP_STAT(espstack, out_discards);
29047c478bd9Sstevel@tonic-gate 		/* NOTE:  esp_insert_esp() only fails if there's no memory. */
2905bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
2906f4b3ec61Sdh155122 		    DROPPER(ipss, ipds_esp_nomem),
2907f4b3ec61Sdh155122 		    &espstack->esp_dropper);
29087c478bd9Sstevel@tonic-gate 		freeb(espmp);
2909bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2910bd670b35SErik Nordmark 		if (need_refrele)
2911bd670b35SErik Nordmark 			ixa_refrele(ixa);
2912bd670b35SErik Nordmark 		return (NULL);
29137c478bd9Sstevel@tonic-gate 	}
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 	/* Append padding (and leave room for ICV). */
29167c478bd9Sstevel@tonic-gate 	for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont)
29177c478bd9Sstevel@tonic-gate 		;
29187c478bd9Sstevel@tonic-gate 	if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) {
29197c478bd9Sstevel@tonic-gate 		tailmp->b_cont = allocb(alloclen, BPRI_HI);
29207c478bd9Sstevel@tonic-gate 		if (tailmp->b_cont == NULL) {
2921f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, out_discards);
29227c478bd9Sstevel@tonic-gate 			esp0dbg(("esp_outbound:  Can't allocate tailmp.\n"));
2923bd670b35SErik Nordmark 			ip_drop_packet(data_mp, B_FALSE, ill,
2924f4b3ec61Sdh155122 			    DROPPER(ipss, ipds_esp_nomem),
2925f4b3ec61Sdh155122 			    &espstack->esp_dropper);
2926bd670b35SErik Nordmark 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2927bd670b35SErik Nordmark 			if (need_refrele)
2928bd670b35SErik Nordmark 				ixa_refrele(ixa);
2929bd670b35SErik Nordmark 			return (NULL);
29307c478bd9Sstevel@tonic-gate 		}
29317c478bd9Sstevel@tonic-gate 		tailmp = tailmp->b_cont;
29327c478bd9Sstevel@tonic-gate 	}
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate 	/*
29357c478bd9Sstevel@tonic-gate 	 * If there's padding, N bytes of padding must be of the form 0x1,
29367c478bd9Sstevel@tonic-gate 	 * 0x2, 0x3... 0xN.
29377c478bd9Sstevel@tonic-gate 	 */
29387c478bd9Sstevel@tonic-gate 	for (i = 0; i < padlen; ) {
29397c478bd9Sstevel@tonic-gate 		i++;
29407c478bd9Sstevel@tonic-gate 		*tailmp->b_wptr++ = i;
29417c478bd9Sstevel@tonic-gate 	}
29427c478bd9Sstevel@tonic-gate 	*tailmp->b_wptr++ = i;
29437c478bd9Sstevel@tonic-gate 	*tailmp->b_wptr++ = protocol;
29447c478bd9Sstevel@tonic-gate 
2945f4b3ec61Sdh155122 	esp2dbg(espstack, ("data_Mp before encryption:\n"));
2946f4b3ec61Sdh155122 	esp2dbg(espstack, (dump_msg(data_mp)));
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate 	/*
29497c478bd9Sstevel@tonic-gate 	 * Okay.  I've set up the pre-encryption ESP.  Let's do it!
29507c478bd9Sstevel@tonic-gate 	 */
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	if (mac_len > 0) {
29537c478bd9Sstevel@tonic-gate 		ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim);
29547c478bd9Sstevel@tonic-gate 		icv_buf = tailmp->b_wptr;
29557c478bd9Sstevel@tonic-gate 		tailmp->b_wptr += mac_len;
29567c478bd9Sstevel@tonic-gate 	} else {
29577c478bd9Sstevel@tonic-gate 		icv_buf = NULL;
29587c478bd9Sstevel@tonic-gate 	}
29597c478bd9Sstevel@tonic-gate 
2960bd670b35SErik Nordmark 	data_mp = esp_submit_req_outbound(data_mp, ixa, assoc, icv_buf,
2961bd670b35SErik Nordmark 	    datalen + padlen + 2);
2962bd670b35SErik Nordmark 	if (need_refrele)
2963bd670b35SErik Nordmark 		ixa_refrele(ixa);
2964bd670b35SErik Nordmark 	return (data_mp);
29657c478bd9Sstevel@tonic-gate }
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate /*
29687c478bd9Sstevel@tonic-gate  * IP calls this to validate the ICMP errors that
29697c478bd9Sstevel@tonic-gate  * we got from the network.
29707c478bd9Sstevel@tonic-gate  */
2971bd670b35SErik Nordmark mblk_t *
ipsecesp_icmp_error(mblk_t * data_mp,ip_recv_attr_t * ira)2972bd670b35SErik Nordmark ipsecesp_icmp_error(mblk_t *data_mp, ip_recv_attr_t *ira)
29737c478bd9Sstevel@tonic-gate {
2974bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
2975bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
2976bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
2977f4b3ec61Sdh155122 
29787c478bd9Sstevel@tonic-gate 	/*
29797c478bd9Sstevel@tonic-gate 	 * Unless we get an entire packet back, this function is useless.
29807c478bd9Sstevel@tonic-gate 	 * Why?
29817c478bd9Sstevel@tonic-gate 	 *
29827c478bd9Sstevel@tonic-gate 	 * 1.)	Partial packets are useless, because the "next header"
29837c478bd9Sstevel@tonic-gate 	 *	is at the end of the decrypted ESP packet.  Without the
29847c478bd9Sstevel@tonic-gate 	 *	whole packet, this is useless.
29857c478bd9Sstevel@tonic-gate 	 *
29867c478bd9Sstevel@tonic-gate 	 * 2.)	If we every use a stateful cipher, such as a stream or a
29877c478bd9Sstevel@tonic-gate 	 *	one-time pad, we can't do anything.
29887c478bd9Sstevel@tonic-gate 	 *
29897c478bd9Sstevel@tonic-gate 	 * Since the chances of us getting an entire packet back are very
29907c478bd9Sstevel@tonic-gate 	 * very small, we discard here.
29917c478bd9Sstevel@tonic-gate 	 */
2992f4b3ec61Sdh155122 	IP_ESP_BUMP_STAT(ipss, in_discards);
2993bd670b35SErik Nordmark 	ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
2994f4b3ec61Sdh155122 	    DROPPER(ipss, ipds_esp_icmp),
2995f4b3ec61Sdh155122 	    &espstack->esp_dropper);
2996bd670b35SErik Nordmark 	return (NULL);
29977c478bd9Sstevel@tonic-gate }
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate /*
30007c478bd9Sstevel@tonic-gate  * Construct an SADB_REGISTER message with the current algorithms.
3001628b0c67SMark Fenwick  * This function gets called when 'ipsecalgs -s' is run or when
3002628b0c67SMark Fenwick  * in.iked (or other KMD) starts.
30037c478bd9Sstevel@tonic-gate  */
30047c478bd9Sstevel@tonic-gate static boolean_t
esp_register_out(uint32_t sequence,uint32_t pid,uint_t serial,ipsecesp_stack_t * espstack,cred_t * cr)3005f4b3ec61Sdh155122 esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
3006bd670b35SErik Nordmark     ipsecesp_stack_t *espstack, cred_t *cr)
30077c478bd9Sstevel@tonic-gate {
30087c478bd9Sstevel@tonic-gate 	mblk_t *pfkey_msg_mp, *keysock_out_mp;
30097c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
30107c478bd9Sstevel@tonic-gate 	sadb_supported_t *sasupp_auth = NULL;
30117c478bd9Sstevel@tonic-gate 	sadb_supported_t *sasupp_encr = NULL;
30127c478bd9Sstevel@tonic-gate 	sadb_alg_t *saalg;
30137c478bd9Sstevel@tonic-gate 	uint_t allocsize = sizeof (*samsg);
30147c478bd9Sstevel@tonic-gate 	uint_t i, numalgs_snap;
30157c478bd9Sstevel@tonic-gate 	int current_aalgs;
30167c478bd9Sstevel@tonic-gate 	ipsec_alginfo_t **authalgs;
30177c478bd9Sstevel@tonic-gate 	uint_t num_aalgs;
30187c478bd9Sstevel@tonic-gate 	int current_ealgs;
30197c478bd9Sstevel@tonic-gate 	ipsec_alginfo_t **encralgs;
30207c478bd9Sstevel@tonic-gate 	uint_t num_ealgs;
3021f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
30225d3b8cb7SBill Sommerfeld 	sadb_sens_t *sens;
30235d3b8cb7SBill Sommerfeld 	size_t sens_len = 0;
30245d3b8cb7SBill Sommerfeld 	sadb_ext_t *nextext;
3025bd670b35SErik Nordmark 	ts_label_t *sens_tsl = NULL;
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	/* Allocate the KEYSOCK_OUT. */
30287c478bd9Sstevel@tonic-gate 	keysock_out_mp = sadb_keysock_out(serial);
30297c478bd9Sstevel@tonic-gate 	if (keysock_out_mp == NULL) {
30307c478bd9Sstevel@tonic-gate 		esp0dbg(("esp_register_out: couldn't allocate mblk.\n"));
30317c478bd9Sstevel@tonic-gate 		return (B_FALSE);
30327c478bd9Sstevel@tonic-gate 	}
30337c478bd9Sstevel@tonic-gate 
3034bd670b35SErik Nordmark 	if (is_system_labeled() && (cr != NULL)) {
3035bd670b35SErik Nordmark 		sens_tsl = crgetlabel(cr);
3036bd670b35SErik Nordmark 		if (sens_tsl != NULL) {
3037bd670b35SErik Nordmark 			sens_len = sadb_sens_len_from_label(sens_tsl);
30385d3b8cb7SBill Sommerfeld 			allocsize += sens_len;
30395d3b8cb7SBill Sommerfeld 		}
30405d3b8cb7SBill Sommerfeld 	}
30415d3b8cb7SBill Sommerfeld 
30427c478bd9Sstevel@tonic-gate 	/*
30437c478bd9Sstevel@tonic-gate 	 * Allocate the PF_KEY message that follows KEYSOCK_OUT.
30447c478bd9Sstevel@tonic-gate 	 */
30457c478bd9Sstevel@tonic-gate 
3046f4b3ec61Sdh155122 	mutex_enter(&ipss->ipsec_alg_lock);
30477c478bd9Sstevel@tonic-gate 	/*
30487c478bd9Sstevel@tonic-gate 	 * Fill SADB_REGISTER message's algorithm descriptors.  Hold
30497c478bd9Sstevel@tonic-gate 	 * down the lock while filling it.
30507c478bd9Sstevel@tonic-gate 	 *
30517c478bd9Sstevel@tonic-gate 	 * Return only valid algorithms, so the number of algorithms
30527c478bd9Sstevel@tonic-gate 	 * to send up may be less than the number of algorithm entries
30537c478bd9Sstevel@tonic-gate 	 * in the table.
30547c478bd9Sstevel@tonic-gate 	 */
3055f4b3ec61Sdh155122 	authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
30567c478bd9Sstevel@tonic-gate 	for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
30577c478bd9Sstevel@tonic-gate 		if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
30587c478bd9Sstevel@tonic-gate 			num_aalgs++;
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 	if (num_aalgs != 0) {
30617c478bd9Sstevel@tonic-gate 		allocsize += (num_aalgs * sizeof (*saalg));
30627c478bd9Sstevel@tonic-gate 		allocsize += sizeof (*sasupp_auth);
30637c478bd9Sstevel@tonic-gate 	}
3064f4b3ec61Sdh155122 	encralgs = ipss->ipsec_alglists[IPSEC_ALG_ENCR];
30657c478bd9Sstevel@tonic-gate 	for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
30667c478bd9Sstevel@tonic-gate 		if (encralgs[i] != NULL && ALG_VALID(encralgs[i]))
30677c478bd9Sstevel@tonic-gate 			num_ealgs++;
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate 	if (num_ealgs != 0) {
30707c478bd9Sstevel@tonic-gate 		allocsize += (num_ealgs * sizeof (*saalg));
30717c478bd9Sstevel@tonic-gate 		allocsize += sizeof (*sasupp_encr);
30727c478bd9Sstevel@tonic-gate 	}
30737c478bd9Sstevel@tonic-gate 	keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI);
30747c478bd9Sstevel@tonic-gate 	if (keysock_out_mp->b_cont == NULL) {
3075f4b3ec61Sdh155122 		mutex_exit(&ipss->ipsec_alg_lock);
30767c478bd9Sstevel@tonic-gate 		freemsg(keysock_out_mp);
30777c478bd9Sstevel@tonic-gate 		return (B_FALSE);
30787c478bd9Sstevel@tonic-gate 	}
30797c478bd9Sstevel@tonic-gate 	pfkey_msg_mp = keysock_out_mp->b_cont;
30807c478bd9Sstevel@tonic-gate 	pfkey_msg_mp->b_wptr += allocsize;
30815d3b8cb7SBill Sommerfeld 
30825d3b8cb7SBill Sommerfeld 	nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
30835d3b8cb7SBill Sommerfeld 
30847c478bd9Sstevel@tonic-gate 	if (num_aalgs != 0) {
30855d3b8cb7SBill Sommerfeld 		sasupp_auth = (sadb_supported_t *)nextext;
30867c478bd9Sstevel@tonic-gate 		saalg = (sadb_alg_t *)(sasupp_auth + 1);
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 		ASSERT(((ulong_t)saalg & 0x7) == 0);
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 		numalgs_snap = 0;
30917c478bd9Sstevel@tonic-gate 		for (i = 0;
3092f4b3ec61Sdh155122 		    ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs));
3093f4b3ec61Sdh155122 		    i++) {
30947c478bd9Sstevel@tonic-gate 			if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
30957c478bd9Sstevel@tonic-gate 				continue;
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_id = authalgs[i]->alg_id;
30987c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_ivlen = 0;
30997c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_minbits	= authalgs[i]->alg_ef_minbits;
31007c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_maxbits	= authalgs[i]->alg_ef_maxbits;
31017c478bd9Sstevel@tonic-gate 			saalg->sadb_x_alg_increment =
31027c478bd9Sstevel@tonic-gate 			    authalgs[i]->alg_increment;
3103628b0c67SMark Fenwick 			saalg->sadb_x_alg_saltbits = SADB_8TO1(
3104628b0c67SMark Fenwick 			    authalgs[i]->alg_saltlen);
31057c478bd9Sstevel@tonic-gate 			numalgs_snap++;
31067c478bd9Sstevel@tonic-gate 			saalg++;
31077c478bd9Sstevel@tonic-gate 		}
31087c478bd9Sstevel@tonic-gate 		ASSERT(numalgs_snap == num_aalgs);
31097c478bd9Sstevel@tonic-gate #ifdef DEBUG
31107c478bd9Sstevel@tonic-gate 		/*
31117c478bd9Sstevel@tonic-gate 		 * Reality check to make sure I snagged all of the
31127c478bd9Sstevel@tonic-gate 		 * algorithms.
31137c478bd9Sstevel@tonic-gate 		 */
31147c478bd9Sstevel@tonic-gate 		for (; i < IPSEC_MAX_ALGS; i++) {
31157c478bd9Sstevel@tonic-gate 			if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) {
31167c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC, "esp_register_out()! "
31177c478bd9Sstevel@tonic-gate 				    "Missed aalg #%d.\n", i);
31187c478bd9Sstevel@tonic-gate 			}
31197c478bd9Sstevel@tonic-gate 		}
31207c478bd9Sstevel@tonic-gate #endif /* DEBUG */
31215d3b8cb7SBill Sommerfeld 		nextext = (sadb_ext_t *)saalg;
31227c478bd9Sstevel@tonic-gate 	}
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate 	if (num_ealgs != 0) {
31255d3b8cb7SBill Sommerfeld 		sasupp_encr = (sadb_supported_t *)nextext;
31267c478bd9Sstevel@tonic-gate 		saalg = (sadb_alg_t *)(sasupp_encr + 1);
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate 		numalgs_snap = 0;
31297c478bd9Sstevel@tonic-gate 		for (i = 0;
31307c478bd9Sstevel@tonic-gate 		    ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) {
31317c478bd9Sstevel@tonic-gate 			if (encralgs[i] == NULL || !ALG_VALID(encralgs[i]))
31327c478bd9Sstevel@tonic-gate 				continue;
31337c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_id = encralgs[i]->alg_id;
3134628b0c67SMark Fenwick 			saalg->sadb_alg_ivlen = encralgs[i]->alg_ivlen;
31357c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_minbits	= encralgs[i]->alg_ef_minbits;
31367c478bd9Sstevel@tonic-gate 			saalg->sadb_alg_maxbits	= encralgs[i]->alg_ef_maxbits;
3137628b0c67SMark Fenwick 			/*
3138628b0c67SMark Fenwick 			 * We could advertise the ICV length, except there
3139628b0c67SMark Fenwick 			 * is not a value in sadb_x_algb to do this.
3140628b0c67SMark Fenwick 			 * saalg->sadb_alg_maclen = encralgs[i]->alg_maclen;
3141628b0c67SMark Fenwick 			 */
31427c478bd9Sstevel@tonic-gate 			saalg->sadb_x_alg_increment =
31437c478bd9Sstevel@tonic-gate 			    encralgs[i]->alg_increment;
3144628b0c67SMark Fenwick 			saalg->sadb_x_alg_saltbits =
3145628b0c67SMark Fenwick 			    SADB_8TO1(encralgs[i]->alg_saltlen);
3146628b0c67SMark Fenwick 
31477c478bd9Sstevel@tonic-gate 			numalgs_snap++;
31487c478bd9Sstevel@tonic-gate 			saalg++;
31497c478bd9Sstevel@tonic-gate 		}
31507c478bd9Sstevel@tonic-gate 		ASSERT(numalgs_snap == num_ealgs);
31517c478bd9Sstevel@tonic-gate #ifdef DEBUG
31527c478bd9Sstevel@tonic-gate 		/*
31537c478bd9Sstevel@tonic-gate 		 * Reality check to make sure I snagged all of the
31547c478bd9Sstevel@tonic-gate 		 * algorithms.
31557c478bd9Sstevel@tonic-gate 		 */
31567c478bd9Sstevel@tonic-gate 		for (; i < IPSEC_MAX_ALGS; i++) {
31577c478bd9Sstevel@tonic-gate 			if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) {
31587c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC, "esp_register_out()! "
31597c478bd9Sstevel@tonic-gate 				    "Missed ealg #%d.\n", i);
31607c478bd9Sstevel@tonic-gate 			}
31617c478bd9Sstevel@tonic-gate 		}
31627c478bd9Sstevel@tonic-gate #endif /* DEBUG */
31635d3b8cb7SBill Sommerfeld 		nextext = (sadb_ext_t *)saalg;
31647c478bd9Sstevel@tonic-gate 	}
31657c478bd9Sstevel@tonic-gate 
31667c478bd9Sstevel@tonic-gate 	current_aalgs = num_aalgs;
31677c478bd9Sstevel@tonic-gate 	current_ealgs = num_ealgs;
31687c478bd9Sstevel@tonic-gate 
3169f4b3ec61Sdh155122 	mutex_exit(&ipss->ipsec_alg_lock);
31707c478bd9Sstevel@tonic-gate 
3171bd670b35SErik Nordmark 	if (sens_tsl != NULL) {
31725d3b8cb7SBill Sommerfeld 		sens = (sadb_sens_t *)nextext;
3173bd670b35SErik Nordmark 		sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
3174bd670b35SErik Nordmark 		    sens_tsl, sens_len);
31755d3b8cb7SBill Sommerfeld 
31765d3b8cb7SBill Sommerfeld 		nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
31775d3b8cb7SBill Sommerfeld 	}
31785d3b8cb7SBill Sommerfeld 
31797c478bd9Sstevel@tonic-gate 	/* Now fill the rest of the SADB_REGISTER message. */
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate 	samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
31827c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_version = PF_KEY_V2;
31837c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_type = SADB_REGISTER;
31847c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_errno = 0;
31857c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_satype = SADB_SATYPE_ESP;
31867c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_len = SADB_8TO64(allocsize);
31877c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_reserved = 0;
31887c478bd9Sstevel@tonic-gate 	/*
31897c478bd9Sstevel@tonic-gate 	 * Assume caller has sufficient sequence/pid number info.  If it's one
31907c478bd9Sstevel@tonic-gate 	 * from me over a new alg., I could give two hoots about sequence.
31917c478bd9Sstevel@tonic-gate 	 */
31927c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_seq = sequence;
31937c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_pid = pid;
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	if (sasupp_auth != NULL) {
3196437220cdSdanmcd 		sasupp_auth->sadb_supported_len = SADB_8TO64(
3197437220cdSdanmcd 		    sizeof (*sasupp_auth) + sizeof (*saalg) * current_aalgs);
31987c478bd9Sstevel@tonic-gate 		sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
31997c478bd9Sstevel@tonic-gate 		sasupp_auth->sadb_supported_reserved = 0;
32007c478bd9Sstevel@tonic-gate 	}
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 	if (sasupp_encr != NULL) {
3203437220cdSdanmcd 		sasupp_encr->sadb_supported_len = SADB_8TO64(
3204437220cdSdanmcd 		    sizeof (*sasupp_encr) + sizeof (*saalg) * current_ealgs);
32057c478bd9Sstevel@tonic-gate 		sasupp_encr->sadb_supported_exttype =
32067c478bd9Sstevel@tonic-gate 		    SADB_EXT_SUPPORTED_ENCRYPT;
32077c478bd9Sstevel@tonic-gate 		sasupp_encr->sadb_supported_reserved = 0;
32087c478bd9Sstevel@tonic-gate 	}
32097c478bd9Sstevel@tonic-gate 
3210f4b3ec61Sdh155122 	if (espstack->esp_pfkey_q != NULL)
3211f4b3ec61Sdh155122 		putnext(espstack->esp_pfkey_q, keysock_out_mp);
32127c478bd9Sstevel@tonic-gate 	else {
32137c478bd9Sstevel@tonic-gate 		freemsg(keysock_out_mp);
32147c478bd9Sstevel@tonic-gate 		return (B_FALSE);
32157c478bd9Sstevel@tonic-gate 	}
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	return (B_TRUE);
32187c478bd9Sstevel@tonic-gate }
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate /*
32217c478bd9Sstevel@tonic-gate  * Invoked when the algorithm table changes. Causes SADB_REGISTER
32227c478bd9Sstevel@tonic-gate  * messages continaining the current list of algorithms to be
32237c478bd9Sstevel@tonic-gate  * sent up to the ESP listeners.
32247c478bd9Sstevel@tonic-gate  */
32257c478bd9Sstevel@tonic-gate void
ipsecesp_algs_changed(netstack_t * ns)3226f4b3ec61Sdh155122 ipsecesp_algs_changed(netstack_t *ns)
32277c478bd9Sstevel@tonic-gate {
3228f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = ns->netstack_ipsecesp;
3229f4b3ec61Sdh155122 
32307c478bd9Sstevel@tonic-gate 	/*
32317c478bd9Sstevel@tonic-gate 	 * Time to send a PF_KEY SADB_REGISTER message to ESP listeners
32327c478bd9Sstevel@tonic-gate 	 * everywhere.  (The function itself checks for NULL esp_pfkey_q.)
32337c478bd9Sstevel@tonic-gate 	 */
32345d3b8cb7SBill Sommerfeld 	(void) esp_register_out(0, 0, 0, espstack, NULL);
32357c478bd9Sstevel@tonic-gate }
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate /*
323873184bc7SDan McDonald  * Stub function that taskq_dispatch() invokes to take the mblk (in arg)
3239bd670b35SErik Nordmark  * and send() it into ESP and IP again.
32407c478bd9Sstevel@tonic-gate  */
32417c478bd9Sstevel@tonic-gate static void
inbound_task(void * arg)32427c478bd9Sstevel@tonic-gate inbound_task(void *arg)
32437c478bd9Sstevel@tonic-gate {
32447c478bd9Sstevel@tonic-gate 	mblk_t		*mp = (mblk_t *)arg;
3245bd670b35SErik Nordmark 	mblk_t		*async_mp;
3246bd670b35SErik Nordmark 	ip_recv_attr_t	iras;
32477c478bd9Sstevel@tonic-gate 
3248bd670b35SErik Nordmark 	async_mp = mp;
3249bd670b35SErik Nordmark 	mp = async_mp->b_cont;
3250bd670b35SErik Nordmark 	async_mp->b_cont = NULL;
3251bd670b35SErik Nordmark 	if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
3252bd670b35SErik Nordmark 		/* The ill or ip_stack_t disappeared on us */
3253bd670b35SErik Nordmark 		ip_drop_input("ip_recv_attr_from_mblk", mp, NULL);
325473184bc7SDan McDonald 		freemsg(mp);
3255bd670b35SErik Nordmark 		goto done;
325673184bc7SDan McDonald 	}
325773184bc7SDan McDonald 
3258bd670b35SErik Nordmark 	esp_inbound_restart(mp, &iras);
3259bd670b35SErik Nordmark done:
3260bd670b35SErik Nordmark 	ira_cleanup(&iras, B_TRUE);
3261bd670b35SErik Nordmark }
3262bd670b35SErik Nordmark 
3263bd670b35SErik Nordmark /*
3264bd670b35SErik Nordmark  * Restart ESP after the SA has been added.
3265bd670b35SErik Nordmark  */
3266bd670b35SErik Nordmark static void
esp_inbound_restart(mblk_t * mp,ip_recv_attr_t * ira)3267bd670b35SErik Nordmark esp_inbound_restart(mblk_t *mp, ip_recv_attr_t *ira)
3268bd670b35SErik Nordmark {
3269bd670b35SErik Nordmark 	esph_t		*esph;
3270bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
3271bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
327273184bc7SDan McDonald 
3273f4b3ec61Sdh155122 	esp2dbg(espstack, ("in ESP inbound_task"));
3274f4b3ec61Sdh155122 	ASSERT(espstack != NULL);
32757c478bd9Sstevel@tonic-gate 
3276bd670b35SErik Nordmark 	mp = ipsec_inbound_esp_sa(mp, ira, &esph);
3277bd670b35SErik Nordmark 	if (mp == NULL)
3278bd670b35SErik Nordmark 		return;
3279bd670b35SErik Nordmark 
3280bd670b35SErik Nordmark 	ASSERT(esph != NULL);
3281bd670b35SErik Nordmark 	ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE);
3282bd670b35SErik Nordmark 	ASSERT(ira->ira_ipsec_esp_sa != NULL);
3283bd670b35SErik Nordmark 
3284bd670b35SErik Nordmark 	mp = ira->ira_ipsec_esp_sa->ipsa_input_func(mp, esph, ira);
3285bd670b35SErik Nordmark 	if (mp == NULL) {
3286bd670b35SErik Nordmark 		/*
3287bd670b35SErik Nordmark 		 * Either it failed or is pending. In the former case
3288bd670b35SErik Nordmark 		 * ipIfStatsInDiscards was increased.
3289bd670b35SErik Nordmark 		 */
3290bd670b35SErik Nordmark 		return;
32917c478bd9Sstevel@tonic-gate 	}
3292bd670b35SErik Nordmark 
3293bd670b35SErik Nordmark 	ip_input_post_ipsec(mp, ira);
329473184bc7SDan McDonald }
32957c478bd9Sstevel@tonic-gate 
32967c478bd9Sstevel@tonic-gate /*
32977c478bd9Sstevel@tonic-gate  * Now that weak-key passed, actually ADD the security association, and
32987c478bd9Sstevel@tonic-gate  * send back a reply ADD message.
32997c478bd9Sstevel@tonic-gate  */
33007c478bd9Sstevel@tonic-gate static int
esp_add_sa_finish(mblk_t * mp,sadb_msg_t * samsg,keysock_in_t * ksi,int * diagnostic,ipsecesp_stack_t * espstack)33018810c16bSdanmcd esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
3302f4b3ec61Sdh155122     int *diagnostic, ipsecesp_stack_t *espstack)
33037c478bd9Sstevel@tonic-gate {
33045d3b8cb7SBill Sommerfeld 	isaf_t *primary = NULL, *secondary;
33055d3b8cb7SBill Sommerfeld 	boolean_t clone = B_FALSE, is_inbound = B_FALSE;
33067c478bd9Sstevel@tonic-gate 	ipsa_t *larval = NULL;
33077c478bd9Sstevel@tonic-gate 	ipsacq_t *acqrec;
33087c478bd9Sstevel@tonic-gate 	iacqf_t *acq_bucket;
33097c478bd9Sstevel@tonic-gate 	mblk_t *acq_msgs = NULL;
33107c478bd9Sstevel@tonic-gate 	int rc;
33117c478bd9Sstevel@tonic-gate 	mblk_t *lpkt;
33125d3b8cb7SBill Sommerfeld 	int error;
33135d3b8cb7SBill Sommerfeld 	ipsa_query_t sq;
3314f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = espstack->ipsecesp_netstack->netstack_ipsec;
33157c478bd9Sstevel@tonic-gate 
33167c478bd9Sstevel@tonic-gate 	/*
33177c478bd9Sstevel@tonic-gate 	 * Locate the appropriate table(s).
33187c478bd9Sstevel@tonic-gate 	 */
33195d3b8cb7SBill Sommerfeld 	sq.spp = &espstack->esp_sadb;	/* XXX */
33205d3b8cb7SBill Sommerfeld 	error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
33215d3b8cb7SBill Sommerfeld 	    IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
33225d3b8cb7SBill Sommerfeld 	    &sq, diagnostic);
33235d3b8cb7SBill Sommerfeld 	if (error)
33245d3b8cb7SBill Sommerfeld 		return (error);
332507b56925Ssommerfe 
332638d95a78Smarkfen 	/*
332738d95a78Smarkfen 	 * Use the direction flags provided by the KMD to determine
332838d95a78Smarkfen 	 * if the inbound or outbound table should be the primary
332938d95a78Smarkfen 	 * for this SA. If these flags were absent then make this
333038d95a78Smarkfen 	 * decision based on the addresses.
333138d95a78Smarkfen 	 */
33325d3b8cb7SBill Sommerfeld 	if (sq.assoc->sadb_sa_flags & IPSA_F_INBOUND) {
33335d3b8cb7SBill Sommerfeld 		primary = sq.inbound;
33345d3b8cb7SBill Sommerfeld 		secondary = sq.outbound;
333538d95a78Smarkfen 		is_inbound = B_TRUE;
33365d3b8cb7SBill Sommerfeld 		if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
333738d95a78Smarkfen 			clone = B_TRUE;
33385d3b8cb7SBill Sommerfeld 	} else if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
33395d3b8cb7SBill Sommerfeld 		primary = sq.outbound;
33405d3b8cb7SBill Sommerfeld 		secondary = sq.inbound;
334138d95a78Smarkfen 	}
334238d95a78Smarkfen 
334338d95a78Smarkfen 	if (primary == NULL) {
334438d95a78Smarkfen 		/*
334538d95a78Smarkfen 		 * The KMD did not set a direction flag, determine which
334638d95a78Smarkfen 		 * table to insert the SA into based on addresses.
334738d95a78Smarkfen 		 */
33487c478bd9Sstevel@tonic-gate 		switch (ksi->ks_in_dsttype) {
33497c478bd9Sstevel@tonic-gate 		case KS_IN_ADDR_MBCAST:
33507c478bd9Sstevel@tonic-gate 			clone = B_TRUE;	/* All mcast SAs can be bidirectional */
33515d3b8cb7SBill Sommerfeld 			sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
33527c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
33537c478bd9Sstevel@tonic-gate 		/*
33547c478bd9Sstevel@tonic-gate 		 * If the source address is either one of mine, or unspecified
33557c478bd9Sstevel@tonic-gate 		 * (which is best summed up by saying "not 'not mine'"),
33567c478bd9Sstevel@tonic-gate 		 * then the association is potentially bi-directional,
33577c478bd9Sstevel@tonic-gate 		 * in that it can be used for inbound traffic and outbound
33587c478bd9Sstevel@tonic-gate 		 * traffic.  The best example of such an SA is a multicast
33597c478bd9Sstevel@tonic-gate 		 * SA (which allows me to receive the outbound traffic).
33607c478bd9Sstevel@tonic-gate 		 */
336138d95a78Smarkfen 		case KS_IN_ADDR_ME:
33625d3b8cb7SBill Sommerfeld 			sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
33635d3b8cb7SBill Sommerfeld 			primary = sq.inbound;
33645d3b8cb7SBill Sommerfeld 			secondary = sq.outbound;
33657c478bd9Sstevel@tonic-gate 			if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
33667c478bd9Sstevel@tonic-gate 				clone = B_TRUE;
33677c478bd9Sstevel@tonic-gate 			is_inbound = B_TRUE;
33687c478bd9Sstevel@tonic-gate 			break;
33697c478bd9Sstevel@tonic-gate 		/*
33707c478bd9Sstevel@tonic-gate 		 * If the source address literally not mine (either
33717c478bd9Sstevel@tonic-gate 		 * unspecified or not mine), then this SA may have an
33727c478bd9Sstevel@tonic-gate 		 * address that WILL be mine after some configuration.
33737c478bd9Sstevel@tonic-gate 		 * We pay the price for this by making it a bi-directional
33747c478bd9Sstevel@tonic-gate 		 * SA.
33757c478bd9Sstevel@tonic-gate 		 */
337638d95a78Smarkfen 		case KS_IN_ADDR_NOTME:
33775d3b8cb7SBill Sommerfeld 			sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
33785d3b8cb7SBill Sommerfeld 			primary = sq.outbound;
33795d3b8cb7SBill Sommerfeld 			secondary = sq.inbound;
338038d95a78Smarkfen 			if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
33815d3b8cb7SBill Sommerfeld 				sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
33827c478bd9Sstevel@tonic-gate 				clone = B_TRUE;
338338d95a78Smarkfen 			}
33847c478bd9Sstevel@tonic-gate 			break;
33857c478bd9Sstevel@tonic-gate 		default:
33868810c16bSdanmcd 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
33877c478bd9Sstevel@tonic-gate 			return (EINVAL);
33887c478bd9Sstevel@tonic-gate 		}
338938d95a78Smarkfen 	}
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate 	/*
33927c478bd9Sstevel@tonic-gate 	 * Find a ACQUIRE list entry if possible.  If we've added an SA that
33937c478bd9Sstevel@tonic-gate 	 * suits the needs of an ACQUIRE list entry, we can eliminate the
33947c478bd9Sstevel@tonic-gate 	 * ACQUIRE list entry and transmit the enqueued packets.  Use the
33957c478bd9Sstevel@tonic-gate 	 * high-bit of the sequence number to queue it.  Key off destination
33967c478bd9Sstevel@tonic-gate 	 * addr, and change acqrec's state.
33977c478bd9Sstevel@tonic-gate 	 */
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate 	if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
34005d3b8cb7SBill Sommerfeld 		acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
34017c478bd9Sstevel@tonic-gate 		mutex_enter(&acq_bucket->iacqf_lock);
34027c478bd9Sstevel@tonic-gate 		for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
34037c478bd9Sstevel@tonic-gate 		    acqrec = acqrec->ipsacq_next) {
34047c478bd9Sstevel@tonic-gate 			mutex_enter(&acqrec->ipsacq_lock);
34057c478bd9Sstevel@tonic-gate 			/*
34067c478bd9Sstevel@tonic-gate 			 * Q:  I only check sequence.  Should I check dst?
34077c478bd9Sstevel@tonic-gate 			 * A: Yes, check dest because those are the packets
34087c478bd9Sstevel@tonic-gate 			 *    that are queued up.
34097c478bd9Sstevel@tonic-gate 			 */
34107c478bd9Sstevel@tonic-gate 			if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
34115d3b8cb7SBill Sommerfeld 			    IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
34127c478bd9Sstevel@tonic-gate 			    acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
34137c478bd9Sstevel@tonic-gate 				break;
34147c478bd9Sstevel@tonic-gate 			mutex_exit(&acqrec->ipsacq_lock);
34157c478bd9Sstevel@tonic-gate 		}
34167c478bd9Sstevel@tonic-gate 		if (acqrec != NULL) {
34177c478bd9Sstevel@tonic-gate 			/*
34187c478bd9Sstevel@tonic-gate 			 * AHA!  I found an ACQUIRE record for this SA.
34197c478bd9Sstevel@tonic-gate 			 * Grab the msg list, and free the acquire record.
34207c478bd9Sstevel@tonic-gate 			 * I already am holding the lock for this record,
34217c478bd9Sstevel@tonic-gate 			 * so all I have to do is free it.
34227c478bd9Sstevel@tonic-gate 			 */
34237c478bd9Sstevel@tonic-gate 			acq_msgs = acqrec->ipsacq_mp;
34247c478bd9Sstevel@tonic-gate 			acqrec->ipsacq_mp = NULL;
34257c478bd9Sstevel@tonic-gate 			mutex_exit(&acqrec->ipsacq_lock);
3426f4b3ec61Sdh155122 			sadb_destroy_acquire(acqrec,
3427f4b3ec61Sdh155122 			    espstack->ipsecesp_netstack);
34287c478bd9Sstevel@tonic-gate 		}
34297c478bd9Sstevel@tonic-gate 		mutex_exit(&acq_bucket->iacqf_lock);
34307c478bd9Sstevel@tonic-gate 	}
34317c478bd9Sstevel@tonic-gate 
34327c478bd9Sstevel@tonic-gate 	/*
34337c478bd9Sstevel@tonic-gate 	 * Find PF_KEY message, and see if I'm an update.  If so, find entry
34347c478bd9Sstevel@tonic-gate 	 * in larval list (if there).
34357c478bd9Sstevel@tonic-gate 	 */
34367c478bd9Sstevel@tonic-gate 	if (samsg->sadb_msg_type == SADB_UPDATE) {
34375d3b8cb7SBill Sommerfeld 		mutex_enter(&sq.inbound->isaf_lock);
34385d3b8cb7SBill Sommerfeld 		larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
34395d3b8cb7SBill Sommerfeld 		    ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
34405d3b8cb7SBill Sommerfeld 		mutex_exit(&sq.inbound->isaf_lock);
34417c478bd9Sstevel@tonic-gate 
344272bd9b6bSdanmcd 		if ((larval == NULL) ||
344372bd9b6bSdanmcd 		    (larval->ipsa_state != IPSA_STATE_LARVAL)) {
344438d95a78Smarkfen 			*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
344572bd9b6bSdanmcd 			if (larval != NULL) {
344672bd9b6bSdanmcd 				IPSA_REFRELE(larval);
344772bd9b6bSdanmcd 			}
34487c478bd9Sstevel@tonic-gate 			esp0dbg(("Larval update, but larval disappeared.\n"));
34497c478bd9Sstevel@tonic-gate 			return (ESRCH);
34507c478bd9Sstevel@tonic-gate 		} /* Else sadb_common_add unlinks it for me! */
34517c478bd9Sstevel@tonic-gate 	}
34527c478bd9Sstevel@tonic-gate 
3453930af642SDan McDonald 	if (larval != NULL) {
3454930af642SDan McDonald 		/*
3455930af642SDan McDonald 		 * Hold again, because sadb_common_add() consumes a reference,
3456930af642SDan McDonald 		 * and we don't want to clear_lpkt() without a reference.
3457930af642SDan McDonald 		 */
3458930af642SDan McDonald 		IPSA_REFHOLD(larval);
3459930af642SDan McDonald 	}
34607c478bd9Sstevel@tonic-gate 
3461bd670b35SErik Nordmark 	rc = sadb_common_add(espstack->esp_pfkey_q,
3462f4b3ec61Sdh155122 	    mp, samsg, ksi, primary, secondary, larval, clone, is_inbound,
346338d95a78Smarkfen 	    diagnostic, espstack->ipsecesp_netstack, &espstack->esp_sadb);
34647c478bd9Sstevel@tonic-gate 
3465930af642SDan McDonald 	if (larval != NULL) {
3466bd670b35SErik Nordmark 		if (rc == 0) {
3467930af642SDan McDonald 			lpkt = sadb_clear_lpkt(larval);
3468930af642SDan McDonald 			if (lpkt != NULL) {
3469bd670b35SErik Nordmark 				rc = !taskq_dispatch(esp_taskq, inbound_task,
3470bd670b35SErik Nordmark 				    lpkt, TQ_NOSLEEP);
3471bd670b35SErik Nordmark 			}
34727c478bd9Sstevel@tonic-gate 		}
3473930af642SDan McDonald 		IPSA_REFRELE(larval);
3474bd670b35SErik Nordmark 	}
34757c478bd9Sstevel@tonic-gate 
34767c478bd9Sstevel@tonic-gate 	/*
34777c478bd9Sstevel@tonic-gate 	 * How much more stack will I create with all of these
34787c478bd9Sstevel@tonic-gate 	 * esp_outbound() calls?
34797c478bd9Sstevel@tonic-gate 	 */
34807c478bd9Sstevel@tonic-gate 
3481bd670b35SErik Nordmark 	/* Handle the packets queued waiting for the SA */
34827c478bd9Sstevel@tonic-gate 	while (acq_msgs != NULL) {
3483bd670b35SErik Nordmark 		mblk_t		*asyncmp;
3484bd670b35SErik Nordmark 		mblk_t		*data_mp;
3485bd670b35SErik Nordmark 		ip_xmit_attr_t	ixas;
3486bd670b35SErik Nordmark 		ill_t		*ill;
34877c478bd9Sstevel@tonic-gate 
3488bd670b35SErik Nordmark 		asyncmp = acq_msgs;
34897c478bd9Sstevel@tonic-gate 		acq_msgs = acq_msgs->b_next;
3490bd670b35SErik Nordmark 		asyncmp->b_next = NULL;
34917c478bd9Sstevel@tonic-gate 
3492bd670b35SErik Nordmark 		/*
3493bd670b35SErik Nordmark 		 * Extract the ip_xmit_attr_t from the first mblk.
3494bd670b35SErik Nordmark 		 * Verifies that the netstack and ill is still around; could
3495bd670b35SErik Nordmark 		 * have vanished while iked was doing its work.
3496bd670b35SErik Nordmark 		 * On succesful return we have a nce_t and the ill/ipst can't
3497bd670b35SErik Nordmark 		 * disappear until we do the nce_refrele in ixa_cleanup.
3498bd670b35SErik Nordmark 		 */
3499bd670b35SErik Nordmark 		data_mp = asyncmp->b_cont;
3500bd670b35SErik Nordmark 		asyncmp->b_cont = NULL;
3501bd670b35SErik Nordmark 		if (!ip_xmit_attr_from_mblk(asyncmp, &ixas)) {
3502f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, out_discards);
3503bd670b35SErik Nordmark 			ip_drop_packet(data_mp, B_FALSE, NULL,
3504f4b3ec61Sdh155122 			    DROPPER(ipss, ipds_sadb_acquire_timeout),
3505f4b3ec61Sdh155122 			    &espstack->esp_dropper);
3506bd670b35SErik Nordmark 		} else if (rc != 0) {
3507bd670b35SErik Nordmark 			ill = ixas.ixa_nce->nce_ill;
3508bd670b35SErik Nordmark 			ESP_BUMP_STAT(espstack, out_discards);
3509bd670b35SErik Nordmark 			ip_drop_packet(data_mp, B_FALSE, ill,
3510bd670b35SErik Nordmark 			    DROPPER(ipss, ipds_sadb_acquire_timeout),
3511bd670b35SErik Nordmark 			    &espstack->esp_dropper);
3512bd670b35SErik Nordmark 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3513bd670b35SErik Nordmark 		} else {
3514bd670b35SErik Nordmark 			esp_outbound_finish(data_mp, &ixas);
3515bd670b35SErik Nordmark 		}
3516bd670b35SErik Nordmark 		ixa_cleanup(&ixas);
35177c478bd9Sstevel@tonic-gate 	}
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	return (rc);
35207c478bd9Sstevel@tonic-gate }
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate /*
3523bd670b35SErik Nordmark  * Process one of the queued messages (from ipsacq_mp) once the SA
3524bd670b35SErik Nordmark  * has been added.
3525bd670b35SErik Nordmark  */
3526bd670b35SErik Nordmark static void
esp_outbound_finish(mblk_t * data_mp,ip_xmit_attr_t * ixa)3527bd670b35SErik Nordmark esp_outbound_finish(mblk_t *data_mp, ip_xmit_attr_t *ixa)
3528bd670b35SErik Nordmark {
3529bd670b35SErik Nordmark 	netstack_t	*ns = ixa->ixa_ipst->ips_netstack;
3530bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
3531bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
3532bd670b35SErik Nordmark 	ill_t		*ill = ixa->ixa_nce->nce_ill;
3533bd670b35SErik Nordmark 
3534bd670b35SErik Nordmark 	if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_ESP)) {
3535bd670b35SErik Nordmark 		ESP_BUMP_STAT(espstack, out_discards);
3536bd670b35SErik Nordmark 		ip_drop_packet(data_mp, B_FALSE, ill,
3537bd670b35SErik Nordmark 		    DROPPER(ipss, ipds_sadb_acquire_timeout),
3538bd670b35SErik Nordmark 		    &espstack->esp_dropper);
3539bd670b35SErik Nordmark 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3540bd670b35SErik Nordmark 		return;
3541bd670b35SErik Nordmark 	}
3542bd670b35SErik Nordmark 
3543bd670b35SErik Nordmark 	data_mp = esp_outbound(data_mp, ixa);
3544bd670b35SErik Nordmark 	if (data_mp == NULL)
3545bd670b35SErik Nordmark 		return;
3546bd670b35SErik Nordmark 
3547bd670b35SErik Nordmark 	/* do AH processing if needed */
3548bd670b35SErik Nordmark 	data_mp = esp_do_outbound_ah(data_mp, ixa);
3549bd670b35SErik Nordmark 	if (data_mp == NULL)
3550bd670b35SErik Nordmark 		return;
3551bd670b35SErik Nordmark 
3552bd670b35SErik Nordmark 	(void) ip_output_post_ipsec(data_mp, ixa);
3553bd670b35SErik Nordmark }
3554bd670b35SErik Nordmark 
3555bd670b35SErik Nordmark /*
35567c478bd9Sstevel@tonic-gate  * Add new ESP security association.  This may become a generic AH/ESP
35577c478bd9Sstevel@tonic-gate  * routine eventually.
35587c478bd9Sstevel@tonic-gate  */
35597c478bd9Sstevel@tonic-gate static int
esp_add_sa(mblk_t * mp,keysock_in_t * ksi,int * diagnostic,netstack_t * ns)3560f4b3ec61Sdh155122 esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
35617c478bd9Sstevel@tonic-gate {
35627c478bd9Sstevel@tonic-gate 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
35637c478bd9Sstevel@tonic-gate 	sadb_address_t *srcext =
35647c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
35657c478bd9Sstevel@tonic-gate 	sadb_address_t *dstext =
35667c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
35678810c16bSdanmcd 	sadb_address_t *isrcext =
35688810c16bSdanmcd 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC];
35698810c16bSdanmcd 	sadb_address_t *idstext =
35708810c16bSdanmcd 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST];
35717c478bd9Sstevel@tonic-gate 	sadb_address_t *nttext_loc =
35727c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC];
35737c478bd9Sstevel@tonic-gate 	sadb_address_t *nttext_rem =
35747c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM];
35757c478bd9Sstevel@tonic-gate 	sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
35767c478bd9Sstevel@tonic-gate 	sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
35777c478bd9Sstevel@tonic-gate 	struct sockaddr_in *src, *dst;
35787c478bd9Sstevel@tonic-gate 	struct sockaddr_in *natt_loc, *natt_rem;
35797c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *natt_loc6, *natt_rem6;
35807c478bd9Sstevel@tonic-gate 	sadb_lifetime_t *soft =
35817c478bd9Sstevel@tonic-gate 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
35827c478bd9Sstevel@tonic-gate 	sadb_lifetime_t *hard =
35837c478bd9Sstevel@tonic-gate 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
35849c2c14abSThejaswini Singarajipura 	sadb_lifetime_t *idle =
35859c2c14abSThejaswini Singarajipura 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
3586f4b3ec61Sdh155122 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
3587f4b3ec61Sdh155122 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
35887c478bd9Sstevel@tonic-gate 
35895d3b8cb7SBill Sommerfeld 
35905d3b8cb7SBill Sommerfeld 
35917c478bd9Sstevel@tonic-gate 	/* I need certain extensions present for an ADD message. */
35927c478bd9Sstevel@tonic-gate 	if (srcext == NULL) {
35937c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
35947c478bd9Sstevel@tonic-gate 		return (EINVAL);
35957c478bd9Sstevel@tonic-gate 	}
35967c478bd9Sstevel@tonic-gate 	if (dstext == NULL) {
35977c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
35987c478bd9Sstevel@tonic-gate 		return (EINVAL);
35997c478bd9Sstevel@tonic-gate 	}
36008810c16bSdanmcd 	if (isrcext == NULL && idstext != NULL) {
36018810c16bSdanmcd 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC;
36028810c16bSdanmcd 		return (EINVAL);
36038810c16bSdanmcd 	}
36048810c16bSdanmcd 	if (isrcext != NULL && idstext == NULL) {
36058810c16bSdanmcd 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST;
36068810c16bSdanmcd 		return (EINVAL);
36078810c16bSdanmcd 	}
36087c478bd9Sstevel@tonic-gate 	if (assoc == NULL) {
36097c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
36107c478bd9Sstevel@tonic-gate 		return (EINVAL);
36117c478bd9Sstevel@tonic-gate 	}
36127c478bd9Sstevel@tonic-gate 	if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) {
36137c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY;
36147c478bd9Sstevel@tonic-gate 		return (EINVAL);
36157c478bd9Sstevel@tonic-gate 	}
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate 	src = (struct sockaddr_in *)(srcext + 1);
36187c478bd9Sstevel@tonic-gate 	dst = (struct sockaddr_in *)(dstext + 1);
36197c478bd9Sstevel@tonic-gate 	natt_loc = (struct sockaddr_in *)(nttext_loc + 1);
36207c478bd9Sstevel@tonic-gate 	natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1);
36217c478bd9Sstevel@tonic-gate 	natt_rem = (struct sockaddr_in *)(nttext_rem + 1);
36227c478bd9Sstevel@tonic-gate 	natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1);
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate 	/* Sundry ADD-specific reality checks. */
36257c478bd9Sstevel@tonic-gate 	/* XXX STATS :  Logging/stats here? */
36269c2c14abSThejaswini Singarajipura 
36279c2c14abSThejaswini Singarajipura 	if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) &&
36289c2c14abSThejaswini Singarajipura 	    (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
36297c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
36307c478bd9Sstevel@tonic-gate 		return (EINVAL);
36317c478bd9Sstevel@tonic-gate 	}
36327c478bd9Sstevel@tonic-gate 	if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) {
36337c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
36347c478bd9Sstevel@tonic-gate 		return (EINVAL);
36357c478bd9Sstevel@tonic-gate 	}
36367c478bd9Sstevel@tonic-gate 
3637bd670b35SErik Nordmark #ifndef IPSEC_LATENCY_TEST
36387c478bd9Sstevel@tonic-gate 	if (assoc->sadb_sa_encrypt == SADB_EALG_NULL &&
36397c478bd9Sstevel@tonic-gate 	    assoc->sadb_sa_auth == SADB_AALG_NONE) {
36407c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
36417c478bd9Sstevel@tonic-gate 		return (EINVAL);
36427c478bd9Sstevel@tonic-gate 	}
3643bd670b35SErik Nordmark #endif
36447c478bd9Sstevel@tonic-gate 
364572bd9b6bSdanmcd 	if (assoc->sadb_sa_flags & ~espstack->esp_sadb.s_addflags) {
36467c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
36477c478bd9Sstevel@tonic-gate 		return (EINVAL);
36487c478bd9Sstevel@tonic-gate 	}
36497c478bd9Sstevel@tonic-gate 
36509c2c14abSThejaswini Singarajipura 	if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) {
36517c478bd9Sstevel@tonic-gate 		return (EINVAL);
36527c478bd9Sstevel@tonic-gate 	}
36538810c16bSdanmcd 	ASSERT(src->sin_family == dst->sin_family);
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) {
36567c478bd9Sstevel@tonic-gate 		if (nttext_loc == NULL) {
36577c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC;
36587c478bd9Sstevel@tonic-gate 			return (EINVAL);
36597c478bd9Sstevel@tonic-gate 		}
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate 		if (natt_loc->sin_family == AF_INET6 &&
36627c478bd9Sstevel@tonic-gate 		    !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) {
36637c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC;
36647c478bd9Sstevel@tonic-gate 			return (EINVAL);
36657c478bd9Sstevel@tonic-gate 		}
36667c478bd9Sstevel@tonic-gate 	}
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate 	if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) {
36697c478bd9Sstevel@tonic-gate 		if (nttext_rem == NULL) {
36707c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM;
36717c478bd9Sstevel@tonic-gate 			return (EINVAL);
36727c478bd9Sstevel@tonic-gate 		}
36737c478bd9Sstevel@tonic-gate 		if (natt_rem->sin_family == AF_INET6 &&
36747c478bd9Sstevel@tonic-gate 		    !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) {
36757c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM;
36767c478bd9Sstevel@tonic-gate 			return (EINVAL);
36777c478bd9Sstevel@tonic-gate 		}
36787c478bd9Sstevel@tonic-gate 	}
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate 	/* Stuff I don't support, for now.  XXX Diagnostic? */
36825d3b8cb7SBill Sommerfeld 	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
36837c478bd9Sstevel@tonic-gate 		return (EOPNOTSUPP);
36847c478bd9Sstevel@tonic-gate 
36855d3b8cb7SBill Sommerfeld 	if ((*diagnostic = sadb_labelchk(ksi)) != 0)
36865d3b8cb7SBill Sommerfeld 		return (EINVAL);
36875d3b8cb7SBill Sommerfeld 
36887c478bd9Sstevel@tonic-gate 	/*
36895d3b8cb7SBill Sommerfeld 	 * XXX Policy :  I'm not checking identities at this time,
36905d3b8cb7SBill Sommerfeld 	 * but if I did, I'd do them here, before I sent
36917c478bd9Sstevel@tonic-gate 	 * the weak key check up to the algorithm.
36927c478bd9Sstevel@tonic-gate 	 */
36937c478bd9Sstevel@tonic-gate 
3694f4b3ec61Sdh155122 	mutex_enter(&ipss->ipsec_alg_lock);
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate 	/*
36977c478bd9Sstevel@tonic-gate 	 * First locate the authentication algorithm.
36987c478bd9Sstevel@tonic-gate 	 */
3699bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST
3700bd670b35SErik Nordmark 	if (akey != NULL && assoc->sadb_sa_auth != SADB_AALG_NONE) {
3701bd670b35SErik Nordmark #else
37027c478bd9Sstevel@tonic-gate 	if (akey != NULL) {
3703bd670b35SErik Nordmark #endif
37047c478bd9Sstevel@tonic-gate 		ipsec_alginfo_t *aalg;
37057c478bd9Sstevel@tonic-gate 
3706f4b3ec61Sdh155122 		aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
3707f4b3ec61Sdh155122 		    [assoc->sadb_sa_auth];
37087c478bd9Sstevel@tonic-gate 		if (aalg == NULL || !ALG_VALID(aalg)) {
3709f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
3710f4b3ec61Sdh155122 			esp1dbg(espstack, ("Couldn't find auth alg #%d.\n",
37117c478bd9Sstevel@tonic-gate 			    assoc->sadb_sa_auth));
37127c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
37137c478bd9Sstevel@tonic-gate 			return (EINVAL);
37147c478bd9Sstevel@tonic-gate 		}
37157c478bd9Sstevel@tonic-gate 
371646c444baSmarkfen 		/*
371746c444baSmarkfen 		 * Sanity check key sizes.
371846c444baSmarkfen 		 * Note: It's not possible to use SADB_AALG_NONE because
371946c444baSmarkfen 		 * this auth_alg is not defined with ALG_FLAG_VALID. If this
372046c444baSmarkfen 		 * ever changes, the same check for SADB_AALG_NONE and
372146c444baSmarkfen 		 * a auth_key != NULL should be made here ( see below).
372246c444baSmarkfen 		 */
37237c478bd9Sstevel@tonic-gate 		if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) {
3724f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
37257c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
37267c478bd9Sstevel@tonic-gate 			return (EINVAL);
37277c478bd9Sstevel@tonic-gate 		}
372846c444baSmarkfen 		ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 		/* check key and fix parity if needed */
37317c478bd9Sstevel@tonic-gate 		if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE,
37327c478bd9Sstevel@tonic-gate 		    diagnostic) != 0) {
3733f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
37347c478bd9Sstevel@tonic-gate 			return (EINVAL);
37357c478bd9Sstevel@tonic-gate 		}
37367c478bd9Sstevel@tonic-gate 	}
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 	/*
37397c478bd9Sstevel@tonic-gate 	 * Then locate the encryption algorithm.
37407c478bd9Sstevel@tonic-gate 	 */
37417c478bd9Sstevel@tonic-gate 	if (ekey != NULL) {
3742628b0c67SMark Fenwick 		uint_t keybits;
37437c478bd9Sstevel@tonic-gate 		ipsec_alginfo_t *ealg;
37447c478bd9Sstevel@tonic-gate 
3745f4b3ec61Sdh155122 		ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
3746f4b3ec61Sdh155122 		    [assoc->sadb_sa_encrypt];
37477c478bd9Sstevel@tonic-gate 		if (ealg == NULL || !ALG_VALID(ealg)) {
3748f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
3749f4b3ec61Sdh155122 			esp1dbg(espstack, ("Couldn't find encr alg #%d.\n",
37507c478bd9Sstevel@tonic-gate 			    assoc->sadb_sa_encrypt));
37517c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
37527c478bd9Sstevel@tonic-gate 			return (EINVAL);
37537c478bd9Sstevel@tonic-gate 		}
37547c478bd9Sstevel@tonic-gate 
375546c444baSmarkfen 		/*
375646c444baSmarkfen 		 * Sanity check key sizes. If the encryption algorithm is
375746c444baSmarkfen 		 * SADB_EALG_NULL but the encryption key is NOT
375846c444baSmarkfen 		 * NULL then complain.
3759628b0c67SMark Fenwick 		 *
3760628b0c67SMark Fenwick 		 * The keying material includes salt bits if required by
3761628b0c67SMark Fenwick 		 * algorithm and optionally the Initial IV, check the
3762628b0c67SMark Fenwick 		 * length of whats left.
376346c444baSmarkfen 		 */
3764628b0c67SMark Fenwick 		keybits = ekey->sadb_key_bits;
3765628b0c67SMark Fenwick 		keybits -= ekey->sadb_key_reserved;
3766628b0c67SMark Fenwick 		keybits -= SADB_8TO1(ealg->alg_saltlen);
376746c444baSmarkfen 		if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) ||
3768628b0c67SMark Fenwick 		    (!ipsec_valid_key_size(keybits, ealg))) {
3769f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
37707c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
37717c478bd9Sstevel@tonic-gate 			return (EINVAL);
37727c478bd9Sstevel@tonic-gate 		}
377346c444baSmarkfen 		ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
37747c478bd9Sstevel@tonic-gate 
37757c478bd9Sstevel@tonic-gate 		/* check key */
37767c478bd9Sstevel@tonic-gate 		if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE,
37777c478bd9Sstevel@tonic-gate 		    diagnostic) != 0) {
3778f4b3ec61Sdh155122 			mutex_exit(&ipss->ipsec_alg_lock);
37797c478bd9Sstevel@tonic-gate 			return (EINVAL);
37807c478bd9Sstevel@tonic-gate 		}
37817c478bd9Sstevel@tonic-gate 	}
3782f4b3ec61Sdh155122 	mutex_exit(&ipss->ipsec_alg_lock);
37837c478bd9Sstevel@tonic-gate 
37848810c16bSdanmcd 	return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
3785f4b3ec61Sdh155122 	    diagnostic, espstack));
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate /*
37897c478bd9Sstevel@tonic-gate  * Update a security association.  Updates come in two varieties.  The first
37907c478bd9Sstevel@tonic-gate  * is an update of lifetimes on a non-larval SA.  The second is an update of
37917c478bd9Sstevel@tonic-gate  * a larval SA, which ends up looking a lot more like an add.
37927c478bd9Sstevel@tonic-gate  */
37937c478bd9Sstevel@tonic-gate static int
3794f4b3ec61Sdh155122 esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
379538d95a78Smarkfen     ipsecesp_stack_t *espstack, uint8_t sadb_msg_type)
37967c478bd9Sstevel@tonic-gate {
37979c2c14abSThejaswini Singarajipura 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
37989c2c14abSThejaswini Singarajipura 	mblk_t    *buf_pkt;
37999c2c14abSThejaswini Singarajipura 	int rcode;
38009c2c14abSThejaswini Singarajipura 
38017c478bd9Sstevel@tonic-gate 	sadb_address_t *dstext =
38027c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
38037c478bd9Sstevel@tonic-gate 
38047c478bd9Sstevel@tonic-gate 	if (dstext == NULL) {
38057c478bd9Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
38067c478bd9Sstevel@tonic-gate 		return (EINVAL);
38077c478bd9Sstevel@tonic-gate 	}
38087c478bd9Sstevel@tonic-gate 
38099c2c14abSThejaswini Singarajipura 	rcode = sadb_update_sa(mp, ksi, &buf_pkt, &espstack->esp_sadb,
38109c2c14abSThejaswini Singarajipura 	    diagnostic, espstack->esp_pfkey_q, esp_add_sa,
38119c2c14abSThejaswini Singarajipura 	    espstack->ipsecesp_netstack, sadb_msg_type);
38129c2c14abSThejaswini Singarajipura 
38139c2c14abSThejaswini Singarajipura 	if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) ||
38149c2c14abSThejaswini Singarajipura 	    (rcode != 0)) {
38159c2c14abSThejaswini Singarajipura 		return (rcode);
38169c2c14abSThejaswini Singarajipura 	}
38179c2c14abSThejaswini Singarajipura 
381873184bc7SDan McDonald 	HANDLE_BUF_PKT(esp_taskq, espstack->ipsecesp_netstack->netstack_ipsec,
38199c2c14abSThejaswini Singarajipura 	    espstack->esp_dropper, buf_pkt);
38209c2c14abSThejaswini Singarajipura 
38219c2c14abSThejaswini Singarajipura 	return (rcode);
38227c478bd9Sstevel@tonic-gate }
38237c478bd9Sstevel@tonic-gate 
38245d3b8cb7SBill Sommerfeld /* XXX refactor me */
38257c478bd9Sstevel@tonic-gate /*
38267c478bd9Sstevel@tonic-gate  * Delete a security association.  This is REALLY likely to be code common to
38277c478bd9Sstevel@tonic-gate  * both AH and ESP.  Find the association, then unlink it.
38287c478bd9Sstevel@tonic-gate  */
38297c478bd9Sstevel@tonic-gate static int
3830f4b3ec61Sdh155122 esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
383138d95a78Smarkfen     ipsecesp_stack_t *espstack, uint8_t sadb_msg_type)
38327c478bd9Sstevel@tonic-gate {
38337c478bd9Sstevel@tonic-gate 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
38347c478bd9Sstevel@tonic-gate 	sadb_address_t *dstext =
38357c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
38367c478bd9Sstevel@tonic-gate 	sadb_address_t *srcext =
38377c478bd9Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
38387c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
38397c478bd9Sstevel@tonic-gate 
38407c478bd9Sstevel@tonic-gate 	if (assoc == NULL) {
38417c478bd9Sstevel@tonic-gate 		if (dstext != NULL) {
38427c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)(dstext + 1);
38437c478bd9Sstevel@tonic-gate 		} else if (srcext != NULL) {
38447c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)(srcext + 1);
38457c478bd9Sstevel@tonic-gate 		} else {
38467c478bd9Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
38477c478bd9Sstevel@tonic-gate 			return (EINVAL);
38487c478bd9Sstevel@tonic-gate 		}
38498810c16bSdanmcd 		return (sadb_purge_sa(mp, ksi,
3850f4b3ec61Sdh155122 		    (sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 :
38515d3b8cb7SBill Sommerfeld 		    &espstack->esp_sadb.s_v4, diagnostic,
3852bd670b35SErik Nordmark 		    espstack->esp_pfkey_q));
38537c478bd9Sstevel@tonic-gate 	}
38547c478bd9Sstevel@tonic-gate 
385538d95a78Smarkfen 	return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic,
385638d95a78Smarkfen 	    espstack->esp_pfkey_q, sadb_msg_type));
38577c478bd9Sstevel@tonic-gate }
38587c478bd9Sstevel@tonic-gate 
38595d3b8cb7SBill Sommerfeld /* XXX refactor me */
38607c478bd9Sstevel@tonic-gate /*
38617c478bd9Sstevel@tonic-gate  * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP
38627c478bd9Sstevel@tonic-gate  * messages.
38637c478bd9Sstevel@tonic-gate  */
38647c478bd9Sstevel@tonic-gate static void
3865f4b3ec61Sdh155122 esp_dump(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack)
38667c478bd9Sstevel@tonic-gate {
38677c478bd9Sstevel@tonic-gate 	int error;
38687c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate 	/*
38717c478bd9Sstevel@tonic-gate 	 * Dump each fanout, bailing if error is non-zero.
38727c478bd9Sstevel@tonic-gate 	 */
38737c478bd9Sstevel@tonic-gate 
38749c2c14abSThejaswini Singarajipura 	error = sadb_dump(espstack->esp_pfkey_q, mp, ksi,
3875f4b3ec61Sdh155122 	    &espstack->esp_sadb.s_v4);
38767c478bd9Sstevel@tonic-gate 	if (error != 0)
38777c478bd9Sstevel@tonic-gate 		goto bail;
38787c478bd9Sstevel@tonic-gate 
38799c2c14abSThejaswini Singarajipura 	error = sadb_dump(espstack->esp_pfkey_q, mp, ksi,
3880f4b3ec61Sdh155122 	    &espstack->esp_sadb.s_v6);
38817c478bd9Sstevel@tonic-gate bail:
38827c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_cont != NULL);
38837c478bd9Sstevel@tonic-gate 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
38847c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_errno = (uint8_t)error;
3885f4b3ec61Sdh155122 	sadb_pfkey_echo(espstack->esp_pfkey_q, mp,
3886f4b3ec61Sdh155122 	    (sadb_msg_t *)mp->b_cont->b_rptr, ksi, NULL);
38877c478bd9Sstevel@tonic-gate }
38887c478bd9Sstevel@tonic-gate 
38897c478bd9Sstevel@tonic-gate /*
38908810c16bSdanmcd  * First-cut reality check for an inbound PF_KEY message.
38918810c16bSdanmcd  */
38928810c16bSdanmcd static boolean_t
3893f4b3ec61Sdh155122 esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi,
3894f4b3ec61Sdh155122     ipsecesp_stack_t *espstack)
38958810c16bSdanmcd {
38968810c16bSdanmcd 	int diagnostic;
38978810c16bSdanmcd 
38988810c16bSdanmcd 	if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) {
38998810c16bSdanmcd 		diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT;
39008810c16bSdanmcd 		goto badmsg;
39018810c16bSdanmcd 	}
39028810c16bSdanmcd 	if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL ||
39038810c16bSdanmcd 	    ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) {
39048810c16bSdanmcd 		diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT;
39058810c16bSdanmcd 		goto badmsg;
39068810c16bSdanmcd 	}
39078810c16bSdanmcd 	return (B_FALSE);	/* False ==> no failures */
39088810c16bSdanmcd 
39098810c16bSdanmcd badmsg:
3910f4b3ec61Sdh155122 	sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic,
39118810c16bSdanmcd 	    ksi->ks_in_serial);
39128810c16bSdanmcd 	return (B_TRUE);	/* True ==> failures */
39138810c16bSdanmcd }
39148810c16bSdanmcd 
39158810c16bSdanmcd /*
39167c478bd9Sstevel@tonic-gate  * ESP parsing of PF_KEY messages.  Keysock did most of the really silly
39177c478bd9Sstevel@tonic-gate  * error cases.  What I receive is a fully-formed, syntactically legal
39187c478bd9Sstevel@tonic-gate  * PF_KEY message.  I then need to check semantics...
39197c478bd9Sstevel@tonic-gate  *
39207c478bd9Sstevel@tonic-gate  * This code may become common to AH and ESP.  Stay tuned.
39217c478bd9Sstevel@tonic-gate  *
39227c478bd9Sstevel@tonic-gate  * I also make the assumption that db_ref's are cool.  If this assumption
39237c478bd9Sstevel@tonic-gate  * is wrong, this means that someone other than keysock or me has been
39247c478bd9Sstevel@tonic-gate  * mucking with PF_KEY messages.
39257c478bd9Sstevel@tonic-gate  */
39267c478bd9Sstevel@tonic-gate static void
3927f4b3ec61Sdh155122 esp_parse_pfkey(mblk_t *mp, ipsecesp_stack_t *espstack)
39287c478bd9Sstevel@tonic-gate {
39297c478bd9Sstevel@tonic-gate 	mblk_t *msg = mp->b_cont;
39307c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
39317c478bd9Sstevel@tonic-gate 	keysock_in_t *ksi;
39327c478bd9Sstevel@tonic-gate 	int error;
39337c478bd9Sstevel@tonic-gate 	int diagnostic = SADB_X_DIAGNOSTIC_NONE;
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate 	ASSERT(msg != NULL);
3936f4b3ec61Sdh155122 
39377c478bd9Sstevel@tonic-gate 	samsg = (sadb_msg_t *)msg->b_rptr;
39387c478bd9Sstevel@tonic-gate 	ksi = (keysock_in_t *)mp->b_rptr;
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 	/*
39417c478bd9Sstevel@tonic-gate 	 * If applicable, convert unspecified AF_INET6 to unspecified
39428810c16bSdanmcd 	 * AF_INET.  And do other address reality checks.
39437c478bd9Sstevel@tonic-gate 	 */
3944f4b3ec61Sdh155122 	if (!sadb_addrfix(ksi, espstack->esp_pfkey_q, mp,
3945f4b3ec61Sdh155122 	    espstack->ipsecesp_netstack) ||
3946f4b3ec61Sdh155122 	    esp_pfkey_reality_failures(mp, ksi, espstack)) {
39478810c16bSdanmcd 		return;
39488810c16bSdanmcd 	}
39497c478bd9Sstevel@tonic-gate 
39507c478bd9Sstevel@tonic-gate 	switch (samsg->sadb_msg_type) {
39517c478bd9Sstevel@tonic-gate 	case SADB_ADD:
3952f4b3ec61Sdh155122 		error = esp_add_sa(mp, ksi, &diagnostic,
3953f4b3ec61Sdh155122 		    espstack->ipsecesp_netstack);
39547c478bd9Sstevel@tonic-gate 		if (error != 0) {
3955f4b3ec61Sdh155122 			sadb_pfkey_error(espstack->esp_pfkey_q, mp, error,
3956f4b3ec61Sdh155122 			    diagnostic, ksi->ks_in_serial);
39577c478bd9Sstevel@tonic-gate 		}
39587c478bd9Sstevel@tonic-gate 		/* else esp_add_sa() took care of things. */
39597c478bd9Sstevel@tonic-gate 		break;
39607c478bd9Sstevel@tonic-gate 	case SADB_DELETE:
396138d95a78Smarkfen 	case SADB_X_DELPAIR:
39629c2c14abSThejaswini Singarajipura 	case SADB_X_DELPAIR_STATE:
396338d95a78Smarkfen 		error = esp_del_sa(mp, ksi, &diagnostic, espstack,
396438d95a78Smarkfen 		    samsg->sadb_msg_type);
39657c478bd9Sstevel@tonic-gate 		if (error != 0) {
3966f4b3ec61Sdh155122 			sadb_pfkey_error(espstack->esp_pfkey_q, mp, error,
3967f4b3ec61Sdh155122 			    diagnostic, ksi->ks_in_serial);
39687c478bd9Sstevel@tonic-gate 		}
39697c478bd9Sstevel@tonic-gate 		/* Else esp_del_sa() took care of things. */
39707c478bd9Sstevel@tonic-gate 		break;
39717c478bd9Sstevel@tonic-gate 	case SADB_GET:
397238d95a78Smarkfen 		error = sadb_delget_sa(mp, ksi, &espstack->esp_sadb,
397338d95a78Smarkfen 		    &diagnostic, espstack->esp_pfkey_q, samsg->sadb_msg_type);
39747c478bd9Sstevel@tonic-gate 		if (error != 0) {
3975f4b3ec61Sdh155122 			sadb_pfkey_error(espstack->esp_pfkey_q, mp, error,
3976f4b3ec61Sdh155122 			    diagnostic, ksi->ks_in_serial);
39777c478bd9Sstevel@tonic-gate 		}
39787c478bd9Sstevel@tonic-gate 		/* Else sadb_get_sa() took care of things. */
39797c478bd9Sstevel@tonic-gate 		break;
39807c478bd9Sstevel@tonic-gate 	case SADB_FLUSH:
3981f4b3ec61Sdh155122 		sadbp_flush(&espstack->esp_sadb, espstack->ipsecesp_netstack);
3982f4b3ec61Sdh155122 		sadb_pfkey_echo(espstack->esp_pfkey_q, mp, samsg, ksi, NULL);
39837c478bd9Sstevel@tonic-gate 		break;
39847c478bd9Sstevel@tonic-gate 	case SADB_REGISTER:
39857c478bd9Sstevel@tonic-gate 		/*
39867c478bd9Sstevel@tonic-gate 		 * Hmmm, let's do it!  Check for extensions (there should
39877c478bd9Sstevel@tonic-gate 		 * be none), extract the fields, call esp_register_out(),
39887c478bd9Sstevel@tonic-gate 		 * then either free or report an error.
39897c478bd9Sstevel@tonic-gate 		 *
39907c478bd9Sstevel@tonic-gate 		 * Keysock takes care of the PF_KEY bookkeeping for this.
39917c478bd9Sstevel@tonic-gate 		 */
39927c478bd9Sstevel@tonic-gate 		if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
3993bd670b35SErik Nordmark 		    ksi->ks_in_serial, espstack, msg_getcred(mp, NULL))) {
39947c478bd9Sstevel@tonic-gate 			freemsg(mp);
39957c478bd9Sstevel@tonic-gate 		} else {
39967c478bd9Sstevel@tonic-gate 			/*
39977c478bd9Sstevel@tonic-gate 			 * Only way this path hits is if there is a memory
39987c478bd9Sstevel@tonic-gate 			 * failure.  It will not return B_FALSE because of
39997c478bd9Sstevel@tonic-gate 			 * lack of esp_pfkey_q if I am in wput().
40007c478bd9Sstevel@tonic-gate 			 */
4001f4b3ec61Sdh155122 			sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM,
4002f4b3ec61Sdh155122 			    diagnostic, ksi->ks_in_serial);
40037c478bd9Sstevel@tonic-gate 		}
40047c478bd9Sstevel@tonic-gate 		break;
40057c478bd9Sstevel@tonic-gate 	case SADB_UPDATE:
400638d95a78Smarkfen 	case SADB_X_UPDATEPAIR:
40077c478bd9Sstevel@tonic-gate 		/*
40087c478bd9Sstevel@tonic-gate 		 * Find a larval, if not there, find a full one and get
40097c478bd9Sstevel@tonic-gate 		 * strict.
40107c478bd9Sstevel@tonic-gate 		 */
401138d95a78Smarkfen 		error = esp_update_sa(mp, ksi, &diagnostic, espstack,
401238d95a78Smarkfen 		    samsg->sadb_msg_type);
40137c478bd9Sstevel@tonic-gate 		if (error != 0) {
4014f4b3ec61Sdh155122 			sadb_pfkey_error(espstack->esp_pfkey_q, mp, error,
4015f4b3ec61Sdh155122 			    diagnostic, ksi->ks_in_serial);
40167c478bd9Sstevel@tonic-gate 		}
40177c478bd9Sstevel@tonic-gate 		/* else esp_update_sa() took care of things. */
40187c478bd9Sstevel@tonic-gate 		break;
40197c478bd9Sstevel@tonic-gate 	case SADB_GETSPI:
40207c478bd9Sstevel@tonic-gate 		/*
40217c478bd9Sstevel@tonic-gate 		 * Reserve a new larval entry.
40227c478bd9Sstevel@tonic-gate 		 */
4023f4b3ec61Sdh155122 		esp_getspi(mp, ksi, espstack);
40247c478bd9Sstevel@tonic-gate 		break;
40257c478bd9Sstevel@tonic-gate 	case SADB_ACQUIRE:
40267c478bd9Sstevel@tonic-gate 		/*
40277c478bd9Sstevel@tonic-gate 		 * Find larval and/or ACQUIRE record and kill it (them), I'm
40287c478bd9Sstevel@tonic-gate 		 * most likely an error.  Inbound ACQUIRE messages should only
40297c478bd9Sstevel@tonic-gate 		 * have the base header.
40307c478bd9Sstevel@tonic-gate 		 */
4031f4b3ec61Sdh155122 		sadb_in_acquire(samsg, &espstack->esp_sadb,
4032f4b3ec61Sdh155122 		    espstack->esp_pfkey_q, espstack->ipsecesp_netstack);
40337c478bd9Sstevel@tonic-gate 		freemsg(mp);
40347c478bd9Sstevel@tonic-gate 		break;
40357c478bd9Sstevel@tonic-gate 	case SADB_DUMP:
40367c478bd9Sstevel@tonic-gate 		/*
40377c478bd9Sstevel@tonic-gate 		 * Dump all entries.
40387c478bd9Sstevel@tonic-gate 		 */
4039f4b3ec61Sdh155122 		esp_dump(mp, ksi, espstack);
40407c478bd9Sstevel@tonic-gate 		/* esp_dump will take care of the return message, etc. */
40417c478bd9Sstevel@tonic-gate 		break;
40427c478bd9Sstevel@tonic-gate 	case SADB_EXPIRE:
40437c478bd9Sstevel@tonic-gate 		/* Should never reach me. */
4044f4b3ec61Sdh155122 		sadb_pfkey_error(espstack->esp_pfkey_q, mp, EOPNOTSUPP,
4045f4b3ec61Sdh155122 		    diagnostic, ksi->ks_in_serial);
40467c478bd9Sstevel@tonic-gate 		break;
40477c478bd9Sstevel@tonic-gate 	default:
4048f4b3ec61Sdh155122 		sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL,
40497c478bd9Sstevel@tonic-gate 		    SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial);
40507c478bd9Sstevel@tonic-gate 		break;
40517c478bd9Sstevel@tonic-gate 	}
40527c478bd9Sstevel@tonic-gate }
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate /*
40557c478bd9Sstevel@tonic-gate  * Handle case where PF_KEY says it can't find a keysock for one of my
40567c478bd9Sstevel@tonic-gate  * ACQUIRE messages.
40577c478bd9Sstevel@tonic-gate  */
40587c478bd9Sstevel@tonic-gate static void
4059f4b3ec61Sdh155122 esp_keysock_no_socket(mblk_t *mp, ipsecesp_stack_t *espstack)
40607c478bd9Sstevel@tonic-gate {
40617c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
40627c478bd9Sstevel@tonic-gate 	keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr;
40637c478bd9Sstevel@tonic-gate 
40647c478bd9Sstevel@tonic-gate 	if (mp->b_cont == NULL) {
40657c478bd9Sstevel@tonic-gate 		freemsg(mp);
40667c478bd9Sstevel@tonic-gate 		return;
40677c478bd9Sstevel@tonic-gate 	}
40687c478bd9Sstevel@tonic-gate 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
40697c478bd9Sstevel@tonic-gate 
40707c478bd9Sstevel@tonic-gate 	/*
40717c478bd9Sstevel@tonic-gate 	 * If keysock can't find any registered, delete the acquire record
40727c478bd9Sstevel@tonic-gate 	 * immediately, and handle errors.
40737c478bd9Sstevel@tonic-gate 	 */
40747c478bd9Sstevel@tonic-gate 	if (samsg->sadb_msg_type == SADB_ACQUIRE) {
40757c478bd9Sstevel@tonic-gate 		samsg->sadb_msg_errno = kse->ks_err_errno;
40767c478bd9Sstevel@tonic-gate 		samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
40777c478bd9Sstevel@tonic-gate 		/*
4078bd670b35SErik Nordmark 		 * Use the write-side of the esp_pfkey_q
40797c478bd9Sstevel@tonic-gate 		 */
4080f4b3ec61Sdh155122 		sadb_in_acquire(samsg, &espstack->esp_sadb,
4081f4b3ec61Sdh155122 		    WR(espstack->esp_pfkey_q), espstack->ipsecesp_netstack);
40827c478bd9Sstevel@tonic-gate 	}
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 	freemsg(mp);
40857c478bd9Sstevel@tonic-gate }
40867c478bd9Sstevel@tonic-gate 
40877c478bd9Sstevel@tonic-gate /*
40887c478bd9Sstevel@tonic-gate  * ESP module write put routine.
40897c478bd9Sstevel@tonic-gate  */
40907c478bd9Sstevel@tonic-gate static void
40917c478bd9Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp)
40927c478bd9Sstevel@tonic-gate {
40937c478bd9Sstevel@tonic-gate 	ipsec_info_t *ii;
40947c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
4095f4b3ec61Sdh155122 	ipsecesp_stack_t	*espstack = (ipsecesp_stack_t *)q->q_ptr;
40967c478bd9Sstevel@tonic-gate 
4097f4b3ec61Sdh155122 	esp3dbg(espstack, ("In esp_wput().\n"));
40987c478bd9Sstevel@tonic-gate 
40997c478bd9Sstevel@tonic-gate 	/* NOTE: Each case must take care of freeing or passing mp. */
41007c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
41017c478bd9Sstevel@tonic-gate 	case M_CTL:
41027c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) {
41037c478bd9Sstevel@tonic-gate 			/* Not big enough message. */
41047c478bd9Sstevel@tonic-gate 			freemsg(mp);
41057c478bd9Sstevel@tonic-gate 			break;
41067c478bd9Sstevel@tonic-gate 		}
41077c478bd9Sstevel@tonic-gate 		ii = (ipsec_info_t *)mp->b_rptr;
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 		switch (ii->ipsec_info_type) {
41107c478bd9Sstevel@tonic-gate 		case KEYSOCK_OUT_ERR:
4111f4b3ec61Sdh155122 			esp1dbg(espstack, ("Got KEYSOCK_OUT_ERR message.\n"));
4112f4b3ec61Sdh155122 			esp_keysock_no_socket(mp, espstack);
41137c478bd9Sstevel@tonic-gate 			break;
41147c478bd9Sstevel@tonic-gate 		case KEYSOCK_IN:
4115f4b3ec61Sdh155122 			ESP_BUMP_STAT(espstack, keysock_in);
4116f4b3ec61Sdh155122 			esp3dbg(espstack, ("Got KEYSOCK_IN message.\n"));
41177c478bd9Sstevel@tonic-gate 
41188810c16bSdanmcd 			/* Parse the message. */
4119f4b3ec61Sdh155122 			esp_parse_pfkey(mp, espstack);
41207c478bd9Sstevel@tonic-gate 			break;
41217c478bd9Sstevel@tonic-gate 		case KEYSOCK_HELLO:
4122f4b3ec61Sdh155122 			sadb_keysock_hello(&espstack->esp_pfkey_q, q, mp,
4123f4b3ec61Sdh155122 			    esp_ager, (void *)espstack, &espstack->esp_event,
4124f4b3ec61Sdh155122 			    SADB_SATYPE_ESP);
41257c478bd9Sstevel@tonic-gate 			break;
41267c478bd9Sstevel@tonic-gate 		default:
4127f4b3ec61Sdh155122 			esp2dbg(espstack, ("Got M_CTL from above of 0x%x.\n",
41287c478bd9Sstevel@tonic-gate 			    ii->ipsec_info_type));
41297c478bd9Sstevel@tonic-gate 			freemsg(mp);
41307c478bd9Sstevel@tonic-gate 			break;
41317c478bd9Sstevel@tonic-gate 		}
41327c478bd9Sstevel@tonic-gate 		break;
41337c478bd9Sstevel@tonic-gate 	case M_IOCTL:
41347c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
41357c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
41367c478bd9Sstevel@tonic-gate 		case ND_SET:
41377c478bd9Sstevel@tonic-gate 		case ND_GET:
4138f4b3ec61Sdh155122 			if (nd_getset(q, espstack->ipsecesp_g_nd, mp)) {
41397c478bd9Sstevel@tonic-gate 				qreply(q, mp);
41407c478bd9Sstevel@tonic-gate 				return;
41417c478bd9Sstevel@tonic-gate 			} else {
41427c478bd9Sstevel@tonic-gate 				iocp->ioc_error = ENOENT;
41437c478bd9Sstevel@tonic-gate 			}
41447c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
41457c478bd9Sstevel@tonic-gate 		default:
41467c478bd9Sstevel@tonic-gate 			/* We really don't support any other ioctls, do we? */
41477c478bd9Sstevel@tonic-gate 
41487c478bd9Sstevel@tonic-gate 			/* Return EINVAL */
41497c478bd9Sstevel@tonic-gate 			if (iocp->ioc_error != ENOENT)
41507c478bd9Sstevel@tonic-gate 				iocp->ioc_error = EINVAL;
41517c478bd9Sstevel@tonic-gate 			iocp->ioc_count = 0;
41527c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
41537c478bd9Sstevel@tonic-gate 			qreply(q, mp);
41547c478bd9Sstevel@tonic-gate 			return;
41557c478bd9Sstevel@tonic-gate 		}
41567c478bd9Sstevel@tonic-gate 	default:
4157f4b3ec61Sdh155122 		esp3dbg(espstack,
4158f4b3ec61Sdh155122 		    ("Got default message, type %d, passing to IP.\n",
41597c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type));
41607c478bd9Sstevel@tonic-gate 		putnext(q, mp);
41617c478bd9Sstevel@tonic-gate 	}
41627c478bd9Sstevel@tonic-gate }
41637c478bd9Sstevel@tonic-gate 
41647c478bd9Sstevel@tonic-gate /*
41657c478bd9Sstevel@tonic-gate  * Wrapper to allow IP to trigger an ESP association failure message
41667c478bd9Sstevel@tonic-gate  * during inbound SA selection.
41677c478bd9Sstevel@tonic-gate  */
41687c478bd9Sstevel@tonic-gate void
41697c478bd9Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt,
4170bd670b35SErik Nordmark     uint32_t spi, void *addr, int af, ip_recv_attr_t *ira)
41717c478bd9Sstevel@tonic-gate {
4172bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
4173bd670b35SErik Nordmark 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
4174bd670b35SErik Nordmark 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
4175f4b3ec61Sdh155122 
4176f4b3ec61Sdh155122 	if (espstack->ipsecesp_log_unknown_spi) {
41777c478bd9Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi,
4178f4b3ec61Sdh155122 		    addr, af, espstack->ipsecesp_netstack);
41797c478bd9Sstevel@tonic-gate 	}
41807c478bd9Sstevel@tonic-gate 
4181bd670b35SErik Nordmark 	ip_drop_packet(mp, B_TRUE, ira->ira_ill,
4182f4b3ec61Sdh155122 	    DROPPER(ipss, ipds_esp_no_sa),
4183f4b3ec61Sdh155122 	    &espstack->esp_dropper);
41847c478bd9Sstevel@tonic-gate }
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate /*
41877c478bd9Sstevel@tonic-gate  * Initialize the ESP input and output processing functions.
41887c478bd9Sstevel@tonic-gate  */
41897c478bd9Sstevel@tonic-gate void
41907c478bd9Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa)
41917c478bd9Sstevel@tonic-gate {
41927c478bd9Sstevel@tonic-gate 	if (sa->ipsa_output_func == NULL)
41937c478bd9Sstevel@tonic-gate 		sa->ipsa_output_func = esp_outbound;
41947c478bd9Sstevel@tonic-gate 	if (sa->ipsa_input_func == NULL)
41957c478bd9Sstevel@tonic-gate 		sa->ipsa_input_func = esp_inbound;
41967c478bd9Sstevel@tonic-gate }
4197