1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/stream.h> 31*0Sstevel@tonic-gate #include <sys/stropts.h> 32*0Sstevel@tonic-gate #include <sys/errno.h> 33*0Sstevel@tonic-gate #include <sys/strlog.h> 34*0Sstevel@tonic-gate #include <sys/tihdr.h> 35*0Sstevel@tonic-gate #include <sys/socket.h> 36*0Sstevel@tonic-gate #include <sys/ddi.h> 37*0Sstevel@tonic-gate #include <sys/sunddi.h> 38*0Sstevel@tonic-gate #include <sys/kmem.h> 39*0Sstevel@tonic-gate #include <sys/sysmacros.h> 40*0Sstevel@tonic-gate #include <sys/cmn_err.h> 41*0Sstevel@tonic-gate #include <sys/vtrace.h> 42*0Sstevel@tonic-gate #include <sys/debug.h> 43*0Sstevel@tonic-gate #include <sys/atomic.h> 44*0Sstevel@tonic-gate #include <sys/strsun.h> 45*0Sstevel@tonic-gate #include <sys/random.h> 46*0Sstevel@tonic-gate #include <netinet/in.h> 47*0Sstevel@tonic-gate #include <net/if.h> 48*0Sstevel@tonic-gate #include <netinet/ip6.h> 49*0Sstevel@tonic-gate #include <net/pfkeyv2.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include <inet/common.h> 52*0Sstevel@tonic-gate #include <inet/mi.h> 53*0Sstevel@tonic-gate #include <inet/nd.h> 54*0Sstevel@tonic-gate #include <inet/ip.h> 55*0Sstevel@tonic-gate #include <inet/ip6.h> 56*0Sstevel@tonic-gate #include <inet/sadb.h> 57*0Sstevel@tonic-gate #include <inet/ipsec_info.h> 58*0Sstevel@tonic-gate #include <inet/ipsec_impl.h> 59*0Sstevel@tonic-gate #include <inet/ipsecesp.h> 60*0Sstevel@tonic-gate #include <inet/ipdrop.h> 61*0Sstevel@tonic-gate #include <inet/tcp.h> 62*0Sstevel@tonic-gate #include <sys/kstat.h> 63*0Sstevel@tonic-gate #include <sys/policy.h> 64*0Sstevel@tonic-gate #include <sys/strsun.h> 65*0Sstevel@tonic-gate #include <inet/udp_impl.h> 66*0Sstevel@tonic-gate #include <sys/taskq.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* EXPORT DELETE START */ 69*0Sstevel@tonic-gate #include <sys/iphada.h> 70*0Sstevel@tonic-gate /* EXPORT DELETE END */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* Packet dropper for ESP drops. */ 73*0Sstevel@tonic-gate static ipdropper_t esp_dropper; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static kmutex_t ipsecesp_param_lock; /* Protects ipsecesp_param_arr[] below. */ 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * Table of ND variables supported by ipsecesp. These are loaded into 78*0Sstevel@tonic-gate * ipsecesp_g_nd in ipsecesp_init_nd. 79*0Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate static ipsecespparam_t ipsecesp_param_arr[] = { 82*0Sstevel@tonic-gate /* min max value name */ 83*0Sstevel@tonic-gate { 0, 3, 0, "ipsecesp_debug"}, 84*0Sstevel@tonic-gate { 125, 32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"}, 85*0Sstevel@tonic-gate { 1, 10, 1, "ipsecesp_reap_delay"}, 86*0Sstevel@tonic-gate { 1, SADB_MAX_REPLAY, 64, "ipsecesp_replay_size"}, 87*0Sstevel@tonic-gate { 1, 300, 15, "ipsecesp_acquire_timeout"}, 88*0Sstevel@tonic-gate { 1, 1800, 90, "ipsecesp_larval_timeout"}, 89*0Sstevel@tonic-gate /* Default lifetime values for ACQUIRE messages. */ 90*0Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_bytes"}, 91*0Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_bytes"}, 92*0Sstevel@tonic-gate { 0, 0xffffffffU, 24000, "ipsecesp_default_soft_addtime"}, 93*0Sstevel@tonic-gate { 0, 0xffffffffU, 28800, "ipsecesp_default_hard_addtime"}, 94*0Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_usetime"}, 95*0Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_usetime"}, 96*0Sstevel@tonic-gate { 0, 1, 0, "ipsecesp_log_unknown_spi"}, 97*0Sstevel@tonic-gate { 0, 2, 1, "ipsecesp_padding_check"}, 98*0Sstevel@tonic-gate }; 99*0Sstevel@tonic-gate #define ipsecesp_debug ipsecesp_param_arr[0].ipsecesp_param_value 100*0Sstevel@tonic-gate #define ipsecesp_age_interval ipsecesp_param_arr[1].ipsecesp_param_value 101*0Sstevel@tonic-gate #define ipsecesp_age_int_max ipsecesp_param_arr[1].ipsecesp_param_max 102*0Sstevel@tonic-gate #define ipsecesp_reap_delay ipsecesp_param_arr[2].ipsecesp_param_value 103*0Sstevel@tonic-gate #define ipsecesp_replay_size ipsecesp_param_arr[3].ipsecesp_param_value 104*0Sstevel@tonic-gate #define ipsecesp_acquire_timeout ipsecesp_param_arr[4].ipsecesp_param_value 105*0Sstevel@tonic-gate #define ipsecesp_larval_timeout ipsecesp_param_arr[5].ipsecesp_param_value 106*0Sstevel@tonic-gate #define ipsecesp_default_soft_bytes \ 107*0Sstevel@tonic-gate ipsecesp_param_arr[6].ipsecesp_param_value 108*0Sstevel@tonic-gate #define ipsecesp_default_hard_bytes \ 109*0Sstevel@tonic-gate ipsecesp_param_arr[7].ipsecesp_param_value 110*0Sstevel@tonic-gate #define ipsecesp_default_soft_addtime \ 111*0Sstevel@tonic-gate ipsecesp_param_arr[8].ipsecesp_param_value 112*0Sstevel@tonic-gate #define ipsecesp_default_hard_addtime \ 113*0Sstevel@tonic-gate ipsecesp_param_arr[9].ipsecesp_param_value 114*0Sstevel@tonic-gate #define ipsecesp_default_soft_usetime \ 115*0Sstevel@tonic-gate ipsecesp_param_arr[10].ipsecesp_param_value 116*0Sstevel@tonic-gate #define ipsecesp_default_hard_usetime \ 117*0Sstevel@tonic-gate ipsecesp_param_arr[11].ipsecesp_param_value 118*0Sstevel@tonic-gate #define ipsecesp_log_unknown_spi \ 119*0Sstevel@tonic-gate ipsecesp_param_arr[12].ipsecesp_param_value 120*0Sstevel@tonic-gate #define ipsecesp_padding_check \ 121*0Sstevel@tonic-gate ipsecesp_param_arr[13].ipsecesp_param_value 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate #define esp0dbg(a) printf a 124*0Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 125*0Sstevel@tonic-gate #define esp1dbg(a) if (ipsecesp_debug != 0) printf a 126*0Sstevel@tonic-gate #define esp2dbg(a) if (ipsecesp_debug > 1) printf a 127*0Sstevel@tonic-gate #define esp3dbg(a) if (ipsecesp_debug > 2) printf a 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate static IDP ipsecesp_g_nd; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *); 132*0Sstevel@tonic-gate static int ipsecesp_close(queue_t *); 133*0Sstevel@tonic-gate static void ipsecesp_rput(queue_t *, mblk_t *); 134*0Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *); 135*0Sstevel@tonic-gate static void esp_send_acquire(ipsacq_t *, mblk_t *); 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* EXPORT DELETE START */ 138*0Sstevel@tonic-gate static ipsec_status_t esp_outbound_accelerated(mblk_t *, uint_t); 139*0Sstevel@tonic-gate static ipsec_status_t esp_inbound_accelerated(mblk_t *, mblk_t *, 140*0Sstevel@tonic-gate boolean_t, ipsa_t *); 141*0Sstevel@tonic-gate /* EXPORT DELETE END */ 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static boolean_t esp_register_out(uint32_t, uint32_t, uint_t); 144*0Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t, 145*0Sstevel@tonic-gate kstat_named_t **); 146*0Sstevel@tonic-gate static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t); 147*0Sstevel@tonic-gate static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *, 148*0Sstevel@tonic-gate uint_t); 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate static struct module_info info = { 151*0Sstevel@tonic-gate 5137, "ipsecesp", 0, INFPSZ, 65536, 1024 152*0Sstevel@tonic-gate }; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate static struct qinit rinit = { 155*0Sstevel@tonic-gate (pfi_t)ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 156*0Sstevel@tonic-gate NULL 157*0Sstevel@tonic-gate }; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate static struct qinit winit = { 160*0Sstevel@tonic-gate (pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 161*0Sstevel@tonic-gate NULL 162*0Sstevel@tonic-gate }; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate struct streamtab ipsecespinfo = { 165*0Sstevel@tonic-gate &rinit, &winit, NULL, NULL 166*0Sstevel@tonic-gate }; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * Keysock instance of ESP. "There can be only one." :) 170*0Sstevel@tonic-gate * Use casptr() on this because I don't set it until KEYSOCK_HELLO comes down. 171*0Sstevel@tonic-gate * Paired up with the esp_pfkey_q is the esp_event, which will age SAs. 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate static queue_t *esp_pfkey_q; 174*0Sstevel@tonic-gate static timeout_id_t esp_event; 175*0Sstevel@tonic-gate static taskq_t *esp_taskq; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /* 178*0Sstevel@tonic-gate * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now. 179*0Sstevel@tonic-gate * 180*0Sstevel@tonic-gate * Question: Do I need this, given that all instance's esps->esps_wq point 181*0Sstevel@tonic-gate * to IP? 182*0Sstevel@tonic-gate * 183*0Sstevel@tonic-gate * Answer: Yes, because I need to know which queue is BOUND to 184*0Sstevel@tonic-gate * IPPROTO_ESP 185*0Sstevel@tonic-gate */ 186*0Sstevel@tonic-gate static mblk_t *esp_ip_unbind; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate /* 189*0Sstevel@tonic-gate * Stats. This may eventually become a full-blown SNMP MIB once that spec 190*0Sstevel@tonic-gate * stabilizes. 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate typedef struct { 194*0Sstevel@tonic-gate kstat_named_t esp_stat_num_aalgs; 195*0Sstevel@tonic-gate kstat_named_t esp_stat_good_auth; 196*0Sstevel@tonic-gate kstat_named_t esp_stat_bad_auth; 197*0Sstevel@tonic-gate kstat_named_t esp_stat_bad_padding; 198*0Sstevel@tonic-gate kstat_named_t esp_stat_replay_failures; 199*0Sstevel@tonic-gate kstat_named_t esp_stat_replay_early_failures; 200*0Sstevel@tonic-gate kstat_named_t esp_stat_keysock_in; 201*0Sstevel@tonic-gate kstat_named_t esp_stat_out_requests; 202*0Sstevel@tonic-gate kstat_named_t esp_stat_acquire_requests; 203*0Sstevel@tonic-gate kstat_named_t esp_stat_bytes_expired; 204*0Sstevel@tonic-gate kstat_named_t esp_stat_out_discards; 205*0Sstevel@tonic-gate kstat_named_t esp_stat_in_accelerated; 206*0Sstevel@tonic-gate kstat_named_t esp_stat_out_accelerated; 207*0Sstevel@tonic-gate kstat_named_t esp_stat_noaccel; 208*0Sstevel@tonic-gate kstat_named_t esp_stat_crypto_sync; 209*0Sstevel@tonic-gate kstat_named_t esp_stat_crypto_async; 210*0Sstevel@tonic-gate kstat_named_t esp_stat_crypto_failures; 211*0Sstevel@tonic-gate /* EXPORT DELETE START */ 212*0Sstevel@tonic-gate kstat_named_t esp_stat_num_ealgs; 213*0Sstevel@tonic-gate kstat_named_t esp_stat_bad_decrypt; 214*0Sstevel@tonic-gate /* EXPORT DELETE END */ 215*0Sstevel@tonic-gate } esp_kstats_t; 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate #define ESP_BUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64++ 218*0Sstevel@tonic-gate #define ESP_DEBUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64-- 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate static kstat_t *esp_ksp; 221*0Sstevel@tonic-gate static esp_kstats_t *esp_kstats; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate static int esp_kstat_update(kstat_t *, int); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate static boolean_t 226*0Sstevel@tonic-gate esp_kstat_init(void) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate esp_ksp = kstat_create("ipsecesp", 0, "esp_stat", "net", 229*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (*esp_kstats) / sizeof (kstat_named_t), 230*0Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if (esp_ksp == NULL) 233*0Sstevel@tonic-gate return (B_FALSE); 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate esp_kstats = esp_ksp->ks_data; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate esp_ksp->ks_update = esp_kstat_update; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate #define K64 KSTAT_DATA_UINT64 240*0Sstevel@tonic-gate #define KI(x) kstat_named_init(&(esp_kstats->esp_stat_##x), #x, K64) 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate KI(num_aalgs); 243*0Sstevel@tonic-gate /* EXPORT DELETE START */ 244*0Sstevel@tonic-gate KI(num_ealgs); 245*0Sstevel@tonic-gate /* EXPORT DELETE END */ 246*0Sstevel@tonic-gate KI(good_auth); 247*0Sstevel@tonic-gate KI(bad_auth); 248*0Sstevel@tonic-gate KI(bad_padding); 249*0Sstevel@tonic-gate KI(replay_failures); 250*0Sstevel@tonic-gate KI(replay_early_failures); 251*0Sstevel@tonic-gate KI(keysock_in); 252*0Sstevel@tonic-gate KI(out_requests); 253*0Sstevel@tonic-gate KI(acquire_requests); 254*0Sstevel@tonic-gate KI(bytes_expired); 255*0Sstevel@tonic-gate KI(out_discards); 256*0Sstevel@tonic-gate KI(in_accelerated); 257*0Sstevel@tonic-gate KI(out_accelerated); 258*0Sstevel@tonic-gate KI(noaccel); 259*0Sstevel@tonic-gate KI(crypto_sync); 260*0Sstevel@tonic-gate KI(crypto_async); 261*0Sstevel@tonic-gate KI(crypto_failures); 262*0Sstevel@tonic-gate /* EXPORT DELETE START */ 263*0Sstevel@tonic-gate KI(bad_decrypt); 264*0Sstevel@tonic-gate /* EXPORT DELETE END */ 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate #undef KI 267*0Sstevel@tonic-gate #undef K64 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate kstat_install(esp_ksp); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate return (B_TRUE); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate static int 275*0Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw) 276*0Sstevel@tonic-gate { 277*0Sstevel@tonic-gate esp_kstats_t *ekp; 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 280*0Sstevel@tonic-gate return (EIO); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) 283*0Sstevel@tonic-gate return (EACCES); 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate ASSERT(kp == esp_ksp); 286*0Sstevel@tonic-gate ekp = (esp_kstats_t *)kp->ks_data; 287*0Sstevel@tonic-gate ASSERT(ekp == esp_kstats); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate mutex_enter(&alg_lock); 290*0Sstevel@tonic-gate ekp->esp_stat_num_aalgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_AUTH]; 291*0Sstevel@tonic-gate /* EXPORT DELETE START */ 292*0Sstevel@tonic-gate ekp->esp_stat_num_ealgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_ENCR]; 293*0Sstevel@tonic-gate /* EXPORT DELETE END */ 294*0Sstevel@tonic-gate mutex_exit(&alg_lock); 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate return (0); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate #ifdef DEBUG 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Debug routine, useful to see pre-encryption data. 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate static char * 304*0Sstevel@tonic-gate dump_msg(mblk_t *mp) 305*0Sstevel@tonic-gate { 306*0Sstevel@tonic-gate char tmp_str[3], tmp_line[256]; 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate while (mp != NULL) { 309*0Sstevel@tonic-gate unsigned char *ptr; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate printf("mblk address 0x%p, length %ld, db_ref %d " 312*0Sstevel@tonic-gate "type %d, base 0x%p, lim 0x%p\n", 313*0Sstevel@tonic-gate (void *) mp, (long)(mp->b_wptr - mp->b_rptr), 314*0Sstevel@tonic-gate mp->b_datap->db_ref, mp->b_datap->db_type, 315*0Sstevel@tonic-gate (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim); 316*0Sstevel@tonic-gate ptr = mp->b_rptr; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate tmp_line[0] = '\0'; 319*0Sstevel@tonic-gate while (ptr < mp->b_wptr) { 320*0Sstevel@tonic-gate uint_t diff; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate diff = (ptr - mp->b_rptr); 323*0Sstevel@tonic-gate if (!(diff & 0x1f)) { 324*0Sstevel@tonic-gate if (strlen(tmp_line) > 0) { 325*0Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 326*0Sstevel@tonic-gate tmp_line[0] = '\0'; 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate if (!(diff & 0x3)) 330*0Sstevel@tonic-gate (void) strcat(tmp_line, " "); 331*0Sstevel@tonic-gate (void) sprintf(tmp_str, "%02x", *ptr); 332*0Sstevel@tonic-gate (void) strcat(tmp_line, tmp_str); 333*0Sstevel@tonic-gate ptr++; 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate if (strlen(tmp_line) > 0) 336*0Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate mp = mp->b_cont; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate return ("\n"); 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate #else /* DEBUG */ 345*0Sstevel@tonic-gate static char * 346*0Sstevel@tonic-gate dump_msg(mblk_t *mp) 347*0Sstevel@tonic-gate { 348*0Sstevel@tonic-gate printf("Find value of mp %p.\n", mp); 349*0Sstevel@tonic-gate return ("\n"); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate #endif /* DEBUG */ 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * Don't have to lock age_interval, as only one thread will access it at 355*0Sstevel@tonic-gate * a time, because I control the one function that does with timeout(). 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate /* ARGSUSED */ 358*0Sstevel@tonic-gate static void 359*0Sstevel@tonic-gate esp_ager(void *ignoreme) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate hrtime_t begin = gethrtime(); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate sadb_ager(&esp_sadb.s_v4, esp_pfkey_q, esp_sadb.s_ip_q, 364*0Sstevel@tonic-gate ipsecesp_reap_delay); 365*0Sstevel@tonic-gate sadb_ager(&esp_sadb.s_v6, esp_pfkey_q, esp_sadb.s_ip_q, 366*0Sstevel@tonic-gate ipsecesp_reap_delay); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate esp_event = sadb_retimeout(begin, esp_pfkey_q, esp_ager, 369*0Sstevel@tonic-gate &(ipsecesp_age_interval), ipsecesp_age_int_max, info.mi_idnum); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Get an ESP NDD parameter. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate /* ARGSUSED */ 376*0Sstevel@tonic-gate static int 377*0Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr) 378*0Sstevel@tonic-gate queue_t *q; 379*0Sstevel@tonic-gate mblk_t *mp; 380*0Sstevel@tonic-gate caddr_t cp; 381*0Sstevel@tonic-gate cred_t *cr; 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 384*0Sstevel@tonic-gate uint_t value; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate mutex_enter(&ipsecesp_param_lock); 387*0Sstevel@tonic-gate value = ipsecesppa->ipsecesp_param_value; 388*0Sstevel@tonic-gate mutex_exit(&ipsecesp_param_lock); 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 391*0Sstevel@tonic-gate return (0); 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate /* 395*0Sstevel@tonic-gate * This routine sets an NDD variable in a ipsecespparam_t structure. 396*0Sstevel@tonic-gate */ 397*0Sstevel@tonic-gate /* ARGSUSED */ 398*0Sstevel@tonic-gate static int 399*0Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr) 400*0Sstevel@tonic-gate queue_t *q; 401*0Sstevel@tonic-gate mblk_t *mp; 402*0Sstevel@tonic-gate char *value; 403*0Sstevel@tonic-gate caddr_t cp; 404*0Sstevel@tonic-gate cred_t *cr; 405*0Sstevel@tonic-gate { 406*0Sstevel@tonic-gate ulong_t new_value; 407*0Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * Fail the request if the new value does not lie within the 411*0Sstevel@tonic-gate * required bounds. 412*0Sstevel@tonic-gate */ 413*0Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 414*0Sstevel@tonic-gate new_value < ipsecesppa->ipsecesp_param_min || 415*0Sstevel@tonic-gate new_value > ipsecesppa->ipsecesp_param_max) { 416*0Sstevel@tonic-gate return (EINVAL); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* Set the new value */ 420*0Sstevel@tonic-gate mutex_enter(&ipsecesp_param_lock); 421*0Sstevel@tonic-gate ipsecesppa->ipsecesp_param_value = new_value; 422*0Sstevel@tonic-gate mutex_exit(&ipsecesp_param_lock); 423*0Sstevel@tonic-gate return (0); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * Using lifetime NDD variables, fill in an extended combination's 428*0Sstevel@tonic-gate * lifetime information. 429*0Sstevel@tonic-gate */ 430*0Sstevel@tonic-gate void 431*0Sstevel@tonic-gate ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb) 432*0Sstevel@tonic-gate { 433*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_bytes = ipsecesp_default_soft_bytes; 434*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_bytes = ipsecesp_default_hard_bytes; 435*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_addtime = ipsecesp_default_soft_addtime; 436*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_addtime = ipsecesp_default_hard_addtime; 437*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_usetime = ipsecesp_default_soft_usetime; 438*0Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_usetime = ipsecesp_default_hard_usetime; 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Initialize things for ESP at module load time. 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate boolean_t 445*0Sstevel@tonic-gate ipsecesp_ddi_init(void) 446*0Sstevel@tonic-gate { 447*0Sstevel@tonic-gate int count; 448*0Sstevel@tonic-gate ipsecespparam_t *espp = ipsecesp_param_arr; 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate for (count = A_CNT(ipsecesp_param_arr); count-- > 0; espp++) { 451*0Sstevel@tonic-gate if (espp->ipsecesp_param_name != NULL && 452*0Sstevel@tonic-gate espp->ipsecesp_param_name[0]) { 453*0Sstevel@tonic-gate if (!nd_load(&ipsecesp_g_nd, espp->ipsecesp_param_name, 454*0Sstevel@tonic-gate ipsecesp_param_get, ipsecesp_param_set, 455*0Sstevel@tonic-gate (caddr_t)espp)) { 456*0Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 457*0Sstevel@tonic-gate return (B_FALSE); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate if (!esp_kstat_init()) { 463*0Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 464*0Sstevel@tonic-gate return (B_FALSE); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate esp_sadb.s_acquire_timeout = &ipsecesp_acquire_timeout; 468*0Sstevel@tonic-gate esp_sadb.s_acqfn = esp_send_acquire; 469*0Sstevel@tonic-gate sadbp_init(&esp_sadb, SADB_SATYPE_ESP); 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate esp_taskq = taskq_create("esp_taskq", 1, minclsyspri, 472*0Sstevel@tonic-gate IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate mutex_init(&ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate ip_drop_register(&esp_dropper, "IPsec ESP"); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate return (B_TRUE); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /* 482*0Sstevel@tonic-gate * Destroy things for ESP at module unload time. 483*0Sstevel@tonic-gate */ 484*0Sstevel@tonic-gate void 485*0Sstevel@tonic-gate ipsecesp_ddi_destroy(void) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate esp1dbg(("In ipsecesp_ddi_destroy.\n")); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate sadbp_destroy(&esp_sadb); 490*0Sstevel@tonic-gate ip_drop_unregister(&esp_dropper); 491*0Sstevel@tonic-gate taskq_destroy(esp_taskq); 492*0Sstevel@tonic-gate mutex_destroy(&ipsecesp_param_lock); 493*0Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 494*0Sstevel@tonic-gate kstat_delete(esp_ksp); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate /* 498*0Sstevel@tonic-gate * ESP module open routine. 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate /* ARGSUSED */ 501*0Sstevel@tonic-gate static int 502*0Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 503*0Sstevel@tonic-gate { 504*0Sstevel@tonic-gate if (secpolicy_net_config(credp, B_FALSE) != 0) { 505*0Sstevel@tonic-gate esp1dbg(("Non-privileged user trying to open ipsecesp.\n")); 506*0Sstevel@tonic-gate return (EPERM); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate if (q->q_ptr != NULL) 510*0Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if (sflag != MODOPEN) 513*0Sstevel@tonic-gate return (EINVAL); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * ASSUMPTIONS (because I'm MT_OCEXCL): 517*0Sstevel@tonic-gate * 518*0Sstevel@tonic-gate * * I'm being pushed on top of IP for all my opens (incl. #1). 519*0Sstevel@tonic-gate * * Only ipsecesp_open() can write into esp_sadb.s_ip_q. 520*0Sstevel@tonic-gate * * Because of this, I can check lazily for esp_sadb.s_ip_q. 521*0Sstevel@tonic-gate * 522*0Sstevel@tonic-gate * If these assumptions are wrong, I'm in BIG trouble... 523*0Sstevel@tonic-gate */ 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate q->q_ptr = q; /* just so I know I'm open */ 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate if (esp_sadb.s_ip_q == NULL) { 528*0Sstevel@tonic-gate struct T_unbind_req *tur; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate esp_sadb.s_ip_q = WR(q); 531*0Sstevel@tonic-gate /* Allocate an unbind... */ 532*0Sstevel@tonic-gate esp_ip_unbind = allocb(sizeof (struct T_unbind_req), BPRI_HI); 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * Send down T_BIND_REQ to bind IPPROTO_ESP. 536*0Sstevel@tonic-gate * Handle the ACK here in ESP. 537*0Sstevel@tonic-gate */ 538*0Sstevel@tonic-gate qprocson(q); 539*0Sstevel@tonic-gate if (esp_ip_unbind == NULL || 540*0Sstevel@tonic-gate !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) { 541*0Sstevel@tonic-gate if (esp_ip_unbind != NULL) { 542*0Sstevel@tonic-gate freeb(esp_ip_unbind); 543*0Sstevel@tonic-gate esp_ip_unbind = NULL; 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate q->q_ptr = NULL; 546*0Sstevel@tonic-gate return (ENOMEM); 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate esp_ip_unbind->b_datap->db_type = M_PROTO; 550*0Sstevel@tonic-gate tur = (struct T_unbind_req *)esp_ip_unbind->b_rptr; 551*0Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 552*0Sstevel@tonic-gate } else { 553*0Sstevel@tonic-gate qprocson(q); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate /* 557*0Sstevel@tonic-gate * For now, there's not much I can do. I'll be getting a message 558*0Sstevel@tonic-gate * passed down to me from keysock (in my wput), and a T_BIND_ACK 559*0Sstevel@tonic-gate * up from IP (in my rput). 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate return (0); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * ESP module close routine. 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate static int 569*0Sstevel@tonic-gate ipsecesp_close(queue_t *q) 570*0Sstevel@tonic-gate { 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * If esp_sadb.s_ip_q is attached to this instance, send a 573*0Sstevel@tonic-gate * T_UNBIND_REQ to IP for the instance before doing 574*0Sstevel@tonic-gate * a qprocsoff(). 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate if (WR(q) == esp_sadb.s_ip_q && esp_ip_unbind != NULL) { 577*0Sstevel@tonic-gate putnext(WR(q), esp_ip_unbind); 578*0Sstevel@tonic-gate esp_ip_unbind = NULL; 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * Clean up q_ptr, if needed. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate qprocsoff(q); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* Keysock queue check is safe, because of OCEXCL perimeter. */ 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate if (q == esp_pfkey_q) { 589*0Sstevel@tonic-gate esp0dbg(("ipsecesp_close: Ummm... keysock is closing ESP.\n")); 590*0Sstevel@tonic-gate esp_pfkey_q = NULL; 591*0Sstevel@tonic-gate /* Detach qtimeouts. */ 592*0Sstevel@tonic-gate (void) quntimeout(q, esp_event); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate if (WR(q) == esp_sadb.s_ip_q) { 596*0Sstevel@tonic-gate /* 597*0Sstevel@tonic-gate * If the esp_sadb.s_ip_q is attached to this instance, find 598*0Sstevel@tonic-gate * another. The OCEXCL outer perimeter helps us here. 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate /* 603*0Sstevel@tonic-gate * Find a replacement queue for esp_sadb.s_ip_q. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate if (esp_pfkey_q != NULL && esp_pfkey_q != RD(q)) { 606*0Sstevel@tonic-gate /* 607*0Sstevel@tonic-gate * See if we can use the pfkey_q. 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate esp_sadb.s_ip_q = WR(esp_pfkey_q); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate if (esp_sadb.s_ip_q == NULL || 613*0Sstevel@tonic-gate !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) { 614*0Sstevel@tonic-gate esp1dbg(("ipsecesp: Can't reassign ip_q.\n")); 615*0Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 616*0Sstevel@tonic-gate } else { 617*0Sstevel@tonic-gate esp_ip_unbind = allocb(sizeof (struct T_unbind_req), 618*0Sstevel@tonic-gate BPRI_HI); 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate if (esp_ip_unbind != NULL) { 621*0Sstevel@tonic-gate struct T_unbind_req *tur; 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate esp_ip_unbind->b_datap->db_type = M_PROTO; 624*0Sstevel@tonic-gate tur = (struct T_unbind_req *) 625*0Sstevel@tonic-gate esp_ip_unbind->b_rptr; 626*0Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate /* If it's NULL, I can't do much here. */ 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate return (0); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate /* 636*0Sstevel@tonic-gate * Add a number of bytes to what the SA has protected so far. Return 637*0Sstevel@tonic-gate * B_TRUE if the SA can still protect that many bytes. 638*0Sstevel@tonic-gate * 639*0Sstevel@tonic-gate * Caller must REFRELE the passed-in assoc. This function must REFRELE 640*0Sstevel@tonic-gate * any obtained peer SA. 641*0Sstevel@tonic-gate */ 642*0Sstevel@tonic-gate static boolean_t 643*0Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound) 644*0Sstevel@tonic-gate { 645*0Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 646*0Sstevel@tonic-gate isaf_t *bucket; 647*0Sstevel@tonic-gate boolean_t inrc, outrc, isv6; 648*0Sstevel@tonic-gate sadb_t *sp; 649*0Sstevel@tonic-gate int outhash; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate /* No peer? No problem! */ 652*0Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 653*0Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, assoc, bytes, 654*0Sstevel@tonic-gate B_TRUE)); 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 659*0Sstevel@tonic-gate * There might be a race for this, but if it's a real race, two 660*0Sstevel@tonic-gate * expire messages may occur. We limit this by only sending the 661*0Sstevel@tonic-gate * expire message on one of the peers, we'll pick the inbound 662*0Sstevel@tonic-gate * arbitrarily. 663*0Sstevel@tonic-gate * 664*0Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 665*0Sstevel@tonic-gate * reconsider. 666*0Sstevel@tonic-gate */ 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 669*0Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 670*0Sstevel@tonic-gate sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate if (inbound) { 673*0Sstevel@tonic-gate inassoc = assoc; 674*0Sstevel@tonic-gate if (isv6) { 675*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V6(*((in6_addr_t *) 676*0Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 677*0Sstevel@tonic-gate } else { 678*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V4(*((ipaddr_t *) 679*0Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 682*0Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 683*0Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 684*0Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 685*0Sstevel@tonic-gate inassoc->ipsa_addrfam); 686*0Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 687*0Sstevel@tonic-gate if (outassoc == NULL) { 688*0Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 689*0Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 690*0Sstevel@tonic-gate "can't find peer for inbound.\n")); 691*0Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, inassoc, 692*0Sstevel@tonic-gate bytes, B_TRUE)); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate } else { 695*0Sstevel@tonic-gate outassoc = assoc; 696*0Sstevel@tonic-gate bucket = &sp->sdb_if[INBOUND_HASH(outassoc->ipsa_spi)]; 697*0Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 698*0Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 699*0Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 700*0Sstevel@tonic-gate outassoc->ipsa_addrfam); 701*0Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 702*0Sstevel@tonic-gate if (inassoc == NULL) { 703*0Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 704*0Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 705*0Sstevel@tonic-gate "can't find peer for outbound.\n")); 706*0Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, outassoc, 707*0Sstevel@tonic-gate bytes, B_TRUE)); 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate inrc = sadb_age_bytes(esp_pfkey_q, inassoc, bytes, B_TRUE); 712*0Sstevel@tonic-gate outrc = sadb_age_bytes(esp_pfkey_q, outassoc, bytes, B_FALSE); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /* 715*0Sstevel@tonic-gate * REFRELE any peer SA. 716*0Sstevel@tonic-gate * 717*0Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 718*0Sstevel@tonic-gate * them in { }. 719*0Sstevel@tonic-gate */ 720*0Sstevel@tonic-gate if (inbound) { 721*0Sstevel@tonic-gate IPSA_REFRELE(outassoc); 722*0Sstevel@tonic-gate } else { 723*0Sstevel@tonic-gate IPSA_REFRELE(inassoc); 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate return (inrc && outrc); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate /* 730*0Sstevel@tonic-gate * Do incoming NAT-T manipulations for packet. 731*0Sstevel@tonic-gate */ 732*0Sstevel@tonic-gate static ipsec_status_t 733*0Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc) 734*0Sstevel@tonic-gate { 735*0Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 736*0Sstevel@tonic-gate tcpha_t *tcph; 737*0Sstevel@tonic-gate udpha_t *udpha; 738*0Sstevel@tonic-gate /* Initialize to our inbound cksum adjustment... */ 739*0Sstevel@tonic-gate uint32_t sum = assoc->ipsa_inbound_cksum; 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate switch (ipha->ipha_protocol) { 742*0Sstevel@tonic-gate case IPPROTO_TCP: 743*0Sstevel@tonic-gate tcph = (tcpha_t *)(data_mp->b_rptr + 744*0Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate #define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16) 747*0Sstevel@tonic-gate sum += ~ntohs(tcph->tha_sum) & 0xFFFF; 748*0Sstevel@tonic-gate DOWN_SUM(sum); 749*0Sstevel@tonic-gate DOWN_SUM(sum); 750*0Sstevel@tonic-gate tcph->tha_sum = ~htons(sum); 751*0Sstevel@tonic-gate break; 752*0Sstevel@tonic-gate case IPPROTO_UDP: 753*0Sstevel@tonic-gate udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha)); 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate if (udpha->uha_checksum != 0) { 756*0Sstevel@tonic-gate /* Adujst if the inbound one was not zero. */ 757*0Sstevel@tonic-gate sum += ~ntohs(udpha->uha_checksum) & 0xFFFF; 758*0Sstevel@tonic-gate DOWN_SUM(sum); 759*0Sstevel@tonic-gate DOWN_SUM(sum); 760*0Sstevel@tonic-gate udpha->uha_checksum = ~htons(sum); 761*0Sstevel@tonic-gate if (udpha->uha_checksum == 0) 762*0Sstevel@tonic-gate udpha->uha_checksum = 0xFFFF; 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate #undef DOWN_SUM 765*0Sstevel@tonic-gate break; 766*0Sstevel@tonic-gate case IPPROTO_IP: 767*0Sstevel@tonic-gate /* 768*0Sstevel@tonic-gate * This case is only an issue for self-encapsulated 769*0Sstevel@tonic-gate * packets. So for now, fall through. 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate break; 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate /* 778*0Sstevel@tonic-gate * Strip ESP header and fix IP header 779*0Sstevel@tonic-gate * Returns B_TRUE on success, B_FALSE if an error occured. 780*0Sstevel@tonic-gate */ 781*0Sstevel@tonic-gate static boolean_t 782*0Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen, 783*0Sstevel@tonic-gate kstat_named_t **counter) 784*0Sstevel@tonic-gate { 785*0Sstevel@tonic-gate ipha_t *ipha; 786*0Sstevel@tonic-gate ip6_t *ip6h; 787*0Sstevel@tonic-gate uint_t divpoint; 788*0Sstevel@tonic-gate mblk_t *scratch; 789*0Sstevel@tonic-gate uint8_t nexthdr, padlen; 790*0Sstevel@tonic-gate uint8_t lastpad; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * Strip ESP data and fix IP header. 794*0Sstevel@tonic-gate * 795*0Sstevel@tonic-gate * XXX In case the beginning of esp_inbound() changes to not do a 796*0Sstevel@tonic-gate * pullup, this part of the code can remain unchanged. 797*0Sstevel@tonic-gate */ 798*0Sstevel@tonic-gate if (isv4) { 799*0Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t)); 800*0Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 801*0Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) + 802*0Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 803*0Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 804*0Sstevel@tonic-gate } else { 805*0Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t)); 806*0Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 807*0Sstevel@tonic-gate divpoint = ip_hdr_length_v6(data_mp, ip6h); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate scratch = data_mp; 811*0Sstevel@tonic-gate while (scratch->b_cont != NULL) 812*0Sstevel@tonic-gate scratch = scratch->b_cont; 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3); 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * "Next header" and padding length are the last two bytes in the 818*0Sstevel@tonic-gate * ESP-protected datagram, thus the explicit - 1 and - 2. 819*0Sstevel@tonic-gate * lastpad is the last byte of the padding, which can be used for 820*0Sstevel@tonic-gate * a quick check to see if the padding is correct. 821*0Sstevel@tonic-gate */ 822*0Sstevel@tonic-gate nexthdr = *(scratch->b_wptr - 1); 823*0Sstevel@tonic-gate padlen = *(scratch->b_wptr - 2); 824*0Sstevel@tonic-gate lastpad = *(scratch->b_wptr - 3); 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate if (isv4) { 827*0Sstevel@tonic-gate /* Fix part of the IP header. */ 828*0Sstevel@tonic-gate ipha->ipha_protocol = nexthdr; 829*0Sstevel@tonic-gate /* 830*0Sstevel@tonic-gate * Reality check the padlen. The explicit - 2 is for the 831*0Sstevel@tonic-gate * padding length and the next-header bytes. 832*0Sstevel@tonic-gate */ 833*0Sstevel@tonic-gate if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 - 834*0Sstevel@tonic-gate sizeof (esph_t) - ivlen) { 835*0Sstevel@tonic-gate /* EXPORT DELETE START */ 836*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_decrypt); 837*0Sstevel@tonic-gate /* EXPORT DELETE END */ 838*0Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 839*0Sstevel@tonic-gate "Possibly corrupt ESP packet."); 840*0Sstevel@tonic-gate esp1dbg(("padlen (%d) is greater than:\n", padlen)); 841*0Sstevel@tonic-gate esp1dbg(("pkt len(%d) - ip hdr - esp hdr - ivlen(%d) " 842*0Sstevel@tonic-gate "= %d.\n", ntohs(ipha->ipha_length), ivlen, 843*0Sstevel@tonic-gate (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) - 844*0Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen))); 845*0Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padlen; 846*0Sstevel@tonic-gate return (B_FALSE); 847*0Sstevel@tonic-gate } 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate /* 850*0Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 851*0Sstevel@tonic-gate * padding length and the next-header bytes. 852*0Sstevel@tonic-gate */ 853*0Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen - 854*0Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 855*0Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 856*0Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 857*0Sstevel@tonic-gate } else { 858*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_ESP) { 859*0Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 860*0Sstevel@tonic-gate } else { 861*0Sstevel@tonic-gate ip6_pkt_t ipp; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 864*0Sstevel@tonic-gate (void) ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 865*0Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL) { 866*0Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt = nexthdr; 867*0Sstevel@tonic-gate } else if (ipp.ipp_rthdr != NULL) { 868*0Sstevel@tonic-gate ipp.ipp_rthdr->ip6r_nxt = nexthdr; 869*0Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 870*0Sstevel@tonic-gate ipp.ipp_hopopts->ip6h_nxt = nexthdr; 871*0Sstevel@tonic-gate } else { 872*0Sstevel@tonic-gate /* Panic a DEBUG kernel. */ 873*0Sstevel@tonic-gate ASSERT(ipp.ipp_hopopts != NULL); 874*0Sstevel@tonic-gate /* Otherwise, pretend it's IP + ESP. */ 875*0Sstevel@tonic-gate cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n"); 876*0Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate } 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) - 881*0Sstevel@tonic-gate ivlen) { 882*0Sstevel@tonic-gate /* EXPORT DELETE START */ 883*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_decrypt); 884*0Sstevel@tonic-gate /* EXPORT DELETE END */ 885*0Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 886*0Sstevel@tonic-gate "Possibly corrupt ESP packet."); 887*0Sstevel@tonic-gate esp1dbg(("padlen (%d) is greater than:\n", padlen)); 888*0Sstevel@tonic-gate esp1dbg(("pkt len(%u) - ip hdr - esp hdr - ivlen(%d)" 889*0Sstevel@tonic-gate " = %u.\n", (unsigned)(ntohs(ip6h->ip6_plen) 890*0Sstevel@tonic-gate + sizeof (ip6_t)), ivlen, 891*0Sstevel@tonic-gate (unsigned)(ntohs(ip6h->ip6_plen) - 2 - 892*0Sstevel@tonic-gate sizeof (esph_t) - ivlen))); 893*0Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padlen; 894*0Sstevel@tonic-gate return (B_FALSE); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate /* 899*0Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 900*0Sstevel@tonic-gate * padding length and the next-header bytes. IPv6 is nice, 901*0Sstevel@tonic-gate * because there's no hdr checksum! 902*0Sstevel@tonic-gate */ 903*0Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen - 904*0Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate if (ipsecesp_padding_check > 0 && 908*0Sstevel@tonic-gate padlen != lastpad && padlen != 0) { 909*0Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 910*0Sstevel@tonic-gate "Possibly corrupt ESP packet."); 911*0Sstevel@tonic-gate esp1dbg(("lastpad (%d) not equal to padlen (%d):\n", 912*0Sstevel@tonic-gate lastpad, padlen)); 913*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_padding); 914*0Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padding; 915*0Sstevel@tonic-gate return (B_FALSE); 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate if (ipsecesp_padding_check > 1) { 919*0Sstevel@tonic-gate uint8_t *last = (uint8_t *)(scratch->b_wptr - 3); 920*0Sstevel@tonic-gate uint8_t lastval = *last; 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * this assert may have to become an if 924*0Sstevel@tonic-gate * and a pullup if we start accepting 925*0Sstevel@tonic-gate * multi-dblk mblks. Any packet here will 926*0Sstevel@tonic-gate * have been pulled up in esp_inbound. 927*0Sstevel@tonic-gate */ 928*0Sstevel@tonic-gate ASSERT(MBLKL(scratch) >= lastval + 3); 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate while (lastval != 0) { 931*0Sstevel@tonic-gate if (lastval != *last) { 932*0Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, 933*0Sstevel@tonic-gate SL_ERROR | SL_WARN, 934*0Sstevel@tonic-gate "Possibly corrupt ESP packet."); 935*0Sstevel@tonic-gate esp1dbg(("padding not in correct" 936*0Sstevel@tonic-gate " format:\n")); 937*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_padding); 938*0Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padding; 939*0Sstevel@tonic-gate return (B_FALSE); 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate lastval--; last--; 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate /* Trim off the padding. */ 946*0Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 947*0Sstevel@tonic-gate data_mp->b_wptr -= (padlen + 2); 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate /* 950*0Sstevel@tonic-gate * Remove the ESP header. 951*0Sstevel@tonic-gate * 952*0Sstevel@tonic-gate * The above assertions about data_mp's size will make this work. 953*0Sstevel@tonic-gate * 954*0Sstevel@tonic-gate * XXX Question: If I send up and get back a contiguous mblk, 955*0Sstevel@tonic-gate * would it be quicker to bcopy over, or keep doing the dupb stuff? 956*0Sstevel@tonic-gate * I go with copying for now. 957*0Sstevel@tonic-gate */ 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) && 960*0Sstevel@tonic-gate IS_P2ALIGNED(ivlen, sizeof (uint32_t))) { 961*0Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 962*0Sstevel@tonic-gate uint32_t *src, *dst; 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate src = (uint32_t *)(start + divpoint); 965*0Sstevel@tonic-gate dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen); 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) && 968*0Sstevel@tonic-gate IS_P2ALIGNED(src, sizeof (uint32_t))); 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate do { 971*0Sstevel@tonic-gate src--; 972*0Sstevel@tonic-gate dst--; 973*0Sstevel@tonic-gate *dst = *src; 974*0Sstevel@tonic-gate } while (src != (uint32_t *)start); 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate data_mp->b_rptr = (uchar_t *)dst; 977*0Sstevel@tonic-gate } else { 978*0Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 979*0Sstevel@tonic-gate uint8_t *src, *dst; 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate src = start + divpoint; 982*0Sstevel@tonic-gate dst = src + sizeof (esph_t) + ivlen; 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate do { 985*0Sstevel@tonic-gate src--; 986*0Sstevel@tonic-gate dst--; 987*0Sstevel@tonic-gate *dst = *src; 988*0Sstevel@tonic-gate } while (src != start); 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate data_mp->b_rptr = dst; 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate esp2dbg(("data_mp after inbound ESP adjustment:\n")); 994*0Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate return (B_TRUE); 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate /* 1000*0Sstevel@tonic-gate * Updating use times can be tricky business if the ipsa_haspeer flag is 1001*0Sstevel@tonic-gate * set. This function is called once in an SA's lifetime. 1002*0Sstevel@tonic-gate * 1003*0Sstevel@tonic-gate * Caller has to REFRELE "assoc" which is passed in. This function has 1004*0Sstevel@tonic-gate * to REFRELE any peer SA that is obtained. 1005*0Sstevel@tonic-gate */ 1006*0Sstevel@tonic-gate static void 1007*0Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound) 1008*0Sstevel@tonic-gate { 1009*0Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 1010*0Sstevel@tonic-gate isaf_t *bucket; 1011*0Sstevel@tonic-gate sadb_t *sp; 1012*0Sstevel@tonic-gate int outhash; 1013*0Sstevel@tonic-gate boolean_t isv6; 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate /* No peer? No problem! */ 1016*0Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 1017*0Sstevel@tonic-gate sadb_set_usetime(assoc); 1018*0Sstevel@tonic-gate return; 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate /* 1022*0Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 1023*0Sstevel@tonic-gate * There might be a race for this, but if it's a real race, the times 1024*0Sstevel@tonic-gate * will be out-of-synch by at most a second, and since our time 1025*0Sstevel@tonic-gate * granularity is a second, this won't be a problem. 1026*0Sstevel@tonic-gate * 1027*0Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 1028*0Sstevel@tonic-gate * reconsider. 1029*0Sstevel@tonic-gate */ 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 1032*0Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 1033*0Sstevel@tonic-gate sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4; 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate if (inbound) { 1036*0Sstevel@tonic-gate inassoc = assoc; 1037*0Sstevel@tonic-gate if (isv6) { 1038*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V6(*((in6_addr_t *) 1039*0Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 1040*0Sstevel@tonic-gate } else { 1041*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V4(*((ipaddr_t *) 1042*0Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 1045*0Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 1046*0Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 1047*0Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 1048*0Sstevel@tonic-gate inassoc->ipsa_addrfam); 1049*0Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 1050*0Sstevel@tonic-gate if (outassoc == NULL) { 1051*0Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 1052*0Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 1053*0Sstevel@tonic-gate "can't find peer for inbound.\n")); 1054*0Sstevel@tonic-gate sadb_set_usetime(inassoc); 1055*0Sstevel@tonic-gate return; 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate outassoc = assoc; 1059*0Sstevel@tonic-gate bucket = &sp->sdb_if[INBOUND_HASH(outassoc->ipsa_spi)]; 1060*0Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 1061*0Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 1062*0Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 1063*0Sstevel@tonic-gate outassoc->ipsa_addrfam); 1064*0Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 1065*0Sstevel@tonic-gate if (inassoc == NULL) { 1066*0Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 1067*0Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 1068*0Sstevel@tonic-gate "can't find peer for outbound.\n")); 1069*0Sstevel@tonic-gate sadb_set_usetime(outassoc); 1070*0Sstevel@tonic-gate return; 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate } 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate /* Update usetime on both. */ 1075*0Sstevel@tonic-gate sadb_set_usetime(inassoc); 1076*0Sstevel@tonic-gate sadb_set_usetime(outassoc); 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate /* 1079*0Sstevel@tonic-gate * REFRELE any peer SA. 1080*0Sstevel@tonic-gate * 1081*0Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 1082*0Sstevel@tonic-gate * them in { }. 1083*0Sstevel@tonic-gate */ 1084*0Sstevel@tonic-gate if (inbound) { 1085*0Sstevel@tonic-gate IPSA_REFRELE(outassoc); 1086*0Sstevel@tonic-gate } else { 1087*0Sstevel@tonic-gate IPSA_REFRELE(inassoc); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate /* 1092*0Sstevel@tonic-gate * Handle ESP inbound data for IPv4 and IPv6. 1093*0Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 1094*0Sstevel@tonic-gate * mblk chain ipsec_in_mp. 1095*0Sstevel@tonic-gate */ 1096*0Sstevel@tonic-gate ipsec_status_t 1097*0Sstevel@tonic-gate esp_inbound(mblk_t *ipsec_in_mp, void *arg) 1098*0Sstevel@tonic-gate { 1099*0Sstevel@tonic-gate mblk_t *data_mp = ipsec_in_mp->b_cont; 1100*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 1101*0Sstevel@tonic-gate esph_t *esph = (esph_t *)arg; 1102*0Sstevel@tonic-gate ipsa_t *ipsa = ii->ipsec_in_esp_sa; 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate if (ipsa->ipsa_usetime == 0) 1105*0Sstevel@tonic-gate esp_set_usetime(ipsa, B_TRUE); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate /* 1108*0Sstevel@tonic-gate * We may wish to check replay in-range-only here as an optimization. 1109*0Sstevel@tonic-gate * Include the reality check of ipsa->ipsa_replay > 1110*0Sstevel@tonic-gate * ipsa->ipsa_replay_wsize for times when it's the first N packets, 1111*0Sstevel@tonic-gate * where N == ipsa->ipsa_replay_wsize. 1112*0Sstevel@tonic-gate * 1113*0Sstevel@tonic-gate * Another check that may come here later is the "collision" check. 1114*0Sstevel@tonic-gate * If legitimate packets flow quickly enough, this won't be a problem, 1115*0Sstevel@tonic-gate * but collisions may cause authentication algorithm crunching to 1116*0Sstevel@tonic-gate * take place when it doesn't need to. 1117*0Sstevel@tonic-gate */ 1118*0Sstevel@tonic-gate if (!sadb_replay_peek(ipsa, esph->esph_replay)) { 1119*0Sstevel@tonic-gate ESP_BUMP_STAT(replay_early_failures); 1120*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 1121*0Sstevel@tonic-gate /* 1122*0Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 1123*0Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 1124*0Sstevel@tonic-gate */ 1125*0Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 1126*0Sstevel@tonic-gate &ipdrops_esp_early_replay, &esp_dropper); 1127*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 1128*0Sstevel@tonic-gate } 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1131*0Sstevel@tonic-gate /* 1132*0Sstevel@tonic-gate * Has this packet already been processed by a hardware 1133*0Sstevel@tonic-gate * IPsec accelerator? 1134*0Sstevel@tonic-gate */ 1135*0Sstevel@tonic-gate if (ii->ipsec_in_accelerated) { 1136*0Sstevel@tonic-gate ipsec_status_t rv; 1137*0Sstevel@tonic-gate esp3dbg(("esp_inbound: pkt processed by ill=%d isv6=%d\n", 1138*0Sstevel@tonic-gate ii->ipsec_in_ill_index, !ii->ipsec_in_v4)); 1139*0Sstevel@tonic-gate rv = esp_inbound_accelerated(ipsec_in_mp, 1140*0Sstevel@tonic-gate data_mp, ii->ipsec_in_v4, ipsa); 1141*0Sstevel@tonic-gate return (rv); 1142*0Sstevel@tonic-gate } 1143*0Sstevel@tonic-gate ESP_BUMP_STAT(noaccel); 1144*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate /* 1147*0Sstevel@tonic-gate * Adjust the IP header's payload length to reflect the removal 1148*0Sstevel@tonic-gate * of the ICV. 1149*0Sstevel@tonic-gate */ 1150*0Sstevel@tonic-gate if (!ii->ipsec_in_v4) { 1151*0Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 1152*0Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - 1153*0Sstevel@tonic-gate ipsa->ipsa_mac_len); 1154*0Sstevel@tonic-gate } else { 1155*0Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 1156*0Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - 1157*0Sstevel@tonic-gate ipsa->ipsa_mac_len); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate /* submit the request to the crypto framework */ 1161*0Sstevel@tonic-gate return (esp_submit_req_inbound(ipsec_in_mp, ipsa, 1162*0Sstevel@tonic-gate (uint8_t *)esph - data_mp->b_rptr)); 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate /* 1166*0Sstevel@tonic-gate * Perform the really difficult work of inserting the proposed situation. 1167*0Sstevel@tonic-gate * Called while holding the algorithm lock. 1168*0Sstevel@tonic-gate */ 1169*0Sstevel@tonic-gate static void 1170*0Sstevel@tonic-gate esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs) 1171*0Sstevel@tonic-gate { 1172*0Sstevel@tonic-gate sadb_comb_t *comb = (sadb_comb_t *)(prop + 1); 1173*0Sstevel@tonic-gate ipsec_out_t *io; 1174*0Sstevel@tonic-gate ipsec_action_t *ap; 1175*0Sstevel@tonic-gate ipsec_prot_t *prot; 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&alg_lock)); 1178*0Sstevel@tonic-gate io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr; 1179*0Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; 1182*0Sstevel@tonic-gate prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t)); 1183*0Sstevel@tonic-gate *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate prop->sadb_prop_replay = ipsecesp_replay_size; 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* 1188*0Sstevel@tonic-gate * Based upon algorithm properties, and what-not, prioritize 1189*0Sstevel@tonic-gate * a proposal. If the IPSEC_OUT message has an algorithm specified, 1190*0Sstevel@tonic-gate * use it first and foremost. 1191*0Sstevel@tonic-gate * 1192*0Sstevel@tonic-gate * For each action in policy list 1193*0Sstevel@tonic-gate * Add combination. If I've hit limit, return. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate for (ap = acqrec->ipsacq_act; ap != NULL; 1197*0Sstevel@tonic-gate ap = ap->ipa_next) { 1198*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1199*0Sstevel@tonic-gate ipsec_alginfo_t *ealg = NULL; 1200*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1201*0Sstevel@tonic-gate ipsec_alginfo_t *aalg = NULL; 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) 1204*0Sstevel@tonic-gate continue; 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate prot = &ap->ipa_act.ipa_apply; 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate if (!(prot->ipp_use_esp)) 1209*0Sstevel@tonic-gate continue; 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate if (prot->ipp_esp_auth_alg != 0) { 1212*0Sstevel@tonic-gate aalg = ipsec_alglists[IPSEC_ALG_AUTH] 1213*0Sstevel@tonic-gate [prot->ipp_esp_auth_alg]; 1214*0Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) 1215*0Sstevel@tonic-gate continue; 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1219*0Sstevel@tonic-gate ASSERT(prot->ipp_encr_alg > 0); 1220*0Sstevel@tonic-gate ealg = ipsec_alglists[IPSEC_ALG_ENCR][prot->ipp_encr_alg]; 1221*0Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) 1222*0Sstevel@tonic-gate continue; 1223*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate comb->sadb_comb_flags = 0; 1226*0Sstevel@tonic-gate comb->sadb_comb_reserved = 0; 1227*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1228*0Sstevel@tonic-gate comb->sadb_comb_encrypt = ealg->alg_id; 1229*0Sstevel@tonic-gate comb->sadb_comb_encrypt_minbits = prot->ipp_espe_minbits; 1230*0Sstevel@tonic-gate comb->sadb_comb_encrypt_maxbits = prot->ipp_espe_maxbits; 1231*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1232*0Sstevel@tonic-gate if (aalg == NULL) { 1233*0Sstevel@tonic-gate comb->sadb_comb_auth = 0; 1234*0Sstevel@tonic-gate comb->sadb_comb_auth_minbits = 0; 1235*0Sstevel@tonic-gate comb->sadb_comb_auth_maxbits = 0; 1236*0Sstevel@tonic-gate } else { 1237*0Sstevel@tonic-gate comb->sadb_comb_auth = aalg->alg_id; 1238*0Sstevel@tonic-gate comb->sadb_comb_auth_minbits = prot->ipp_espa_minbits; 1239*0Sstevel@tonic-gate comb->sadb_comb_auth_maxbits = prot->ipp_espa_maxbits; 1240*0Sstevel@tonic-gate } 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate /* 1243*0Sstevel@tonic-gate * The following may be based on algorithm 1244*0Sstevel@tonic-gate * properties, but in the meantime, we just pick 1245*0Sstevel@tonic-gate * some good, sensible numbers. Key mgmt. can 1246*0Sstevel@tonic-gate * (and perhaps should) be the place to finalize 1247*0Sstevel@tonic-gate * such decisions. 1248*0Sstevel@tonic-gate */ 1249*0Sstevel@tonic-gate 1250*0Sstevel@tonic-gate /* 1251*0Sstevel@tonic-gate * No limits on allocations, since we really don't 1252*0Sstevel@tonic-gate * support that concept currently. 1253*0Sstevel@tonic-gate */ 1254*0Sstevel@tonic-gate comb->sadb_comb_soft_allocations = 0; 1255*0Sstevel@tonic-gate comb->sadb_comb_hard_allocations = 0; 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate /* 1258*0Sstevel@tonic-gate * These may want to come from policy rule.. 1259*0Sstevel@tonic-gate */ 1260*0Sstevel@tonic-gate comb->sadb_comb_soft_bytes = ipsecesp_default_soft_bytes; 1261*0Sstevel@tonic-gate comb->sadb_comb_hard_bytes = ipsecesp_default_hard_bytes; 1262*0Sstevel@tonic-gate comb->sadb_comb_soft_addtime = ipsecesp_default_soft_addtime; 1263*0Sstevel@tonic-gate comb->sadb_comb_hard_addtime = ipsecesp_default_hard_addtime; 1264*0Sstevel@tonic-gate comb->sadb_comb_soft_usetime = ipsecesp_default_soft_usetime; 1265*0Sstevel@tonic-gate comb->sadb_comb_hard_usetime = ipsecesp_default_hard_usetime; 1266*0Sstevel@tonic-gate 1267*0Sstevel@tonic-gate prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); 1268*0Sstevel@tonic-gate if (--combs == 0) 1269*0Sstevel@tonic-gate break; /* out of space.. */ 1270*0Sstevel@tonic-gate comb++; 1271*0Sstevel@tonic-gate } 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate /* 1275*0Sstevel@tonic-gate * Prepare and actually send the SADB_ACQUIRE message to PF_KEY. 1276*0Sstevel@tonic-gate */ 1277*0Sstevel@tonic-gate static void 1278*0Sstevel@tonic-gate esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended) 1279*0Sstevel@tonic-gate { 1280*0Sstevel@tonic-gate mblk_t *pfkeymp, *msgmp; 1281*0Sstevel@tonic-gate uint_t allocsize, combs; 1282*0Sstevel@tonic-gate sadb_msg_t *samsg; 1283*0Sstevel@tonic-gate sadb_prop_t *prop; 1284*0Sstevel@tonic-gate uint8_t *cur, *end; 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate ESP_BUMP_STAT(acquire_requests); 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock)); 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate pfkeymp = sadb_keysock_out(0); 1291*0Sstevel@tonic-gate if (pfkeymp == NULL) { 1292*0Sstevel@tonic-gate esp0dbg(("esp_send_acquire: 1st allocb() failed.\n")); 1293*0Sstevel@tonic-gate /* Just bail. */ 1294*0Sstevel@tonic-gate goto done; 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate /* 1298*0Sstevel@tonic-gate * First, allocate a basic ACQUIRE message. Beyond that, 1299*0Sstevel@tonic-gate * you need to extract certificate info from 1300*0Sstevel@tonic-gate */ 1301*0Sstevel@tonic-gate allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) + 1302*0Sstevel@tonic-gate sizeof (sadb_address_t) + sizeof (sadb_prop_t); 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate switch (acqrec->ipsacq_addrfam) { 1305*0Sstevel@tonic-gate case AF_INET: 1306*0Sstevel@tonic-gate allocsize += 2 * sizeof (struct sockaddr_in); 1307*0Sstevel@tonic-gate break; 1308*0Sstevel@tonic-gate case AF_INET6: 1309*0Sstevel@tonic-gate allocsize += 2 * sizeof (struct sockaddr_in6); 1310*0Sstevel@tonic-gate break; 1311*0Sstevel@tonic-gate } 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate mutex_enter(&alg_lock); 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1316*0Sstevel@tonic-gate #if 0 1317*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1318*0Sstevel@tonic-gate combs = ipsec_nalgs[IPSEC_ALG_AUTH]; 1319*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1320*0Sstevel@tonic-gate #else 1321*0Sstevel@tonic-gate combs = ipsec_nalgs[IPSEC_ALG_AUTH] * ipsec_nalgs[IPSEC_ALG_ENCR]; 1322*0Sstevel@tonic-gate #endif 1323*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate allocsize += combs * sizeof (sadb_comb_t); 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate /* 1328*0Sstevel@tonic-gate * XXX If there are: 1329*0Sstevel@tonic-gate * certificate IDs 1330*0Sstevel@tonic-gate * proxy address 1331*0Sstevel@tonic-gate * <Others> 1332*0Sstevel@tonic-gate * add additional allocation size. 1333*0Sstevel@tonic-gate */ 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate msgmp = allocb(allocsize, BPRI_HI); 1336*0Sstevel@tonic-gate if (msgmp == NULL) { 1337*0Sstevel@tonic-gate esp0dbg(("esp_send_acquire: 2nd allocb() failed.\n")); 1338*0Sstevel@tonic-gate /* Just bail. */ 1339*0Sstevel@tonic-gate freemsg(pfkeymp); 1340*0Sstevel@tonic-gate pfkeymp = NULL; 1341*0Sstevel@tonic-gate goto done; 1342*0Sstevel@tonic-gate } 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate cur = msgmp->b_rptr; 1345*0Sstevel@tonic-gate end = cur + allocsize; 1346*0Sstevel@tonic-gate samsg = (sadb_msg_t *)cur; 1347*0Sstevel@tonic-gate pfkeymp->b_cont = msgmp; 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate /* Set up ACQUIRE. */ 1350*0Sstevel@tonic-gate cur = sadb_setup_acquire(cur, end, acqrec); 1351*0Sstevel@tonic-gate if (cur == NULL) { 1352*0Sstevel@tonic-gate esp0dbg(("sadb_setup_acquire failed.\n")); 1353*0Sstevel@tonic-gate /* Just bail. */ 1354*0Sstevel@tonic-gate freemsg(pfkeymp); 1355*0Sstevel@tonic-gate pfkeymp = NULL; 1356*0Sstevel@tonic-gate goto done; 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate /* XXX Insert proxy address information here. */ 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate /* XXX Insert identity information here. */ 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate /* XXXMLS Insert sensitivity information here. */ 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate /* Insert proposal here. */ 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len); 1369*0Sstevel@tonic-gate esp_insert_prop(prop, acqrec, combs); 1370*0Sstevel@tonic-gate samsg->sadb_msg_len += prop->sadb_prop_len; 1371*0Sstevel@tonic-gate msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len); 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate done: 1374*0Sstevel@tonic-gate mutex_exit(&alg_lock); 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate /* 1377*0Sstevel@tonic-gate * Must mutex_exit() before sending PF_KEY message up, in 1378*0Sstevel@tonic-gate * order to avoid recursive mutex_enter() if there are no registered 1379*0Sstevel@tonic-gate * listeners. 1380*0Sstevel@tonic-gate * 1381*0Sstevel@tonic-gate * Once I've sent the message, I'm cool anyway. 1382*0Sstevel@tonic-gate */ 1383*0Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 1384*0Sstevel@tonic-gate if (esp_pfkey_q != NULL && pfkeymp != NULL) { 1385*0Sstevel@tonic-gate if (extended != NULL) { 1386*0Sstevel@tonic-gate putnext(esp_pfkey_q, extended); 1387*0Sstevel@tonic-gate } 1388*0Sstevel@tonic-gate putnext(esp_pfkey_q, pfkeymp); 1389*0Sstevel@tonic-gate return; 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate /* XXX freemsg() works for extended == NULL. */ 1392*0Sstevel@tonic-gate freemsg(extended); 1393*0Sstevel@tonic-gate freemsg(pfkeymp); 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate /* 1397*0Sstevel@tonic-gate * Handle the SADB_GETSPI message. Create a larval SA. 1398*0Sstevel@tonic-gate */ 1399*0Sstevel@tonic-gate static void 1400*0Sstevel@tonic-gate esp_getspi(mblk_t *mp, keysock_in_t *ksi) 1401*0Sstevel@tonic-gate { 1402*0Sstevel@tonic-gate ipsa_t *newbie, *target; 1403*0Sstevel@tonic-gate isaf_t *outbound, *inbound; 1404*0Sstevel@tonic-gate int rc, diagnostic; 1405*0Sstevel@tonic-gate sadb_sa_t *assoc; 1406*0Sstevel@tonic-gate keysock_out_t *kso; 1407*0Sstevel@tonic-gate uint32_t newspi; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate /* 1410*0Sstevel@tonic-gate * Randomly generate a proposed SPI value 1411*0Sstevel@tonic-gate */ 1412*0Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t)); 1413*0Sstevel@tonic-gate newbie = sadb_getspi(ksi, newspi, &diagnostic); 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate if (newbie == NULL) { 1416*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic, 1417*0Sstevel@tonic-gate ksi->ks_in_serial); 1418*0Sstevel@tonic-gate return; 1419*0Sstevel@tonic-gate } else if (newbie == (ipsa_t *)-1) { 1420*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic, 1421*0Sstevel@tonic-gate ksi->ks_in_serial); 1422*0Sstevel@tonic-gate return; 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate /* 1426*0Sstevel@tonic-gate * XXX - We may randomly collide. We really should recover from this. 1427*0Sstevel@tonic-gate * Unfortunately, that could require spending way-too-much-time 1428*0Sstevel@tonic-gate * in here. For now, let the user retry. 1429*0Sstevel@tonic-gate */ 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate if (newbie->ipsa_addrfam == AF_INET6) { 1432*0Sstevel@tonic-gate outbound = &esp_sadb.s_v6.sdb_of[ 1433*0Sstevel@tonic-gate OUTBOUND_HASH_V6(*(uint32_t *)(newbie->ipsa_dstaddr))]; 1434*0Sstevel@tonic-gate inbound = &esp_sadb.s_v6.sdb_if[INBOUND_HASH(newbie->ipsa_spi)]; 1435*0Sstevel@tonic-gate } else { 1436*0Sstevel@tonic-gate ASSERT(newbie->ipsa_addrfam == AF_INET); 1437*0Sstevel@tonic-gate outbound = &esp_sadb.s_v4.sdb_of[ 1438*0Sstevel@tonic-gate OUTBOUND_HASH_V4(*(uint32_t *)(newbie->ipsa_dstaddr))]; 1439*0Sstevel@tonic-gate inbound = &esp_sadb.s_v4.sdb_if[INBOUND_HASH(newbie->ipsa_spi)]; 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate 1442*0Sstevel@tonic-gate mutex_enter(&outbound->isaf_lock); 1443*0Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate /* 1446*0Sstevel@tonic-gate * Check for collisions (i.e. did sadb_getspi() return with something 1447*0Sstevel@tonic-gate * that already exists?). 1448*0Sstevel@tonic-gate * 1449*0Sstevel@tonic-gate * Try outbound first. Even though SADB_GETSPI is traditionally 1450*0Sstevel@tonic-gate * for inbound SAs, you never know what a user might do. 1451*0Sstevel@tonic-gate */ 1452*0Sstevel@tonic-gate target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi, 1453*0Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam); 1454*0Sstevel@tonic-gate if (target == NULL) { 1455*0Sstevel@tonic-gate target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi, 1456*0Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, 1457*0Sstevel@tonic-gate newbie->ipsa_addrfam); 1458*0Sstevel@tonic-gate } 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate /* 1461*0Sstevel@tonic-gate * I don't have collisions elsewhere! 1462*0Sstevel@tonic-gate * (Nor will I because I'm still holding inbound/outbound locks.) 1463*0Sstevel@tonic-gate */ 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate if (target != NULL) { 1466*0Sstevel@tonic-gate rc = EEXIST; 1467*0Sstevel@tonic-gate IPSA_REFRELE(target); 1468*0Sstevel@tonic-gate } else { 1469*0Sstevel@tonic-gate /* 1470*0Sstevel@tonic-gate * sadb_insertassoc() also checks for collisions, so 1471*0Sstevel@tonic-gate * if there's a colliding entry, rc will be set 1472*0Sstevel@tonic-gate * to EEXIST. 1473*0Sstevel@tonic-gate */ 1474*0Sstevel@tonic-gate rc = sadb_insertassoc(newbie, inbound); 1475*0Sstevel@tonic-gate (void) drv_getparm(TIME, &newbie->ipsa_hardexpiretime); 1476*0Sstevel@tonic-gate newbie->ipsa_hardexpiretime += ipsecesp_larval_timeout; 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate /* 1480*0Sstevel@tonic-gate * Can exit outbound mutex. Hold inbound until we're done 1481*0Sstevel@tonic-gate * with newbie. 1482*0Sstevel@tonic-gate */ 1483*0Sstevel@tonic-gate mutex_exit(&outbound->isaf_lock); 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate if (rc != 0) { 1486*0Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 1487*0Sstevel@tonic-gate IPSA_REFRELE(newbie); 1488*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, rc, SADB_X_DIAGNOSTIC_NONE, 1489*0Sstevel@tonic-gate ksi->ks_in_serial); 1490*0Sstevel@tonic-gate return; 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate /* Can write here because I'm still holding the bucket lock. */ 1495*0Sstevel@tonic-gate newbie->ipsa_type = SADB_SATYPE_ESP; 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate /* 1498*0Sstevel@tonic-gate * Construct successful return message. We have one thing going 1499*0Sstevel@tonic-gate * for us in PF_KEY v2. That's the fact that 1500*0Sstevel@tonic-gate * sizeof (sadb_spirange_t) == sizeof (sadb_sa_t) 1501*0Sstevel@tonic-gate */ 1502*0Sstevel@tonic-gate assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE]; 1503*0Sstevel@tonic-gate assoc->sadb_sa_exttype = SADB_EXT_SA; 1504*0Sstevel@tonic-gate assoc->sadb_sa_spi = newbie->ipsa_spi; 1505*0Sstevel@tonic-gate *((uint64_t *)(&assoc->sadb_sa_replay)) = 0; 1506*0Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate /* Convert KEYSOCK_IN to KEYSOCK_OUT. */ 1509*0Sstevel@tonic-gate kso = (keysock_out_t *)ksi; 1510*0Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso); 1511*0Sstevel@tonic-gate kso->ks_out_serial = ksi->ks_in_serial; 1512*0Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT; 1513*0Sstevel@tonic-gate 1514*0Sstevel@tonic-gate /* 1515*0Sstevel@tonic-gate * Can safely putnext() to esp_pfkey_q, because this is a turnaround 1516*0Sstevel@tonic-gate * from the esp_pfkey_q. 1517*0Sstevel@tonic-gate */ 1518*0Sstevel@tonic-gate putnext(esp_pfkey_q, mp); 1519*0Sstevel@tonic-gate } 1520*0Sstevel@tonic-gate 1521*0Sstevel@tonic-gate /* 1522*0Sstevel@tonic-gate * Insert the ESP header into a packet. Duplicate an mblk, and insert a newly 1523*0Sstevel@tonic-gate * allocated mblk with the ESP header in between the two. 1524*0Sstevel@tonic-gate */ 1525*0Sstevel@tonic-gate static boolean_t 1526*0Sstevel@tonic-gate esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint) 1527*0Sstevel@tonic-gate { 1528*0Sstevel@tonic-gate mblk_t *split_mp = mp; 1529*0Sstevel@tonic-gate uint_t wheretodiv = divpoint; 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) { 1532*0Sstevel@tonic-gate wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr); 1533*0Sstevel@tonic-gate split_mp = split_mp->b_cont; 1534*0Sstevel@tonic-gate ASSERT(split_mp != NULL); 1535*0Sstevel@tonic-gate } 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) { 1538*0Sstevel@tonic-gate mblk_t *scratch; 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate /* "scratch" is the 2nd half, split_mp is the first. */ 1541*0Sstevel@tonic-gate scratch = dupb(split_mp); 1542*0Sstevel@tonic-gate if (scratch == NULL) { 1543*0Sstevel@tonic-gate esp1dbg(("esp_insert_esp: can't allocate scratch.\n")); 1544*0Sstevel@tonic-gate return (B_FALSE); 1545*0Sstevel@tonic-gate } 1546*0Sstevel@tonic-gate /* NOTE: dupb() doesn't set b_cont appropriately. */ 1547*0Sstevel@tonic-gate scratch->b_cont = split_mp->b_cont; 1548*0Sstevel@tonic-gate scratch->b_rptr += wheretodiv; 1549*0Sstevel@tonic-gate split_mp->b_wptr = split_mp->b_rptr + wheretodiv; 1550*0Sstevel@tonic-gate split_mp->b_cont = scratch; 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate /* 1553*0Sstevel@tonic-gate * At this point, split_mp is exactly "wheretodiv" bytes long, and 1554*0Sstevel@tonic-gate * holds the end of the pre-ESP part of the datagram. 1555*0Sstevel@tonic-gate */ 1556*0Sstevel@tonic-gate esp_mp->b_cont = split_mp->b_cont; 1557*0Sstevel@tonic-gate split_mp->b_cont = esp_mp; 1558*0Sstevel@tonic-gate 1559*0Sstevel@tonic-gate return (B_TRUE); 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate /* 1563*0Sstevel@tonic-gate * Finish processing of an inbound ESP packet after processing by the 1564*0Sstevel@tonic-gate * crypto framework. 1565*0Sstevel@tonic-gate * - Remove the ESP header. 1566*0Sstevel@tonic-gate * - Send packet back to IP. 1567*0Sstevel@tonic-gate * If authentication was performed on the packet, this function is called 1568*0Sstevel@tonic-gate * only if the authentication succeeded. 1569*0Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 1570*0Sstevel@tonic-gate * mblk chain ipsec_in_mp. 1571*0Sstevel@tonic-gate */ 1572*0Sstevel@tonic-gate static ipsec_status_t 1573*0Sstevel@tonic-gate esp_in_done(mblk_t *ipsec_in_mp) 1574*0Sstevel@tonic-gate { 1575*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 1576*0Sstevel@tonic-gate mblk_t *data_mp; 1577*0Sstevel@tonic-gate ipsa_t *assoc; 1578*0Sstevel@tonic-gate uint_t espstart; 1579*0Sstevel@tonic-gate uint32_t ivlen = 0; 1580*0Sstevel@tonic-gate uint_t processed_len; 1581*0Sstevel@tonic-gate esph_t *esph; 1582*0Sstevel@tonic-gate kstat_named_t *counter; 1583*0Sstevel@tonic-gate boolean_t is_natt; 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate assoc = ii->ipsec_in_esp_sa; 1586*0Sstevel@tonic-gate ASSERT(assoc != NULL); 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate /* get the pointer to the ESP header */ 1591*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1592*0Sstevel@tonic-gate if (assoc->ipsa_encr_alg == SADB_EALG_NULL) { 1593*0Sstevel@tonic-gate /* authentication-only ESP */ 1594*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1595*0Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset; 1596*0Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length; 1597*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1598*0Sstevel@tonic-gate } else { 1599*0Sstevel@tonic-gate /* encryption present */ 1600*0Sstevel@tonic-gate ivlen = assoc->ipsa_iv_len; 1601*0Sstevel@tonic-gate if (assoc->ipsa_auth_alg == SADB_AALG_NONE) { 1602*0Sstevel@tonic-gate /* encryption-only ESP */ 1603*0Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset - 1604*0Sstevel@tonic-gate sizeof (esph_t) - assoc->ipsa_iv_len; 1605*0Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length + 1606*0Sstevel@tonic-gate ivlen; 1607*0Sstevel@tonic-gate } else { 1608*0Sstevel@tonic-gate /* encryption with authentication */ 1609*0Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_dual_data.dd_offset1; 1610*0Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_dual_data.dd_len2 + 1611*0Sstevel@tonic-gate ivlen; 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate data_mp = ipsec_in_mp->b_cont; 1617*0Sstevel@tonic-gate esph = (esph_t *)(data_mp->b_rptr + espstart); 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 1620*0Sstevel@tonic-gate /* authentication passed if we reach this point */ 1621*0Sstevel@tonic-gate ESP_BUMP_STAT(good_auth); 1622*0Sstevel@tonic-gate data_mp->b_wptr -= assoc->ipsa_mac_len; 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate /* 1625*0Sstevel@tonic-gate * Check replay window here! 1626*0Sstevel@tonic-gate * For right now, assume keysock will set the replay window 1627*0Sstevel@tonic-gate * size to zero for SAs that have an unspecified sender. 1628*0Sstevel@tonic-gate * This may change... 1629*0Sstevel@tonic-gate */ 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate if (!sadb_replay_check(assoc, esph->esph_replay)) { 1632*0Sstevel@tonic-gate /* 1633*0Sstevel@tonic-gate * Log the event. As of now we print out an event. 1634*0Sstevel@tonic-gate * Do not print the replay failure number, or else 1635*0Sstevel@tonic-gate * syslog cannot collate the error messages. Printing 1636*0Sstevel@tonic-gate * the replay number that failed opens a denial-of- 1637*0Sstevel@tonic-gate * service attack. 1638*0Sstevel@tonic-gate */ 1639*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 1640*0Sstevel@tonic-gate SL_ERROR | SL_WARN, 1641*0Sstevel@tonic-gate "Replay failed for ESP spi 0x%x, dst %s.\n", 1642*0Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, 1643*0Sstevel@tonic-gate assoc->ipsa_addrfam); 1644*0Sstevel@tonic-gate ESP_BUMP_STAT(replay_failures); 1645*0Sstevel@tonic-gate counter = &ipdrops_esp_replay; 1646*0Sstevel@tonic-gate goto drop_and_bail; 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gate if (!esp_age_bytes(assoc, processed_len, B_TRUE)) { 1651*0Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 1652*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 1653*0Sstevel@tonic-gate SL_ERROR | SL_WARN, 1654*0Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 1655*0Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 1656*0Sstevel@tonic-gate ESP_BUMP_STAT(bytes_expired); 1657*0Sstevel@tonic-gate counter = &ipdrops_esp_bytes_expire; 1658*0Sstevel@tonic-gate goto drop_and_bail; 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate /* 1662*0Sstevel@tonic-gate * Remove ESP header and padding from packet. I hope the compiler 1663*0Sstevel@tonic-gate * spews "branch, predict taken" code for this. 1664*0Sstevel@tonic-gate */ 1665*0Sstevel@tonic-gate 1666*0Sstevel@tonic-gate if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter)) { 1667*0Sstevel@tonic-gate if (is_natt) 1668*0Sstevel@tonic-gate return (esp_fix_natt_checksums(data_mp, assoc)); 1669*0Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 1670*0Sstevel@tonic-gate } 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gate esp1dbg(("esp_in_done: esp_strip_header() failed\n")); 1673*0Sstevel@tonic-gate drop_and_bail: 1674*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 1675*0Sstevel@tonic-gate /* 1676*0Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN message's 1677*0Sstevel@tonic-gate * ii->ipsec_in_rill_index. 1678*0Sstevel@tonic-gate */ 1679*0Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, counter, &esp_dropper); 1680*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 1681*0Sstevel@tonic-gate } 1682*0Sstevel@tonic-gate 1683*0Sstevel@tonic-gate /* 1684*0Sstevel@tonic-gate * Called upon failing the inbound ICV check. The message passed as 1685*0Sstevel@tonic-gate * argument is freed. 1686*0Sstevel@tonic-gate */ 1687*0Sstevel@tonic-gate static void 1688*0Sstevel@tonic-gate esp_log_bad_auth(mblk_t *ipsec_in) 1689*0Sstevel@tonic-gate { 1690*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr; 1691*0Sstevel@tonic-gate ipsa_t *assoc = ii->ipsec_in_esp_sa; 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate /* 1694*0Sstevel@tonic-gate * Log the event. Don't print to the console, block 1695*0Sstevel@tonic-gate * potential denial-of-service attack. 1696*0Sstevel@tonic-gate */ 1697*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_auth); 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 1700*0Sstevel@tonic-gate "ESP Authentication failed for spi 0x%x, dst %s.\n", 1701*0Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 1702*0Sstevel@tonic-gate 1703*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 1704*0Sstevel@tonic-gate /* 1705*0Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 1706*0Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 1707*0Sstevel@tonic-gate */ 1708*0Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_esp_bad_auth, 1709*0Sstevel@tonic-gate &esp_dropper); 1710*0Sstevel@tonic-gate } 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate /* 1714*0Sstevel@tonic-gate * Invoked for outbound packets after ESP processing. If the packet 1715*0Sstevel@tonic-gate * also requires AH, performs the AH SA selection and AH processing. 1716*0Sstevel@tonic-gate * Returns B_TRUE if the AH processing was not needed or if it was 1717*0Sstevel@tonic-gate * performed successfully. Returns B_FALSE and consumes the passed mblk 1718*0Sstevel@tonic-gate * if AH processing was required but could not be performed. 1719*0Sstevel@tonic-gate */ 1720*0Sstevel@tonic-gate static boolean_t 1721*0Sstevel@tonic-gate esp_do_outbound_ah(mblk_t *ipsec_mp) 1722*0Sstevel@tonic-gate { 1723*0Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 1724*0Sstevel@tonic-gate ipsec_status_t ipsec_rc; 1725*0Sstevel@tonic-gate ipsec_action_t *ap; 1726*0Sstevel@tonic-gate 1727*0Sstevel@tonic-gate ap = io->ipsec_out_act; 1728*0Sstevel@tonic-gate if (ap == NULL) { 1729*0Sstevel@tonic-gate ipsec_policy_t *pp = io->ipsec_out_policy; 1730*0Sstevel@tonic-gate ap = pp->ipsp_act; 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate 1733*0Sstevel@tonic-gate if (!ap->ipa_want_ah) 1734*0Sstevel@tonic-gate return (B_TRUE); 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_done == B_FALSE); 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate if (io->ipsec_out_ah_sa == NULL) { 1739*0Sstevel@tonic-gate if (!ipsec_outbound_sa(ipsec_mp, IPPROTO_AH)) { 1740*0Sstevel@tonic-gate sadb_acquire(ipsec_mp, io, B_TRUE, B_FALSE); 1741*0Sstevel@tonic-gate return (B_FALSE); 1742*0Sstevel@tonic-gate } 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_sa != NULL); 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate io->ipsec_out_ah_done = B_TRUE; 1747*0Sstevel@tonic-gate ipsec_rc = io->ipsec_out_ah_sa->ipsa_output_func(ipsec_mp); 1748*0Sstevel@tonic-gate return (ipsec_rc == IPSEC_STATUS_SUCCESS); 1749*0Sstevel@tonic-gate } 1750*0Sstevel@tonic-gate 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate /* 1753*0Sstevel@tonic-gate * Kernel crypto framework callback invoked after completion of async 1754*0Sstevel@tonic-gate * crypto requests. 1755*0Sstevel@tonic-gate */ 1756*0Sstevel@tonic-gate static void 1757*0Sstevel@tonic-gate esp_kcf_callback(void *arg, int status) 1758*0Sstevel@tonic-gate { 1759*0Sstevel@tonic-gate mblk_t *ipsec_mp = (mblk_t *)arg; 1760*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 1761*0Sstevel@tonic-gate boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN); 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL); 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate if (status == CRYPTO_SUCCESS) { 1766*0Sstevel@tonic-gate if (is_inbound) { 1767*0Sstevel@tonic-gate if (esp_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) 1768*0Sstevel@tonic-gate return; 1769*0Sstevel@tonic-gate 1770*0Sstevel@tonic-gate /* finish IPsec processing */ 1771*0Sstevel@tonic-gate ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL); 1772*0Sstevel@tonic-gate } else { 1773*0Sstevel@tonic-gate /* 1774*0Sstevel@tonic-gate * If a ICV was computed, it was stored by the 1775*0Sstevel@tonic-gate * crypto framework at the end of the packet. 1776*0Sstevel@tonic-gate */ 1777*0Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr; 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate /* do AH processing if needed */ 1780*0Sstevel@tonic-gate if (!esp_do_outbound_ah(ipsec_mp)) 1781*0Sstevel@tonic-gate return; 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate /* finish IPsec processing */ 1784*0Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IP_VERSION) { 1785*0Sstevel@tonic-gate ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, 1786*0Sstevel@tonic-gate NULL); 1787*0Sstevel@tonic-gate } else { 1788*0Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 1789*0Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h, 1790*0Sstevel@tonic-gate NULL, NULL); 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate } else if (status == CRYPTO_INVALID_MAC) { 1795*0Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate } else { 1798*0Sstevel@tonic-gate esp1dbg(("esp_kcf_callback: crypto failed with 0x%x\n", 1799*0Sstevel@tonic-gate status)); 1800*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_failures); 1801*0Sstevel@tonic-gate if (is_inbound) 1802*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 1803*0Sstevel@tonic-gate else 1804*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 1805*0Sstevel@tonic-gate ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL, 1806*0Sstevel@tonic-gate &ipdrops_esp_crypto_failed, &esp_dropper); 1807*0Sstevel@tonic-gate } 1808*0Sstevel@tonic-gate } 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate /* 1811*0Sstevel@tonic-gate * Invoked on crypto framework failure during inbound and outbound processing. 1812*0Sstevel@tonic-gate */ 1813*0Sstevel@tonic-gate static void 1814*0Sstevel@tonic-gate esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc) 1815*0Sstevel@tonic-gate { 1816*0Sstevel@tonic-gate esp1dbg(("crypto failed for %s ESP with 0x%x\n", 1817*0Sstevel@tonic-gate is_inbound ? "inbound" : "outbound", kef_rc)); 1818*0Sstevel@tonic-gate ip_drop_packet(mp, is_inbound, NULL, NULL, &ipdrops_esp_crypto_failed, 1819*0Sstevel@tonic-gate &esp_dropper); 1820*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_failures); 1821*0Sstevel@tonic-gate if (is_inbound) 1822*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 1823*0Sstevel@tonic-gate else 1824*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate #define ESP_INIT_CALLREQ(_cr) { \ 1828*0Sstevel@tonic-gate (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED; \ 1829*0Sstevel@tonic-gate (_cr)->cr_callback_arg = ipsec_mp; \ 1830*0Sstevel@tonic-gate (_cr)->cr_callback_func = esp_kcf_callback; \ 1831*0Sstevel@tonic-gate } 1832*0Sstevel@tonic-gate 1833*0Sstevel@tonic-gate #define ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \ 1834*0Sstevel@tonic-gate (mac)->cd_format = CRYPTO_DATA_RAW; \ 1835*0Sstevel@tonic-gate (mac)->cd_offset = 0; \ 1836*0Sstevel@tonic-gate (mac)->cd_length = icvlen; \ 1837*0Sstevel@tonic-gate (mac)->cd_raw.iov_base = (char *)icvbuf; \ 1838*0Sstevel@tonic-gate (mac)->cd_raw.iov_len = icvlen; \ 1839*0Sstevel@tonic-gate } 1840*0Sstevel@tonic-gate 1841*0Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DATA(data, mp, off, len) { \ 1842*0Sstevel@tonic-gate if (MBLKL(mp) >= (len) + (off)) { \ 1843*0Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_RAW; \ 1844*0Sstevel@tonic-gate (data)->cd_raw.iov_base = (char *)(mp)->b_rptr; \ 1845*0Sstevel@tonic-gate (data)->cd_raw.iov_len = MBLKL(mp); \ 1846*0Sstevel@tonic-gate (data)->cd_offset = off; \ 1847*0Sstevel@tonic-gate } else { \ 1848*0Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_MBLK; \ 1849*0Sstevel@tonic-gate (data)->cd_mp = mp; \ 1850*0Sstevel@tonic-gate (data)->cd_offset = off; \ 1851*0Sstevel@tonic-gate } \ 1852*0Sstevel@tonic-gate (data)->cd_length = len; \ 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate 1855*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1856*0Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) { \ 1857*0Sstevel@tonic-gate (data)->dd_format = CRYPTO_DATA_MBLK; \ 1858*0Sstevel@tonic-gate (data)->dd_mp = mp; \ 1859*0Sstevel@tonic-gate (data)->dd_len1 = len1; \ 1860*0Sstevel@tonic-gate (data)->dd_offset1 = off1; \ 1861*0Sstevel@tonic-gate (data)->dd_len2 = len2; \ 1862*0Sstevel@tonic-gate (data)->dd_offset2 = off2; \ 1863*0Sstevel@tonic-gate } 1864*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1865*0Sstevel@tonic-gate 1866*0Sstevel@tonic-gate static ipsec_status_t 1867*0Sstevel@tonic-gate esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset) 1868*0Sstevel@tonic-gate { 1869*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 1870*0Sstevel@tonic-gate boolean_t do_auth; 1871*0Sstevel@tonic-gate uint_t auth_offset, msg_len, auth_len; 1872*0Sstevel@tonic-gate crypto_call_req_t call_req; 1873*0Sstevel@tonic-gate mblk_t *esp_mp; 1874*0Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 1875*0Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 1876*0Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 1877*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1878*0Sstevel@tonic-gate boolean_t do_encr; 1879*0Sstevel@tonic-gate uint_t encr_offset, encr_len; 1880*0Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 1881*0Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 1882*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gate ASSERT(ii->ipsec_in_type == IPSEC_IN); 1885*0Sstevel@tonic-gate 1886*0Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 1887*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1888*0Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate /* 1891*0Sstevel@tonic-gate * An inbound packet is of the form: 1892*0Sstevel@tonic-gate * IPSEC_IN -> [IP,options,ESP,IV,data,ICV,pad] 1893*0Sstevel@tonic-gate */ 1894*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1895*0Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont; 1896*0Sstevel@tonic-gate msg_len = MBLKL(esp_mp); 1897*0Sstevel@tonic-gate 1898*0Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 1899*0Sstevel@tonic-gate 1900*0Sstevel@tonic-gate if (do_auth) { 1901*0Sstevel@tonic-gate /* force asynchronous processing? */ 1902*0Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 1903*0Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 1904*0Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 1905*0Sstevel@tonic-gate 1906*0Sstevel@tonic-gate /* authentication context template */ 1907*0Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 1908*0Sstevel@tonic-gate auth_ctx_tmpl); 1909*0Sstevel@tonic-gate 1910*0Sstevel@tonic-gate /* ICV to be verified */ 1911*0Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac, 1912*0Sstevel@tonic-gate icv_len, esp_mp->b_wptr - icv_len); 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate /* authentication starts at the ESP header */ 1915*0Sstevel@tonic-gate auth_offset = esph_offset; 1916*0Sstevel@tonic-gate auth_len = msg_len - auth_offset - icv_len; 1917*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1918*0Sstevel@tonic-gate if (!do_encr) { 1919*0Sstevel@tonic-gate /* authentication only */ 1920*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1921*0Sstevel@tonic-gate /* initialize input data argument */ 1922*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 1923*0Sstevel@tonic-gate esp_mp, auth_offset, auth_len); 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate /* call the crypto framework */ 1926*0Sstevel@tonic-gate kef_rc = crypto_mac_verify(&assoc->ipsa_amech, 1927*0Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 1928*0Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 1929*0Sstevel@tonic-gate &ii->ipsec_in_crypto_mac, &call_req); 1930*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1933*0Sstevel@tonic-gate } 1934*0Sstevel@tonic-gate 1935*0Sstevel@tonic-gate /* EXPORT DELETE START */ 1936*0Sstevel@tonic-gate if (do_encr) { 1937*0Sstevel@tonic-gate /* force asynchronous processing? */ 1938*0Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 1939*0Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 1940*0Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate /* encryption template */ 1943*0Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 1944*0Sstevel@tonic-gate encr_ctx_tmpl); 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate /* skip IV, since it is passed separately */ 1947*0Sstevel@tonic-gate encr_offset = esph_offset + sizeof (esph_t) + iv_len; 1948*0Sstevel@tonic-gate encr_len = msg_len - encr_offset; 1949*0Sstevel@tonic-gate 1950*0Sstevel@tonic-gate if (!do_auth) { 1951*0Sstevel@tonic-gate /* decryption only */ 1952*0Sstevel@tonic-gate /* initialize input data argument */ 1953*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 1954*0Sstevel@tonic-gate esp_mp, encr_offset, encr_len); 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate /* specify IV */ 1957*0Sstevel@tonic-gate ii->ipsec_in_crypto_data.cd_miscdata = 1958*0Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 1959*0Sstevel@tonic-gate esph_offset; 1960*0Sstevel@tonic-gate 1961*0Sstevel@tonic-gate /* call the crypto framework */ 1962*0Sstevel@tonic-gate kef_rc = crypto_decrypt(&assoc->ipsa_emech, 1963*0Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 1964*0Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 1965*0Sstevel@tonic-gate NULL, &call_req); 1966*0Sstevel@tonic-gate } 1967*0Sstevel@tonic-gate } 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate if (do_auth && do_encr) { 1970*0Sstevel@tonic-gate /* dual operation */ 1971*0Sstevel@tonic-gate /* initialize input data argument */ 1972*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&ii->ipsec_in_crypto_dual_data, 1973*0Sstevel@tonic-gate esp_mp, auth_offset, auth_len, 1974*0Sstevel@tonic-gate encr_offset, encr_len - icv_len); 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate /* specify IV */ 1977*0Sstevel@tonic-gate ii->ipsec_in_crypto_dual_data.dd_miscdata = 1978*0Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate /* call the framework */ 1981*0Sstevel@tonic-gate kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech, 1982*0Sstevel@tonic-gate &assoc->ipsa_emech, &ii->ipsec_in_crypto_dual_data, 1983*0Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey, 1984*0Sstevel@tonic-gate auth_ctx_tmpl, encr_ctx_tmpl, &ii->ipsec_in_crypto_mac, 1985*0Sstevel@tonic-gate NULL, &call_req); 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate /* EXPORT DELETE END */ 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate switch (kef_rc) { 1990*0Sstevel@tonic-gate case CRYPTO_SUCCESS: 1991*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 1992*0Sstevel@tonic-gate return (esp_in_done(ipsec_mp)); 1993*0Sstevel@tonic-gate case CRYPTO_QUEUED: 1994*0Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 1995*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_async); 1996*0Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 1997*0Sstevel@tonic-gate case CRYPTO_INVALID_MAC: 1998*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 1999*0Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 2000*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2001*0Sstevel@tonic-gate } 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc); 2004*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2005*0Sstevel@tonic-gate } 2006*0Sstevel@tonic-gate 2007*0Sstevel@tonic-gate static ipsec_status_t 2008*0Sstevel@tonic-gate esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf, 2009*0Sstevel@tonic-gate uint_t payload_len) 2010*0Sstevel@tonic-gate { 2011*0Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 2012*0Sstevel@tonic-gate uint_t auth_len; 2013*0Sstevel@tonic-gate crypto_call_req_t call_req; 2014*0Sstevel@tonic-gate mblk_t *esp_mp; 2015*0Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 2016*0Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 2017*0Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 2018*0Sstevel@tonic-gate boolean_t do_auth; 2019*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2020*0Sstevel@tonic-gate boolean_t do_encr; 2021*0Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 2022*0Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 2023*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2024*0Sstevel@tonic-gate boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 2025*0Sstevel@tonic-gate size_t esph_offset = (is_natt ? UDPH_SIZE : 0); 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate esp3dbg(("esp_submit_req_outbound:%s", is_natt ? "natt" : "not natt")); 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2032*0Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 2033*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2034*0Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 2035*0Sstevel@tonic-gate 2036*0Sstevel@tonic-gate /* 2037*0Sstevel@tonic-gate * EXPORT DELETE START 2038*0Sstevel@tonic-gate * Outbound IPsec packets are of the form: 2039*0Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV] 2040*0Sstevel@tonic-gate * unless it's NATT, then it's 2041*0Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV] 2042*0Sstevel@tonic-gate * EXPORT DELETE END 2043*0Sstevel@tonic-gate * Get a pointer to the mblk containing the ESP header. 2044*0Sstevel@tonic-gate */ 2045*0Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL && ipsec_mp->b_cont->b_cont != NULL); 2046*0Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont->b_cont; 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 2049*0Sstevel@tonic-gate 2050*0Sstevel@tonic-gate if (do_auth) { 2051*0Sstevel@tonic-gate /* force asynchronous processing? */ 2052*0Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 2053*0Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 2054*0Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 2055*0Sstevel@tonic-gate 2056*0Sstevel@tonic-gate /* authentication context template */ 2057*0Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 2058*0Sstevel@tonic-gate auth_ctx_tmpl); 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate /* where to store the computed mac */ 2061*0Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac, 2062*0Sstevel@tonic-gate icv_len, icv_buf); 2063*0Sstevel@tonic-gate 2064*0Sstevel@tonic-gate /* authentication starts at the ESP header */ 2065*0Sstevel@tonic-gate auth_len = payload_len + 2066*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2067*0Sstevel@tonic-gate iv_len + 2068*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2069*0Sstevel@tonic-gate sizeof (esph_t); 2070*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2071*0Sstevel@tonic-gate if (!do_encr) { 2072*0Sstevel@tonic-gate /* authentication only */ 2073*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2074*0Sstevel@tonic-gate /* initialize input data argument */ 2075*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 2076*0Sstevel@tonic-gate esp_mp, esph_offset, auth_len); 2077*0Sstevel@tonic-gate 2078*0Sstevel@tonic-gate /* call the crypto framework */ 2079*0Sstevel@tonic-gate kef_rc = crypto_mac(&assoc->ipsa_amech, 2080*0Sstevel@tonic-gate &io->ipsec_out_crypto_data, 2081*0Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 2082*0Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 2083*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2084*0Sstevel@tonic-gate } 2085*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2086*0Sstevel@tonic-gate } 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2089*0Sstevel@tonic-gate if (do_encr) { 2090*0Sstevel@tonic-gate /* force asynchronous processing? */ 2091*0Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 2092*0Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 2093*0Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 2094*0Sstevel@tonic-gate 2095*0Sstevel@tonic-gate /* encryption context template */ 2096*0Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 2097*0Sstevel@tonic-gate encr_ctx_tmpl); 2098*0Sstevel@tonic-gate 2099*0Sstevel@tonic-gate if (!do_auth) { 2100*0Sstevel@tonic-gate /* encryption only, skip mblk that contains ESP hdr */ 2101*0Sstevel@tonic-gate /* initialize input data argument */ 2102*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 2103*0Sstevel@tonic-gate esp_mp->b_cont, 0, payload_len); 2104*0Sstevel@tonic-gate 2105*0Sstevel@tonic-gate /* specify IV */ 2106*0Sstevel@tonic-gate io->ipsec_out_crypto_data.cd_miscdata = 2107*0Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 2108*0Sstevel@tonic-gate esph_offset; 2109*0Sstevel@tonic-gate 2110*0Sstevel@tonic-gate /* call the crypto framework */ 2111*0Sstevel@tonic-gate kef_rc = crypto_encrypt(&assoc->ipsa_emech, 2112*0Sstevel@tonic-gate &io->ipsec_out_crypto_data, 2113*0Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 2114*0Sstevel@tonic-gate NULL, &call_req); 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate } 2117*0Sstevel@tonic-gate 2118*0Sstevel@tonic-gate if (do_auth && do_encr) { 2119*0Sstevel@tonic-gate /* 2120*0Sstevel@tonic-gate * Encryption and authentication: 2121*0Sstevel@tonic-gate * Pass the pointer to the mblk chain starting at the ESP 2122*0Sstevel@tonic-gate * header to the framework. Skip the ESP header mblk 2123*0Sstevel@tonic-gate * for encryption, which is reflected by an encryption 2124*0Sstevel@tonic-gate * offset equal to the length of that mblk. Start 2125*0Sstevel@tonic-gate * the authentication at the ESP header, i.e. use an 2126*0Sstevel@tonic-gate * authentication offset of zero. 2127*0Sstevel@tonic-gate */ 2128*0Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&io->ipsec_out_crypto_dual_data, 2129*0Sstevel@tonic-gate esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len); 2130*0Sstevel@tonic-gate 2131*0Sstevel@tonic-gate /* specify IV */ 2132*0Sstevel@tonic-gate io->ipsec_out_crypto_dual_data.dd_miscdata = 2133*0Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate /* call the framework */ 2136*0Sstevel@tonic-gate kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech, 2137*0Sstevel@tonic-gate &assoc->ipsa_amech, NULL, 2138*0Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey, 2139*0Sstevel@tonic-gate encr_ctx_tmpl, auth_ctx_tmpl, 2140*0Sstevel@tonic-gate &io->ipsec_out_crypto_dual_data, 2141*0Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 2142*0Sstevel@tonic-gate } 2143*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate switch (kef_rc) { 2146*0Sstevel@tonic-gate case CRYPTO_SUCCESS: 2147*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 2148*0Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 2149*0Sstevel@tonic-gate case CRYPTO_QUEUED: 2150*0Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 2151*0Sstevel@tonic-gate ESP_BUMP_STAT(crypto_async); 2152*0Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 2153*0Sstevel@tonic-gate } 2154*0Sstevel@tonic-gate 2155*0Sstevel@tonic-gate esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc); 2156*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2157*0Sstevel@tonic-gate } 2158*0Sstevel@tonic-gate 2159*0Sstevel@tonic-gate /* 2160*0Sstevel@tonic-gate * Handle outbound IPsec processing for IPv4 and IPv6 2161*0Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 2162*0Sstevel@tonic-gate * mblk chain ipsec_in_mp. 2163*0Sstevel@tonic-gate */ 2164*0Sstevel@tonic-gate static ipsec_status_t 2165*0Sstevel@tonic-gate esp_outbound(mblk_t *mp) 2166*0Sstevel@tonic-gate { 2167*0Sstevel@tonic-gate mblk_t *ipsec_out_mp, *data_mp, *espmp, *tailmp; 2168*0Sstevel@tonic-gate ipsec_out_t *io; 2169*0Sstevel@tonic-gate ipha_t *ipha; 2170*0Sstevel@tonic-gate ip6_t *ip6h; 2171*0Sstevel@tonic-gate esph_t *esph; 2172*0Sstevel@tonic-gate uint_t af; 2173*0Sstevel@tonic-gate uint8_t *nhp; 2174*0Sstevel@tonic-gate uintptr_t divpoint, datalen, adj, padlen, i, alloclen; 2175*0Sstevel@tonic-gate uintptr_t esplen = sizeof (esph_t); 2176*0Sstevel@tonic-gate uint8_t protocol; 2177*0Sstevel@tonic-gate ipsa_t *assoc; 2178*0Sstevel@tonic-gate uint_t iv_len = 0, mac_len = 0; 2179*0Sstevel@tonic-gate uchar_t *icv_buf; 2180*0Sstevel@tonic-gate udpha_t *udpha; 2181*0Sstevel@tonic-gate boolean_t is_natt = B_FALSE; 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate ESP_BUMP_STAT(out_requests); 2184*0Sstevel@tonic-gate 2185*0Sstevel@tonic-gate ipsec_out_mp = mp; 2186*0Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 2187*0Sstevel@tonic-gate 2188*0Sstevel@tonic-gate /* 2189*0Sstevel@tonic-gate * <sigh> We have to copy the message here, because TCP (for example) 2190*0Sstevel@tonic-gate * keeps a dupb() of the message lying around for retransmission. 2191*0Sstevel@tonic-gate * Since ESP changes the whole of the datagram, we have to create our 2192*0Sstevel@tonic-gate * own copy lest we clobber TCP's data. Since we have to copy anyway, 2193*0Sstevel@tonic-gate * we might as well make use of msgpullup() and get the mblk into one 2194*0Sstevel@tonic-gate * contiguous piece! 2195*0Sstevel@tonic-gate */ 2196*0Sstevel@tonic-gate ipsec_out_mp->b_cont = msgpullup(data_mp, -1); 2197*0Sstevel@tonic-gate if (ipsec_out_mp->b_cont == NULL) { 2198*0Sstevel@tonic-gate esp0dbg(("esp_outbound: msgpullup() failed, " 2199*0Sstevel@tonic-gate "dropping packet.\n")); 2200*0Sstevel@tonic-gate ipsec_out_mp->b_cont = data_mp; 2201*0Sstevel@tonic-gate /* 2202*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2203*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2204*0Sstevel@tonic-gate */ 2205*0Sstevel@tonic-gate ip_drop_packet(ipsec_out_mp, B_FALSE, NULL, NULL, 2206*0Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 2207*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2208*0Sstevel@tonic-gate } else { 2209*0Sstevel@tonic-gate freemsg(data_mp); 2210*0Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate 2213*0Sstevel@tonic-gate io = (ipsec_out_t *)ipsec_out_mp->b_rptr; 2214*0Sstevel@tonic-gate 2215*0Sstevel@tonic-gate /* 2216*0Sstevel@tonic-gate * Reality check.... 2217*0Sstevel@tonic-gate */ 2218*0Sstevel@tonic-gate 2219*0Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */ 2220*0Sstevel@tonic-gate 2221*0Sstevel@tonic-gate if (io->ipsec_out_v4) { 2222*0Sstevel@tonic-gate af = AF_INET; 2223*0Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 2224*0Sstevel@tonic-gate datalen = ntohs(ipha->ipha_length) - divpoint; 2225*0Sstevel@tonic-gate nhp = (uint8_t *)&ipha->ipha_protocol; 2226*0Sstevel@tonic-gate } else { 2227*0Sstevel@tonic-gate ip6_pkt_t ipp; 2228*0Sstevel@tonic-gate 2229*0Sstevel@tonic-gate af = AF_INET6; 2230*0Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 2231*0Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 2232*0Sstevel@tonic-gate divpoint = ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 2233*0Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL && 2234*0Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) { 2235*0Sstevel@tonic-gate /* 2236*0Sstevel@tonic-gate * Destination options are tricky. If we get in here, 2237*0Sstevel@tonic-gate * then we have a terminal header following the 2238*0Sstevel@tonic-gate * destination options. We need to adjust backwards 2239*0Sstevel@tonic-gate * so we insert ESP BEFORE the destination options 2240*0Sstevel@tonic-gate * bag. (So that the dstopts get encrypted!) 2241*0Sstevel@tonic-gate * 2242*0Sstevel@tonic-gate * Since this is for outbound packets only, we know 2243*0Sstevel@tonic-gate * that non-terminal destination options only precede 2244*0Sstevel@tonic-gate * routing headers. 2245*0Sstevel@tonic-gate */ 2246*0Sstevel@tonic-gate divpoint -= ipp.ipp_dstoptslen; 2247*0Sstevel@tonic-gate } 2248*0Sstevel@tonic-gate datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint; 2249*0Sstevel@tonic-gate 2250*0Sstevel@tonic-gate if (ipp.ipp_rthdr != NULL) { 2251*0Sstevel@tonic-gate nhp = &ipp.ipp_rthdr->ip6r_nxt; 2252*0Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 2253*0Sstevel@tonic-gate nhp = &ipp.ipp_hopopts->ip6h_nxt; 2254*0Sstevel@tonic-gate } else { 2255*0Sstevel@tonic-gate ASSERT(divpoint == sizeof (ip6_t)); 2256*0Sstevel@tonic-gate /* It's probably IP + ESP. */ 2257*0Sstevel@tonic-gate nhp = &ip6h->ip6_nxt; 2258*0Sstevel@tonic-gate } 2259*0Sstevel@tonic-gate } 2260*0Sstevel@tonic-gate assoc = io->ipsec_out_esp_sa; 2261*0Sstevel@tonic-gate ASSERT(assoc != NULL); 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate if (assoc->ipsa_usetime == 0) 2264*0Sstevel@tonic-gate esp_set_usetime(assoc, B_FALSE); 2265*0Sstevel@tonic-gate 2266*0Sstevel@tonic-gate if (assoc->ipsa_auth_alg != SADB_AALG_NONE) 2267*0Sstevel@tonic-gate mac_len = assoc->ipsa_mac_len; 2268*0Sstevel@tonic-gate 2269*0Sstevel@tonic-gate if (assoc->ipsa_flags & IPSA_F_NATT) { 2270*0Sstevel@tonic-gate /* wedge in fake UDP */ 2271*0Sstevel@tonic-gate is_natt = B_TRUE; 2272*0Sstevel@tonic-gate esplen += UDPH_SIZE; 2273*0Sstevel@tonic-gate } 2274*0Sstevel@tonic-gate 2275*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2276*0Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) 2277*0Sstevel@tonic-gate iv_len = assoc->ipsa_iv_len; 2278*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2279*0Sstevel@tonic-gate 2280*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2281*0Sstevel@tonic-gate /* 2282*0Sstevel@tonic-gate * Set up ESP header and encryption padding for ENCR PI request. 2283*0Sstevel@tonic-gate */ 2284*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2285*0Sstevel@tonic-gate 2286*0Sstevel@tonic-gate /* 2287*0Sstevel@tonic-gate * Determine the padding length. Pad to 4-bytes. 2288*0Sstevel@tonic-gate * 2289*0Sstevel@tonic-gate * Include the two additional bytes (hence the - 2) for the padding 2290*0Sstevel@tonic-gate * length and the next header. Take this into account when 2291*0Sstevel@tonic-gate * calculating the actual length of the padding. 2292*0Sstevel@tonic-gate */ 2293*0Sstevel@tonic-gate 2294*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2295*0Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) { 2296*0Sstevel@tonic-gate padlen = ((unsigned)(iv_len - datalen - 2)) % iv_len; 2297*0Sstevel@tonic-gate } else { 2298*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2299*0Sstevel@tonic-gate padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) % 2300*0Sstevel@tonic-gate sizeof (uint32_t); 2301*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2302*0Sstevel@tonic-gate } 2303*0Sstevel@tonic-gate 2304*0Sstevel@tonic-gate /* Allocate ESP header and IV. */ 2305*0Sstevel@tonic-gate esplen += iv_len; 2306*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate /* 2309*0Sstevel@tonic-gate * Update association byte-count lifetimes. Don't forget to take 2310*0Sstevel@tonic-gate * into account the padding length and next-header (hence the + 2). 2311*0Sstevel@tonic-gate * EXPORT DELETE START 2312*0Sstevel@tonic-gate * Use the amount of data fed into the "encryption algorithm". This 2313*0Sstevel@tonic-gate * is the IV, the data length, the padding length, and the final two 2314*0Sstevel@tonic-gate * bytes (padlen, and next-header). 2315*0Sstevel@tonic-gate * 2316*0Sstevel@tonic-gate * EXPORT DELETE END 2317*0Sstevel@tonic-gate */ 2318*0Sstevel@tonic-gate 2319*0Sstevel@tonic-gate if (!esp_age_bytes(assoc, datalen + padlen + 2320*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2321*0Sstevel@tonic-gate iv_len + 2322*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2323*0Sstevel@tonic-gate 2, B_FALSE)) { 2324*0Sstevel@tonic-gate /* 2325*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2326*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2327*0Sstevel@tonic-gate */ 2328*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 2329*0Sstevel@tonic-gate &ipdrops_esp_bytes_expire, &esp_dropper); 2330*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2331*0Sstevel@tonic-gate } 2332*0Sstevel@tonic-gate 2333*0Sstevel@tonic-gate espmp = allocb(esplen, BPRI_HI); 2334*0Sstevel@tonic-gate if (espmp == NULL) { 2335*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 2336*0Sstevel@tonic-gate esp1dbg(("esp_outbound: can't allocate espmp.\n")); 2337*0Sstevel@tonic-gate /* 2338*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2339*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2340*0Sstevel@tonic-gate */ 2341*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem, 2342*0Sstevel@tonic-gate &esp_dropper); 2343*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2344*0Sstevel@tonic-gate } 2345*0Sstevel@tonic-gate espmp->b_wptr += esplen; 2346*0Sstevel@tonic-gate esph = (esph_t *)espmp->b_rptr; 2347*0Sstevel@tonic-gate 2348*0Sstevel@tonic-gate if (is_natt) { 2349*0Sstevel@tonic-gate esp3dbg(("esp_outbound: NATT")); 2350*0Sstevel@tonic-gate 2351*0Sstevel@tonic-gate udpha = (udpha_t *)espmp->b_rptr; 2352*0Sstevel@tonic-gate udpha->uha_src_port = htons(IPPORT_IKE_NATT); 2353*0Sstevel@tonic-gate if (assoc->ipsa_remote_port != 0) 2354*0Sstevel@tonic-gate udpha->uha_dst_port = assoc->ipsa_remote_port; 2355*0Sstevel@tonic-gate else 2356*0Sstevel@tonic-gate udpha->uha_dst_port = htons(IPPORT_IKE_NATT); 2357*0Sstevel@tonic-gate /* 2358*0Sstevel@tonic-gate * Set the checksum to 0, so that the ip_wput_ipsec_out() 2359*0Sstevel@tonic-gate * can do the right thing. 2360*0Sstevel@tonic-gate */ 2361*0Sstevel@tonic-gate udpha->uha_checksum = 0; 2362*0Sstevel@tonic-gate esph = (esph_t *)(udpha + 1); 2363*0Sstevel@tonic-gate } 2364*0Sstevel@tonic-gate 2365*0Sstevel@tonic-gate esph->esph_spi = assoc->ipsa_spi; 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate esph->esph_replay = htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1)); 2368*0Sstevel@tonic-gate if (esph->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) { 2369*0Sstevel@tonic-gate /* 2370*0Sstevel@tonic-gate * XXX We have replay counter wrapping. 2371*0Sstevel@tonic-gate * We probably want to nuke this SA (and its peer). 2372*0Sstevel@tonic-gate */ 2373*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 2374*0Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 2375*0Sstevel@tonic-gate "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n", 2376*0Sstevel@tonic-gate esph->esph_spi, assoc->ipsa_dstaddr, af); 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 2379*0Sstevel@tonic-gate sadb_replay_delete(assoc); 2380*0Sstevel@tonic-gate /* 2381*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2382*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2383*0Sstevel@tonic-gate */ 2384*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_replay, 2385*0Sstevel@tonic-gate &esp_dropper); 2386*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2387*0Sstevel@tonic-gate } 2388*0Sstevel@tonic-gate 2389*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2390*0Sstevel@tonic-gate /* 2391*0Sstevel@tonic-gate * Set the IV to a random quantity. We do not require the 2392*0Sstevel@tonic-gate * highest quality random bits, but for best security with CBC 2393*0Sstevel@tonic-gate * mode ciphers, the value must be unlikely to repeat and also 2394*0Sstevel@tonic-gate * must not be known in advance to an adversary capable of 2395*0Sstevel@tonic-gate * influencing the plaintext. 2396*0Sstevel@tonic-gate */ 2397*0Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)(esph + 1), iv_len); 2398*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2399*0Sstevel@tonic-gate 2400*0Sstevel@tonic-gate /* Fix the IP header. */ 2401*0Sstevel@tonic-gate alloclen = padlen + 2 + mac_len; 2402*0Sstevel@tonic-gate adj = alloclen + (espmp->b_wptr - espmp->b_rptr); 2403*0Sstevel@tonic-gate 2404*0Sstevel@tonic-gate protocol = *nhp; 2405*0Sstevel@tonic-gate 2406*0Sstevel@tonic-gate if (io->ipsec_out_v4) { 2407*0Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj); 2408*0Sstevel@tonic-gate if (is_natt) { 2409*0Sstevel@tonic-gate *nhp = IPPROTO_UDP; 2410*0Sstevel@tonic-gate udpha->uha_length = htons(ntohs(ipha->ipha_length) - 2411*0Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 2412*0Sstevel@tonic-gate } else { 2413*0Sstevel@tonic-gate *nhp = IPPROTO_ESP; 2414*0Sstevel@tonic-gate } 2415*0Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 2416*0Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 2417*0Sstevel@tonic-gate } else { 2418*0Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj); 2419*0Sstevel@tonic-gate *nhp = IPPROTO_ESP; 2420*0Sstevel@tonic-gate } 2421*0Sstevel@tonic-gate 2422*0Sstevel@tonic-gate /* I've got the two ESP mblks, now insert them. */ 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate esp2dbg(("data_mp before outbound ESP adjustment:\n")); 2425*0Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 2426*0Sstevel@tonic-gate 2427*0Sstevel@tonic-gate if (!esp_insert_esp(data_mp, espmp, divpoint)) { 2428*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 2429*0Sstevel@tonic-gate /* NOTE: esp_insert_esp() only fails if there's no memory. */ 2430*0Sstevel@tonic-gate /* 2431*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2432*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2433*0Sstevel@tonic-gate */ 2434*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem, 2435*0Sstevel@tonic-gate &esp_dropper); 2436*0Sstevel@tonic-gate freeb(espmp); 2437*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2438*0Sstevel@tonic-gate } 2439*0Sstevel@tonic-gate 2440*0Sstevel@tonic-gate /* Append padding (and leave room for ICV). */ 2441*0Sstevel@tonic-gate for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont) 2442*0Sstevel@tonic-gate ; 2443*0Sstevel@tonic-gate if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) { 2444*0Sstevel@tonic-gate tailmp->b_cont = allocb(alloclen, BPRI_HI); 2445*0Sstevel@tonic-gate if (tailmp->b_cont == NULL) { 2446*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 2447*0Sstevel@tonic-gate esp0dbg(("esp_outbound: Can't allocate tailmp.\n")); 2448*0Sstevel@tonic-gate /* 2449*0Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 2450*0Sstevel@tonic-gate * pass it to ip_drop_packet(). 2451*0Sstevel@tonic-gate */ 2452*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 2453*0Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 2454*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2455*0Sstevel@tonic-gate } 2456*0Sstevel@tonic-gate tailmp = tailmp->b_cont; 2457*0Sstevel@tonic-gate } 2458*0Sstevel@tonic-gate 2459*0Sstevel@tonic-gate /* 2460*0Sstevel@tonic-gate * If there's padding, N bytes of padding must be of the form 0x1, 2461*0Sstevel@tonic-gate * 0x2, 0x3... 0xN. 2462*0Sstevel@tonic-gate */ 2463*0Sstevel@tonic-gate for (i = 0; i < padlen; ) { 2464*0Sstevel@tonic-gate i++; 2465*0Sstevel@tonic-gate *tailmp->b_wptr++ = i; 2466*0Sstevel@tonic-gate } 2467*0Sstevel@tonic-gate *tailmp->b_wptr++ = i; 2468*0Sstevel@tonic-gate *tailmp->b_wptr++ = protocol; 2469*0Sstevel@tonic-gate 2470*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2471*0Sstevel@tonic-gate esp2dbg(("data_Mp before encryption:\n")); 2472*0Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 2473*0Sstevel@tonic-gate 2474*0Sstevel@tonic-gate /* 2475*0Sstevel@tonic-gate * The packet is eligible for hardware acceleration if the 2476*0Sstevel@tonic-gate * following conditions are satisfied: 2477*0Sstevel@tonic-gate * 2478*0Sstevel@tonic-gate * 1. the packet will not be fragmented 2479*0Sstevel@tonic-gate * 2. the provider supports the algorithms specified by SA 2480*0Sstevel@tonic-gate * 3. there is no pending control message being exchanged 2481*0Sstevel@tonic-gate * 4. snoop is not attached 2482*0Sstevel@tonic-gate * 5. the destination address is not a multicast address 2483*0Sstevel@tonic-gate * 2484*0Sstevel@tonic-gate * All five of these conditions are checked by IP prior to 2485*0Sstevel@tonic-gate * sending the packet to ESP. 2486*0Sstevel@tonic-gate * 2487*0Sstevel@tonic-gate * But We, and We Alone, can, nay MUST check if the packet 2488*0Sstevel@tonic-gate * is over NATT, and then disqualify it from hardware 2489*0Sstevel@tonic-gate * acceleration. 2490*0Sstevel@tonic-gate */ 2491*0Sstevel@tonic-gate 2492*0Sstevel@tonic-gate if (io->ipsec_out_is_capab_ill && !(assoc->ipsa_flags & IPSA_F_NATT)) { 2493*0Sstevel@tonic-gate return (esp_outbound_accelerated(ipsec_out_mp, mac_len)); 2494*0Sstevel@tonic-gate } 2495*0Sstevel@tonic-gate ESP_BUMP_STAT(noaccel); 2496*0Sstevel@tonic-gate 2497*0Sstevel@tonic-gate /* 2498*0Sstevel@tonic-gate * Okay. I've set up the pre-encryption ESP. Let's do it! 2499*0Sstevel@tonic-gate */ 2500*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2501*0Sstevel@tonic-gate 2502*0Sstevel@tonic-gate if (mac_len > 0) { 2503*0Sstevel@tonic-gate ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim); 2504*0Sstevel@tonic-gate icv_buf = tailmp->b_wptr; 2505*0Sstevel@tonic-gate tailmp->b_wptr += mac_len; 2506*0Sstevel@tonic-gate } else { 2507*0Sstevel@tonic-gate icv_buf = NULL; 2508*0Sstevel@tonic-gate } 2509*0Sstevel@tonic-gate 2510*0Sstevel@tonic-gate return (esp_submit_req_outbound(ipsec_out_mp, assoc, icv_buf, 2511*0Sstevel@tonic-gate datalen + padlen + 2)); 2512*0Sstevel@tonic-gate } 2513*0Sstevel@tonic-gate 2514*0Sstevel@tonic-gate /* 2515*0Sstevel@tonic-gate * IP calls this to validate the ICMP errors that 2516*0Sstevel@tonic-gate * we got from the network. 2517*0Sstevel@tonic-gate */ 2518*0Sstevel@tonic-gate ipsec_status_t 2519*0Sstevel@tonic-gate ipsecesp_icmp_error(mblk_t *ipsec_mp) 2520*0Sstevel@tonic-gate { 2521*0Sstevel@tonic-gate /* 2522*0Sstevel@tonic-gate * Unless we get an entire packet back, this function is useless. 2523*0Sstevel@tonic-gate * Why? 2524*0Sstevel@tonic-gate * 2525*0Sstevel@tonic-gate * 1.) Partial packets are useless, because the "next header" 2526*0Sstevel@tonic-gate * is at the end of the decrypted ESP packet. Without the 2527*0Sstevel@tonic-gate * whole packet, this is useless. 2528*0Sstevel@tonic-gate * 2529*0Sstevel@tonic-gate * 2.) If we every use a stateful cipher, such as a stream or a 2530*0Sstevel@tonic-gate * one-time pad, we can't do anything. 2531*0Sstevel@tonic-gate * 2532*0Sstevel@tonic-gate * Since the chances of us getting an entire packet back are very 2533*0Sstevel@tonic-gate * very small, we discard here. 2534*0Sstevel@tonic-gate */ 2535*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 2536*0Sstevel@tonic-gate ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_esp_icmp, 2537*0Sstevel@tonic-gate &esp_dropper); 2538*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 2539*0Sstevel@tonic-gate } 2540*0Sstevel@tonic-gate 2541*0Sstevel@tonic-gate /* 2542*0Sstevel@tonic-gate * ESP module read put routine. 2543*0Sstevel@tonic-gate */ 2544*0Sstevel@tonic-gate /* ARGSUSED */ 2545*0Sstevel@tonic-gate static void 2546*0Sstevel@tonic-gate ipsecesp_rput(queue_t *q, mblk_t *mp) 2547*0Sstevel@tonic-gate { 2548*0Sstevel@tonic-gate keysock_in_t *ksi; 2549*0Sstevel@tonic-gate int *addrtype; 2550*0Sstevel@tonic-gate ire_t *ire; 2551*0Sstevel@tonic-gate mblk_t *ire_mp, *last_mp; 2552*0Sstevel@tonic-gate 2553*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2554*0Sstevel@tonic-gate case M_CTL: 2555*0Sstevel@tonic-gate /* 2556*0Sstevel@tonic-gate * IPsec request of some variety from IP. IPSEC_{IN,OUT} 2557*0Sstevel@tonic-gate * are the common cases, but even ICMP error messages from IP 2558*0Sstevel@tonic-gate * may rise up here. 2559*0Sstevel@tonic-gate * 2560*0Sstevel@tonic-gate * Ummmm, actually, this can also be the reflected KEYSOCK_IN 2561*0Sstevel@tonic-gate * message, with an IRE_DB_TYPE hung off at the end. 2562*0Sstevel@tonic-gate */ 2563*0Sstevel@tonic-gate switch (((ipsec_info_t *)(mp->b_rptr))->ipsec_info_type) { 2564*0Sstevel@tonic-gate case KEYSOCK_IN: 2565*0Sstevel@tonic-gate last_mp = mp; 2566*0Sstevel@tonic-gate while (last_mp->b_cont != NULL && 2567*0Sstevel@tonic-gate last_mp->b_cont->b_datap->db_type != IRE_DB_TYPE) 2568*0Sstevel@tonic-gate last_mp = last_mp->b_cont; 2569*0Sstevel@tonic-gate 2570*0Sstevel@tonic-gate if (last_mp->b_cont == NULL) { 2571*0Sstevel@tonic-gate freemsg(mp); 2572*0Sstevel@tonic-gate break; /* Out of switch. */ 2573*0Sstevel@tonic-gate } 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate ire_mp = last_mp->b_cont; 2576*0Sstevel@tonic-gate last_mp->b_cont = NULL; 2577*0Sstevel@tonic-gate 2578*0Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 2579*0Sstevel@tonic-gate 2580*0Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) 2581*0Sstevel@tonic-gate addrtype = &ksi->ks_in_srctype; 2582*0Sstevel@tonic-gate else if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) 2583*0Sstevel@tonic-gate addrtype = &ksi->ks_in_dsttype; 2584*0Sstevel@tonic-gate else if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) 2585*0Sstevel@tonic-gate addrtype = &ksi->ks_in_proxytype; 2586*0Sstevel@tonic-gate 2587*0Sstevel@tonic-gate ire = (ire_t *)ire_mp->b_rptr; 2588*0Sstevel@tonic-gate 2589*0Sstevel@tonic-gate *addrtype = sadb_addrset(ire); 2590*0Sstevel@tonic-gate 2591*0Sstevel@tonic-gate freemsg(ire_mp); 2592*0Sstevel@tonic-gate if (esp_pfkey_q != NULL) { 2593*0Sstevel@tonic-gate /* 2594*0Sstevel@tonic-gate * Decrement counter to make up for 2595*0Sstevel@tonic-gate * auto-increment in ipsecesp_wput(). 2596*0Sstevel@tonic-gate * I'm running all MT-hot through here, so 2597*0Sstevel@tonic-gate * don't worry about perimeters and lateral 2598*0Sstevel@tonic-gate * puts. 2599*0Sstevel@tonic-gate */ 2600*0Sstevel@tonic-gate ESP_DEBUMP_STAT(keysock_in); 2601*0Sstevel@tonic-gate ipsecesp_wput(WR(esp_pfkey_q), mp); 2602*0Sstevel@tonic-gate } else { 2603*0Sstevel@tonic-gate freemsg(mp); 2604*0Sstevel@tonic-gate } 2605*0Sstevel@tonic-gate break; 2606*0Sstevel@tonic-gate default: 2607*0Sstevel@tonic-gate freemsg(mp); 2608*0Sstevel@tonic-gate break; 2609*0Sstevel@tonic-gate } 2610*0Sstevel@tonic-gate break; 2611*0Sstevel@tonic-gate case M_PROTO: 2612*0Sstevel@tonic-gate case M_PCPROTO: 2613*0Sstevel@tonic-gate /* TPI message of some sort. */ 2614*0Sstevel@tonic-gate switch (*((t_scalar_t *)mp->b_rptr)) { 2615*0Sstevel@tonic-gate case T_BIND_ACK: 2616*0Sstevel@tonic-gate esp3dbg(("Thank you IP from ESP for T_BIND_ACK\n")); 2617*0Sstevel@tonic-gate break; 2618*0Sstevel@tonic-gate case T_ERROR_ACK: 2619*0Sstevel@tonic-gate cmn_err(CE_WARN, 2620*0Sstevel@tonic-gate "ipsecesp: ESP received T_ERROR_ACK from IP."); 2621*0Sstevel@tonic-gate /* 2622*0Sstevel@tonic-gate * Make esp_sadb.s_ip_q NULL, and in the 2623*0Sstevel@tonic-gate * future, perhaps try again. 2624*0Sstevel@tonic-gate */ 2625*0Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 2626*0Sstevel@tonic-gate break; 2627*0Sstevel@tonic-gate case T_OK_ACK: 2628*0Sstevel@tonic-gate /* Probably from a (rarely sent) T_UNBIND_REQ. */ 2629*0Sstevel@tonic-gate break; 2630*0Sstevel@tonic-gate default: 2631*0Sstevel@tonic-gate esp0dbg(("Unknown M_{,PC}PROTO message.\n")); 2632*0Sstevel@tonic-gate } 2633*0Sstevel@tonic-gate freemsg(mp); 2634*0Sstevel@tonic-gate break; 2635*0Sstevel@tonic-gate default: 2636*0Sstevel@tonic-gate /* For now, passthru message. */ 2637*0Sstevel@tonic-gate esp2dbg(("ESP got unknown mblk type %d.\n", 2638*0Sstevel@tonic-gate mp->b_datap->db_type)); 2639*0Sstevel@tonic-gate putnext(q, mp); 2640*0Sstevel@tonic-gate } 2641*0Sstevel@tonic-gate } 2642*0Sstevel@tonic-gate 2643*0Sstevel@tonic-gate /* 2644*0Sstevel@tonic-gate * Construct an SADB_REGISTER message with the current algorithms. 2645*0Sstevel@tonic-gate */ 2646*0Sstevel@tonic-gate static boolean_t 2647*0Sstevel@tonic-gate esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial) 2648*0Sstevel@tonic-gate { 2649*0Sstevel@tonic-gate mblk_t *pfkey_msg_mp, *keysock_out_mp; 2650*0Sstevel@tonic-gate sadb_msg_t *samsg; 2651*0Sstevel@tonic-gate sadb_supported_t *sasupp_auth = NULL; 2652*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2653*0Sstevel@tonic-gate sadb_supported_t *sasupp_encr = NULL; 2654*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2655*0Sstevel@tonic-gate sadb_alg_t *saalg; 2656*0Sstevel@tonic-gate uint_t allocsize = sizeof (*samsg); 2657*0Sstevel@tonic-gate uint_t i, numalgs_snap; 2658*0Sstevel@tonic-gate int current_aalgs; 2659*0Sstevel@tonic-gate ipsec_alginfo_t **authalgs; 2660*0Sstevel@tonic-gate uint_t num_aalgs; 2661*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2662*0Sstevel@tonic-gate int current_ealgs; 2663*0Sstevel@tonic-gate ipsec_alginfo_t **encralgs; 2664*0Sstevel@tonic-gate uint_t num_ealgs; 2665*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2666*0Sstevel@tonic-gate 2667*0Sstevel@tonic-gate /* Allocate the KEYSOCK_OUT. */ 2668*0Sstevel@tonic-gate keysock_out_mp = sadb_keysock_out(serial); 2669*0Sstevel@tonic-gate if (keysock_out_mp == NULL) { 2670*0Sstevel@tonic-gate esp0dbg(("esp_register_out: couldn't allocate mblk.\n")); 2671*0Sstevel@tonic-gate return (B_FALSE); 2672*0Sstevel@tonic-gate } 2673*0Sstevel@tonic-gate 2674*0Sstevel@tonic-gate /* 2675*0Sstevel@tonic-gate * Allocate the PF_KEY message that follows KEYSOCK_OUT. 2676*0Sstevel@tonic-gate */ 2677*0Sstevel@tonic-gate 2678*0Sstevel@tonic-gate mutex_enter(&alg_lock); 2679*0Sstevel@tonic-gate 2680*0Sstevel@tonic-gate /* 2681*0Sstevel@tonic-gate * Fill SADB_REGISTER message's algorithm descriptors. Hold 2682*0Sstevel@tonic-gate * down the lock while filling it. 2683*0Sstevel@tonic-gate * 2684*0Sstevel@tonic-gate * Return only valid algorithms, so the number of algorithms 2685*0Sstevel@tonic-gate * to send up may be less than the number of algorithm entries 2686*0Sstevel@tonic-gate * in the table. 2687*0Sstevel@tonic-gate */ 2688*0Sstevel@tonic-gate authalgs = ipsec_alglists[IPSEC_ALG_AUTH]; 2689*0Sstevel@tonic-gate for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 2690*0Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 2691*0Sstevel@tonic-gate num_aalgs++; 2692*0Sstevel@tonic-gate 2693*0Sstevel@tonic-gate if (num_aalgs != 0) { 2694*0Sstevel@tonic-gate allocsize += (num_aalgs * sizeof (*saalg)); 2695*0Sstevel@tonic-gate allocsize += sizeof (*sasupp_auth); 2696*0Sstevel@tonic-gate } 2697*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2698*0Sstevel@tonic-gate encralgs = ipsec_alglists[IPSEC_ALG_ENCR]; 2699*0Sstevel@tonic-gate for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 2700*0Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) 2701*0Sstevel@tonic-gate num_ealgs++; 2702*0Sstevel@tonic-gate 2703*0Sstevel@tonic-gate if (num_ealgs != 0) { 2704*0Sstevel@tonic-gate allocsize += (num_ealgs * sizeof (*saalg)); 2705*0Sstevel@tonic-gate allocsize += sizeof (*sasupp_encr); 2706*0Sstevel@tonic-gate } 2707*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2708*0Sstevel@tonic-gate keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI); 2709*0Sstevel@tonic-gate if (keysock_out_mp->b_cont == NULL) { 2710*0Sstevel@tonic-gate mutex_exit(&alg_lock); 2711*0Sstevel@tonic-gate freemsg(keysock_out_mp); 2712*0Sstevel@tonic-gate return (B_FALSE); 2713*0Sstevel@tonic-gate } 2714*0Sstevel@tonic-gate 2715*0Sstevel@tonic-gate pfkey_msg_mp = keysock_out_mp->b_cont; 2716*0Sstevel@tonic-gate pfkey_msg_mp->b_wptr += allocsize; 2717*0Sstevel@tonic-gate if (num_aalgs != 0) { 2718*0Sstevel@tonic-gate sasupp_auth = (sadb_supported_t *) 2719*0Sstevel@tonic-gate (pfkey_msg_mp->b_rptr + sizeof (*samsg)); 2720*0Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_auth + 1); 2721*0Sstevel@tonic-gate 2722*0Sstevel@tonic-gate ASSERT(((ulong_t)saalg & 0x7) == 0); 2723*0Sstevel@tonic-gate 2724*0Sstevel@tonic-gate numalgs_snap = 0; 2725*0Sstevel@tonic-gate for (i = 0; 2726*0Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); i++) { 2727*0Sstevel@tonic-gate if (authalgs[i] == NULL || !ALG_VALID(authalgs[i])) 2728*0Sstevel@tonic-gate continue; 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate saalg->sadb_alg_id = authalgs[i]->alg_id; 2731*0Sstevel@tonic-gate saalg->sadb_alg_ivlen = 0; 2732*0Sstevel@tonic-gate saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits; 2733*0Sstevel@tonic-gate saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits; 2734*0Sstevel@tonic-gate saalg->sadb_x_alg_defincr = authalgs[i]->alg_ef_default; 2735*0Sstevel@tonic-gate saalg->sadb_x_alg_increment = 2736*0Sstevel@tonic-gate authalgs[i]->alg_increment; 2737*0Sstevel@tonic-gate numalgs_snap++; 2738*0Sstevel@tonic-gate saalg++; 2739*0Sstevel@tonic-gate } 2740*0Sstevel@tonic-gate ASSERT(numalgs_snap == num_aalgs); 2741*0Sstevel@tonic-gate #ifdef DEBUG 2742*0Sstevel@tonic-gate /* 2743*0Sstevel@tonic-gate * Reality check to make sure I snagged all of the 2744*0Sstevel@tonic-gate * algorithms. 2745*0Sstevel@tonic-gate */ 2746*0Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 2747*0Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) { 2748*0Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 2749*0Sstevel@tonic-gate "Missed aalg #%d.\n", i); 2750*0Sstevel@tonic-gate } 2751*0Sstevel@tonic-gate } 2752*0Sstevel@tonic-gate #endif /* DEBUG */ 2753*0Sstevel@tonic-gate } else { 2754*0Sstevel@tonic-gate saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg)); 2755*0Sstevel@tonic-gate } 2756*0Sstevel@tonic-gate 2757*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2758*0Sstevel@tonic-gate if (num_ealgs != 0) { 2759*0Sstevel@tonic-gate sasupp_encr = (sadb_supported_t *)saalg; 2760*0Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_encr + 1); 2761*0Sstevel@tonic-gate 2762*0Sstevel@tonic-gate numalgs_snap = 0; 2763*0Sstevel@tonic-gate for (i = 0; 2764*0Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) { 2765*0Sstevel@tonic-gate if (encralgs[i] == NULL || !ALG_VALID(encralgs[i])) 2766*0Sstevel@tonic-gate continue; 2767*0Sstevel@tonic-gate saalg->sadb_alg_id = encralgs[i]->alg_id; 2768*0Sstevel@tonic-gate saalg->sadb_alg_ivlen = encralgs[i]->alg_datalen; 2769*0Sstevel@tonic-gate saalg->sadb_alg_minbits = encralgs[i]->alg_ef_minbits; 2770*0Sstevel@tonic-gate saalg->sadb_alg_maxbits = encralgs[i]->alg_ef_maxbits; 2771*0Sstevel@tonic-gate saalg->sadb_x_alg_defincr = encralgs[i]->alg_ef_default; 2772*0Sstevel@tonic-gate saalg->sadb_x_alg_increment = 2773*0Sstevel@tonic-gate encralgs[i]->alg_increment; 2774*0Sstevel@tonic-gate numalgs_snap++; 2775*0Sstevel@tonic-gate saalg++; 2776*0Sstevel@tonic-gate } 2777*0Sstevel@tonic-gate ASSERT(numalgs_snap == num_ealgs); 2778*0Sstevel@tonic-gate #ifdef DEBUG 2779*0Sstevel@tonic-gate /* 2780*0Sstevel@tonic-gate * Reality check to make sure I snagged all of the 2781*0Sstevel@tonic-gate * algorithms. 2782*0Sstevel@tonic-gate */ 2783*0Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 2784*0Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) { 2785*0Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 2786*0Sstevel@tonic-gate "Missed ealg #%d.\n", i); 2787*0Sstevel@tonic-gate } 2788*0Sstevel@tonic-gate } 2789*0Sstevel@tonic-gate #endif /* DEBUG */ 2790*0Sstevel@tonic-gate } 2791*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2792*0Sstevel@tonic-gate 2793*0Sstevel@tonic-gate current_aalgs = num_aalgs; 2794*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2795*0Sstevel@tonic-gate current_ealgs = num_ealgs; 2796*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2797*0Sstevel@tonic-gate 2798*0Sstevel@tonic-gate mutex_exit(&alg_lock); 2799*0Sstevel@tonic-gate 2800*0Sstevel@tonic-gate /* Now fill the rest of the SADB_REGISTER message. */ 2801*0Sstevel@tonic-gate 2802*0Sstevel@tonic-gate samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr; 2803*0Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2; 2804*0Sstevel@tonic-gate samsg->sadb_msg_type = SADB_REGISTER; 2805*0Sstevel@tonic-gate samsg->sadb_msg_errno = 0; 2806*0Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 2807*0Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(allocsize); 2808*0Sstevel@tonic-gate samsg->sadb_msg_reserved = 0; 2809*0Sstevel@tonic-gate /* 2810*0Sstevel@tonic-gate * Assume caller has sufficient sequence/pid number info. If it's one 2811*0Sstevel@tonic-gate * from me over a new alg., I could give two hoots about sequence. 2812*0Sstevel@tonic-gate */ 2813*0Sstevel@tonic-gate samsg->sadb_msg_seq = sequence; 2814*0Sstevel@tonic-gate samsg->sadb_msg_pid = pid; 2815*0Sstevel@tonic-gate 2816*0Sstevel@tonic-gate if (sasupp_auth != NULL) { 2817*0Sstevel@tonic-gate sasupp_auth->sadb_supported_len = 2818*0Sstevel@tonic-gate SADB_8TO64(sizeof (*sasupp_auth) + 2819*0Sstevel@tonic-gate sizeof (*saalg) * current_aalgs); 2820*0Sstevel@tonic-gate sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 2821*0Sstevel@tonic-gate sasupp_auth->sadb_supported_reserved = 0; 2822*0Sstevel@tonic-gate } 2823*0Sstevel@tonic-gate 2824*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2825*0Sstevel@tonic-gate if (sasupp_encr != NULL) { 2826*0Sstevel@tonic-gate sasupp_encr->sadb_supported_len = 2827*0Sstevel@tonic-gate SADB_8TO64(sizeof (*sasupp_encr) + 2828*0Sstevel@tonic-gate sizeof (*saalg) * current_ealgs); 2829*0Sstevel@tonic-gate sasupp_encr->sadb_supported_exttype = 2830*0Sstevel@tonic-gate SADB_EXT_SUPPORTED_ENCRYPT; 2831*0Sstevel@tonic-gate sasupp_encr->sadb_supported_reserved = 0; 2832*0Sstevel@tonic-gate } 2833*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2834*0Sstevel@tonic-gate 2835*0Sstevel@tonic-gate if (esp_pfkey_q != NULL) 2836*0Sstevel@tonic-gate putnext(esp_pfkey_q, keysock_out_mp); 2837*0Sstevel@tonic-gate else { 2838*0Sstevel@tonic-gate freemsg(keysock_out_mp); 2839*0Sstevel@tonic-gate return (B_FALSE); 2840*0Sstevel@tonic-gate } 2841*0Sstevel@tonic-gate 2842*0Sstevel@tonic-gate return (B_TRUE); 2843*0Sstevel@tonic-gate } 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate /* 2846*0Sstevel@tonic-gate * Invoked when the algorithm table changes. Causes SADB_REGISTER 2847*0Sstevel@tonic-gate * messages continaining the current list of algorithms to be 2848*0Sstevel@tonic-gate * sent up to the ESP listeners. 2849*0Sstevel@tonic-gate */ 2850*0Sstevel@tonic-gate void 2851*0Sstevel@tonic-gate ipsecesp_algs_changed(void) 2852*0Sstevel@tonic-gate { 2853*0Sstevel@tonic-gate /* 2854*0Sstevel@tonic-gate * Time to send a PF_KEY SADB_REGISTER message to ESP listeners 2855*0Sstevel@tonic-gate * everywhere. (The function itself checks for NULL esp_pfkey_q.) 2856*0Sstevel@tonic-gate */ 2857*0Sstevel@tonic-gate (void) esp_register_out(0, 0, 0); 2858*0Sstevel@tonic-gate } 2859*0Sstevel@tonic-gate 2860*0Sstevel@tonic-gate /* 2861*0Sstevel@tonic-gate * taskq_dispatch handler. 2862*0Sstevel@tonic-gate */ 2863*0Sstevel@tonic-gate static void 2864*0Sstevel@tonic-gate inbound_task(void *arg) 2865*0Sstevel@tonic-gate { 2866*0Sstevel@tonic-gate esph_t *esph; 2867*0Sstevel@tonic-gate mblk_t *mp = (mblk_t *)arg; 2868*0Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr; 2869*0Sstevel@tonic-gate int ipsec_rc; 2870*0Sstevel@tonic-gate 2871*0Sstevel@tonic-gate esp2dbg(("in ESP inbound_task")); 2872*0Sstevel@tonic-gate 2873*0Sstevel@tonic-gate esph = ipsec_inbound_esp_sa(mp); 2874*0Sstevel@tonic-gate if (esph == NULL) 2875*0Sstevel@tonic-gate return; 2876*0Sstevel@tonic-gate ASSERT(ii->ipsec_in_esp_sa != NULL); 2877*0Sstevel@tonic-gate ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(mp, esph); 2878*0Sstevel@tonic-gate if (ipsec_rc != IPSEC_STATUS_SUCCESS) 2879*0Sstevel@tonic-gate return; 2880*0Sstevel@tonic-gate ip_fanout_proto_again(mp, NULL, NULL, NULL); 2881*0Sstevel@tonic-gate } 2882*0Sstevel@tonic-gate 2883*0Sstevel@tonic-gate /* 2884*0Sstevel@tonic-gate * Now that weak-key passed, actually ADD the security association, and 2885*0Sstevel@tonic-gate * send back a reply ADD message. 2886*0Sstevel@tonic-gate */ 2887*0Sstevel@tonic-gate static int 2888*0Sstevel@tonic-gate esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi) 2889*0Sstevel@tonic-gate { 2890*0Sstevel@tonic-gate isaf_t *primary, *secondary, *inbound; 2891*0Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 2892*0Sstevel@tonic-gate sadb_address_t *dstext = 2893*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 2894*0Sstevel@tonic-gate struct sockaddr_in *dst; 2895*0Sstevel@tonic-gate struct sockaddr_in6 *dst6; 2896*0Sstevel@tonic-gate boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE; 2897*0Sstevel@tonic-gate uint32_t *dstaddr; 2898*0Sstevel@tonic-gate ipsa_t *larval = NULL; 2899*0Sstevel@tonic-gate ipsacq_t *acqrec; 2900*0Sstevel@tonic-gate iacqf_t *acq_bucket; 2901*0Sstevel@tonic-gate mblk_t *acq_msgs = NULL; 2902*0Sstevel@tonic-gate int rc; 2903*0Sstevel@tonic-gate sadb_t *sp; 2904*0Sstevel@tonic-gate int outhash; 2905*0Sstevel@tonic-gate mblk_t *lpkt; 2906*0Sstevel@tonic-gate 2907*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2908*0Sstevel@tonic-gate #if 0 2909*0Sstevel@tonic-gate /* 2910*0Sstevel@tonic-gate * Gross hack for export control. Since esp_encr_keycheck 2911*0Sstevel@tonic-gate * is gone, I have to somehow enforce that exportable ESP source 2912*0Sstevel@tonic-gate * can't have encryption. 2913*0Sstevel@tonic-gate */ 2914*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2915*0Sstevel@tonic-gate if (assoc->sadb_sa_encrypt != SADB_EALG_NULL) { 2916*0Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 2917*0Sstevel@tonic-gate return (EINVAL); 2918*0Sstevel@tonic-gate } 2919*0Sstevel@tonic-gate /* EXPORT DELETE START */ 2920*0Sstevel@tonic-gate #endif 2921*0Sstevel@tonic-gate /* EXPORT DELETE END */ 2922*0Sstevel@tonic-gate 2923*0Sstevel@tonic-gate /* 2924*0Sstevel@tonic-gate * Locate the appropriate table(s). 2925*0Sstevel@tonic-gate */ 2926*0Sstevel@tonic-gate 2927*0Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 2928*0Sstevel@tonic-gate dst6 = (struct sockaddr_in6 *)dst; 2929*0Sstevel@tonic-gate is_ipv4 = (dst->sin_family == AF_INET); 2930*0Sstevel@tonic-gate if (is_ipv4) { 2931*0Sstevel@tonic-gate sp = &esp_sadb.s_v4; 2932*0Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst->sin_addr); 2933*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V4(*(ipaddr_t *)dstaddr); 2934*0Sstevel@tonic-gate } else { 2935*0Sstevel@tonic-gate sp = &esp_sadb.s_v6; 2936*0Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst6->sin6_addr); 2937*0Sstevel@tonic-gate outhash = OUTBOUND_HASH_V6(*(in6_addr_t *)dstaddr); 2938*0Sstevel@tonic-gate } 2939*0Sstevel@tonic-gate inbound = &sp->sdb_if[INBOUND_HASH(assoc->sadb_sa_spi)]; 2940*0Sstevel@tonic-gate switch (ksi->ks_in_dsttype) { 2941*0Sstevel@tonic-gate case KS_IN_ADDR_MBCAST: 2942*0Sstevel@tonic-gate clone = B_TRUE; /* All mcast SAs can be bidirectional */ 2943*0Sstevel@tonic-gate /* FALLTHRU */ 2944*0Sstevel@tonic-gate case KS_IN_ADDR_ME: 2945*0Sstevel@tonic-gate primary = inbound; 2946*0Sstevel@tonic-gate secondary = &sp->sdb_of[outhash]; 2947*0Sstevel@tonic-gate /* 2948*0Sstevel@tonic-gate * If the source address is either one of mine, or unspecified 2949*0Sstevel@tonic-gate * (which is best summed up by saying "not 'not mine'"), 2950*0Sstevel@tonic-gate * then the association is potentially bi-directional, 2951*0Sstevel@tonic-gate * in that it can be used for inbound traffic and outbound 2952*0Sstevel@tonic-gate * traffic. The best example of such an SA is a multicast 2953*0Sstevel@tonic-gate * SA (which allows me to receive the outbound traffic). 2954*0Sstevel@tonic-gate */ 2955*0Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME) 2956*0Sstevel@tonic-gate clone = B_TRUE; 2957*0Sstevel@tonic-gate is_inbound = B_TRUE; 2958*0Sstevel@tonic-gate break; 2959*0Sstevel@tonic-gate case KS_IN_ADDR_NOTME: 2960*0Sstevel@tonic-gate primary = &sp->sdb_of[outhash]; 2961*0Sstevel@tonic-gate secondary = inbound; 2962*0Sstevel@tonic-gate /* 2963*0Sstevel@tonic-gate * If the source address literally not mine (either 2964*0Sstevel@tonic-gate * unspecified or not mine), then this SA may have an 2965*0Sstevel@tonic-gate * address that WILL be mine after some configuration. 2966*0Sstevel@tonic-gate * We pay the price for this by making it a bi-directional 2967*0Sstevel@tonic-gate * SA. 2968*0Sstevel@tonic-gate */ 2969*0Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_ME) 2970*0Sstevel@tonic-gate clone = B_TRUE; 2971*0Sstevel@tonic-gate break; 2972*0Sstevel@tonic-gate default: 2973*0Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 2974*0Sstevel@tonic-gate return (EINVAL); 2975*0Sstevel@tonic-gate } 2976*0Sstevel@tonic-gate 2977*0Sstevel@tonic-gate /* 2978*0Sstevel@tonic-gate * Find a ACQUIRE list entry if possible. If we've added an SA that 2979*0Sstevel@tonic-gate * suits the needs of an ACQUIRE list entry, we can eliminate the 2980*0Sstevel@tonic-gate * ACQUIRE list entry and transmit the enqueued packets. Use the 2981*0Sstevel@tonic-gate * high-bit of the sequence number to queue it. Key off destination 2982*0Sstevel@tonic-gate * addr, and change acqrec's state. 2983*0Sstevel@tonic-gate */ 2984*0Sstevel@tonic-gate 2985*0Sstevel@tonic-gate if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) { 2986*0Sstevel@tonic-gate acq_bucket = &sp->sdb_acq[outhash]; 2987*0Sstevel@tonic-gate mutex_enter(&acq_bucket->iacqf_lock); 2988*0Sstevel@tonic-gate for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL; 2989*0Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) { 2990*0Sstevel@tonic-gate mutex_enter(&acqrec->ipsacq_lock); 2991*0Sstevel@tonic-gate /* 2992*0Sstevel@tonic-gate * Q: I only check sequence. Should I check dst? 2993*0Sstevel@tonic-gate * A: Yes, check dest because those are the packets 2994*0Sstevel@tonic-gate * that are queued up. 2995*0Sstevel@tonic-gate */ 2996*0Sstevel@tonic-gate if (acqrec->ipsacq_seq == samsg->sadb_msg_seq && 2997*0Sstevel@tonic-gate IPSA_ARE_ADDR_EQUAL(dstaddr, 2998*0Sstevel@tonic-gate acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam)) 2999*0Sstevel@tonic-gate break; 3000*0Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 3001*0Sstevel@tonic-gate } 3002*0Sstevel@tonic-gate if (acqrec != NULL) { 3003*0Sstevel@tonic-gate /* 3004*0Sstevel@tonic-gate * AHA! I found an ACQUIRE record for this SA. 3005*0Sstevel@tonic-gate * Grab the msg list, and free the acquire record. 3006*0Sstevel@tonic-gate * I already am holding the lock for this record, 3007*0Sstevel@tonic-gate * so all I have to do is free it. 3008*0Sstevel@tonic-gate */ 3009*0Sstevel@tonic-gate acq_msgs = acqrec->ipsacq_mp; 3010*0Sstevel@tonic-gate acqrec->ipsacq_mp = NULL; 3011*0Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 3012*0Sstevel@tonic-gate sadb_destroy_acquire(acqrec); 3013*0Sstevel@tonic-gate } 3014*0Sstevel@tonic-gate mutex_exit(&acq_bucket->iacqf_lock); 3015*0Sstevel@tonic-gate } 3016*0Sstevel@tonic-gate 3017*0Sstevel@tonic-gate /* 3018*0Sstevel@tonic-gate * Find PF_KEY message, and see if I'm an update. If so, find entry 3019*0Sstevel@tonic-gate * in larval list (if there). 3020*0Sstevel@tonic-gate */ 3021*0Sstevel@tonic-gate 3022*0Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_UPDATE) { 3023*0Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 3024*0Sstevel@tonic-gate larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi, 3025*0Sstevel@tonic-gate ALL_ZEROES_PTR, dstaddr, dst->sin_family); 3026*0Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 3027*0Sstevel@tonic-gate 3028*0Sstevel@tonic-gate if (larval == NULL) { 3029*0Sstevel@tonic-gate esp0dbg(("Larval update, but larval disappeared.\n")); 3030*0Sstevel@tonic-gate return (ESRCH); 3031*0Sstevel@tonic-gate } /* Else sadb_common_add unlinks it for me! */ 3032*0Sstevel@tonic-gate } 3033*0Sstevel@tonic-gate 3034*0Sstevel@tonic-gate lpkt = NULL; 3035*0Sstevel@tonic-gate if (larval != NULL) 3036*0Sstevel@tonic-gate lpkt = sadb_clear_lpkt(larval); 3037*0Sstevel@tonic-gate 3038*0Sstevel@tonic-gate rc = sadb_common_add(esp_sadb.s_ip_q, esp_pfkey_q, mp, samsg, ksi, 3039*0Sstevel@tonic-gate primary, secondary, larval, clone, is_inbound); 3040*0Sstevel@tonic-gate 3041*0Sstevel@tonic-gate if (rc == 0 && lpkt != NULL) { 3042*0Sstevel@tonic-gate rc = !taskq_dispatch(esp_taskq, inbound_task, 3043*0Sstevel@tonic-gate (void *) lpkt, TQ_NOSLEEP); 3044*0Sstevel@tonic-gate } 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate if (rc != 0) { 3047*0Sstevel@tonic-gate ip_drop_packet(lpkt, B_TRUE, NULL, NULL, 3048*0Sstevel@tonic-gate &ipdrops_sadb_inlarval_timeout, &esp_dropper); 3049*0Sstevel@tonic-gate } 3050*0Sstevel@tonic-gate 3051*0Sstevel@tonic-gate /* 3052*0Sstevel@tonic-gate * How much more stack will I create with all of these 3053*0Sstevel@tonic-gate * esp_outbound() calls? 3054*0Sstevel@tonic-gate */ 3055*0Sstevel@tonic-gate 3056*0Sstevel@tonic-gate while (acq_msgs != NULL) { 3057*0Sstevel@tonic-gate mblk_t *mp = acq_msgs; 3058*0Sstevel@tonic-gate 3059*0Sstevel@tonic-gate acq_msgs = acq_msgs->b_next; 3060*0Sstevel@tonic-gate mp->b_next = NULL; 3061*0Sstevel@tonic-gate if (rc == 0) { 3062*0Sstevel@tonic-gate if (ipsec_outbound_sa(mp, IPPROTO_ESP)) { 3063*0Sstevel@tonic-gate ((ipsec_out_t *)(mp->b_rptr))-> 3064*0Sstevel@tonic-gate ipsec_out_esp_done = B_TRUE; 3065*0Sstevel@tonic-gate if (esp_outbound(mp) == IPSEC_STATUS_SUCCESS) { 3066*0Sstevel@tonic-gate ipha_t *ipha = (ipha_t *) 3067*0Sstevel@tonic-gate mp->b_cont->b_rptr; 3068*0Sstevel@tonic-gate 3069*0Sstevel@tonic-gate /* do AH processing if needed */ 3070*0Sstevel@tonic-gate if (!esp_do_outbound_ah(mp)) 3071*0Sstevel@tonic-gate continue; 3072*0Sstevel@tonic-gate 3073*0Sstevel@tonic-gate /* finish IPsec processing */ 3074*0Sstevel@tonic-gate if (is_ipv4) { 3075*0Sstevel@tonic-gate ip_wput_ipsec_out(NULL, mp, 3076*0Sstevel@tonic-gate ipha, NULL, NULL); 3077*0Sstevel@tonic-gate } else { 3078*0Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 3079*0Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, 3080*0Sstevel@tonic-gate mp, ip6h, NULL, NULL); 3081*0Sstevel@tonic-gate } 3082*0Sstevel@tonic-gate } 3083*0Sstevel@tonic-gate continue; 3084*0Sstevel@tonic-gate } 3085*0Sstevel@tonic-gate } 3086*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 3087*0Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 3088*0Sstevel@tonic-gate &ipdrops_sadb_acquire_timeout, &esp_dropper); 3089*0Sstevel@tonic-gate } 3090*0Sstevel@tonic-gate 3091*0Sstevel@tonic-gate return (rc); 3092*0Sstevel@tonic-gate } 3093*0Sstevel@tonic-gate 3094*0Sstevel@tonic-gate /* 3095*0Sstevel@tonic-gate * Add new ESP security association. This may become a generic AH/ESP 3096*0Sstevel@tonic-gate * routine eventually. 3097*0Sstevel@tonic-gate */ 3098*0Sstevel@tonic-gate static int 3099*0Sstevel@tonic-gate esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 3100*0Sstevel@tonic-gate { 3101*0Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 3102*0Sstevel@tonic-gate sadb_address_t *srcext = 3103*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 3104*0Sstevel@tonic-gate sadb_address_t *dstext = 3105*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 3106*0Sstevel@tonic-gate sadb_address_t *nttext_loc = 3107*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC]; 3108*0Sstevel@tonic-gate sadb_address_t *nttext_rem = 3109*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM]; 3110*0Sstevel@tonic-gate sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH]; 3111*0Sstevel@tonic-gate sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT]; 3112*0Sstevel@tonic-gate struct sockaddr_in *src, *dst; 3113*0Sstevel@tonic-gate struct sockaddr_in *natt_loc, *natt_rem; 3114*0Sstevel@tonic-gate struct sockaddr_in6 *natt_loc6, *natt_rem6; 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate sadb_lifetime_t *soft = 3117*0Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT]; 3118*0Sstevel@tonic-gate sadb_lifetime_t *hard = 3119*0Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD]; 3120*0Sstevel@tonic-gate 3121*0Sstevel@tonic-gate /* I need certain extensions present for an ADD message. */ 3122*0Sstevel@tonic-gate if (srcext == NULL) { 3123*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC; 3124*0Sstevel@tonic-gate return (EINVAL); 3125*0Sstevel@tonic-gate } 3126*0Sstevel@tonic-gate if (dstext == NULL) { 3127*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 3128*0Sstevel@tonic-gate return (EINVAL); 3129*0Sstevel@tonic-gate } 3130*0Sstevel@tonic-gate if (assoc == NULL) { 3131*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 3132*0Sstevel@tonic-gate return (EINVAL); 3133*0Sstevel@tonic-gate } 3134*0Sstevel@tonic-gate if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) { 3135*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY; 3136*0Sstevel@tonic-gate return (EINVAL); 3137*0Sstevel@tonic-gate } 3138*0Sstevel@tonic-gate 3139*0Sstevel@tonic-gate src = (struct sockaddr_in *)(srcext + 1); 3140*0Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 3141*0Sstevel@tonic-gate natt_loc = (struct sockaddr_in *)(nttext_loc + 1); 3142*0Sstevel@tonic-gate natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1); 3143*0Sstevel@tonic-gate natt_rem = (struct sockaddr_in *)(nttext_rem + 1); 3144*0Sstevel@tonic-gate natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1); 3145*0Sstevel@tonic-gate 3146*0Sstevel@tonic-gate /* Sundry ADD-specific reality checks. */ 3147*0Sstevel@tonic-gate /* XXX STATS : Logging/stats here? */ 3148*0Sstevel@tonic-gate if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) { 3149*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE; 3150*0Sstevel@tonic-gate return (EINVAL); 3151*0Sstevel@tonic-gate } 3152*0Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) { 3153*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 3154*0Sstevel@tonic-gate return (EINVAL); 3155*0Sstevel@tonic-gate } 3156*0Sstevel@tonic-gate 3157*0Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NULL && 3158*0Sstevel@tonic-gate assoc->sadb_sa_auth == SADB_AALG_NONE) { 3159*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 3160*0Sstevel@tonic-gate return (EINVAL); 3161*0Sstevel@tonic-gate } 3162*0Sstevel@tonic-gate 3163*0Sstevel@tonic-gate if (assoc->sadb_sa_flags & ~(SADB_SAFLAGS_NOREPLAY | 3164*0Sstevel@tonic-gate SADB_X_SAFLAGS_NATT_LOC | SADB_X_SAFLAGS_NATT_REM)) { 3165*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS; 3166*0Sstevel@tonic-gate return (EINVAL); 3167*0Sstevel@tonic-gate } 3168*0Sstevel@tonic-gate 3169*0Sstevel@tonic-gate if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) { 3170*0Sstevel@tonic-gate return (EINVAL); 3171*0Sstevel@tonic-gate } 3172*0Sstevel@tonic-gate if (src->sin_family != dst->sin_family) { 3173*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH; 3174*0Sstevel@tonic-gate return (EINVAL); 3175*0Sstevel@tonic-gate } 3176*0Sstevel@tonic-gate 3177*0Sstevel@tonic-gate 3178*0Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) { 3179*0Sstevel@tonic-gate if (nttext_loc == NULL) { 3180*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC; 3181*0Sstevel@tonic-gate return (EINVAL); 3182*0Sstevel@tonic-gate } 3183*0Sstevel@tonic-gate 3184*0Sstevel@tonic-gate if (natt_loc->sin_family == AF_INET6 && 3185*0Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) { 3186*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC; 3187*0Sstevel@tonic-gate return (EINVAL); 3188*0Sstevel@tonic-gate } 3189*0Sstevel@tonic-gate } 3190*0Sstevel@tonic-gate 3191*0Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) { 3192*0Sstevel@tonic-gate if (nttext_rem == NULL) { 3193*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM; 3194*0Sstevel@tonic-gate return (EINVAL); 3195*0Sstevel@tonic-gate } 3196*0Sstevel@tonic-gate if (natt_rem->sin_family == AF_INET6 && 3197*0Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) { 3198*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM; 3199*0Sstevel@tonic-gate return (EINVAL); 3200*0Sstevel@tonic-gate } 3201*0Sstevel@tonic-gate } 3202*0Sstevel@tonic-gate 3203*0Sstevel@tonic-gate 3204*0Sstevel@tonic-gate /* Stuff I don't support, for now. XXX Diagnostic? */ 3205*0Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL || 3206*0Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) 3207*0Sstevel@tonic-gate return (EOPNOTSUPP); 3208*0Sstevel@tonic-gate 3209*0Sstevel@tonic-gate /* 3210*0Sstevel@tonic-gate * XXX Policy : I'm not checking identities or sensitivity 3211*0Sstevel@tonic-gate * labels at this time, but if I did, I'd do them here, before I sent 3212*0Sstevel@tonic-gate * the weak key check up to the algorithm. 3213*0Sstevel@tonic-gate */ 3214*0Sstevel@tonic-gate 3215*0Sstevel@tonic-gate mutex_enter(&alg_lock); 3216*0Sstevel@tonic-gate 3217*0Sstevel@tonic-gate /* 3218*0Sstevel@tonic-gate * First locate the authentication algorithm. 3219*0Sstevel@tonic-gate */ 3220*0Sstevel@tonic-gate if (akey != NULL) { 3221*0Sstevel@tonic-gate ipsec_alginfo_t *aalg; 3222*0Sstevel@tonic-gate 3223*0Sstevel@tonic-gate aalg = ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth]; 3224*0Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) { 3225*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3226*0Sstevel@tonic-gate esp1dbg(("Couldn't find auth alg #%d.\n", 3227*0Sstevel@tonic-gate assoc->sadb_sa_auth)); 3228*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 3229*0Sstevel@tonic-gate return (EINVAL); 3230*0Sstevel@tonic-gate } 3231*0Sstevel@tonic-gate ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate /* sanity check key sizes */ 3234*0Sstevel@tonic-gate if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) { 3235*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3236*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS; 3237*0Sstevel@tonic-gate return (EINVAL); 3238*0Sstevel@tonic-gate } 3239*0Sstevel@tonic-gate 3240*0Sstevel@tonic-gate /* check key and fix parity if needed */ 3241*0Sstevel@tonic-gate if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE, 3242*0Sstevel@tonic-gate diagnostic) != 0) { 3243*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3244*0Sstevel@tonic-gate return (EINVAL); 3245*0Sstevel@tonic-gate } 3246*0Sstevel@tonic-gate } 3247*0Sstevel@tonic-gate 3248*0Sstevel@tonic-gate /* EXPORT DELETE START */ 3249*0Sstevel@tonic-gate /* 3250*0Sstevel@tonic-gate * Then locate the encryption algorithm. 3251*0Sstevel@tonic-gate */ 3252*0Sstevel@tonic-gate if (ekey != NULL) { 3253*0Sstevel@tonic-gate ipsec_alginfo_t *ealg; 3254*0Sstevel@tonic-gate 3255*0Sstevel@tonic-gate ealg = ipsec_alglists[IPSEC_ALG_ENCR][assoc->sadb_sa_encrypt]; 3256*0Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) { 3257*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3258*0Sstevel@tonic-gate esp1dbg(("Couldn't find encr alg #%d.\n", 3259*0Sstevel@tonic-gate assoc->sadb_sa_encrypt)); 3260*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 3261*0Sstevel@tonic-gate return (EINVAL); 3262*0Sstevel@tonic-gate } 3263*0Sstevel@tonic-gate ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 3264*0Sstevel@tonic-gate 3265*0Sstevel@tonic-gate /* sanity check key sizes */ 3266*0Sstevel@tonic-gate if (!ipsec_valid_key_size(ekey->sadb_key_bits, ealg)) { 3267*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3268*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS; 3269*0Sstevel@tonic-gate return (EINVAL); 3270*0Sstevel@tonic-gate } 3271*0Sstevel@tonic-gate 3272*0Sstevel@tonic-gate /* check key */ 3273*0Sstevel@tonic-gate if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE, 3274*0Sstevel@tonic-gate diagnostic) != 0) { 3275*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3276*0Sstevel@tonic-gate return (EINVAL); 3277*0Sstevel@tonic-gate } 3278*0Sstevel@tonic-gate } 3279*0Sstevel@tonic-gate /* EXPORT DELETE END */ 3280*0Sstevel@tonic-gate mutex_exit(&alg_lock); 3281*0Sstevel@tonic-gate 3282*0Sstevel@tonic-gate return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi)); 3283*0Sstevel@tonic-gate } 3284*0Sstevel@tonic-gate 3285*0Sstevel@tonic-gate /* 3286*0Sstevel@tonic-gate * Update a security association. Updates come in two varieties. The first 3287*0Sstevel@tonic-gate * is an update of lifetimes on a non-larval SA. The second is an update of 3288*0Sstevel@tonic-gate * a larval SA, which ends up looking a lot more like an add. 3289*0Sstevel@tonic-gate */ 3290*0Sstevel@tonic-gate static int 3291*0Sstevel@tonic-gate esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 3292*0Sstevel@tonic-gate { 3293*0Sstevel@tonic-gate sadb_address_t *dstext = 3294*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 3295*0Sstevel@tonic-gate struct sockaddr_in *sin; 3296*0Sstevel@tonic-gate 3297*0Sstevel@tonic-gate if (dstext == NULL) { 3298*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 3299*0Sstevel@tonic-gate return (EINVAL); 3300*0Sstevel@tonic-gate } 3301*0Sstevel@tonic-gate 3302*0Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 3303*0Sstevel@tonic-gate return (sadb_update_sa(mp, ksi, 3304*0Sstevel@tonic-gate (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 : &esp_sadb.s_v4, 3305*0Sstevel@tonic-gate diagnostic, esp_pfkey_q, esp_add_sa)); 3306*0Sstevel@tonic-gate } 3307*0Sstevel@tonic-gate 3308*0Sstevel@tonic-gate /* 3309*0Sstevel@tonic-gate * Delete a security association. This is REALLY likely to be code common to 3310*0Sstevel@tonic-gate * both AH and ESP. Find the association, then unlink it. 3311*0Sstevel@tonic-gate */ 3312*0Sstevel@tonic-gate static int 3313*0Sstevel@tonic-gate esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 3314*0Sstevel@tonic-gate { 3315*0Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 3316*0Sstevel@tonic-gate sadb_address_t *dstext = 3317*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 3318*0Sstevel@tonic-gate sadb_address_t *srcext = 3319*0Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 3320*0Sstevel@tonic-gate struct sockaddr_in *sin; 3321*0Sstevel@tonic-gate 3322*0Sstevel@tonic-gate if (assoc == NULL) { 3323*0Sstevel@tonic-gate if (dstext != NULL) { 3324*0Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 3325*0Sstevel@tonic-gate } else if (srcext != NULL) { 3326*0Sstevel@tonic-gate sin = (struct sockaddr_in *)(srcext + 1); 3327*0Sstevel@tonic-gate } else { 3328*0Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 3329*0Sstevel@tonic-gate return (EINVAL); 3330*0Sstevel@tonic-gate } 3331*0Sstevel@tonic-gate return sadb_purge_sa(mp, ksi, 3332*0Sstevel@tonic-gate (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 : 3333*0Sstevel@tonic-gate &esp_sadb.s_v4, 3334*0Sstevel@tonic-gate diagnostic, esp_pfkey_q, esp_sadb.s_ip_q); 3335*0Sstevel@tonic-gate } 3336*0Sstevel@tonic-gate 3337*0Sstevel@tonic-gate return (sadb_del_sa(mp, ksi, &esp_sadb, diagnostic, esp_pfkey_q)); 3338*0Sstevel@tonic-gate } 3339*0Sstevel@tonic-gate 3340*0Sstevel@tonic-gate /* 3341*0Sstevel@tonic-gate * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP 3342*0Sstevel@tonic-gate * messages. 3343*0Sstevel@tonic-gate */ 3344*0Sstevel@tonic-gate static void 3345*0Sstevel@tonic-gate esp_dump(mblk_t *mp, keysock_in_t *ksi) 3346*0Sstevel@tonic-gate { 3347*0Sstevel@tonic-gate int error; 3348*0Sstevel@tonic-gate sadb_msg_t *samsg; 3349*0Sstevel@tonic-gate 3350*0Sstevel@tonic-gate /* 3351*0Sstevel@tonic-gate * Dump each fanout, bailing if error is non-zero. 3352*0Sstevel@tonic-gate */ 3353*0Sstevel@tonic-gate 3354*0Sstevel@tonic-gate error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v4); 3355*0Sstevel@tonic-gate if (error != 0) 3356*0Sstevel@tonic-gate goto bail; 3357*0Sstevel@tonic-gate 3358*0Sstevel@tonic-gate error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v6); 3359*0Sstevel@tonic-gate bail: 3360*0Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 3361*0Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 3362*0Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 3363*0Sstevel@tonic-gate sadb_pfkey_echo(esp_pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi, 3364*0Sstevel@tonic-gate NULL); 3365*0Sstevel@tonic-gate } 3366*0Sstevel@tonic-gate 3367*0Sstevel@tonic-gate /* 3368*0Sstevel@tonic-gate * ESP parsing of PF_KEY messages. Keysock did most of the really silly 3369*0Sstevel@tonic-gate * error cases. What I receive is a fully-formed, syntactically legal 3370*0Sstevel@tonic-gate * PF_KEY message. I then need to check semantics... 3371*0Sstevel@tonic-gate * 3372*0Sstevel@tonic-gate * This code may become common to AH and ESP. Stay tuned. 3373*0Sstevel@tonic-gate * 3374*0Sstevel@tonic-gate * I also make the assumption that db_ref's are cool. If this assumption 3375*0Sstevel@tonic-gate * is wrong, this means that someone other than keysock or me has been 3376*0Sstevel@tonic-gate * mucking with PF_KEY messages. 3377*0Sstevel@tonic-gate */ 3378*0Sstevel@tonic-gate static void 3379*0Sstevel@tonic-gate esp_parse_pfkey(mblk_t *mp) 3380*0Sstevel@tonic-gate { 3381*0Sstevel@tonic-gate mblk_t *msg = mp->b_cont; 3382*0Sstevel@tonic-gate sadb_msg_t *samsg; 3383*0Sstevel@tonic-gate keysock_in_t *ksi; 3384*0Sstevel@tonic-gate int error; 3385*0Sstevel@tonic-gate int diagnostic = SADB_X_DIAGNOSTIC_NONE; 3386*0Sstevel@tonic-gate 3387*0Sstevel@tonic-gate ASSERT(msg != NULL); 3388*0Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr; 3389*0Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 3390*0Sstevel@tonic-gate 3391*0Sstevel@tonic-gate /* 3392*0Sstevel@tonic-gate * If applicable, convert unspecified AF_INET6 to unspecified 3393*0Sstevel@tonic-gate * AF_INET. 3394*0Sstevel@tonic-gate */ 3395*0Sstevel@tonic-gate sadb_srcaddrfix(ksi); 3396*0Sstevel@tonic-gate 3397*0Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 3398*0Sstevel@tonic-gate case SADB_ADD: 3399*0Sstevel@tonic-gate error = esp_add_sa(mp, ksi, &diagnostic); 3400*0Sstevel@tonic-gate if (error != 0) { 3401*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 3402*0Sstevel@tonic-gate ksi->ks_in_serial); 3403*0Sstevel@tonic-gate } 3404*0Sstevel@tonic-gate /* else esp_add_sa() took care of things. */ 3405*0Sstevel@tonic-gate break; 3406*0Sstevel@tonic-gate case SADB_DELETE: 3407*0Sstevel@tonic-gate error = esp_del_sa(mp, ksi, &diagnostic); 3408*0Sstevel@tonic-gate if (error != 0) { 3409*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 3410*0Sstevel@tonic-gate ksi->ks_in_serial); 3411*0Sstevel@tonic-gate } 3412*0Sstevel@tonic-gate /* Else esp_del_sa() took care of things. */ 3413*0Sstevel@tonic-gate break; 3414*0Sstevel@tonic-gate case SADB_GET: 3415*0Sstevel@tonic-gate error = sadb_get_sa(mp, ksi, &esp_sadb, &diagnostic, 3416*0Sstevel@tonic-gate esp_pfkey_q); 3417*0Sstevel@tonic-gate if (error != 0) { 3418*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 3419*0Sstevel@tonic-gate ksi->ks_in_serial); 3420*0Sstevel@tonic-gate } 3421*0Sstevel@tonic-gate /* Else sadb_get_sa() took care of things. */ 3422*0Sstevel@tonic-gate break; 3423*0Sstevel@tonic-gate case SADB_FLUSH: 3424*0Sstevel@tonic-gate sadbp_flush(&esp_sadb); 3425*0Sstevel@tonic-gate sadb_pfkey_echo(esp_pfkey_q, mp, samsg, ksi, NULL); 3426*0Sstevel@tonic-gate break; 3427*0Sstevel@tonic-gate case SADB_REGISTER: 3428*0Sstevel@tonic-gate /* 3429*0Sstevel@tonic-gate * Hmmm, let's do it! Check for extensions (there should 3430*0Sstevel@tonic-gate * be none), extract the fields, call esp_register_out(), 3431*0Sstevel@tonic-gate * then either free or report an error. 3432*0Sstevel@tonic-gate * 3433*0Sstevel@tonic-gate * Keysock takes care of the PF_KEY bookkeeping for this. 3434*0Sstevel@tonic-gate */ 3435*0Sstevel@tonic-gate if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid, 3436*0Sstevel@tonic-gate ksi->ks_in_serial)) { 3437*0Sstevel@tonic-gate freemsg(mp); 3438*0Sstevel@tonic-gate } else { 3439*0Sstevel@tonic-gate /* 3440*0Sstevel@tonic-gate * Only way this path hits is if there is a memory 3441*0Sstevel@tonic-gate * failure. It will not return B_FALSE because of 3442*0Sstevel@tonic-gate * lack of esp_pfkey_q if I am in wput(). 3443*0Sstevel@tonic-gate */ 3444*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic, 3445*0Sstevel@tonic-gate ksi->ks_in_serial); 3446*0Sstevel@tonic-gate } 3447*0Sstevel@tonic-gate break; 3448*0Sstevel@tonic-gate case SADB_UPDATE: 3449*0Sstevel@tonic-gate /* 3450*0Sstevel@tonic-gate * Find a larval, if not there, find a full one and get 3451*0Sstevel@tonic-gate * strict. 3452*0Sstevel@tonic-gate */ 3453*0Sstevel@tonic-gate error = esp_update_sa(mp, ksi, &diagnostic); 3454*0Sstevel@tonic-gate if (error != 0) { 3455*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 3456*0Sstevel@tonic-gate ksi->ks_in_serial); 3457*0Sstevel@tonic-gate } 3458*0Sstevel@tonic-gate /* else esp_update_sa() took care of things. */ 3459*0Sstevel@tonic-gate break; 3460*0Sstevel@tonic-gate case SADB_GETSPI: 3461*0Sstevel@tonic-gate /* 3462*0Sstevel@tonic-gate * Reserve a new larval entry. 3463*0Sstevel@tonic-gate */ 3464*0Sstevel@tonic-gate esp_getspi(mp, ksi); 3465*0Sstevel@tonic-gate break; 3466*0Sstevel@tonic-gate case SADB_ACQUIRE: 3467*0Sstevel@tonic-gate /* 3468*0Sstevel@tonic-gate * Find larval and/or ACQUIRE record and kill it (them), I'm 3469*0Sstevel@tonic-gate * most likely an error. Inbound ACQUIRE messages should only 3470*0Sstevel@tonic-gate * have the base header. 3471*0Sstevel@tonic-gate */ 3472*0Sstevel@tonic-gate sadb_in_acquire(samsg, &esp_sadb, esp_pfkey_q); 3473*0Sstevel@tonic-gate freemsg(mp); 3474*0Sstevel@tonic-gate break; 3475*0Sstevel@tonic-gate case SADB_DUMP: 3476*0Sstevel@tonic-gate /* 3477*0Sstevel@tonic-gate * Dump all entries. 3478*0Sstevel@tonic-gate */ 3479*0Sstevel@tonic-gate esp_dump(mp, ksi); 3480*0Sstevel@tonic-gate /* esp_dump will take care of the return message, etc. */ 3481*0Sstevel@tonic-gate break; 3482*0Sstevel@tonic-gate case SADB_EXPIRE: 3483*0Sstevel@tonic-gate /* Should never reach me. */ 3484*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EOPNOTSUPP, diagnostic, 3485*0Sstevel@tonic-gate ksi->ks_in_serial); 3486*0Sstevel@tonic-gate break; 3487*0Sstevel@tonic-gate default: 3488*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, 3489*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial); 3490*0Sstevel@tonic-gate break; 3491*0Sstevel@tonic-gate } 3492*0Sstevel@tonic-gate } 3493*0Sstevel@tonic-gate 3494*0Sstevel@tonic-gate /* 3495*0Sstevel@tonic-gate * Handle case where PF_KEY says it can't find a keysock for one of my 3496*0Sstevel@tonic-gate * ACQUIRE messages. 3497*0Sstevel@tonic-gate */ 3498*0Sstevel@tonic-gate static void 3499*0Sstevel@tonic-gate esp_keysock_no_socket(mblk_t *mp) 3500*0Sstevel@tonic-gate { 3501*0Sstevel@tonic-gate sadb_msg_t *samsg; 3502*0Sstevel@tonic-gate keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr; 3503*0Sstevel@tonic-gate 3504*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 3505*0Sstevel@tonic-gate freemsg(mp); 3506*0Sstevel@tonic-gate return; 3507*0Sstevel@tonic-gate } 3508*0Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 3509*0Sstevel@tonic-gate 3510*0Sstevel@tonic-gate /* 3511*0Sstevel@tonic-gate * If keysock can't find any registered, delete the acquire record 3512*0Sstevel@tonic-gate * immediately, and handle errors. 3513*0Sstevel@tonic-gate */ 3514*0Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_ACQUIRE) { 3515*0Sstevel@tonic-gate samsg->sadb_msg_errno = kse->ks_err_errno; 3516*0Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); 3517*0Sstevel@tonic-gate /* 3518*0Sstevel@tonic-gate * Use the write-side of the esp_pfkey_q, in case there is 3519*0Sstevel@tonic-gate * no esp_sadb.s_ip_q. 3520*0Sstevel@tonic-gate */ 3521*0Sstevel@tonic-gate sadb_in_acquire(samsg, &esp_sadb, WR(esp_pfkey_q)); 3522*0Sstevel@tonic-gate } 3523*0Sstevel@tonic-gate 3524*0Sstevel@tonic-gate freemsg(mp); 3525*0Sstevel@tonic-gate } 3526*0Sstevel@tonic-gate 3527*0Sstevel@tonic-gate /* 3528*0Sstevel@tonic-gate * First-cut reality check for an inbound PF_KEY message. 3529*0Sstevel@tonic-gate */ 3530*0Sstevel@tonic-gate static boolean_t 3531*0Sstevel@tonic-gate esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi) 3532*0Sstevel@tonic-gate { 3533*0Sstevel@tonic-gate int diagnostic; 3534*0Sstevel@tonic-gate 3535*0Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) { 3536*0Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT; 3537*0Sstevel@tonic-gate goto badmsg; 3538*0Sstevel@tonic-gate } 3539*0Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL || 3540*0Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) { 3541*0Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT; 3542*0Sstevel@tonic-gate goto badmsg; 3543*0Sstevel@tonic-gate } 3544*0Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_MBCAST) { 3545*0Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC; 3546*0Sstevel@tonic-gate goto badmsg; 3547*0Sstevel@tonic-gate } 3548*0Sstevel@tonic-gate if (ksi->ks_in_dsttype == KS_IN_ADDR_UNSPEC) { 3549*0Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 3550*0Sstevel@tonic-gate goto badmsg; 3551*0Sstevel@tonic-gate } 3552*0Sstevel@tonic-gate 3553*0Sstevel@tonic-gate return (B_FALSE); /* False ==> no failures */ 3554*0Sstevel@tonic-gate 3555*0Sstevel@tonic-gate badmsg: 3556*0Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic, 3557*0Sstevel@tonic-gate ksi->ks_in_serial); 3558*0Sstevel@tonic-gate return (B_TRUE); /* True ==> failures */ 3559*0Sstevel@tonic-gate } 3560*0Sstevel@tonic-gate 3561*0Sstevel@tonic-gate /* 3562*0Sstevel@tonic-gate * ESP module write put routine. 3563*0Sstevel@tonic-gate */ 3564*0Sstevel@tonic-gate static void 3565*0Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp) 3566*0Sstevel@tonic-gate { 3567*0Sstevel@tonic-gate ipsec_info_t *ii; 3568*0Sstevel@tonic-gate keysock_in_t *ksi; 3569*0Sstevel@tonic-gate int rc; 3570*0Sstevel@tonic-gate struct iocblk *iocp; 3571*0Sstevel@tonic-gate 3572*0Sstevel@tonic-gate esp3dbg(("In esp_wput().\n")); 3573*0Sstevel@tonic-gate 3574*0Sstevel@tonic-gate /* NOTE: Each case must take care of freeing or passing mp. */ 3575*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3576*0Sstevel@tonic-gate case M_CTL: 3577*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) { 3578*0Sstevel@tonic-gate /* Not big enough message. */ 3579*0Sstevel@tonic-gate freemsg(mp); 3580*0Sstevel@tonic-gate break; 3581*0Sstevel@tonic-gate } 3582*0Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 3583*0Sstevel@tonic-gate 3584*0Sstevel@tonic-gate switch (ii->ipsec_info_type) { 3585*0Sstevel@tonic-gate case KEYSOCK_OUT_ERR: 3586*0Sstevel@tonic-gate esp1dbg(("Got KEYSOCK_OUT_ERR message.\n")); 3587*0Sstevel@tonic-gate esp_keysock_no_socket(mp); 3588*0Sstevel@tonic-gate break; 3589*0Sstevel@tonic-gate case KEYSOCK_IN: 3590*0Sstevel@tonic-gate ESP_BUMP_STAT(keysock_in); 3591*0Sstevel@tonic-gate esp3dbg(("Got KEYSOCK_IN message.\n")); 3592*0Sstevel@tonic-gate ksi = (keysock_in_t *)ii; 3593*0Sstevel@tonic-gate /* 3594*0Sstevel@tonic-gate * Some common reality checks. 3595*0Sstevel@tonic-gate */ 3596*0Sstevel@tonic-gate 3597*0Sstevel@tonic-gate if (esp_pfkey_reality_failures(mp, ksi)) 3598*0Sstevel@tonic-gate return; 3599*0Sstevel@tonic-gate 3600*0Sstevel@tonic-gate /* 3601*0Sstevel@tonic-gate * Use 'q' instead of esp_sadb.s_ip_q, since 3602*0Sstevel@tonic-gate * it's the write side already, and it'll go 3603*0Sstevel@tonic-gate * down to IP. Use esp_pfkey_q because we 3604*0Sstevel@tonic-gate * wouldn't get here if that weren't set, and 3605*0Sstevel@tonic-gate * the RD(q) has been done already. 3606*0Sstevel@tonic-gate */ 3607*0Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) { 3608*0Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 3609*0Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC], 3610*0Sstevel@tonic-gate ksi->ks_in_serial); 3611*0Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 3612*0Sstevel@tonic-gate return; 3613*0Sstevel@tonic-gate else 3614*0Sstevel@tonic-gate ksi->ks_in_srctype = rc; 3615*0Sstevel@tonic-gate } 3616*0Sstevel@tonic-gate if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) { 3617*0Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 3618*0Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_DST], 3619*0Sstevel@tonic-gate ksi->ks_in_serial); 3620*0Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 3621*0Sstevel@tonic-gate return; 3622*0Sstevel@tonic-gate else 3623*0Sstevel@tonic-gate ksi->ks_in_dsttype = rc; 3624*0Sstevel@tonic-gate } 3625*0Sstevel@tonic-gate /* 3626*0Sstevel@tonic-gate * XXX Proxy may be a different address family. 3627*0Sstevel@tonic-gate */ 3628*0Sstevel@tonic-gate if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) { 3629*0Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 3630*0Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_PROXY], 3631*0Sstevel@tonic-gate ksi->ks_in_serial); 3632*0Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 3633*0Sstevel@tonic-gate return; 3634*0Sstevel@tonic-gate else 3635*0Sstevel@tonic-gate ksi->ks_in_proxytype = rc; 3636*0Sstevel@tonic-gate } 3637*0Sstevel@tonic-gate esp_parse_pfkey(mp); 3638*0Sstevel@tonic-gate break; 3639*0Sstevel@tonic-gate case KEYSOCK_HELLO: 3640*0Sstevel@tonic-gate sadb_keysock_hello(&esp_pfkey_q, q, mp, 3641*0Sstevel@tonic-gate esp_ager, &esp_event, SADB_SATYPE_ESP); 3642*0Sstevel@tonic-gate break; 3643*0Sstevel@tonic-gate default: 3644*0Sstevel@tonic-gate esp2dbg(("Got M_CTL from above of 0x%x.\n", 3645*0Sstevel@tonic-gate ii->ipsec_info_type)); 3646*0Sstevel@tonic-gate freemsg(mp); 3647*0Sstevel@tonic-gate break; 3648*0Sstevel@tonic-gate } 3649*0Sstevel@tonic-gate break; 3650*0Sstevel@tonic-gate case M_IOCTL: 3651*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3652*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 3653*0Sstevel@tonic-gate case ND_SET: 3654*0Sstevel@tonic-gate case ND_GET: 3655*0Sstevel@tonic-gate if (nd_getset(q, ipsecesp_g_nd, mp)) { 3656*0Sstevel@tonic-gate qreply(q, mp); 3657*0Sstevel@tonic-gate return; 3658*0Sstevel@tonic-gate } else { 3659*0Sstevel@tonic-gate iocp->ioc_error = ENOENT; 3660*0Sstevel@tonic-gate } 3661*0Sstevel@tonic-gate /* FALLTHRU */ 3662*0Sstevel@tonic-gate default: 3663*0Sstevel@tonic-gate /* We really don't support any other ioctls, do we? */ 3664*0Sstevel@tonic-gate 3665*0Sstevel@tonic-gate /* Return EINVAL */ 3666*0Sstevel@tonic-gate if (iocp->ioc_error != ENOENT) 3667*0Sstevel@tonic-gate iocp->ioc_error = EINVAL; 3668*0Sstevel@tonic-gate iocp->ioc_count = 0; 3669*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3670*0Sstevel@tonic-gate qreply(q, mp); 3671*0Sstevel@tonic-gate return; 3672*0Sstevel@tonic-gate } 3673*0Sstevel@tonic-gate default: 3674*0Sstevel@tonic-gate esp3dbg(("Got default message, type %d, passing to IP.\n", 3675*0Sstevel@tonic-gate mp->b_datap->db_type)); 3676*0Sstevel@tonic-gate putnext(q, mp); 3677*0Sstevel@tonic-gate } 3678*0Sstevel@tonic-gate } 3679*0Sstevel@tonic-gate 3680*0Sstevel@tonic-gate /* EXPORT DELETE START */ 3681*0Sstevel@tonic-gate /* 3682*0Sstevel@tonic-gate * Process an outbound ESP packet that can be accelerated by a IPsec 3683*0Sstevel@tonic-gate * hardware acceleration capable Provider. 3684*0Sstevel@tonic-gate * The caller already inserted and initialized the ESP header. 3685*0Sstevel@tonic-gate * This function allocates a tagging M_CTL, and adds room at the end 3686*0Sstevel@tonic-gate * of the packet to hold the ICV if authentication is needed. 3687*0Sstevel@tonic-gate * 3688*0Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 3689*0Sstevel@tonic-gate * mblk chain ipsec_out. 3690*0Sstevel@tonic-gate */ 3691*0Sstevel@tonic-gate static ipsec_status_t 3692*0Sstevel@tonic-gate esp_outbound_accelerated(mblk_t *ipsec_out, uint_t icv_len) 3693*0Sstevel@tonic-gate { 3694*0Sstevel@tonic-gate ipsec_out_t *io; 3695*0Sstevel@tonic-gate mblk_t *lastmp; 3696*0Sstevel@tonic-gate 3697*0Sstevel@tonic-gate ESP_BUMP_STAT(out_accelerated); 3698*0Sstevel@tonic-gate 3699*0Sstevel@tonic-gate io = (ipsec_out_t *)ipsec_out->b_rptr; 3700*0Sstevel@tonic-gate 3701*0Sstevel@tonic-gate /* mark packet as being accelerated in IPSEC_OUT */ 3702*0Sstevel@tonic-gate ASSERT(io->ipsec_out_accelerated == B_FALSE); 3703*0Sstevel@tonic-gate io->ipsec_out_accelerated = B_TRUE; 3704*0Sstevel@tonic-gate 3705*0Sstevel@tonic-gate /* 3706*0Sstevel@tonic-gate * add room at the end of the packet for the ICV if needed 3707*0Sstevel@tonic-gate */ 3708*0Sstevel@tonic-gate if (icv_len > 0) { 3709*0Sstevel@tonic-gate /* go to last mblk */ 3710*0Sstevel@tonic-gate lastmp = ipsec_out; /* For following while loop. */ 3711*0Sstevel@tonic-gate do { 3712*0Sstevel@tonic-gate lastmp = lastmp->b_cont; 3713*0Sstevel@tonic-gate } while (lastmp->b_cont != NULL); 3714*0Sstevel@tonic-gate 3715*0Sstevel@tonic-gate /* if not enough available room, allocate new mblk */ 3716*0Sstevel@tonic-gate if ((lastmp->b_wptr + icv_len) > lastmp->b_datap->db_lim) { 3717*0Sstevel@tonic-gate lastmp->b_cont = allocb(icv_len, BPRI_HI); 3718*0Sstevel@tonic-gate if (lastmp->b_cont == NULL) { 3719*0Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 3720*0Sstevel@tonic-gate ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 3721*0Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 3722*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 3723*0Sstevel@tonic-gate } 3724*0Sstevel@tonic-gate lastmp = lastmp->b_cont; 3725*0Sstevel@tonic-gate } 3726*0Sstevel@tonic-gate lastmp->b_wptr += icv_len; 3727*0Sstevel@tonic-gate } 3728*0Sstevel@tonic-gate 3729*0Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 3730*0Sstevel@tonic-gate } 3731*0Sstevel@tonic-gate 3732*0Sstevel@tonic-gate /* 3733*0Sstevel@tonic-gate * Process an inbound accelerated ESP packet. 3734*0Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 3735*0Sstevel@tonic-gate * mblk chain ipsec_in. 3736*0Sstevel@tonic-gate */ 3737*0Sstevel@tonic-gate static ipsec_status_t 3738*0Sstevel@tonic-gate esp_inbound_accelerated(mblk_t *ipsec_in, mblk_t *data_mp, boolean_t isv4, 3739*0Sstevel@tonic-gate ipsa_t *assoc) 3740*0Sstevel@tonic-gate { 3741*0Sstevel@tonic-gate ipsec_in_t *ii; 3742*0Sstevel@tonic-gate mblk_t *hada_mp; 3743*0Sstevel@tonic-gate uint32_t icv_len = 0; 3744*0Sstevel@tonic-gate da_ipsec_t *hada; 3745*0Sstevel@tonic-gate ipha_t *ipha; 3746*0Sstevel@tonic-gate ip6_t *ip6h; 3747*0Sstevel@tonic-gate kstat_named_t *counter; 3748*0Sstevel@tonic-gate 3749*0Sstevel@tonic-gate ESP_BUMP_STAT(in_accelerated); 3750*0Sstevel@tonic-gate 3751*0Sstevel@tonic-gate ii = (ipsec_in_t *)ipsec_in->b_rptr; 3752*0Sstevel@tonic-gate hada_mp = ii->ipsec_in_da; 3753*0Sstevel@tonic-gate ASSERT(hada_mp != NULL); 3754*0Sstevel@tonic-gate hada = (da_ipsec_t *)hada_mp->b_rptr; 3755*0Sstevel@tonic-gate 3756*0Sstevel@tonic-gate /* 3757*0Sstevel@tonic-gate * We only support one level of decapsulation in hardware, so 3758*0Sstevel@tonic-gate * nuke the pointer. 3759*0Sstevel@tonic-gate */ 3760*0Sstevel@tonic-gate ii->ipsec_in_da = NULL; 3761*0Sstevel@tonic-gate ii->ipsec_in_accelerated = B_FALSE; 3762*0Sstevel@tonic-gate 3763*0Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 3764*0Sstevel@tonic-gate /* 3765*0Sstevel@tonic-gate * ESP with authentication. We expect the Provider to have 3766*0Sstevel@tonic-gate * computed the ICV and placed it in the hardware acceleration 3767*0Sstevel@tonic-gate * data attributes. 3768*0Sstevel@tonic-gate * 3769*0Sstevel@tonic-gate * Extract ICV length from attributes M_CTL and sanity check 3770*0Sstevel@tonic-gate * its value. We allow the mblk to be smaller than da_ipsec_t 3771*0Sstevel@tonic-gate * for a small ICV, as long as the entire ICV fits within the 3772*0Sstevel@tonic-gate * mblk. 3773*0Sstevel@tonic-gate * 3774*0Sstevel@tonic-gate * Also ensures that the ICV length computed by Provider 3775*0Sstevel@tonic-gate * corresponds to the ICV length of the agorithm specified by 3776*0Sstevel@tonic-gate * the SA. 3777*0Sstevel@tonic-gate */ 3778*0Sstevel@tonic-gate icv_len = hada->da_icv_len; 3779*0Sstevel@tonic-gate if ((icv_len != assoc->ipsa_mac_len) || 3780*0Sstevel@tonic-gate (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) < 3781*0Sstevel@tonic-gate (sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) { 3782*0Sstevel@tonic-gate esp0dbg(("esp_inbound_accelerated: " 3783*0Sstevel@tonic-gate "ICV len (%u) incorrect or mblk too small (%u)\n", 3784*0Sstevel@tonic-gate icv_len, (uint32_t)(MBLKL(hada_mp)))); 3785*0Sstevel@tonic-gate counter = &ipdrops_esp_bad_auth; 3786*0Sstevel@tonic-gate goto esp_in_discard; 3787*0Sstevel@tonic-gate } 3788*0Sstevel@tonic-gate } 3789*0Sstevel@tonic-gate 3790*0Sstevel@tonic-gate /* get pointers to IP header */ 3791*0Sstevel@tonic-gate if (isv4) { 3792*0Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 3793*0Sstevel@tonic-gate } else { 3794*0Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 3795*0Sstevel@tonic-gate } 3796*0Sstevel@tonic-gate 3797*0Sstevel@tonic-gate /* 3798*0Sstevel@tonic-gate * Compare ICV in ESP packet vs ICV computed by adapter. 3799*0Sstevel@tonic-gate * We also remove the ICV from the end of the packet since 3800*0Sstevel@tonic-gate * it will no longer be needed. 3801*0Sstevel@tonic-gate * 3802*0Sstevel@tonic-gate * Assume that esp_inbound() already ensured that the pkt 3803*0Sstevel@tonic-gate * was in one mblk. 3804*0Sstevel@tonic-gate */ 3805*0Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 3806*0Sstevel@tonic-gate data_mp->b_wptr -= icv_len; 3807*0Sstevel@tonic-gate /* adjust IP header */ 3808*0Sstevel@tonic-gate if (isv4) 3809*0Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - icv_len); 3810*0Sstevel@tonic-gate else 3811*0Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - icv_len); 3812*0Sstevel@tonic-gate if (icv_len && bcmp(hada->da_icv, data_mp->b_wptr, icv_len)) { 3813*0Sstevel@tonic-gate int af; 3814*0Sstevel@tonic-gate void *addr; 3815*0Sstevel@tonic-gate 3816*0Sstevel@tonic-gate if (isv4) { 3817*0Sstevel@tonic-gate addr = &ipha->ipha_dst; 3818*0Sstevel@tonic-gate af = AF_INET; 3819*0Sstevel@tonic-gate } else { 3820*0Sstevel@tonic-gate addr = &ip6h->ip6_dst; 3821*0Sstevel@tonic-gate af = AF_INET6; 3822*0Sstevel@tonic-gate } 3823*0Sstevel@tonic-gate 3824*0Sstevel@tonic-gate /* 3825*0Sstevel@tonic-gate * Log the event. Don't print to the console, block 3826*0Sstevel@tonic-gate * potential denial-of-service attack. 3827*0Sstevel@tonic-gate */ 3828*0Sstevel@tonic-gate ESP_BUMP_STAT(bad_auth); 3829*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 3830*0Sstevel@tonic-gate "ESP Authentication failed spi %x, dst_addr %s", 3831*0Sstevel@tonic-gate assoc->ipsa_spi, addr, af); 3832*0Sstevel@tonic-gate counter = &ipdrops_esp_bad_auth; 3833*0Sstevel@tonic-gate goto esp_in_discard; 3834*0Sstevel@tonic-gate } 3835*0Sstevel@tonic-gate 3836*0Sstevel@tonic-gate esp3dbg(("esp_inbound_accelerated: ESP authentication succeeded, " 3837*0Sstevel@tonic-gate "checking replay\n")); 3838*0Sstevel@tonic-gate 3839*0Sstevel@tonic-gate ipsec_in->b_cont = data_mp; 3840*0Sstevel@tonic-gate 3841*0Sstevel@tonic-gate /* 3842*0Sstevel@tonic-gate * Remove ESP header and padding from packet. 3843*0Sstevel@tonic-gate */ 3844*0Sstevel@tonic-gate if (!esp_strip_header(data_mp, ii->ipsec_in_v4, assoc->ipsa_iv_len, 3845*0Sstevel@tonic-gate &counter)) { 3846*0Sstevel@tonic-gate esp1dbg(("esp_inbound_accelerated: " 3847*0Sstevel@tonic-gate "esp_strip_header() failed\n")); 3848*0Sstevel@tonic-gate goto esp_in_discard; 3849*0Sstevel@tonic-gate } 3850*0Sstevel@tonic-gate 3851*0Sstevel@tonic-gate freeb(hada_mp); 3852*0Sstevel@tonic-gate 3853*0Sstevel@tonic-gate /* 3854*0Sstevel@tonic-gate * Account for usage.. 3855*0Sstevel@tonic-gate */ 3856*0Sstevel@tonic-gate if (!esp_age_bytes(assoc, msgdsize(data_mp), B_TRUE)) { 3857*0Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 3858*0Sstevel@tonic-gate ESP_BUMP_STAT(bytes_expired); 3859*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 3860*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 3861*0Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 3862*0Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 3863*0Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 3864*0Sstevel@tonic-gate &ipdrops_esp_bytes_expire, &esp_dropper); 3865*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 3866*0Sstevel@tonic-gate } 3867*0Sstevel@tonic-gate 3868*0Sstevel@tonic-gate /* done processing the packet */ 3869*0Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 3870*0Sstevel@tonic-gate 3871*0Sstevel@tonic-gate esp_in_discard: 3872*0Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 3873*0Sstevel@tonic-gate freeb(hada_mp); 3874*0Sstevel@tonic-gate 3875*0Sstevel@tonic-gate ipsec_in->b_cont = data_mp; /* For ip_drop_packet()'s sake... */ 3876*0Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, &esp_dropper); 3877*0Sstevel@tonic-gate 3878*0Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 3879*0Sstevel@tonic-gate } 3880*0Sstevel@tonic-gate /* EXPORT DELETE END */ 3881*0Sstevel@tonic-gate 3882*0Sstevel@tonic-gate /* 3883*0Sstevel@tonic-gate * Wrapper to allow IP to trigger an ESP association failure message 3884*0Sstevel@tonic-gate * during inbound SA selection. 3885*0Sstevel@tonic-gate */ 3886*0Sstevel@tonic-gate void 3887*0Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt, 3888*0Sstevel@tonic-gate uint32_t spi, void *addr, int af) 3889*0Sstevel@tonic-gate { 3890*0Sstevel@tonic-gate if (ipsecesp_log_unknown_spi) { 3891*0Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi, 3892*0Sstevel@tonic-gate addr, af); 3893*0Sstevel@tonic-gate } 3894*0Sstevel@tonic-gate 3895*0Sstevel@tonic-gate ip_drop_packet(mp, B_TRUE, NULL, NULL, &ipdrops_esp_no_sa, 3896*0Sstevel@tonic-gate &esp_dropper); 3897*0Sstevel@tonic-gate } 3898*0Sstevel@tonic-gate 3899*0Sstevel@tonic-gate /* 3900*0Sstevel@tonic-gate * Initialize the ESP input and output processing functions. 3901*0Sstevel@tonic-gate */ 3902*0Sstevel@tonic-gate void 3903*0Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa) 3904*0Sstevel@tonic-gate { 3905*0Sstevel@tonic-gate if (sa->ipsa_output_func == NULL) 3906*0Sstevel@tonic-gate sa->ipsa_output_func = esp_outbound; 3907*0Sstevel@tonic-gate if (sa->ipsa_input_func == NULL) 3908*0Sstevel@tonic-gate sa->ipsa_input_func = esp_inbound; 3909*0Sstevel@tonic-gate } 3910