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