10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52751Sdanmcd * Common Development and Distribution License (the "License"). 62751Sdanmcd * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 222751Sdanmcd * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/stream.h> 300Sstevel@tonic-gate #include <sys/stropts.h> 310Sstevel@tonic-gate #include <sys/errno.h> 320Sstevel@tonic-gate #include <sys/strlog.h> 330Sstevel@tonic-gate #include <sys/tihdr.h> 340Sstevel@tonic-gate #include <sys/socket.h> 350Sstevel@tonic-gate #include <sys/ddi.h> 360Sstevel@tonic-gate #include <sys/sunddi.h> 370Sstevel@tonic-gate #include <sys/kmem.h> 380Sstevel@tonic-gate #include <sys/sysmacros.h> 390Sstevel@tonic-gate #include <sys/cmn_err.h> 400Sstevel@tonic-gate #include <sys/vtrace.h> 410Sstevel@tonic-gate #include <sys/debug.h> 420Sstevel@tonic-gate #include <sys/atomic.h> 430Sstevel@tonic-gate #include <sys/strsun.h> 440Sstevel@tonic-gate #include <sys/random.h> 450Sstevel@tonic-gate #include <netinet/in.h> 460Sstevel@tonic-gate #include <net/if.h> 470Sstevel@tonic-gate #include <netinet/ip6.h> 480Sstevel@tonic-gate #include <net/pfkeyv2.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate #include <inet/common.h> 510Sstevel@tonic-gate #include <inet/mi.h> 520Sstevel@tonic-gate #include <inet/nd.h> 530Sstevel@tonic-gate #include <inet/ip.h> 540Sstevel@tonic-gate #include <inet/ip6.h> 550Sstevel@tonic-gate #include <inet/sadb.h> 560Sstevel@tonic-gate #include <inet/ipsec_info.h> 570Sstevel@tonic-gate #include <inet/ipsec_impl.h> 580Sstevel@tonic-gate #include <inet/ipsecesp.h> 590Sstevel@tonic-gate #include <inet/ipdrop.h> 600Sstevel@tonic-gate #include <inet/tcp.h> 610Sstevel@tonic-gate #include <sys/kstat.h> 620Sstevel@tonic-gate #include <sys/policy.h> 630Sstevel@tonic-gate #include <sys/strsun.h> 640Sstevel@tonic-gate #include <inet/udp_impl.h> 650Sstevel@tonic-gate #include <sys/taskq.h> 660Sstevel@tonic-gate 670Sstevel@tonic-gate #include <sys/iphada.h> 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* Packet dropper for ESP drops. */ 700Sstevel@tonic-gate static ipdropper_t esp_dropper; 710Sstevel@tonic-gate 720Sstevel@tonic-gate static kmutex_t ipsecesp_param_lock; /* Protects ipsecesp_param_arr[] below. */ 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Table of ND variables supported by ipsecesp. These are loaded into 750Sstevel@tonic-gate * ipsecesp_g_nd in ipsecesp_init_nd. 760Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate static ipsecespparam_t ipsecesp_param_arr[] = { 790Sstevel@tonic-gate /* min max value name */ 800Sstevel@tonic-gate { 0, 3, 0, "ipsecesp_debug"}, 810Sstevel@tonic-gate { 125, 32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"}, 820Sstevel@tonic-gate { 1, 10, 1, "ipsecesp_reap_delay"}, 830Sstevel@tonic-gate { 1, SADB_MAX_REPLAY, 64, "ipsecesp_replay_size"}, 840Sstevel@tonic-gate { 1, 300, 15, "ipsecesp_acquire_timeout"}, 850Sstevel@tonic-gate { 1, 1800, 90, "ipsecesp_larval_timeout"}, 860Sstevel@tonic-gate /* Default lifetime values for ACQUIRE messages. */ 870Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_bytes"}, 880Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_bytes"}, 890Sstevel@tonic-gate { 0, 0xffffffffU, 24000, "ipsecesp_default_soft_addtime"}, 900Sstevel@tonic-gate { 0, 0xffffffffU, 28800, "ipsecesp_default_hard_addtime"}, 910Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_usetime"}, 920Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_usetime"}, 930Sstevel@tonic-gate { 0, 1, 0, "ipsecesp_log_unknown_spi"}, 940Sstevel@tonic-gate { 0, 2, 1, "ipsecesp_padding_check"}, 950Sstevel@tonic-gate }; 960Sstevel@tonic-gate #define ipsecesp_debug ipsecesp_param_arr[0].ipsecesp_param_value 970Sstevel@tonic-gate #define ipsecesp_age_interval ipsecesp_param_arr[1].ipsecesp_param_value 980Sstevel@tonic-gate #define ipsecesp_age_int_max ipsecesp_param_arr[1].ipsecesp_param_max 990Sstevel@tonic-gate #define ipsecesp_reap_delay ipsecesp_param_arr[2].ipsecesp_param_value 1000Sstevel@tonic-gate #define ipsecesp_replay_size ipsecesp_param_arr[3].ipsecesp_param_value 1010Sstevel@tonic-gate #define ipsecesp_acquire_timeout ipsecesp_param_arr[4].ipsecesp_param_value 1020Sstevel@tonic-gate #define ipsecesp_larval_timeout ipsecesp_param_arr[5].ipsecesp_param_value 1030Sstevel@tonic-gate #define ipsecesp_default_soft_bytes \ 1040Sstevel@tonic-gate ipsecesp_param_arr[6].ipsecesp_param_value 1050Sstevel@tonic-gate #define ipsecesp_default_hard_bytes \ 1060Sstevel@tonic-gate ipsecesp_param_arr[7].ipsecesp_param_value 1070Sstevel@tonic-gate #define ipsecesp_default_soft_addtime \ 1080Sstevel@tonic-gate ipsecesp_param_arr[8].ipsecesp_param_value 1090Sstevel@tonic-gate #define ipsecesp_default_hard_addtime \ 1100Sstevel@tonic-gate ipsecesp_param_arr[9].ipsecesp_param_value 1110Sstevel@tonic-gate #define ipsecesp_default_soft_usetime \ 1120Sstevel@tonic-gate ipsecesp_param_arr[10].ipsecesp_param_value 1130Sstevel@tonic-gate #define ipsecesp_default_hard_usetime \ 1140Sstevel@tonic-gate ipsecesp_param_arr[11].ipsecesp_param_value 1150Sstevel@tonic-gate #define ipsecesp_log_unknown_spi \ 1160Sstevel@tonic-gate ipsecesp_param_arr[12].ipsecesp_param_value 1170Sstevel@tonic-gate #define ipsecesp_padding_check \ 1180Sstevel@tonic-gate ipsecesp_param_arr[13].ipsecesp_param_value 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate #define esp0dbg(a) printf a 1210Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 1220Sstevel@tonic-gate #define esp1dbg(a) if (ipsecesp_debug != 0) printf a 1230Sstevel@tonic-gate #define esp2dbg(a) if (ipsecesp_debug > 1) printf a 1240Sstevel@tonic-gate #define esp3dbg(a) if (ipsecesp_debug > 2) printf a 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate static IDP ipsecesp_g_nd; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *); 1290Sstevel@tonic-gate static int ipsecesp_close(queue_t *); 1300Sstevel@tonic-gate static void ipsecesp_rput(queue_t *, mblk_t *); 1310Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *); 1320Sstevel@tonic-gate static void esp_send_acquire(ipsacq_t *, mblk_t *); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate static ipsec_status_t esp_outbound_accelerated(mblk_t *, uint_t); 1350Sstevel@tonic-gate static ipsec_status_t esp_inbound_accelerated(mblk_t *, mblk_t *, 1360Sstevel@tonic-gate boolean_t, ipsa_t *); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate static boolean_t esp_register_out(uint32_t, uint32_t, uint_t); 1390Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t, 1400Sstevel@tonic-gate kstat_named_t **); 1410Sstevel@tonic-gate static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t); 1420Sstevel@tonic-gate static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *, 1430Sstevel@tonic-gate uint_t); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate static struct module_info info = { 1460Sstevel@tonic-gate 5137, "ipsecesp", 0, INFPSZ, 65536, 1024 1470Sstevel@tonic-gate }; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static struct qinit rinit = { 1500Sstevel@tonic-gate (pfi_t)ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1510Sstevel@tonic-gate NULL 1520Sstevel@tonic-gate }; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate static struct qinit winit = { 1550Sstevel@tonic-gate (pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1560Sstevel@tonic-gate NULL 1570Sstevel@tonic-gate }; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate struct streamtab ipsecespinfo = { 1600Sstevel@tonic-gate &rinit, &winit, NULL, NULL 1610Sstevel@tonic-gate }; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Keysock instance of ESP. "There can be only one." :) 1650Sstevel@tonic-gate * Use casptr() on this because I don't set it until KEYSOCK_HELLO comes down. 1660Sstevel@tonic-gate * Paired up with the esp_pfkey_q is the esp_event, which will age SAs. 1670Sstevel@tonic-gate */ 1680Sstevel@tonic-gate static queue_t *esp_pfkey_q; 1690Sstevel@tonic-gate static timeout_id_t esp_event; 1700Sstevel@tonic-gate static taskq_t *esp_taskq; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate /* 1730Sstevel@tonic-gate * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now. 1740Sstevel@tonic-gate * 1750Sstevel@tonic-gate * Question: Do I need this, given that all instance's esps->esps_wq point 1760Sstevel@tonic-gate * to IP? 1770Sstevel@tonic-gate * 1780Sstevel@tonic-gate * Answer: Yes, because I need to know which queue is BOUND to 1790Sstevel@tonic-gate * IPPROTO_ESP 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate static mblk_t *esp_ip_unbind; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate /* 1840Sstevel@tonic-gate * Stats. This may eventually become a full-blown SNMP MIB once that spec 1850Sstevel@tonic-gate * stabilizes. 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate typedef struct { 1890Sstevel@tonic-gate kstat_named_t esp_stat_num_aalgs; 1900Sstevel@tonic-gate kstat_named_t esp_stat_good_auth; 1910Sstevel@tonic-gate kstat_named_t esp_stat_bad_auth; 1920Sstevel@tonic-gate kstat_named_t esp_stat_bad_padding; 1930Sstevel@tonic-gate kstat_named_t esp_stat_replay_failures; 1940Sstevel@tonic-gate kstat_named_t esp_stat_replay_early_failures; 1950Sstevel@tonic-gate kstat_named_t esp_stat_keysock_in; 1960Sstevel@tonic-gate kstat_named_t esp_stat_out_requests; 1970Sstevel@tonic-gate kstat_named_t esp_stat_acquire_requests; 1980Sstevel@tonic-gate kstat_named_t esp_stat_bytes_expired; 1990Sstevel@tonic-gate kstat_named_t esp_stat_out_discards; 2000Sstevel@tonic-gate kstat_named_t esp_stat_in_accelerated; 2010Sstevel@tonic-gate kstat_named_t esp_stat_out_accelerated; 2020Sstevel@tonic-gate kstat_named_t esp_stat_noaccel; 2030Sstevel@tonic-gate kstat_named_t esp_stat_crypto_sync; 2040Sstevel@tonic-gate kstat_named_t esp_stat_crypto_async; 2050Sstevel@tonic-gate kstat_named_t esp_stat_crypto_failures; 2060Sstevel@tonic-gate kstat_named_t esp_stat_num_ealgs; 2070Sstevel@tonic-gate kstat_named_t esp_stat_bad_decrypt; 2080Sstevel@tonic-gate } esp_kstats_t; 2090Sstevel@tonic-gate 210564Ssommerfe uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE; 2110Sstevel@tonic-gate #define ESP_BUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64++ 2120Sstevel@tonic-gate #define ESP_DEBUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64-- 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate static kstat_t *esp_ksp; 2150Sstevel@tonic-gate static esp_kstats_t *esp_kstats; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate static int esp_kstat_update(kstat_t *, int); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate static boolean_t 2200Sstevel@tonic-gate esp_kstat_init(void) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate esp_ksp = kstat_create("ipsecesp", 0, "esp_stat", "net", 2230Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (*esp_kstats) / sizeof (kstat_named_t), 2240Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if (esp_ksp == NULL) 2270Sstevel@tonic-gate return (B_FALSE); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate esp_kstats = esp_ksp->ks_data; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate esp_ksp->ks_update = esp_kstat_update; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate #define K64 KSTAT_DATA_UINT64 2340Sstevel@tonic-gate #define KI(x) kstat_named_init(&(esp_kstats->esp_stat_##x), #x, K64) 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate KI(num_aalgs); 2370Sstevel@tonic-gate KI(num_ealgs); 2380Sstevel@tonic-gate KI(good_auth); 2390Sstevel@tonic-gate KI(bad_auth); 2400Sstevel@tonic-gate KI(bad_padding); 2410Sstevel@tonic-gate KI(replay_failures); 2420Sstevel@tonic-gate KI(replay_early_failures); 2430Sstevel@tonic-gate KI(keysock_in); 2440Sstevel@tonic-gate KI(out_requests); 2450Sstevel@tonic-gate KI(acquire_requests); 2460Sstevel@tonic-gate KI(bytes_expired); 2470Sstevel@tonic-gate KI(out_discards); 2480Sstevel@tonic-gate KI(in_accelerated); 2490Sstevel@tonic-gate KI(out_accelerated); 2500Sstevel@tonic-gate KI(noaccel); 2510Sstevel@tonic-gate KI(crypto_sync); 2520Sstevel@tonic-gate KI(crypto_async); 2530Sstevel@tonic-gate KI(crypto_failures); 2540Sstevel@tonic-gate KI(bad_decrypt); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate #undef KI 2570Sstevel@tonic-gate #undef K64 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate kstat_install(esp_ksp); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate return (B_TRUE); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate static int 2650Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate esp_kstats_t *ekp; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 2700Sstevel@tonic-gate return (EIO); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate if (rw == KSTAT_WRITE) 2730Sstevel@tonic-gate return (EACCES); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate ASSERT(kp == esp_ksp); 2760Sstevel@tonic-gate ekp = (esp_kstats_t *)kp->ks_data; 2770Sstevel@tonic-gate ASSERT(ekp == esp_kstats); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate mutex_enter(&alg_lock); 2800Sstevel@tonic-gate ekp->esp_stat_num_aalgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_AUTH]; 2810Sstevel@tonic-gate ekp->esp_stat_num_ealgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_ENCR]; 2820Sstevel@tonic-gate mutex_exit(&alg_lock); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate return (0); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate #ifdef DEBUG 2880Sstevel@tonic-gate /* 2890Sstevel@tonic-gate * Debug routine, useful to see pre-encryption data. 2900Sstevel@tonic-gate */ 2910Sstevel@tonic-gate static char * 2920Sstevel@tonic-gate dump_msg(mblk_t *mp) 2930Sstevel@tonic-gate { 2940Sstevel@tonic-gate char tmp_str[3], tmp_line[256]; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate while (mp != NULL) { 2970Sstevel@tonic-gate unsigned char *ptr; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate printf("mblk address 0x%p, length %ld, db_ref %d " 3000Sstevel@tonic-gate "type %d, base 0x%p, lim 0x%p\n", 3010Sstevel@tonic-gate (void *) mp, (long)(mp->b_wptr - mp->b_rptr), 3020Sstevel@tonic-gate mp->b_datap->db_ref, mp->b_datap->db_type, 3030Sstevel@tonic-gate (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim); 3040Sstevel@tonic-gate ptr = mp->b_rptr; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate tmp_line[0] = '\0'; 3070Sstevel@tonic-gate while (ptr < mp->b_wptr) { 3080Sstevel@tonic-gate uint_t diff; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate diff = (ptr - mp->b_rptr); 3110Sstevel@tonic-gate if (!(diff & 0x1f)) { 3120Sstevel@tonic-gate if (strlen(tmp_line) > 0) { 3130Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3140Sstevel@tonic-gate tmp_line[0] = '\0'; 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate if (!(diff & 0x3)) 3180Sstevel@tonic-gate (void) strcat(tmp_line, " "); 3190Sstevel@tonic-gate (void) sprintf(tmp_str, "%02x", *ptr); 3200Sstevel@tonic-gate (void) strcat(tmp_line, tmp_str); 3210Sstevel@tonic-gate ptr++; 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate if (strlen(tmp_line) > 0) 3240Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate mp = mp->b_cont; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate return ("\n"); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate #else /* DEBUG */ 3330Sstevel@tonic-gate static char * 3340Sstevel@tonic-gate dump_msg(mblk_t *mp) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate printf("Find value of mp %p.\n", mp); 3370Sstevel@tonic-gate return ("\n"); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate #endif /* DEBUG */ 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Don't have to lock age_interval, as only one thread will access it at 3430Sstevel@tonic-gate * a time, because I control the one function that does with timeout(). 3440Sstevel@tonic-gate */ 3450Sstevel@tonic-gate /* ARGSUSED */ 3460Sstevel@tonic-gate static void 3470Sstevel@tonic-gate esp_ager(void *ignoreme) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate hrtime_t begin = gethrtime(); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate sadb_ager(&esp_sadb.s_v4, esp_pfkey_q, esp_sadb.s_ip_q, 3520Sstevel@tonic-gate ipsecesp_reap_delay); 3530Sstevel@tonic-gate sadb_ager(&esp_sadb.s_v6, esp_pfkey_q, esp_sadb.s_ip_q, 3540Sstevel@tonic-gate ipsecesp_reap_delay); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate esp_event = sadb_retimeout(begin, esp_pfkey_q, esp_ager, 3570Sstevel@tonic-gate &(ipsecesp_age_interval), ipsecesp_age_int_max, info.mi_idnum); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Get an ESP NDD parameter. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate /* ARGSUSED */ 3640Sstevel@tonic-gate static int 3650Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr) 3660Sstevel@tonic-gate queue_t *q; 3670Sstevel@tonic-gate mblk_t *mp; 3680Sstevel@tonic-gate caddr_t cp; 3690Sstevel@tonic-gate cred_t *cr; 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 3720Sstevel@tonic-gate uint_t value; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate mutex_enter(&ipsecesp_param_lock); 3750Sstevel@tonic-gate value = ipsecesppa->ipsecesp_param_value; 3760Sstevel@tonic-gate mutex_exit(&ipsecesp_param_lock); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 3790Sstevel@tonic-gate return (0); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * This routine sets an NDD variable in a ipsecespparam_t structure. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate /* ARGSUSED */ 3860Sstevel@tonic-gate static int 3870Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr) 3880Sstevel@tonic-gate queue_t *q; 3890Sstevel@tonic-gate mblk_t *mp; 3900Sstevel@tonic-gate char *value; 3910Sstevel@tonic-gate caddr_t cp; 3920Sstevel@tonic-gate cred_t *cr; 3930Sstevel@tonic-gate { 3940Sstevel@tonic-gate ulong_t new_value; 3950Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /* 3980Sstevel@tonic-gate * Fail the request if the new value does not lie within the 3990Sstevel@tonic-gate * required bounds. 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 4020Sstevel@tonic-gate new_value < ipsecesppa->ipsecesp_param_min || 4030Sstevel@tonic-gate new_value > ipsecesppa->ipsecesp_param_max) { 4040Sstevel@tonic-gate return (EINVAL); 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* Set the new value */ 4080Sstevel@tonic-gate mutex_enter(&ipsecesp_param_lock); 4090Sstevel@tonic-gate ipsecesppa->ipsecesp_param_value = new_value; 4100Sstevel@tonic-gate mutex_exit(&ipsecesp_param_lock); 4110Sstevel@tonic-gate return (0); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate /* 4150Sstevel@tonic-gate * Using lifetime NDD variables, fill in an extended combination's 4160Sstevel@tonic-gate * lifetime information. 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate void 4190Sstevel@tonic-gate ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb) 4200Sstevel@tonic-gate { 4210Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_bytes = ipsecesp_default_soft_bytes; 4220Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_bytes = ipsecesp_default_hard_bytes; 4230Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_addtime = ipsecesp_default_soft_addtime; 4240Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_addtime = ipsecesp_default_hard_addtime; 4250Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_usetime = ipsecesp_default_soft_usetime; 4260Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_usetime = ipsecesp_default_hard_usetime; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* 4300Sstevel@tonic-gate * Initialize things for ESP at module load time. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate boolean_t 4330Sstevel@tonic-gate ipsecesp_ddi_init(void) 4340Sstevel@tonic-gate { 4350Sstevel@tonic-gate int count; 4360Sstevel@tonic-gate ipsecespparam_t *espp = ipsecesp_param_arr; 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate for (count = A_CNT(ipsecesp_param_arr); count-- > 0; espp++) { 4390Sstevel@tonic-gate if (espp->ipsecesp_param_name != NULL && 4400Sstevel@tonic-gate espp->ipsecesp_param_name[0]) { 4410Sstevel@tonic-gate if (!nd_load(&ipsecesp_g_nd, espp->ipsecesp_param_name, 4420Sstevel@tonic-gate ipsecesp_param_get, ipsecesp_param_set, 4430Sstevel@tonic-gate (caddr_t)espp)) { 4440Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 4450Sstevel@tonic-gate return (B_FALSE); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate if (!esp_kstat_init()) { 4510Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 4520Sstevel@tonic-gate return (B_FALSE); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate esp_sadb.s_acquire_timeout = &ipsecesp_acquire_timeout; 4560Sstevel@tonic-gate esp_sadb.s_acqfn = esp_send_acquire; 457564Ssommerfe sadbp_init("ESP", &esp_sadb, SADB_SATYPE_ESP, esp_hash_size); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate esp_taskq = taskq_create("esp_taskq", 1, minclsyspri, 4600Sstevel@tonic-gate IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate mutex_init(&ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0); 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate ip_drop_register(&esp_dropper, "IPsec ESP"); 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate return (B_TRUE); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * Destroy things for ESP at module unload time. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate void 4730Sstevel@tonic-gate ipsecesp_ddi_destroy(void) 4740Sstevel@tonic-gate { 4750Sstevel@tonic-gate esp1dbg(("In ipsecesp_ddi_destroy.\n")); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate sadbp_destroy(&esp_sadb); 4780Sstevel@tonic-gate ip_drop_unregister(&esp_dropper); 4790Sstevel@tonic-gate taskq_destroy(esp_taskq); 4800Sstevel@tonic-gate mutex_destroy(&ipsecesp_param_lock); 4810Sstevel@tonic-gate nd_free(&ipsecesp_g_nd); 4820Sstevel@tonic-gate kstat_delete(esp_ksp); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * ESP module open routine. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate /* ARGSUSED */ 4890Sstevel@tonic-gate static int 4900Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate if (secpolicy_net_config(credp, B_FALSE) != 0) { 4930Sstevel@tonic-gate esp1dbg(("Non-privileged user trying to open ipsecesp.\n")); 4940Sstevel@tonic-gate return (EPERM); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if (q->q_ptr != NULL) 4980Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate if (sflag != MODOPEN) 5010Sstevel@tonic-gate return (EINVAL); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate /* 5040Sstevel@tonic-gate * ASSUMPTIONS (because I'm MT_OCEXCL): 5050Sstevel@tonic-gate * 5060Sstevel@tonic-gate * * I'm being pushed on top of IP for all my opens (incl. #1). 5070Sstevel@tonic-gate * * Only ipsecesp_open() can write into esp_sadb.s_ip_q. 5080Sstevel@tonic-gate * * Because of this, I can check lazily for esp_sadb.s_ip_q. 5090Sstevel@tonic-gate * 5100Sstevel@tonic-gate * If these assumptions are wrong, I'm in BIG trouble... 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate q->q_ptr = q; /* just so I know I'm open */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate if (esp_sadb.s_ip_q == NULL) { 5160Sstevel@tonic-gate struct T_unbind_req *tur; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate esp_sadb.s_ip_q = WR(q); 5190Sstevel@tonic-gate /* Allocate an unbind... */ 5200Sstevel@tonic-gate esp_ip_unbind = allocb(sizeof (struct T_unbind_req), BPRI_HI); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * Send down T_BIND_REQ to bind IPPROTO_ESP. 5240Sstevel@tonic-gate * Handle the ACK here in ESP. 5250Sstevel@tonic-gate */ 5260Sstevel@tonic-gate qprocson(q); 5270Sstevel@tonic-gate if (esp_ip_unbind == NULL || 5280Sstevel@tonic-gate !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) { 5290Sstevel@tonic-gate if (esp_ip_unbind != NULL) { 5300Sstevel@tonic-gate freeb(esp_ip_unbind); 5310Sstevel@tonic-gate esp_ip_unbind = NULL; 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate q->q_ptr = NULL; 5340Sstevel@tonic-gate return (ENOMEM); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate esp_ip_unbind->b_datap->db_type = M_PROTO; 5380Sstevel@tonic-gate tur = (struct T_unbind_req *)esp_ip_unbind->b_rptr; 5390Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 5400Sstevel@tonic-gate } else { 5410Sstevel@tonic-gate qprocson(q); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * For now, there's not much I can do. I'll be getting a message 5460Sstevel@tonic-gate * passed down to me from keysock (in my wput), and a T_BIND_ACK 5470Sstevel@tonic-gate * up from IP (in my rput). 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate return (0); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * ESP module close routine. 5550Sstevel@tonic-gate */ 5560Sstevel@tonic-gate static int 5570Sstevel@tonic-gate ipsecesp_close(queue_t *q) 5580Sstevel@tonic-gate { 5590Sstevel@tonic-gate /* 5600Sstevel@tonic-gate * If esp_sadb.s_ip_q is attached to this instance, send a 5610Sstevel@tonic-gate * T_UNBIND_REQ to IP for the instance before doing 5620Sstevel@tonic-gate * a qprocsoff(). 5630Sstevel@tonic-gate */ 5640Sstevel@tonic-gate if (WR(q) == esp_sadb.s_ip_q && esp_ip_unbind != NULL) { 5650Sstevel@tonic-gate putnext(WR(q), esp_ip_unbind); 5660Sstevel@tonic-gate esp_ip_unbind = NULL; 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * Clean up q_ptr, if needed. 5710Sstevel@tonic-gate */ 5720Sstevel@tonic-gate qprocsoff(q); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* Keysock queue check is safe, because of OCEXCL perimeter. */ 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (q == esp_pfkey_q) { 5770Sstevel@tonic-gate esp0dbg(("ipsecesp_close: Ummm... keysock is closing ESP.\n")); 5780Sstevel@tonic-gate esp_pfkey_q = NULL; 5790Sstevel@tonic-gate /* Detach qtimeouts. */ 5800Sstevel@tonic-gate (void) quntimeout(q, esp_event); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (WR(q) == esp_sadb.s_ip_q) { 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * If the esp_sadb.s_ip_q is attached to this instance, find 5860Sstevel@tonic-gate * another. The OCEXCL outer perimeter helps us here. 5870Sstevel@tonic-gate */ 5880Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * Find a replacement queue for esp_sadb.s_ip_q. 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate if (esp_pfkey_q != NULL && esp_pfkey_q != RD(q)) { 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * See if we can use the pfkey_q. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate esp_sadb.s_ip_q = WR(esp_pfkey_q); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (esp_sadb.s_ip_q == NULL || 6010Sstevel@tonic-gate !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) { 6020Sstevel@tonic-gate esp1dbg(("ipsecesp: Can't reassign ip_q.\n")); 6030Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 6040Sstevel@tonic-gate } else { 6050Sstevel@tonic-gate esp_ip_unbind = allocb(sizeof (struct T_unbind_req), 6060Sstevel@tonic-gate BPRI_HI); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (esp_ip_unbind != NULL) { 6090Sstevel@tonic-gate struct T_unbind_req *tur; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate esp_ip_unbind->b_datap->db_type = M_PROTO; 6120Sstevel@tonic-gate tur = (struct T_unbind_req *) 6130Sstevel@tonic-gate esp_ip_unbind->b_rptr; 6140Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate /* If it's NULL, I can't do much here. */ 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate return (0); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Add a number of bytes to what the SA has protected so far. Return 6250Sstevel@tonic-gate * B_TRUE if the SA can still protect that many bytes. 6260Sstevel@tonic-gate * 6270Sstevel@tonic-gate * Caller must REFRELE the passed-in assoc. This function must REFRELE 6280Sstevel@tonic-gate * any obtained peer SA. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate static boolean_t 6310Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound) 6320Sstevel@tonic-gate { 6330Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 6340Sstevel@tonic-gate isaf_t *bucket; 6350Sstevel@tonic-gate boolean_t inrc, outrc, isv6; 6360Sstevel@tonic-gate sadb_t *sp; 6370Sstevel@tonic-gate int outhash; 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* No peer? No problem! */ 6400Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 6410Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, assoc, bytes, 6420Sstevel@tonic-gate B_TRUE)); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate /* 6460Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 6470Sstevel@tonic-gate * There might be a race for this, but if it's a real race, two 6480Sstevel@tonic-gate * expire messages may occur. We limit this by only sending the 6490Sstevel@tonic-gate * expire message on one of the peers, we'll pick the inbound 6500Sstevel@tonic-gate * arbitrarily. 6510Sstevel@tonic-gate * 6520Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 6530Sstevel@tonic-gate * reconsider. 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 6570Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 6580Sstevel@tonic-gate sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (inbound) { 6610Sstevel@tonic-gate inassoc = assoc; 6620Sstevel@tonic-gate if (isv6) { 663564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 6640Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 6650Sstevel@tonic-gate } else { 666564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 6670Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 6700Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 6710Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 6720Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 6730Sstevel@tonic-gate inassoc->ipsa_addrfam); 6740Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 6750Sstevel@tonic-gate if (outassoc == NULL) { 6760Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 6770Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 6780Sstevel@tonic-gate "can't find peer for inbound.\n")); 6790Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, inassoc, 6800Sstevel@tonic-gate bytes, B_TRUE)); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate } else { 6830Sstevel@tonic-gate outassoc = assoc; 684564Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 6850Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 6860Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 6870Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 6880Sstevel@tonic-gate outassoc->ipsa_addrfam); 6890Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 6900Sstevel@tonic-gate if (inassoc == NULL) { 6910Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 6920Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 6930Sstevel@tonic-gate "can't find peer for outbound.\n")); 6940Sstevel@tonic-gate return (sadb_age_bytes(esp_pfkey_q, outassoc, 6950Sstevel@tonic-gate bytes, B_TRUE)); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate inrc = sadb_age_bytes(esp_pfkey_q, inassoc, bytes, B_TRUE); 7000Sstevel@tonic-gate outrc = sadb_age_bytes(esp_pfkey_q, outassoc, bytes, B_FALSE); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* 7030Sstevel@tonic-gate * REFRELE any peer SA. 7040Sstevel@tonic-gate * 7050Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 7060Sstevel@tonic-gate * them in { }. 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate if (inbound) { 7090Sstevel@tonic-gate IPSA_REFRELE(outassoc); 7100Sstevel@tonic-gate } else { 7110Sstevel@tonic-gate IPSA_REFRELE(inassoc); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate return (inrc && outrc); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* 7180Sstevel@tonic-gate * Do incoming NAT-T manipulations for packet. 7190Sstevel@tonic-gate */ 7200Sstevel@tonic-gate static ipsec_status_t 7210Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc) 7220Sstevel@tonic-gate { 7230Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 7240Sstevel@tonic-gate tcpha_t *tcph; 7250Sstevel@tonic-gate udpha_t *udpha; 7260Sstevel@tonic-gate /* Initialize to our inbound cksum adjustment... */ 7270Sstevel@tonic-gate uint32_t sum = assoc->ipsa_inbound_cksum; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate switch (ipha->ipha_protocol) { 7300Sstevel@tonic-gate case IPPROTO_TCP: 7310Sstevel@tonic-gate tcph = (tcpha_t *)(data_mp->b_rptr + 7320Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate #define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16) 7350Sstevel@tonic-gate sum += ~ntohs(tcph->tha_sum) & 0xFFFF; 7360Sstevel@tonic-gate DOWN_SUM(sum); 7370Sstevel@tonic-gate DOWN_SUM(sum); 7380Sstevel@tonic-gate tcph->tha_sum = ~htons(sum); 7390Sstevel@tonic-gate break; 7400Sstevel@tonic-gate case IPPROTO_UDP: 7410Sstevel@tonic-gate udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha)); 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if (udpha->uha_checksum != 0) { 7440Sstevel@tonic-gate /* Adujst if the inbound one was not zero. */ 7450Sstevel@tonic-gate sum += ~ntohs(udpha->uha_checksum) & 0xFFFF; 7460Sstevel@tonic-gate DOWN_SUM(sum); 7470Sstevel@tonic-gate DOWN_SUM(sum); 7480Sstevel@tonic-gate udpha->uha_checksum = ~htons(sum); 7490Sstevel@tonic-gate if (udpha->uha_checksum == 0) 7500Sstevel@tonic-gate udpha->uha_checksum = 0xFFFF; 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate #undef DOWN_SUM 7530Sstevel@tonic-gate break; 7540Sstevel@tonic-gate case IPPROTO_IP: 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * This case is only an issue for self-encapsulated 7570Sstevel@tonic-gate * packets. So for now, fall through. 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate /* 7660Sstevel@tonic-gate * Strip ESP header and fix IP header 7670Sstevel@tonic-gate * Returns B_TRUE on success, B_FALSE if an error occured. 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate static boolean_t 7700Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen, 7710Sstevel@tonic-gate kstat_named_t **counter) 7720Sstevel@tonic-gate { 7730Sstevel@tonic-gate ipha_t *ipha; 7740Sstevel@tonic-gate ip6_t *ip6h; 7750Sstevel@tonic-gate uint_t divpoint; 7760Sstevel@tonic-gate mblk_t *scratch; 7770Sstevel@tonic-gate uint8_t nexthdr, padlen; 7780Sstevel@tonic-gate uint8_t lastpad; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate /* 7810Sstevel@tonic-gate * Strip ESP data and fix IP header. 7820Sstevel@tonic-gate * 7830Sstevel@tonic-gate * XXX In case the beginning of esp_inbound() changes to not do a 7840Sstevel@tonic-gate * pullup, this part of the code can remain unchanged. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate if (isv4) { 7870Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t)); 7880Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 7890Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) + 7900Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 7910Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 7920Sstevel@tonic-gate } else { 7930Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t)); 7940Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 7950Sstevel@tonic-gate divpoint = ip_hdr_length_v6(data_mp, ip6h); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate scratch = data_mp; 7990Sstevel@tonic-gate while (scratch->b_cont != NULL) 8000Sstevel@tonic-gate scratch = scratch->b_cont; 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3); 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * "Next header" and padding length are the last two bytes in the 8060Sstevel@tonic-gate * ESP-protected datagram, thus the explicit - 1 and - 2. 8070Sstevel@tonic-gate * lastpad is the last byte of the padding, which can be used for 8080Sstevel@tonic-gate * a quick check to see if the padding is correct. 8090Sstevel@tonic-gate */ 8100Sstevel@tonic-gate nexthdr = *(scratch->b_wptr - 1); 8110Sstevel@tonic-gate padlen = *(scratch->b_wptr - 2); 8120Sstevel@tonic-gate lastpad = *(scratch->b_wptr - 3); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate if (isv4) { 8150Sstevel@tonic-gate /* Fix part of the IP header. */ 8160Sstevel@tonic-gate ipha->ipha_protocol = nexthdr; 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * Reality check the padlen. The explicit - 2 is for the 8190Sstevel@tonic-gate * padding length and the next-header bytes. 8200Sstevel@tonic-gate */ 8210Sstevel@tonic-gate if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 - 8220Sstevel@tonic-gate sizeof (esph_t) - ivlen) { 8230Sstevel@tonic-gate ESP_BUMP_STAT(bad_decrypt); 8240Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 8250Sstevel@tonic-gate "Possibly corrupt ESP packet."); 8260Sstevel@tonic-gate esp1dbg(("padlen (%d) is greater than:\n", padlen)); 8270Sstevel@tonic-gate esp1dbg(("pkt len(%d) - ip hdr - esp hdr - ivlen(%d) " 8280Sstevel@tonic-gate "= %d.\n", ntohs(ipha->ipha_length), ivlen, 8290Sstevel@tonic-gate (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) - 8300Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen))); 8310Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padlen; 8320Sstevel@tonic-gate return (B_FALSE); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 8370Sstevel@tonic-gate * padding length and the next-header bytes. 8380Sstevel@tonic-gate */ 8390Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen - 8400Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 8410Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 8420Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 8430Sstevel@tonic-gate } else { 8440Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_ESP) { 8450Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 8460Sstevel@tonic-gate } else { 8470Sstevel@tonic-gate ip6_pkt_t ipp; 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 8500Sstevel@tonic-gate (void) ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 8510Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL) { 8520Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt = nexthdr; 8530Sstevel@tonic-gate } else if (ipp.ipp_rthdr != NULL) { 8540Sstevel@tonic-gate ipp.ipp_rthdr->ip6r_nxt = nexthdr; 8550Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 8560Sstevel@tonic-gate ipp.ipp_hopopts->ip6h_nxt = nexthdr; 8570Sstevel@tonic-gate } else { 8580Sstevel@tonic-gate /* Panic a DEBUG kernel. */ 8590Sstevel@tonic-gate ASSERT(ipp.ipp_hopopts != NULL); 8600Sstevel@tonic-gate /* Otherwise, pretend it's IP + ESP. */ 8610Sstevel@tonic-gate cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n"); 8620Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) - 8670Sstevel@tonic-gate ivlen) { 8680Sstevel@tonic-gate ESP_BUMP_STAT(bad_decrypt); 8690Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 8700Sstevel@tonic-gate "Possibly corrupt ESP packet."); 8710Sstevel@tonic-gate esp1dbg(("padlen (%d) is greater than:\n", padlen)); 8720Sstevel@tonic-gate esp1dbg(("pkt len(%u) - ip hdr - esp hdr - ivlen(%d)" 8730Sstevel@tonic-gate " = %u.\n", (unsigned)(ntohs(ip6h->ip6_plen) 8740Sstevel@tonic-gate + sizeof (ip6_t)), ivlen, 8750Sstevel@tonic-gate (unsigned)(ntohs(ip6h->ip6_plen) - 2 - 8760Sstevel@tonic-gate sizeof (esph_t) - ivlen))); 8770Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padlen; 8780Sstevel@tonic-gate return (B_FALSE); 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 8840Sstevel@tonic-gate * padding length and the next-header bytes. IPv6 is nice, 8850Sstevel@tonic-gate * because there's no hdr checksum! 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen - 8880Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate if (ipsecesp_padding_check > 0 && 8920Sstevel@tonic-gate padlen != lastpad && padlen != 0) { 8930Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 8940Sstevel@tonic-gate "Possibly corrupt ESP packet."); 8950Sstevel@tonic-gate esp1dbg(("lastpad (%d) not equal to padlen (%d):\n", 8960Sstevel@tonic-gate lastpad, padlen)); 8970Sstevel@tonic-gate ESP_BUMP_STAT(bad_padding); 8980Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padding; 8990Sstevel@tonic-gate return (B_FALSE); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if (ipsecesp_padding_check > 1) { 9030Sstevel@tonic-gate uint8_t *last = (uint8_t *)(scratch->b_wptr - 3); 9040Sstevel@tonic-gate uint8_t lastval = *last; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * this assert may have to become an if 9080Sstevel@tonic-gate * and a pullup if we start accepting 9090Sstevel@tonic-gate * multi-dblk mblks. Any packet here will 9100Sstevel@tonic-gate * have been pulled up in esp_inbound. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate ASSERT(MBLKL(scratch) >= lastval + 3); 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate while (lastval != 0) { 9150Sstevel@tonic-gate if (lastval != *last) { 9160Sstevel@tonic-gate ipsec_rl_strlog(info.mi_idnum, 0, 0, 9170Sstevel@tonic-gate SL_ERROR | SL_WARN, 9180Sstevel@tonic-gate "Possibly corrupt ESP packet."); 9190Sstevel@tonic-gate esp1dbg(("padding not in correct" 9200Sstevel@tonic-gate " format:\n")); 9210Sstevel@tonic-gate ESP_BUMP_STAT(bad_padding); 9220Sstevel@tonic-gate *counter = &ipdrops_esp_bad_padding; 9230Sstevel@tonic-gate return (B_FALSE); 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate lastval--; last--; 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* Trim off the padding. */ 9300Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 9310Sstevel@tonic-gate data_mp->b_wptr -= (padlen + 2); 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Remove the ESP header. 9350Sstevel@tonic-gate * 9360Sstevel@tonic-gate * The above assertions about data_mp's size will make this work. 9370Sstevel@tonic-gate * 9380Sstevel@tonic-gate * XXX Question: If I send up and get back a contiguous mblk, 9390Sstevel@tonic-gate * would it be quicker to bcopy over, or keep doing the dupb stuff? 9400Sstevel@tonic-gate * I go with copying for now. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) && 9440Sstevel@tonic-gate IS_P2ALIGNED(ivlen, sizeof (uint32_t))) { 9450Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 9460Sstevel@tonic-gate uint32_t *src, *dst; 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate src = (uint32_t *)(start + divpoint); 9490Sstevel@tonic-gate dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) && 9520Sstevel@tonic-gate IS_P2ALIGNED(src, sizeof (uint32_t))); 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate do { 9550Sstevel@tonic-gate src--; 9560Sstevel@tonic-gate dst--; 9570Sstevel@tonic-gate *dst = *src; 9580Sstevel@tonic-gate } while (src != (uint32_t *)start); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate data_mp->b_rptr = (uchar_t *)dst; 9610Sstevel@tonic-gate } else { 9620Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 9630Sstevel@tonic-gate uint8_t *src, *dst; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate src = start + divpoint; 9660Sstevel@tonic-gate dst = src + sizeof (esph_t) + ivlen; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate do { 9690Sstevel@tonic-gate src--; 9700Sstevel@tonic-gate dst--; 9710Sstevel@tonic-gate *dst = *src; 9720Sstevel@tonic-gate } while (src != start); 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate data_mp->b_rptr = dst; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate esp2dbg(("data_mp after inbound ESP adjustment:\n")); 9780Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate return (B_TRUE); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate /* 9840Sstevel@tonic-gate * Updating use times can be tricky business if the ipsa_haspeer flag is 9850Sstevel@tonic-gate * set. This function is called once in an SA's lifetime. 9860Sstevel@tonic-gate * 9870Sstevel@tonic-gate * Caller has to REFRELE "assoc" which is passed in. This function has 9880Sstevel@tonic-gate * to REFRELE any peer SA that is obtained. 9890Sstevel@tonic-gate */ 9900Sstevel@tonic-gate static void 9910Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound) 9920Sstevel@tonic-gate { 9930Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 9940Sstevel@tonic-gate isaf_t *bucket; 9950Sstevel@tonic-gate sadb_t *sp; 9960Sstevel@tonic-gate int outhash; 9970Sstevel@tonic-gate boolean_t isv6; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate /* No peer? No problem! */ 10000Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 10010Sstevel@tonic-gate sadb_set_usetime(assoc); 10020Sstevel@tonic-gate return; 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate /* 10060Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 10070Sstevel@tonic-gate * There might be a race for this, but if it's a real race, the times 10080Sstevel@tonic-gate * will be out-of-synch by at most a second, and since our time 10090Sstevel@tonic-gate * granularity is a second, this won't be a problem. 10100Sstevel@tonic-gate * 10110Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 10120Sstevel@tonic-gate * reconsider. 10130Sstevel@tonic-gate */ 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 10160Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 10170Sstevel@tonic-gate sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4; 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate if (inbound) { 10200Sstevel@tonic-gate inassoc = assoc; 10210Sstevel@tonic-gate if (isv6) { 1022564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 10230Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 10240Sstevel@tonic-gate } else { 1025564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 10260Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 10290Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 10300Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 10310Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 10320Sstevel@tonic-gate inassoc->ipsa_addrfam); 10330Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 10340Sstevel@tonic-gate if (outassoc == NULL) { 10350Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 10360Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 10370Sstevel@tonic-gate "can't find peer for inbound.\n")); 10380Sstevel@tonic-gate sadb_set_usetime(inassoc); 10390Sstevel@tonic-gate return; 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate } else { 10420Sstevel@tonic-gate outassoc = assoc; 1043564Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 10440Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 10450Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 10460Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 10470Sstevel@tonic-gate outassoc->ipsa_addrfam); 10480Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 10490Sstevel@tonic-gate if (inassoc == NULL) { 10500Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 10510Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 10520Sstevel@tonic-gate "can't find peer for outbound.\n")); 10530Sstevel@tonic-gate sadb_set_usetime(outassoc); 10540Sstevel@tonic-gate return; 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* Update usetime on both. */ 10590Sstevel@tonic-gate sadb_set_usetime(inassoc); 10600Sstevel@tonic-gate sadb_set_usetime(outassoc); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate /* 10630Sstevel@tonic-gate * REFRELE any peer SA. 10640Sstevel@tonic-gate * 10650Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 10660Sstevel@tonic-gate * them in { }. 10670Sstevel@tonic-gate */ 10680Sstevel@tonic-gate if (inbound) { 10690Sstevel@tonic-gate IPSA_REFRELE(outassoc); 10700Sstevel@tonic-gate } else { 10710Sstevel@tonic-gate IPSA_REFRELE(inassoc); 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate /* 10760Sstevel@tonic-gate * Handle ESP inbound data for IPv4 and IPv6. 10770Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 10780Sstevel@tonic-gate * mblk chain ipsec_in_mp. 10790Sstevel@tonic-gate */ 10800Sstevel@tonic-gate ipsec_status_t 10810Sstevel@tonic-gate esp_inbound(mblk_t *ipsec_in_mp, void *arg) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate mblk_t *data_mp = ipsec_in_mp->b_cont; 10840Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 10850Sstevel@tonic-gate esph_t *esph = (esph_t *)arg; 10860Sstevel@tonic-gate ipsa_t *ipsa = ii->ipsec_in_esp_sa; 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate if (ipsa->ipsa_usetime == 0) 10890Sstevel@tonic-gate esp_set_usetime(ipsa, B_TRUE); 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * We may wish to check replay in-range-only here as an optimization. 10930Sstevel@tonic-gate * Include the reality check of ipsa->ipsa_replay > 10940Sstevel@tonic-gate * ipsa->ipsa_replay_wsize for times when it's the first N packets, 10950Sstevel@tonic-gate * where N == ipsa->ipsa_replay_wsize. 10960Sstevel@tonic-gate * 10970Sstevel@tonic-gate * Another check that may come here later is the "collision" check. 10980Sstevel@tonic-gate * If legitimate packets flow quickly enough, this won't be a problem, 10990Sstevel@tonic-gate * but collisions may cause authentication algorithm crunching to 11000Sstevel@tonic-gate * take place when it doesn't need to. 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate if (!sadb_replay_peek(ipsa, esph->esph_replay)) { 11030Sstevel@tonic-gate ESP_BUMP_STAT(replay_early_failures); 11040Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 11050Sstevel@tonic-gate /* 11060Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 11070Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 11100Sstevel@tonic-gate &ipdrops_esp_early_replay, &esp_dropper); 11110Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * Has this packet already been processed by a hardware 11160Sstevel@tonic-gate * IPsec accelerator? 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate if (ii->ipsec_in_accelerated) { 11190Sstevel@tonic-gate ipsec_status_t rv; 11200Sstevel@tonic-gate esp3dbg(("esp_inbound: pkt processed by ill=%d isv6=%d\n", 11210Sstevel@tonic-gate ii->ipsec_in_ill_index, !ii->ipsec_in_v4)); 11220Sstevel@tonic-gate rv = esp_inbound_accelerated(ipsec_in_mp, 11230Sstevel@tonic-gate data_mp, ii->ipsec_in_v4, ipsa); 11240Sstevel@tonic-gate return (rv); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate ESP_BUMP_STAT(noaccel); 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate /* 11290Sstevel@tonic-gate * Adjust the IP header's payload length to reflect the removal 11300Sstevel@tonic-gate * of the ICV. 11310Sstevel@tonic-gate */ 11320Sstevel@tonic-gate if (!ii->ipsec_in_v4) { 11330Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 11340Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - 11350Sstevel@tonic-gate ipsa->ipsa_mac_len); 11360Sstevel@tonic-gate } else { 11370Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 11380Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - 11390Sstevel@tonic-gate ipsa->ipsa_mac_len); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate /* submit the request to the crypto framework */ 11430Sstevel@tonic-gate return (esp_submit_req_inbound(ipsec_in_mp, ipsa, 11440Sstevel@tonic-gate (uint8_t *)esph - data_mp->b_rptr)); 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate /* 11480Sstevel@tonic-gate * Perform the really difficult work of inserting the proposed situation. 11490Sstevel@tonic-gate * Called while holding the algorithm lock. 11500Sstevel@tonic-gate */ 11510Sstevel@tonic-gate static void 11520Sstevel@tonic-gate esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs) 11530Sstevel@tonic-gate { 11540Sstevel@tonic-gate sadb_comb_t *comb = (sadb_comb_t *)(prop + 1); 11550Sstevel@tonic-gate ipsec_out_t *io; 11560Sstevel@tonic-gate ipsec_action_t *ap; 11570Sstevel@tonic-gate ipsec_prot_t *prot; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate ASSERT(MUTEX_HELD(&alg_lock)); 11600Sstevel@tonic-gate io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr; 11610Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; 11640Sstevel@tonic-gate prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t)); 11650Sstevel@tonic-gate *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate prop->sadb_prop_replay = ipsecesp_replay_size; 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* 11700Sstevel@tonic-gate * Based upon algorithm properties, and what-not, prioritize 11710Sstevel@tonic-gate * a proposal. If the IPSEC_OUT message has an algorithm specified, 11720Sstevel@tonic-gate * use it first and foremost. 11730Sstevel@tonic-gate * 11740Sstevel@tonic-gate * For each action in policy list 11750Sstevel@tonic-gate * Add combination. If I've hit limit, return. 11760Sstevel@tonic-gate */ 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate for (ap = acqrec->ipsacq_act; ap != NULL; 11790Sstevel@tonic-gate ap = ap->ipa_next) { 11800Sstevel@tonic-gate ipsec_alginfo_t *ealg = NULL; 11810Sstevel@tonic-gate ipsec_alginfo_t *aalg = NULL; 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) 11840Sstevel@tonic-gate continue; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate prot = &ap->ipa_act.ipa_apply; 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate if (!(prot->ipp_use_esp)) 11890Sstevel@tonic-gate continue; 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate if (prot->ipp_esp_auth_alg != 0) { 11920Sstevel@tonic-gate aalg = ipsec_alglists[IPSEC_ALG_AUTH] 11930Sstevel@tonic-gate [prot->ipp_esp_auth_alg]; 11940Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) 11950Sstevel@tonic-gate continue; 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate ASSERT(prot->ipp_encr_alg > 0); 11990Sstevel@tonic-gate ealg = ipsec_alglists[IPSEC_ALG_ENCR][prot->ipp_encr_alg]; 12000Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) 12010Sstevel@tonic-gate continue; 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate comb->sadb_comb_flags = 0; 12040Sstevel@tonic-gate comb->sadb_comb_reserved = 0; 12050Sstevel@tonic-gate comb->sadb_comb_encrypt = ealg->alg_id; 12062751Sdanmcd comb->sadb_comb_encrypt_minbits = 12072751Sdanmcd MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits); 12082751Sdanmcd comb->sadb_comb_encrypt_maxbits = 12092751Sdanmcd MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits); 12100Sstevel@tonic-gate if (aalg == NULL) { 12110Sstevel@tonic-gate comb->sadb_comb_auth = 0; 12120Sstevel@tonic-gate comb->sadb_comb_auth_minbits = 0; 12130Sstevel@tonic-gate comb->sadb_comb_auth_maxbits = 0; 12140Sstevel@tonic-gate } else { 12150Sstevel@tonic-gate comb->sadb_comb_auth = aalg->alg_id; 12162751Sdanmcd comb->sadb_comb_auth_minbits = 12172751Sdanmcd MAX(prot->ipp_espa_minbits, aalg->alg_ef_minbits); 12182751Sdanmcd comb->sadb_comb_auth_maxbits = 12192751Sdanmcd MIN(prot->ipp_espa_maxbits, aalg->alg_ef_maxbits); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * The following may be based on algorithm 12240Sstevel@tonic-gate * properties, but in the meantime, we just pick 12250Sstevel@tonic-gate * some good, sensible numbers. Key mgmt. can 12260Sstevel@tonic-gate * (and perhaps should) be the place to finalize 12270Sstevel@tonic-gate * such decisions. 12280Sstevel@tonic-gate */ 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate /* 12310Sstevel@tonic-gate * No limits on allocations, since we really don't 12320Sstevel@tonic-gate * support that concept currently. 12330Sstevel@tonic-gate */ 12340Sstevel@tonic-gate comb->sadb_comb_soft_allocations = 0; 12350Sstevel@tonic-gate comb->sadb_comb_hard_allocations = 0; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate /* 12380Sstevel@tonic-gate * These may want to come from policy rule.. 12390Sstevel@tonic-gate */ 12400Sstevel@tonic-gate comb->sadb_comb_soft_bytes = ipsecesp_default_soft_bytes; 12410Sstevel@tonic-gate comb->sadb_comb_hard_bytes = ipsecesp_default_hard_bytes; 12420Sstevel@tonic-gate comb->sadb_comb_soft_addtime = ipsecesp_default_soft_addtime; 12430Sstevel@tonic-gate comb->sadb_comb_hard_addtime = ipsecesp_default_hard_addtime; 12440Sstevel@tonic-gate comb->sadb_comb_soft_usetime = ipsecesp_default_soft_usetime; 12450Sstevel@tonic-gate comb->sadb_comb_hard_usetime = ipsecesp_default_hard_usetime; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); 12480Sstevel@tonic-gate if (--combs == 0) 12490Sstevel@tonic-gate break; /* out of space.. */ 12500Sstevel@tonic-gate comb++; 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate /* 12550Sstevel@tonic-gate * Prepare and actually send the SADB_ACQUIRE message to PF_KEY. 12560Sstevel@tonic-gate */ 12570Sstevel@tonic-gate static void 12580Sstevel@tonic-gate esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended) 12590Sstevel@tonic-gate { 12600Sstevel@tonic-gate mblk_t *pfkeymp, *msgmp; 12610Sstevel@tonic-gate uint_t allocsize, combs; 12620Sstevel@tonic-gate sadb_msg_t *samsg; 12630Sstevel@tonic-gate sadb_prop_t *prop; 12640Sstevel@tonic-gate uint8_t *cur, *end; 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate ESP_BUMP_STAT(acquire_requests); 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock)); 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate pfkeymp = sadb_keysock_out(0); 12710Sstevel@tonic-gate if (pfkeymp == NULL) { 12720Sstevel@tonic-gate esp0dbg(("esp_send_acquire: 1st allocb() failed.\n")); 12730Sstevel@tonic-gate /* Just bail. */ 12740Sstevel@tonic-gate goto done; 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate /* 12780Sstevel@tonic-gate * First, allocate a basic ACQUIRE message. Beyond that, 12790Sstevel@tonic-gate * you need to extract certificate info from 12800Sstevel@tonic-gate */ 12810Sstevel@tonic-gate allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) + 12820Sstevel@tonic-gate sizeof (sadb_address_t) + sizeof (sadb_prop_t); 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate switch (acqrec->ipsacq_addrfam) { 12850Sstevel@tonic-gate case AF_INET: 12860Sstevel@tonic-gate allocsize += 2 * sizeof (struct sockaddr_in); 12870Sstevel@tonic-gate break; 12880Sstevel@tonic-gate case AF_INET6: 12890Sstevel@tonic-gate allocsize += 2 * sizeof (struct sockaddr_in6); 12900Sstevel@tonic-gate break; 12910Sstevel@tonic-gate } 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate mutex_enter(&alg_lock); 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate combs = ipsec_nalgs[IPSEC_ALG_AUTH] * ipsec_nalgs[IPSEC_ALG_ENCR]; 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate allocsize += combs * sizeof (sadb_comb_t); 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * XXX If there are: 13010Sstevel@tonic-gate * certificate IDs 13020Sstevel@tonic-gate * proxy address 13030Sstevel@tonic-gate * <Others> 13040Sstevel@tonic-gate * add additional allocation size. 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate msgmp = allocb(allocsize, BPRI_HI); 13080Sstevel@tonic-gate if (msgmp == NULL) { 13090Sstevel@tonic-gate esp0dbg(("esp_send_acquire: 2nd allocb() failed.\n")); 13100Sstevel@tonic-gate /* Just bail. */ 13110Sstevel@tonic-gate freemsg(pfkeymp); 13120Sstevel@tonic-gate pfkeymp = NULL; 13130Sstevel@tonic-gate goto done; 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate cur = msgmp->b_rptr; 13170Sstevel@tonic-gate end = cur + allocsize; 13180Sstevel@tonic-gate samsg = (sadb_msg_t *)cur; 13190Sstevel@tonic-gate pfkeymp->b_cont = msgmp; 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate /* Set up ACQUIRE. */ 13220Sstevel@tonic-gate cur = sadb_setup_acquire(cur, end, acqrec); 13230Sstevel@tonic-gate if (cur == NULL) { 13240Sstevel@tonic-gate esp0dbg(("sadb_setup_acquire failed.\n")); 13250Sstevel@tonic-gate /* Just bail. */ 13260Sstevel@tonic-gate freemsg(pfkeymp); 13270Sstevel@tonic-gate pfkeymp = NULL; 13280Sstevel@tonic-gate goto done; 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate /* XXX Insert proxy address information here. */ 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate /* XXX Insert identity information here. */ 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate /* XXXMLS Insert sensitivity information here. */ 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* Insert proposal here. */ 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len); 13410Sstevel@tonic-gate esp_insert_prop(prop, acqrec, combs); 13420Sstevel@tonic-gate samsg->sadb_msg_len += prop->sadb_prop_len; 13430Sstevel@tonic-gate msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len); 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate done: 13460Sstevel@tonic-gate mutex_exit(&alg_lock); 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate /* 13490Sstevel@tonic-gate * Must mutex_exit() before sending PF_KEY message up, in 13500Sstevel@tonic-gate * order to avoid recursive mutex_enter() if there are no registered 13510Sstevel@tonic-gate * listeners. 13520Sstevel@tonic-gate * 13530Sstevel@tonic-gate * Once I've sent the message, I'm cool anyway. 13540Sstevel@tonic-gate */ 13550Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 13560Sstevel@tonic-gate if (esp_pfkey_q != NULL && pfkeymp != NULL) { 13570Sstevel@tonic-gate if (extended != NULL) { 13580Sstevel@tonic-gate putnext(esp_pfkey_q, extended); 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate putnext(esp_pfkey_q, pfkeymp); 13610Sstevel@tonic-gate return; 13620Sstevel@tonic-gate } 13630Sstevel@tonic-gate /* XXX freemsg() works for extended == NULL. */ 13640Sstevel@tonic-gate freemsg(extended); 13650Sstevel@tonic-gate freemsg(pfkeymp); 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate /* 13690Sstevel@tonic-gate * Handle the SADB_GETSPI message. Create a larval SA. 13700Sstevel@tonic-gate */ 13710Sstevel@tonic-gate static void 13720Sstevel@tonic-gate esp_getspi(mblk_t *mp, keysock_in_t *ksi) 13730Sstevel@tonic-gate { 13740Sstevel@tonic-gate ipsa_t *newbie, *target; 13750Sstevel@tonic-gate isaf_t *outbound, *inbound; 13760Sstevel@tonic-gate int rc, diagnostic; 13770Sstevel@tonic-gate sadb_sa_t *assoc; 13780Sstevel@tonic-gate keysock_out_t *kso; 13790Sstevel@tonic-gate uint32_t newspi; 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate /* 13820Sstevel@tonic-gate * Randomly generate a proposed SPI value 13830Sstevel@tonic-gate */ 13840Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t)); 13850Sstevel@tonic-gate newbie = sadb_getspi(ksi, newspi, &diagnostic); 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate if (newbie == NULL) { 13880Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic, 13890Sstevel@tonic-gate ksi->ks_in_serial); 13900Sstevel@tonic-gate return; 13910Sstevel@tonic-gate } else if (newbie == (ipsa_t *)-1) { 13920Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic, 13930Sstevel@tonic-gate ksi->ks_in_serial); 13940Sstevel@tonic-gate return; 13950Sstevel@tonic-gate } 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate /* 13980Sstevel@tonic-gate * XXX - We may randomly collide. We really should recover from this. 13990Sstevel@tonic-gate * Unfortunately, that could require spending way-too-much-time 14000Sstevel@tonic-gate * in here. For now, let the user retry. 14010Sstevel@tonic-gate */ 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate if (newbie->ipsa_addrfam == AF_INET6) { 1404564Ssommerfe outbound = OUTBOUND_BUCKET_V6(&esp_sadb.s_v6, 1405564Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 1406564Ssommerfe inbound = INBOUND_BUCKET(&esp_sadb.s_v6, newbie->ipsa_spi); 14070Sstevel@tonic-gate } else { 14080Sstevel@tonic-gate ASSERT(newbie->ipsa_addrfam == AF_INET); 1409564Ssommerfe outbound = OUTBOUND_BUCKET_V4(&esp_sadb.s_v4, 1410564Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 1411564Ssommerfe inbound = INBOUND_BUCKET(&esp_sadb.s_v4, newbie->ipsa_spi); 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate mutex_enter(&outbound->isaf_lock); 14150Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * Check for collisions (i.e. did sadb_getspi() return with something 14190Sstevel@tonic-gate * that already exists?). 14200Sstevel@tonic-gate * 14210Sstevel@tonic-gate * Try outbound first. Even though SADB_GETSPI is traditionally 14220Sstevel@tonic-gate * for inbound SAs, you never know what a user might do. 14230Sstevel@tonic-gate */ 14240Sstevel@tonic-gate target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi, 14250Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam); 14260Sstevel@tonic-gate if (target == NULL) { 14270Sstevel@tonic-gate target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi, 14280Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, 14290Sstevel@tonic-gate newbie->ipsa_addrfam); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate /* 14330Sstevel@tonic-gate * I don't have collisions elsewhere! 14340Sstevel@tonic-gate * (Nor will I because I'm still holding inbound/outbound locks.) 14350Sstevel@tonic-gate */ 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate if (target != NULL) { 14380Sstevel@tonic-gate rc = EEXIST; 14390Sstevel@tonic-gate IPSA_REFRELE(target); 14400Sstevel@tonic-gate } else { 14410Sstevel@tonic-gate /* 14420Sstevel@tonic-gate * sadb_insertassoc() also checks for collisions, so 14430Sstevel@tonic-gate * if there's a colliding entry, rc will be set 14440Sstevel@tonic-gate * to EEXIST. 14450Sstevel@tonic-gate */ 14460Sstevel@tonic-gate rc = sadb_insertassoc(newbie, inbound); 14470Sstevel@tonic-gate (void) drv_getparm(TIME, &newbie->ipsa_hardexpiretime); 14480Sstevel@tonic-gate newbie->ipsa_hardexpiretime += ipsecesp_larval_timeout; 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate /* 14520Sstevel@tonic-gate * Can exit outbound mutex. Hold inbound until we're done 14530Sstevel@tonic-gate * with newbie. 14540Sstevel@tonic-gate */ 14550Sstevel@tonic-gate mutex_exit(&outbound->isaf_lock); 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate if (rc != 0) { 14580Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 14590Sstevel@tonic-gate IPSA_REFRELE(newbie); 14600Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, rc, SADB_X_DIAGNOSTIC_NONE, 14610Sstevel@tonic-gate ksi->ks_in_serial); 14620Sstevel@tonic-gate return; 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate /* Can write here because I'm still holding the bucket lock. */ 14670Sstevel@tonic-gate newbie->ipsa_type = SADB_SATYPE_ESP; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /* 14700Sstevel@tonic-gate * Construct successful return message. We have one thing going 14710Sstevel@tonic-gate * for us in PF_KEY v2. That's the fact that 14720Sstevel@tonic-gate * sizeof (sadb_spirange_t) == sizeof (sadb_sa_t) 14730Sstevel@tonic-gate */ 14740Sstevel@tonic-gate assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE]; 14750Sstevel@tonic-gate assoc->sadb_sa_exttype = SADB_EXT_SA; 14760Sstevel@tonic-gate assoc->sadb_sa_spi = newbie->ipsa_spi; 14770Sstevel@tonic-gate *((uint64_t *)(&assoc->sadb_sa_replay)) = 0; 14780Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate /* Convert KEYSOCK_IN to KEYSOCK_OUT. */ 14810Sstevel@tonic-gate kso = (keysock_out_t *)ksi; 14820Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso); 14830Sstevel@tonic-gate kso->ks_out_serial = ksi->ks_in_serial; 14840Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT; 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate /* 14870Sstevel@tonic-gate * Can safely putnext() to esp_pfkey_q, because this is a turnaround 14880Sstevel@tonic-gate * from the esp_pfkey_q. 14890Sstevel@tonic-gate */ 14900Sstevel@tonic-gate putnext(esp_pfkey_q, mp); 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate /* 14940Sstevel@tonic-gate * Insert the ESP header into a packet. Duplicate an mblk, and insert a newly 14950Sstevel@tonic-gate * allocated mblk with the ESP header in between the two. 14960Sstevel@tonic-gate */ 14970Sstevel@tonic-gate static boolean_t 14980Sstevel@tonic-gate esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint) 14990Sstevel@tonic-gate { 15000Sstevel@tonic-gate mblk_t *split_mp = mp; 15010Sstevel@tonic-gate uint_t wheretodiv = divpoint; 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) { 15040Sstevel@tonic-gate wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr); 15050Sstevel@tonic-gate split_mp = split_mp->b_cont; 15060Sstevel@tonic-gate ASSERT(split_mp != NULL); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) { 15100Sstevel@tonic-gate mblk_t *scratch; 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate /* "scratch" is the 2nd half, split_mp is the first. */ 15130Sstevel@tonic-gate scratch = dupb(split_mp); 15140Sstevel@tonic-gate if (scratch == NULL) { 15150Sstevel@tonic-gate esp1dbg(("esp_insert_esp: can't allocate scratch.\n")); 15160Sstevel@tonic-gate return (B_FALSE); 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate /* NOTE: dupb() doesn't set b_cont appropriately. */ 15190Sstevel@tonic-gate scratch->b_cont = split_mp->b_cont; 15200Sstevel@tonic-gate scratch->b_rptr += wheretodiv; 15210Sstevel@tonic-gate split_mp->b_wptr = split_mp->b_rptr + wheretodiv; 15220Sstevel@tonic-gate split_mp->b_cont = scratch; 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * At this point, split_mp is exactly "wheretodiv" bytes long, and 15260Sstevel@tonic-gate * holds the end of the pre-ESP part of the datagram. 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate esp_mp->b_cont = split_mp->b_cont; 15290Sstevel@tonic-gate split_mp->b_cont = esp_mp; 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate return (B_TRUE); 15320Sstevel@tonic-gate } 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate /* 15350Sstevel@tonic-gate * Finish processing of an inbound ESP packet after processing by the 15360Sstevel@tonic-gate * crypto framework. 15370Sstevel@tonic-gate * - Remove the ESP header. 15380Sstevel@tonic-gate * - Send packet back to IP. 15390Sstevel@tonic-gate * If authentication was performed on the packet, this function is called 15400Sstevel@tonic-gate * only if the authentication succeeded. 15410Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 15420Sstevel@tonic-gate * mblk chain ipsec_in_mp. 15430Sstevel@tonic-gate */ 15440Sstevel@tonic-gate static ipsec_status_t 15450Sstevel@tonic-gate esp_in_done(mblk_t *ipsec_in_mp) 15460Sstevel@tonic-gate { 15470Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 15480Sstevel@tonic-gate mblk_t *data_mp; 15490Sstevel@tonic-gate ipsa_t *assoc; 15500Sstevel@tonic-gate uint_t espstart; 15510Sstevel@tonic-gate uint32_t ivlen = 0; 15520Sstevel@tonic-gate uint_t processed_len; 15530Sstevel@tonic-gate esph_t *esph; 15540Sstevel@tonic-gate kstat_named_t *counter; 15550Sstevel@tonic-gate boolean_t is_natt; 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate assoc = ii->ipsec_in_esp_sa; 15580Sstevel@tonic-gate ASSERT(assoc != NULL); 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate /* get the pointer to the ESP header */ 15630Sstevel@tonic-gate if (assoc->ipsa_encr_alg == SADB_EALG_NULL) { 15640Sstevel@tonic-gate /* authentication-only ESP */ 15650Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset; 15660Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length; 15670Sstevel@tonic-gate } else { 15680Sstevel@tonic-gate /* encryption present */ 15690Sstevel@tonic-gate ivlen = assoc->ipsa_iv_len; 15700Sstevel@tonic-gate if (assoc->ipsa_auth_alg == SADB_AALG_NONE) { 15710Sstevel@tonic-gate /* encryption-only ESP */ 15720Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset - 15730Sstevel@tonic-gate sizeof (esph_t) - assoc->ipsa_iv_len; 15740Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length + 15750Sstevel@tonic-gate ivlen; 15760Sstevel@tonic-gate } else { 15770Sstevel@tonic-gate /* encryption with authentication */ 15780Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_dual_data.dd_offset1; 15790Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_dual_data.dd_len2 + 15800Sstevel@tonic-gate ivlen; 15810Sstevel@tonic-gate } 15820Sstevel@tonic-gate } 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate data_mp = ipsec_in_mp->b_cont; 15850Sstevel@tonic-gate esph = (esph_t *)(data_mp->b_rptr + espstart); 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 15880Sstevel@tonic-gate /* authentication passed if we reach this point */ 15890Sstevel@tonic-gate ESP_BUMP_STAT(good_auth); 15900Sstevel@tonic-gate data_mp->b_wptr -= assoc->ipsa_mac_len; 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate /* 15930Sstevel@tonic-gate * Check replay window here! 15940Sstevel@tonic-gate * For right now, assume keysock will set the replay window 15950Sstevel@tonic-gate * size to zero for SAs that have an unspecified sender. 15960Sstevel@tonic-gate * This may change... 15970Sstevel@tonic-gate */ 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate if (!sadb_replay_check(assoc, esph->esph_replay)) { 16000Sstevel@tonic-gate /* 16010Sstevel@tonic-gate * Log the event. As of now we print out an event. 16020Sstevel@tonic-gate * Do not print the replay failure number, or else 16030Sstevel@tonic-gate * syslog cannot collate the error messages. Printing 16040Sstevel@tonic-gate * the replay number that failed opens a denial-of- 16050Sstevel@tonic-gate * service attack. 16060Sstevel@tonic-gate */ 16070Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 16080Sstevel@tonic-gate SL_ERROR | SL_WARN, 16090Sstevel@tonic-gate "Replay failed for ESP spi 0x%x, dst %s.\n", 16100Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, 16110Sstevel@tonic-gate assoc->ipsa_addrfam); 16120Sstevel@tonic-gate ESP_BUMP_STAT(replay_failures); 16130Sstevel@tonic-gate counter = &ipdrops_esp_replay; 16140Sstevel@tonic-gate goto drop_and_bail; 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate if (!esp_age_bytes(assoc, processed_len, B_TRUE)) { 16190Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 16200Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 16210Sstevel@tonic-gate SL_ERROR | SL_WARN, 16220Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 16230Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 16240Sstevel@tonic-gate ESP_BUMP_STAT(bytes_expired); 16250Sstevel@tonic-gate counter = &ipdrops_esp_bytes_expire; 16260Sstevel@tonic-gate goto drop_and_bail; 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate /* 16300Sstevel@tonic-gate * Remove ESP header and padding from packet. I hope the compiler 16310Sstevel@tonic-gate * spews "branch, predict taken" code for this. 16320Sstevel@tonic-gate */ 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter)) { 16350Sstevel@tonic-gate if (is_natt) 16360Sstevel@tonic-gate return (esp_fix_natt_checksums(data_mp, assoc)); 16370Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate esp1dbg(("esp_in_done: esp_strip_header() failed\n")); 16410Sstevel@tonic-gate drop_and_bail: 16420Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 16430Sstevel@tonic-gate /* 16440Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN message's 16450Sstevel@tonic-gate * ii->ipsec_in_rill_index. 16460Sstevel@tonic-gate */ 16470Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, counter, &esp_dropper); 16480Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate /* 16520Sstevel@tonic-gate * Called upon failing the inbound ICV check. The message passed as 16530Sstevel@tonic-gate * argument is freed. 16540Sstevel@tonic-gate */ 16550Sstevel@tonic-gate static void 16560Sstevel@tonic-gate esp_log_bad_auth(mblk_t *ipsec_in) 16570Sstevel@tonic-gate { 16580Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr; 16590Sstevel@tonic-gate ipsa_t *assoc = ii->ipsec_in_esp_sa; 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate /* 16620Sstevel@tonic-gate * Log the event. Don't print to the console, block 16630Sstevel@tonic-gate * potential denial-of-service attack. 16640Sstevel@tonic-gate */ 16650Sstevel@tonic-gate ESP_BUMP_STAT(bad_auth); 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 16680Sstevel@tonic-gate "ESP Authentication failed for spi 0x%x, dst %s.\n", 16690Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 16720Sstevel@tonic-gate /* 16730Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 16740Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 16750Sstevel@tonic-gate */ 16760Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_esp_bad_auth, 16770Sstevel@tonic-gate &esp_dropper); 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate 16810Sstevel@tonic-gate /* 16820Sstevel@tonic-gate * Invoked for outbound packets after ESP processing. If the packet 16830Sstevel@tonic-gate * also requires AH, performs the AH SA selection and AH processing. 16840Sstevel@tonic-gate * Returns B_TRUE if the AH processing was not needed or if it was 16850Sstevel@tonic-gate * performed successfully. Returns B_FALSE and consumes the passed mblk 16860Sstevel@tonic-gate * if AH processing was required but could not be performed. 16870Sstevel@tonic-gate */ 16880Sstevel@tonic-gate static boolean_t 16890Sstevel@tonic-gate esp_do_outbound_ah(mblk_t *ipsec_mp) 16900Sstevel@tonic-gate { 16910Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 16920Sstevel@tonic-gate ipsec_status_t ipsec_rc; 16930Sstevel@tonic-gate ipsec_action_t *ap; 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate ap = io->ipsec_out_act; 16960Sstevel@tonic-gate if (ap == NULL) { 16970Sstevel@tonic-gate ipsec_policy_t *pp = io->ipsec_out_policy; 16980Sstevel@tonic-gate ap = pp->ipsp_act; 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate if (!ap->ipa_want_ah) 17020Sstevel@tonic-gate return (B_TRUE); 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_done == B_FALSE); 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate if (io->ipsec_out_ah_sa == NULL) { 17070Sstevel@tonic-gate if (!ipsec_outbound_sa(ipsec_mp, IPPROTO_AH)) { 17080Sstevel@tonic-gate sadb_acquire(ipsec_mp, io, B_TRUE, B_FALSE); 17090Sstevel@tonic-gate return (B_FALSE); 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_sa != NULL); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate io->ipsec_out_ah_done = B_TRUE; 17150Sstevel@tonic-gate ipsec_rc = io->ipsec_out_ah_sa->ipsa_output_func(ipsec_mp); 17160Sstevel@tonic-gate return (ipsec_rc == IPSEC_STATUS_SUCCESS); 17170Sstevel@tonic-gate } 17180Sstevel@tonic-gate 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate /* 17210Sstevel@tonic-gate * Kernel crypto framework callback invoked after completion of async 17220Sstevel@tonic-gate * crypto requests. 17230Sstevel@tonic-gate */ 17240Sstevel@tonic-gate static void 17250Sstevel@tonic-gate esp_kcf_callback(void *arg, int status) 17260Sstevel@tonic-gate { 17270Sstevel@tonic-gate mblk_t *ipsec_mp = (mblk_t *)arg; 17280Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 17290Sstevel@tonic-gate boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN); 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL); 17320Sstevel@tonic-gate 17330Sstevel@tonic-gate if (status == CRYPTO_SUCCESS) { 17340Sstevel@tonic-gate if (is_inbound) { 17350Sstevel@tonic-gate if (esp_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) 17360Sstevel@tonic-gate return; 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate /* finish IPsec processing */ 17390Sstevel@tonic-gate ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL); 17400Sstevel@tonic-gate } else { 17410Sstevel@tonic-gate /* 17420Sstevel@tonic-gate * If a ICV was computed, it was stored by the 17430Sstevel@tonic-gate * crypto framework at the end of the packet. 17440Sstevel@tonic-gate */ 17450Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* do AH processing if needed */ 17480Sstevel@tonic-gate if (!esp_do_outbound_ah(ipsec_mp)) 17490Sstevel@tonic-gate return; 17500Sstevel@tonic-gate 17510Sstevel@tonic-gate /* finish IPsec processing */ 17520Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IP_VERSION) { 17530Sstevel@tonic-gate ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, 17540Sstevel@tonic-gate NULL); 17550Sstevel@tonic-gate } else { 17560Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 17570Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h, 17580Sstevel@tonic-gate NULL, NULL); 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate } 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate } else if (status == CRYPTO_INVALID_MAC) { 17630Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate } else { 17660Sstevel@tonic-gate esp1dbg(("esp_kcf_callback: crypto failed with 0x%x\n", 17670Sstevel@tonic-gate status)); 17680Sstevel@tonic-gate ESP_BUMP_STAT(crypto_failures); 17690Sstevel@tonic-gate if (is_inbound) 17700Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 17710Sstevel@tonic-gate else 17720Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 17730Sstevel@tonic-gate ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL, 17740Sstevel@tonic-gate &ipdrops_esp_crypto_failed, &esp_dropper); 17750Sstevel@tonic-gate } 17760Sstevel@tonic-gate } 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate /* 17790Sstevel@tonic-gate * Invoked on crypto framework failure during inbound and outbound processing. 17800Sstevel@tonic-gate */ 17810Sstevel@tonic-gate static void 17820Sstevel@tonic-gate esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc) 17830Sstevel@tonic-gate { 17840Sstevel@tonic-gate esp1dbg(("crypto failed for %s ESP with 0x%x\n", 17850Sstevel@tonic-gate is_inbound ? "inbound" : "outbound", kef_rc)); 17860Sstevel@tonic-gate ip_drop_packet(mp, is_inbound, NULL, NULL, &ipdrops_esp_crypto_failed, 17870Sstevel@tonic-gate &esp_dropper); 17880Sstevel@tonic-gate ESP_BUMP_STAT(crypto_failures); 17890Sstevel@tonic-gate if (is_inbound) 17900Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 17910Sstevel@tonic-gate else 17920Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate #define ESP_INIT_CALLREQ(_cr) { \ 17960Sstevel@tonic-gate (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED; \ 17970Sstevel@tonic-gate (_cr)->cr_callback_arg = ipsec_mp; \ 17980Sstevel@tonic-gate (_cr)->cr_callback_func = esp_kcf_callback; \ 17990Sstevel@tonic-gate } 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate #define ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \ 18020Sstevel@tonic-gate (mac)->cd_format = CRYPTO_DATA_RAW; \ 18030Sstevel@tonic-gate (mac)->cd_offset = 0; \ 18040Sstevel@tonic-gate (mac)->cd_length = icvlen; \ 18050Sstevel@tonic-gate (mac)->cd_raw.iov_base = (char *)icvbuf; \ 18060Sstevel@tonic-gate (mac)->cd_raw.iov_len = icvlen; \ 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate 18090Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DATA(data, mp, off, len) { \ 18100Sstevel@tonic-gate if (MBLKL(mp) >= (len) + (off)) { \ 18110Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_RAW; \ 18120Sstevel@tonic-gate (data)->cd_raw.iov_base = (char *)(mp)->b_rptr; \ 18130Sstevel@tonic-gate (data)->cd_raw.iov_len = MBLKL(mp); \ 18140Sstevel@tonic-gate (data)->cd_offset = off; \ 18150Sstevel@tonic-gate } else { \ 18160Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_MBLK; \ 18170Sstevel@tonic-gate (data)->cd_mp = mp; \ 18180Sstevel@tonic-gate (data)->cd_offset = off; \ 18190Sstevel@tonic-gate } \ 18200Sstevel@tonic-gate (data)->cd_length = len; \ 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate 18230Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) { \ 18240Sstevel@tonic-gate (data)->dd_format = CRYPTO_DATA_MBLK; \ 18250Sstevel@tonic-gate (data)->dd_mp = mp; \ 18260Sstevel@tonic-gate (data)->dd_len1 = len1; \ 18270Sstevel@tonic-gate (data)->dd_offset1 = off1; \ 18280Sstevel@tonic-gate (data)->dd_len2 = len2; \ 18290Sstevel@tonic-gate (data)->dd_offset2 = off2; \ 18300Sstevel@tonic-gate } 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate static ipsec_status_t 18330Sstevel@tonic-gate esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset) 18340Sstevel@tonic-gate { 18350Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 18360Sstevel@tonic-gate boolean_t do_auth; 18370Sstevel@tonic-gate uint_t auth_offset, msg_len, auth_len; 18380Sstevel@tonic-gate crypto_call_req_t call_req; 18390Sstevel@tonic-gate mblk_t *esp_mp; 18400Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 18410Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 18420Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 18430Sstevel@tonic-gate boolean_t do_encr; 18440Sstevel@tonic-gate uint_t encr_offset, encr_len; 18450Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 18460Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate ASSERT(ii->ipsec_in_type == IPSEC_IN); 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 18510Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate /* 18540Sstevel@tonic-gate * An inbound packet is of the form: 18550Sstevel@tonic-gate * IPSEC_IN -> [IP,options,ESP,IV,data,ICV,pad] 18560Sstevel@tonic-gate */ 18570Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont; 18580Sstevel@tonic-gate msg_len = MBLKL(esp_mp); 18590Sstevel@tonic-gate 18600Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate if (do_auth) { 18630Sstevel@tonic-gate /* force asynchronous processing? */ 18640Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 18650Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 18660Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate /* authentication context template */ 18690Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 18700Sstevel@tonic-gate auth_ctx_tmpl); 18710Sstevel@tonic-gate 18720Sstevel@tonic-gate /* ICV to be verified */ 18730Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac, 18740Sstevel@tonic-gate icv_len, esp_mp->b_wptr - icv_len); 18750Sstevel@tonic-gate 18760Sstevel@tonic-gate /* authentication starts at the ESP header */ 18770Sstevel@tonic-gate auth_offset = esph_offset; 18780Sstevel@tonic-gate auth_len = msg_len - auth_offset - icv_len; 18790Sstevel@tonic-gate if (!do_encr) { 18800Sstevel@tonic-gate /* authentication only */ 18810Sstevel@tonic-gate /* initialize input data argument */ 18820Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 18830Sstevel@tonic-gate esp_mp, auth_offset, auth_len); 18840Sstevel@tonic-gate 18850Sstevel@tonic-gate /* call the crypto framework */ 18860Sstevel@tonic-gate kef_rc = crypto_mac_verify(&assoc->ipsa_amech, 18870Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 18880Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 18890Sstevel@tonic-gate &ii->ipsec_in_crypto_mac, &call_req); 18900Sstevel@tonic-gate } 18910Sstevel@tonic-gate } 18920Sstevel@tonic-gate 18930Sstevel@tonic-gate if (do_encr) { 18940Sstevel@tonic-gate /* force asynchronous processing? */ 18950Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 18960Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 18970Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate /* encryption template */ 19000Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 19010Sstevel@tonic-gate encr_ctx_tmpl); 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate /* skip IV, since it is passed separately */ 19040Sstevel@tonic-gate encr_offset = esph_offset + sizeof (esph_t) + iv_len; 19050Sstevel@tonic-gate encr_len = msg_len - encr_offset; 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate if (!do_auth) { 19080Sstevel@tonic-gate /* decryption only */ 19090Sstevel@tonic-gate /* initialize input data argument */ 19100Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 19110Sstevel@tonic-gate esp_mp, encr_offset, encr_len); 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate /* specify IV */ 19140Sstevel@tonic-gate ii->ipsec_in_crypto_data.cd_miscdata = 19150Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 19160Sstevel@tonic-gate esph_offset; 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate /* call the crypto framework */ 19190Sstevel@tonic-gate kef_rc = crypto_decrypt(&assoc->ipsa_emech, 19200Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 19210Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 19220Sstevel@tonic-gate NULL, &call_req); 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate } 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate if (do_auth && do_encr) { 19270Sstevel@tonic-gate /* dual operation */ 19280Sstevel@tonic-gate /* initialize input data argument */ 19290Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&ii->ipsec_in_crypto_dual_data, 19300Sstevel@tonic-gate esp_mp, auth_offset, auth_len, 19310Sstevel@tonic-gate encr_offset, encr_len - icv_len); 19320Sstevel@tonic-gate 19330Sstevel@tonic-gate /* specify IV */ 19340Sstevel@tonic-gate ii->ipsec_in_crypto_dual_data.dd_miscdata = 19350Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate /* call the framework */ 19380Sstevel@tonic-gate kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech, 19390Sstevel@tonic-gate &assoc->ipsa_emech, &ii->ipsec_in_crypto_dual_data, 19400Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey, 19410Sstevel@tonic-gate auth_ctx_tmpl, encr_ctx_tmpl, &ii->ipsec_in_crypto_mac, 19420Sstevel@tonic-gate NULL, &call_req); 19430Sstevel@tonic-gate } 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate switch (kef_rc) { 19460Sstevel@tonic-gate case CRYPTO_SUCCESS: 19470Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 19480Sstevel@tonic-gate return (esp_in_done(ipsec_mp)); 19490Sstevel@tonic-gate case CRYPTO_QUEUED: 19500Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 19510Sstevel@tonic-gate ESP_BUMP_STAT(crypto_async); 19520Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 19530Sstevel@tonic-gate case CRYPTO_INVALID_MAC: 19540Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 19550Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 19560Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 19570Sstevel@tonic-gate } 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc); 19600Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 19610Sstevel@tonic-gate } 19620Sstevel@tonic-gate 19630Sstevel@tonic-gate static ipsec_status_t 19640Sstevel@tonic-gate esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf, 19650Sstevel@tonic-gate uint_t payload_len) 19660Sstevel@tonic-gate { 19670Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 19680Sstevel@tonic-gate uint_t auth_len; 19690Sstevel@tonic-gate crypto_call_req_t call_req; 19700Sstevel@tonic-gate mblk_t *esp_mp; 19710Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 19720Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 19730Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 19740Sstevel@tonic-gate boolean_t do_auth; 19750Sstevel@tonic-gate boolean_t do_encr; 19760Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 19770Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 19780Sstevel@tonic-gate boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 19790Sstevel@tonic-gate size_t esph_offset = (is_natt ? UDPH_SIZE : 0); 19800Sstevel@tonic-gate 19810Sstevel@tonic-gate esp3dbg(("esp_submit_req_outbound:%s", is_natt ? "natt" : "not natt")); 19820Sstevel@tonic-gate 19830Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 19840Sstevel@tonic-gate 19850Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 19860Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 19870Sstevel@tonic-gate 19880Sstevel@tonic-gate /* 19890Sstevel@tonic-gate * Outbound IPsec packets are of the form: 19900Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV] 19910Sstevel@tonic-gate * unless it's NATT, then it's 19920Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV] 19930Sstevel@tonic-gate * Get a pointer to the mblk containing the ESP header. 19940Sstevel@tonic-gate */ 19950Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL && ipsec_mp->b_cont->b_cont != NULL); 19960Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont->b_cont; 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate if (do_auth) { 20010Sstevel@tonic-gate /* force asynchronous processing? */ 20020Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 20030Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 20040Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate /* authentication context template */ 20070Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 20080Sstevel@tonic-gate auth_ctx_tmpl); 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate /* where to store the computed mac */ 20110Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac, 20120Sstevel@tonic-gate icv_len, icv_buf); 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate /* authentication starts at the ESP header */ 2015134Sdanmcd auth_len = payload_len + iv_len + sizeof (esph_t); 20160Sstevel@tonic-gate if (!do_encr) { 20170Sstevel@tonic-gate /* authentication only */ 20180Sstevel@tonic-gate /* initialize input data argument */ 20190Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 20200Sstevel@tonic-gate esp_mp, esph_offset, auth_len); 20210Sstevel@tonic-gate 20220Sstevel@tonic-gate /* call the crypto framework */ 20230Sstevel@tonic-gate kef_rc = crypto_mac(&assoc->ipsa_amech, 20240Sstevel@tonic-gate &io->ipsec_out_crypto_data, 20250Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 20260Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate } 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate if (do_encr) { 20310Sstevel@tonic-gate /* force asynchronous processing? */ 20320Sstevel@tonic-gate if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 20330Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 20340Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate /* encryption context template */ 20370Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 20380Sstevel@tonic-gate encr_ctx_tmpl); 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate if (!do_auth) { 20410Sstevel@tonic-gate /* encryption only, skip mblk that contains ESP hdr */ 20420Sstevel@tonic-gate /* initialize input data argument */ 20430Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 20440Sstevel@tonic-gate esp_mp->b_cont, 0, payload_len); 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate /* specify IV */ 20470Sstevel@tonic-gate io->ipsec_out_crypto_data.cd_miscdata = 20480Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 20490Sstevel@tonic-gate esph_offset; 20500Sstevel@tonic-gate 20510Sstevel@tonic-gate /* call the crypto framework */ 20520Sstevel@tonic-gate kef_rc = crypto_encrypt(&assoc->ipsa_emech, 20530Sstevel@tonic-gate &io->ipsec_out_crypto_data, 20540Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 20550Sstevel@tonic-gate NULL, &call_req); 20560Sstevel@tonic-gate } 20570Sstevel@tonic-gate } 20580Sstevel@tonic-gate 20590Sstevel@tonic-gate if (do_auth && do_encr) { 20600Sstevel@tonic-gate /* 20610Sstevel@tonic-gate * Encryption and authentication: 20620Sstevel@tonic-gate * Pass the pointer to the mblk chain starting at the ESP 20630Sstevel@tonic-gate * header to the framework. Skip the ESP header mblk 20640Sstevel@tonic-gate * for encryption, which is reflected by an encryption 20650Sstevel@tonic-gate * offset equal to the length of that mblk. Start 20660Sstevel@tonic-gate * the authentication at the ESP header, i.e. use an 20670Sstevel@tonic-gate * authentication offset of zero. 20680Sstevel@tonic-gate */ 20690Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&io->ipsec_out_crypto_dual_data, 20700Sstevel@tonic-gate esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len); 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate /* specify IV */ 20730Sstevel@tonic-gate io->ipsec_out_crypto_dual_data.dd_miscdata = 20740Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 20750Sstevel@tonic-gate 20760Sstevel@tonic-gate /* call the framework */ 20770Sstevel@tonic-gate kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech, 20780Sstevel@tonic-gate &assoc->ipsa_amech, NULL, 20790Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey, 20800Sstevel@tonic-gate encr_ctx_tmpl, auth_ctx_tmpl, 20810Sstevel@tonic-gate &io->ipsec_out_crypto_dual_data, 20820Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate switch (kef_rc) { 20860Sstevel@tonic-gate case CRYPTO_SUCCESS: 20870Sstevel@tonic-gate ESP_BUMP_STAT(crypto_sync); 20880Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 20890Sstevel@tonic-gate case CRYPTO_QUEUED: 20900Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 20910Sstevel@tonic-gate ESP_BUMP_STAT(crypto_async); 20920Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc); 20960Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate /* 21000Sstevel@tonic-gate * Handle outbound IPsec processing for IPv4 and IPv6 21010Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 21020Sstevel@tonic-gate * mblk chain ipsec_in_mp. 21030Sstevel@tonic-gate */ 21040Sstevel@tonic-gate static ipsec_status_t 21050Sstevel@tonic-gate esp_outbound(mblk_t *mp) 21060Sstevel@tonic-gate { 21070Sstevel@tonic-gate mblk_t *ipsec_out_mp, *data_mp, *espmp, *tailmp; 21080Sstevel@tonic-gate ipsec_out_t *io; 21090Sstevel@tonic-gate ipha_t *ipha; 21100Sstevel@tonic-gate ip6_t *ip6h; 21110Sstevel@tonic-gate esph_t *esph; 21120Sstevel@tonic-gate uint_t af; 21130Sstevel@tonic-gate uint8_t *nhp; 21140Sstevel@tonic-gate uintptr_t divpoint, datalen, adj, padlen, i, alloclen; 21150Sstevel@tonic-gate uintptr_t esplen = sizeof (esph_t); 21160Sstevel@tonic-gate uint8_t protocol; 21170Sstevel@tonic-gate ipsa_t *assoc; 21180Sstevel@tonic-gate uint_t iv_len = 0, mac_len = 0; 21190Sstevel@tonic-gate uchar_t *icv_buf; 21200Sstevel@tonic-gate udpha_t *udpha; 21210Sstevel@tonic-gate boolean_t is_natt = B_FALSE; 21220Sstevel@tonic-gate 21230Sstevel@tonic-gate ESP_BUMP_STAT(out_requests); 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate ipsec_out_mp = mp; 21260Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate /* 21290Sstevel@tonic-gate * <sigh> We have to copy the message here, because TCP (for example) 21300Sstevel@tonic-gate * keeps a dupb() of the message lying around for retransmission. 21310Sstevel@tonic-gate * Since ESP changes the whole of the datagram, we have to create our 21320Sstevel@tonic-gate * own copy lest we clobber TCP's data. Since we have to copy anyway, 21330Sstevel@tonic-gate * we might as well make use of msgpullup() and get the mblk into one 21340Sstevel@tonic-gate * contiguous piece! 21350Sstevel@tonic-gate */ 21360Sstevel@tonic-gate ipsec_out_mp->b_cont = msgpullup(data_mp, -1); 21370Sstevel@tonic-gate if (ipsec_out_mp->b_cont == NULL) { 21380Sstevel@tonic-gate esp0dbg(("esp_outbound: msgpullup() failed, " 21390Sstevel@tonic-gate "dropping packet.\n")); 21400Sstevel@tonic-gate ipsec_out_mp->b_cont = data_mp; 21410Sstevel@tonic-gate /* 21420Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 21430Sstevel@tonic-gate * pass it to ip_drop_packet(). 21440Sstevel@tonic-gate */ 21450Sstevel@tonic-gate ip_drop_packet(ipsec_out_mp, B_FALSE, NULL, NULL, 21460Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 21470Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 21480Sstevel@tonic-gate } else { 21490Sstevel@tonic-gate freemsg(data_mp); 21500Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 21510Sstevel@tonic-gate } 21520Sstevel@tonic-gate 21530Sstevel@tonic-gate io = (ipsec_out_t *)ipsec_out_mp->b_rptr; 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate /* 21560Sstevel@tonic-gate * Reality check.... 21570Sstevel@tonic-gate */ 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */ 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate if (io->ipsec_out_v4) { 21620Sstevel@tonic-gate af = AF_INET; 21630Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 21640Sstevel@tonic-gate datalen = ntohs(ipha->ipha_length) - divpoint; 21650Sstevel@tonic-gate nhp = (uint8_t *)&ipha->ipha_protocol; 21660Sstevel@tonic-gate } else { 21670Sstevel@tonic-gate ip6_pkt_t ipp; 21680Sstevel@tonic-gate 21690Sstevel@tonic-gate af = AF_INET6; 21700Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 21710Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 21720Sstevel@tonic-gate divpoint = ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 21730Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL && 21740Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) { 21750Sstevel@tonic-gate /* 21760Sstevel@tonic-gate * Destination options are tricky. If we get in here, 21770Sstevel@tonic-gate * then we have a terminal header following the 21780Sstevel@tonic-gate * destination options. We need to adjust backwards 21790Sstevel@tonic-gate * so we insert ESP BEFORE the destination options 21800Sstevel@tonic-gate * bag. (So that the dstopts get encrypted!) 21810Sstevel@tonic-gate * 21820Sstevel@tonic-gate * Since this is for outbound packets only, we know 21830Sstevel@tonic-gate * that non-terminal destination options only precede 21840Sstevel@tonic-gate * routing headers. 21850Sstevel@tonic-gate */ 21860Sstevel@tonic-gate divpoint -= ipp.ipp_dstoptslen; 21870Sstevel@tonic-gate } 21880Sstevel@tonic-gate datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint; 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate if (ipp.ipp_rthdr != NULL) { 21910Sstevel@tonic-gate nhp = &ipp.ipp_rthdr->ip6r_nxt; 21920Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 21930Sstevel@tonic-gate nhp = &ipp.ipp_hopopts->ip6h_nxt; 21940Sstevel@tonic-gate } else { 21950Sstevel@tonic-gate ASSERT(divpoint == sizeof (ip6_t)); 21960Sstevel@tonic-gate /* It's probably IP + ESP. */ 21970Sstevel@tonic-gate nhp = &ip6h->ip6_nxt; 21980Sstevel@tonic-gate } 21990Sstevel@tonic-gate } 22000Sstevel@tonic-gate assoc = io->ipsec_out_esp_sa; 22010Sstevel@tonic-gate ASSERT(assoc != NULL); 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate if (assoc->ipsa_usetime == 0) 22040Sstevel@tonic-gate esp_set_usetime(assoc, B_FALSE); 22050Sstevel@tonic-gate 22060Sstevel@tonic-gate if (assoc->ipsa_auth_alg != SADB_AALG_NONE) 22070Sstevel@tonic-gate mac_len = assoc->ipsa_mac_len; 22080Sstevel@tonic-gate 22090Sstevel@tonic-gate if (assoc->ipsa_flags & IPSA_F_NATT) { 22100Sstevel@tonic-gate /* wedge in fake UDP */ 22110Sstevel@tonic-gate is_natt = B_TRUE; 22120Sstevel@tonic-gate esplen += UDPH_SIZE; 22130Sstevel@tonic-gate } 22140Sstevel@tonic-gate 22150Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) 22160Sstevel@tonic-gate iv_len = assoc->ipsa_iv_len; 2217134Sdanmcd 22180Sstevel@tonic-gate /* 22190Sstevel@tonic-gate * Set up ESP header and encryption padding for ENCR PI request. 22200Sstevel@tonic-gate */ 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate /* 22230Sstevel@tonic-gate * Determine the padding length. Pad to 4-bytes. 22240Sstevel@tonic-gate * 22250Sstevel@tonic-gate * Include the two additional bytes (hence the - 2) for the padding 22260Sstevel@tonic-gate * length and the next header. Take this into account when 22270Sstevel@tonic-gate * calculating the actual length of the padding. 22280Sstevel@tonic-gate */ 22290Sstevel@tonic-gate 22300Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) { 22310Sstevel@tonic-gate padlen = ((unsigned)(iv_len - datalen - 2)) % iv_len; 22320Sstevel@tonic-gate } else { 22330Sstevel@tonic-gate padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) % 22340Sstevel@tonic-gate sizeof (uint32_t); 22350Sstevel@tonic-gate } 22360Sstevel@tonic-gate 22370Sstevel@tonic-gate /* Allocate ESP header and IV. */ 22380Sstevel@tonic-gate esplen += iv_len; 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate /* 22410Sstevel@tonic-gate * Update association byte-count lifetimes. Don't forget to take 22420Sstevel@tonic-gate * into account the padding length and next-header (hence the + 2). 2243134Sdanmcd * 22440Sstevel@tonic-gate * Use the amount of data fed into the "encryption algorithm". This 22450Sstevel@tonic-gate * is the IV, the data length, the padding length, and the final two 22460Sstevel@tonic-gate * bytes (padlen, and next-header). 22470Sstevel@tonic-gate * 22480Sstevel@tonic-gate */ 22490Sstevel@tonic-gate 2250134Sdanmcd if (!esp_age_bytes(assoc, datalen + padlen + iv_len + 2, B_FALSE)) { 22510Sstevel@tonic-gate /* 22520Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 22530Sstevel@tonic-gate * pass it to ip_drop_packet(). 22540Sstevel@tonic-gate */ 22550Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 22560Sstevel@tonic-gate &ipdrops_esp_bytes_expire, &esp_dropper); 22570Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 22580Sstevel@tonic-gate } 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate espmp = allocb(esplen, BPRI_HI); 22610Sstevel@tonic-gate if (espmp == NULL) { 22620Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 22630Sstevel@tonic-gate esp1dbg(("esp_outbound: can't allocate espmp.\n")); 22640Sstevel@tonic-gate /* 22650Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 22660Sstevel@tonic-gate * pass it to ip_drop_packet(). 22670Sstevel@tonic-gate */ 22680Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem, 22690Sstevel@tonic-gate &esp_dropper); 22700Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 22710Sstevel@tonic-gate } 22720Sstevel@tonic-gate espmp->b_wptr += esplen; 22730Sstevel@tonic-gate esph = (esph_t *)espmp->b_rptr; 22740Sstevel@tonic-gate 22750Sstevel@tonic-gate if (is_natt) { 22760Sstevel@tonic-gate esp3dbg(("esp_outbound: NATT")); 22770Sstevel@tonic-gate 22780Sstevel@tonic-gate udpha = (udpha_t *)espmp->b_rptr; 22790Sstevel@tonic-gate udpha->uha_src_port = htons(IPPORT_IKE_NATT); 22800Sstevel@tonic-gate if (assoc->ipsa_remote_port != 0) 22810Sstevel@tonic-gate udpha->uha_dst_port = assoc->ipsa_remote_port; 22820Sstevel@tonic-gate else 22830Sstevel@tonic-gate udpha->uha_dst_port = htons(IPPORT_IKE_NATT); 22840Sstevel@tonic-gate /* 22850Sstevel@tonic-gate * Set the checksum to 0, so that the ip_wput_ipsec_out() 22860Sstevel@tonic-gate * can do the right thing. 22870Sstevel@tonic-gate */ 22880Sstevel@tonic-gate udpha->uha_checksum = 0; 22890Sstevel@tonic-gate esph = (esph_t *)(udpha + 1); 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate esph->esph_spi = assoc->ipsa_spi; 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate esph->esph_replay = htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1)); 22950Sstevel@tonic-gate if (esph->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) { 22960Sstevel@tonic-gate /* 22970Sstevel@tonic-gate * XXX We have replay counter wrapping. 22980Sstevel@tonic-gate * We probably want to nuke this SA (and its peer). 22990Sstevel@tonic-gate */ 23000Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 23010Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 23020Sstevel@tonic-gate "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n", 23030Sstevel@tonic-gate esph->esph_spi, assoc->ipsa_dstaddr, af); 23040Sstevel@tonic-gate 23050Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 23060Sstevel@tonic-gate sadb_replay_delete(assoc); 23070Sstevel@tonic-gate /* 23080Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 23090Sstevel@tonic-gate * pass it to ip_drop_packet(). 23100Sstevel@tonic-gate */ 23110Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_replay, 23120Sstevel@tonic-gate &esp_dropper); 23130Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 23140Sstevel@tonic-gate } 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate /* 23170Sstevel@tonic-gate * Set the IV to a random quantity. We do not require the 23180Sstevel@tonic-gate * highest quality random bits, but for best security with CBC 23190Sstevel@tonic-gate * mode ciphers, the value must be unlikely to repeat and also 23200Sstevel@tonic-gate * must not be known in advance to an adversary capable of 23210Sstevel@tonic-gate * influencing the plaintext. 23220Sstevel@tonic-gate */ 23230Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)(esph + 1), iv_len); 23240Sstevel@tonic-gate 23250Sstevel@tonic-gate /* Fix the IP header. */ 23260Sstevel@tonic-gate alloclen = padlen + 2 + mac_len; 23270Sstevel@tonic-gate adj = alloclen + (espmp->b_wptr - espmp->b_rptr); 23280Sstevel@tonic-gate 23290Sstevel@tonic-gate protocol = *nhp; 23300Sstevel@tonic-gate 23310Sstevel@tonic-gate if (io->ipsec_out_v4) { 23320Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj); 23330Sstevel@tonic-gate if (is_natt) { 23340Sstevel@tonic-gate *nhp = IPPROTO_UDP; 23350Sstevel@tonic-gate udpha->uha_length = htons(ntohs(ipha->ipha_length) - 23360Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 23370Sstevel@tonic-gate } else { 23380Sstevel@tonic-gate *nhp = IPPROTO_ESP; 23390Sstevel@tonic-gate } 23400Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 23410Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 23420Sstevel@tonic-gate } else { 23430Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj); 23440Sstevel@tonic-gate *nhp = IPPROTO_ESP; 23450Sstevel@tonic-gate } 23460Sstevel@tonic-gate 23470Sstevel@tonic-gate /* I've got the two ESP mblks, now insert them. */ 23480Sstevel@tonic-gate 23490Sstevel@tonic-gate esp2dbg(("data_mp before outbound ESP adjustment:\n")); 23500Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 23510Sstevel@tonic-gate 23520Sstevel@tonic-gate if (!esp_insert_esp(data_mp, espmp, divpoint)) { 23530Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 23540Sstevel@tonic-gate /* NOTE: esp_insert_esp() only fails if there's no memory. */ 23550Sstevel@tonic-gate /* 23560Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 23570Sstevel@tonic-gate * pass it to ip_drop_packet(). 23580Sstevel@tonic-gate */ 23590Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem, 23600Sstevel@tonic-gate &esp_dropper); 23610Sstevel@tonic-gate freeb(espmp); 23620Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 23630Sstevel@tonic-gate } 23640Sstevel@tonic-gate 23650Sstevel@tonic-gate /* Append padding (and leave room for ICV). */ 23660Sstevel@tonic-gate for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont) 23670Sstevel@tonic-gate ; 23680Sstevel@tonic-gate if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) { 23690Sstevel@tonic-gate tailmp->b_cont = allocb(alloclen, BPRI_HI); 23700Sstevel@tonic-gate if (tailmp->b_cont == NULL) { 23710Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 23720Sstevel@tonic-gate esp0dbg(("esp_outbound: Can't allocate tailmp.\n")); 23730Sstevel@tonic-gate /* 23740Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 23750Sstevel@tonic-gate * pass it to ip_drop_packet(). 23760Sstevel@tonic-gate */ 23770Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 23780Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 23790Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 23800Sstevel@tonic-gate } 23810Sstevel@tonic-gate tailmp = tailmp->b_cont; 23820Sstevel@tonic-gate } 23830Sstevel@tonic-gate 23840Sstevel@tonic-gate /* 23850Sstevel@tonic-gate * If there's padding, N bytes of padding must be of the form 0x1, 23860Sstevel@tonic-gate * 0x2, 0x3... 0xN. 23870Sstevel@tonic-gate */ 23880Sstevel@tonic-gate for (i = 0; i < padlen; ) { 23890Sstevel@tonic-gate i++; 23900Sstevel@tonic-gate *tailmp->b_wptr++ = i; 23910Sstevel@tonic-gate } 23920Sstevel@tonic-gate *tailmp->b_wptr++ = i; 23930Sstevel@tonic-gate *tailmp->b_wptr++ = protocol; 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate esp2dbg(("data_Mp before encryption:\n")); 23960Sstevel@tonic-gate esp2dbg((dump_msg(data_mp))); 23970Sstevel@tonic-gate 23980Sstevel@tonic-gate /* 23990Sstevel@tonic-gate * The packet is eligible for hardware acceleration if the 24000Sstevel@tonic-gate * following conditions are satisfied: 24010Sstevel@tonic-gate * 24020Sstevel@tonic-gate * 1. the packet will not be fragmented 24030Sstevel@tonic-gate * 2. the provider supports the algorithms specified by SA 24040Sstevel@tonic-gate * 3. there is no pending control message being exchanged 24050Sstevel@tonic-gate * 4. snoop is not attached 24060Sstevel@tonic-gate * 5. the destination address is not a multicast address 24070Sstevel@tonic-gate * 24080Sstevel@tonic-gate * All five of these conditions are checked by IP prior to 24090Sstevel@tonic-gate * sending the packet to ESP. 24100Sstevel@tonic-gate * 24110Sstevel@tonic-gate * But We, and We Alone, can, nay MUST check if the packet 24120Sstevel@tonic-gate * is over NATT, and then disqualify it from hardware 24130Sstevel@tonic-gate * acceleration. 24140Sstevel@tonic-gate */ 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate if (io->ipsec_out_is_capab_ill && !(assoc->ipsa_flags & IPSA_F_NATT)) { 24170Sstevel@tonic-gate return (esp_outbound_accelerated(ipsec_out_mp, mac_len)); 24180Sstevel@tonic-gate } 24190Sstevel@tonic-gate ESP_BUMP_STAT(noaccel); 24200Sstevel@tonic-gate 24210Sstevel@tonic-gate /* 24220Sstevel@tonic-gate * Okay. I've set up the pre-encryption ESP. Let's do it! 24230Sstevel@tonic-gate */ 24240Sstevel@tonic-gate 24250Sstevel@tonic-gate if (mac_len > 0) { 24260Sstevel@tonic-gate ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim); 24270Sstevel@tonic-gate icv_buf = tailmp->b_wptr; 24280Sstevel@tonic-gate tailmp->b_wptr += mac_len; 24290Sstevel@tonic-gate } else { 24300Sstevel@tonic-gate icv_buf = NULL; 24310Sstevel@tonic-gate } 24320Sstevel@tonic-gate 24330Sstevel@tonic-gate return (esp_submit_req_outbound(ipsec_out_mp, assoc, icv_buf, 24340Sstevel@tonic-gate datalen + padlen + 2)); 24350Sstevel@tonic-gate } 24360Sstevel@tonic-gate 24370Sstevel@tonic-gate /* 24380Sstevel@tonic-gate * IP calls this to validate the ICMP errors that 24390Sstevel@tonic-gate * we got from the network. 24400Sstevel@tonic-gate */ 24410Sstevel@tonic-gate ipsec_status_t 24420Sstevel@tonic-gate ipsecesp_icmp_error(mblk_t *ipsec_mp) 24430Sstevel@tonic-gate { 24440Sstevel@tonic-gate /* 24450Sstevel@tonic-gate * Unless we get an entire packet back, this function is useless. 24460Sstevel@tonic-gate * Why? 24470Sstevel@tonic-gate * 24480Sstevel@tonic-gate * 1.) Partial packets are useless, because the "next header" 24490Sstevel@tonic-gate * is at the end of the decrypted ESP packet. Without the 24500Sstevel@tonic-gate * whole packet, this is useless. 24510Sstevel@tonic-gate * 24520Sstevel@tonic-gate * 2.) If we every use a stateful cipher, such as a stream or a 24530Sstevel@tonic-gate * one-time pad, we can't do anything. 24540Sstevel@tonic-gate * 24550Sstevel@tonic-gate * Since the chances of us getting an entire packet back are very 24560Sstevel@tonic-gate * very small, we discard here. 24570Sstevel@tonic-gate */ 24580Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 24590Sstevel@tonic-gate ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_esp_icmp, 24600Sstevel@tonic-gate &esp_dropper); 24610Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 24620Sstevel@tonic-gate } 24630Sstevel@tonic-gate 24640Sstevel@tonic-gate /* 24650Sstevel@tonic-gate * ESP module read put routine. 24660Sstevel@tonic-gate */ 24670Sstevel@tonic-gate /* ARGSUSED */ 24680Sstevel@tonic-gate static void 24690Sstevel@tonic-gate ipsecesp_rput(queue_t *q, mblk_t *mp) 24700Sstevel@tonic-gate { 24710Sstevel@tonic-gate keysock_in_t *ksi; 24720Sstevel@tonic-gate int *addrtype; 24730Sstevel@tonic-gate ire_t *ire; 24740Sstevel@tonic-gate mblk_t *ire_mp, *last_mp; 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate switch (mp->b_datap->db_type) { 24770Sstevel@tonic-gate case M_CTL: 24780Sstevel@tonic-gate /* 24790Sstevel@tonic-gate * IPsec request of some variety from IP. IPSEC_{IN,OUT} 24800Sstevel@tonic-gate * are the common cases, but even ICMP error messages from IP 24810Sstevel@tonic-gate * may rise up here. 24820Sstevel@tonic-gate * 24830Sstevel@tonic-gate * Ummmm, actually, this can also be the reflected KEYSOCK_IN 24840Sstevel@tonic-gate * message, with an IRE_DB_TYPE hung off at the end. 24850Sstevel@tonic-gate */ 24860Sstevel@tonic-gate switch (((ipsec_info_t *)(mp->b_rptr))->ipsec_info_type) { 24870Sstevel@tonic-gate case KEYSOCK_IN: 24880Sstevel@tonic-gate last_mp = mp; 24890Sstevel@tonic-gate while (last_mp->b_cont != NULL && 24900Sstevel@tonic-gate last_mp->b_cont->b_datap->db_type != IRE_DB_TYPE) 24910Sstevel@tonic-gate last_mp = last_mp->b_cont; 24920Sstevel@tonic-gate 24930Sstevel@tonic-gate if (last_mp->b_cont == NULL) { 24940Sstevel@tonic-gate freemsg(mp); 24950Sstevel@tonic-gate break; /* Out of switch. */ 24960Sstevel@tonic-gate } 24970Sstevel@tonic-gate 24980Sstevel@tonic-gate ire_mp = last_mp->b_cont; 24990Sstevel@tonic-gate last_mp->b_cont = NULL; 25000Sstevel@tonic-gate 25010Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 25020Sstevel@tonic-gate 25030Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) 25040Sstevel@tonic-gate addrtype = &ksi->ks_in_srctype; 25050Sstevel@tonic-gate else if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) 25060Sstevel@tonic-gate addrtype = &ksi->ks_in_dsttype; 25070Sstevel@tonic-gate else if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) 25080Sstevel@tonic-gate addrtype = &ksi->ks_in_proxytype; 25090Sstevel@tonic-gate 25100Sstevel@tonic-gate ire = (ire_t *)ire_mp->b_rptr; 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate *addrtype = sadb_addrset(ire); 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate freemsg(ire_mp); 25150Sstevel@tonic-gate if (esp_pfkey_q != NULL) { 25160Sstevel@tonic-gate /* 25170Sstevel@tonic-gate * Decrement counter to make up for 25180Sstevel@tonic-gate * auto-increment in ipsecesp_wput(). 25190Sstevel@tonic-gate * I'm running all MT-hot through here, so 25200Sstevel@tonic-gate * don't worry about perimeters and lateral 25210Sstevel@tonic-gate * puts. 25220Sstevel@tonic-gate */ 25230Sstevel@tonic-gate ESP_DEBUMP_STAT(keysock_in); 25240Sstevel@tonic-gate ipsecesp_wput(WR(esp_pfkey_q), mp); 25250Sstevel@tonic-gate } else { 25260Sstevel@tonic-gate freemsg(mp); 25270Sstevel@tonic-gate } 25280Sstevel@tonic-gate break; 25290Sstevel@tonic-gate default: 25300Sstevel@tonic-gate freemsg(mp); 25310Sstevel@tonic-gate break; 25320Sstevel@tonic-gate } 25330Sstevel@tonic-gate break; 25340Sstevel@tonic-gate case M_PROTO: 25350Sstevel@tonic-gate case M_PCPROTO: 25360Sstevel@tonic-gate /* TPI message of some sort. */ 25370Sstevel@tonic-gate switch (*((t_scalar_t *)mp->b_rptr)) { 25380Sstevel@tonic-gate case T_BIND_ACK: 25390Sstevel@tonic-gate esp3dbg(("Thank you IP from ESP for T_BIND_ACK\n")); 25400Sstevel@tonic-gate break; 25410Sstevel@tonic-gate case T_ERROR_ACK: 25420Sstevel@tonic-gate cmn_err(CE_WARN, 25430Sstevel@tonic-gate "ipsecesp: ESP received T_ERROR_ACK from IP."); 25440Sstevel@tonic-gate /* 25450Sstevel@tonic-gate * Make esp_sadb.s_ip_q NULL, and in the 25460Sstevel@tonic-gate * future, perhaps try again. 25470Sstevel@tonic-gate */ 25480Sstevel@tonic-gate esp_sadb.s_ip_q = NULL; 25490Sstevel@tonic-gate break; 25500Sstevel@tonic-gate case T_OK_ACK: 25510Sstevel@tonic-gate /* Probably from a (rarely sent) T_UNBIND_REQ. */ 25520Sstevel@tonic-gate break; 25530Sstevel@tonic-gate default: 25540Sstevel@tonic-gate esp0dbg(("Unknown M_{,PC}PROTO message.\n")); 25550Sstevel@tonic-gate } 25560Sstevel@tonic-gate freemsg(mp); 25570Sstevel@tonic-gate break; 25580Sstevel@tonic-gate default: 25590Sstevel@tonic-gate /* For now, passthru message. */ 25600Sstevel@tonic-gate esp2dbg(("ESP got unknown mblk type %d.\n", 25610Sstevel@tonic-gate mp->b_datap->db_type)); 25620Sstevel@tonic-gate putnext(q, mp); 25630Sstevel@tonic-gate } 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate 25660Sstevel@tonic-gate /* 25670Sstevel@tonic-gate * Construct an SADB_REGISTER message with the current algorithms. 25680Sstevel@tonic-gate */ 25690Sstevel@tonic-gate static boolean_t 25700Sstevel@tonic-gate esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial) 25710Sstevel@tonic-gate { 25720Sstevel@tonic-gate mblk_t *pfkey_msg_mp, *keysock_out_mp; 25730Sstevel@tonic-gate sadb_msg_t *samsg; 25740Sstevel@tonic-gate sadb_supported_t *sasupp_auth = NULL; 25750Sstevel@tonic-gate sadb_supported_t *sasupp_encr = NULL; 25760Sstevel@tonic-gate sadb_alg_t *saalg; 25770Sstevel@tonic-gate uint_t allocsize = sizeof (*samsg); 25780Sstevel@tonic-gate uint_t i, numalgs_snap; 25790Sstevel@tonic-gate int current_aalgs; 25800Sstevel@tonic-gate ipsec_alginfo_t **authalgs; 25810Sstevel@tonic-gate uint_t num_aalgs; 25820Sstevel@tonic-gate int current_ealgs; 25830Sstevel@tonic-gate ipsec_alginfo_t **encralgs; 25840Sstevel@tonic-gate uint_t num_ealgs; 25850Sstevel@tonic-gate 25860Sstevel@tonic-gate /* Allocate the KEYSOCK_OUT. */ 25870Sstevel@tonic-gate keysock_out_mp = sadb_keysock_out(serial); 25880Sstevel@tonic-gate if (keysock_out_mp == NULL) { 25890Sstevel@tonic-gate esp0dbg(("esp_register_out: couldn't allocate mblk.\n")); 25900Sstevel@tonic-gate return (B_FALSE); 25910Sstevel@tonic-gate } 25920Sstevel@tonic-gate 25930Sstevel@tonic-gate /* 25940Sstevel@tonic-gate * Allocate the PF_KEY message that follows KEYSOCK_OUT. 25950Sstevel@tonic-gate */ 25960Sstevel@tonic-gate 25970Sstevel@tonic-gate mutex_enter(&alg_lock); 25980Sstevel@tonic-gate 25990Sstevel@tonic-gate /* 26000Sstevel@tonic-gate * Fill SADB_REGISTER message's algorithm descriptors. Hold 26010Sstevel@tonic-gate * down the lock while filling it. 26020Sstevel@tonic-gate * 26030Sstevel@tonic-gate * Return only valid algorithms, so the number of algorithms 26040Sstevel@tonic-gate * to send up may be less than the number of algorithm entries 26050Sstevel@tonic-gate * in the table. 26060Sstevel@tonic-gate */ 26070Sstevel@tonic-gate authalgs = ipsec_alglists[IPSEC_ALG_AUTH]; 26080Sstevel@tonic-gate for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 26090Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 26100Sstevel@tonic-gate num_aalgs++; 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate if (num_aalgs != 0) { 26130Sstevel@tonic-gate allocsize += (num_aalgs * sizeof (*saalg)); 26140Sstevel@tonic-gate allocsize += sizeof (*sasupp_auth); 26150Sstevel@tonic-gate } 26160Sstevel@tonic-gate encralgs = ipsec_alglists[IPSEC_ALG_ENCR]; 26170Sstevel@tonic-gate for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 26180Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) 26190Sstevel@tonic-gate num_ealgs++; 26200Sstevel@tonic-gate 26210Sstevel@tonic-gate if (num_ealgs != 0) { 26220Sstevel@tonic-gate allocsize += (num_ealgs * sizeof (*saalg)); 26230Sstevel@tonic-gate allocsize += sizeof (*sasupp_encr); 26240Sstevel@tonic-gate } 26250Sstevel@tonic-gate keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI); 26260Sstevel@tonic-gate if (keysock_out_mp->b_cont == NULL) { 26270Sstevel@tonic-gate mutex_exit(&alg_lock); 26280Sstevel@tonic-gate freemsg(keysock_out_mp); 26290Sstevel@tonic-gate return (B_FALSE); 26300Sstevel@tonic-gate } 26310Sstevel@tonic-gate 26320Sstevel@tonic-gate pfkey_msg_mp = keysock_out_mp->b_cont; 26330Sstevel@tonic-gate pfkey_msg_mp->b_wptr += allocsize; 26340Sstevel@tonic-gate if (num_aalgs != 0) { 26350Sstevel@tonic-gate sasupp_auth = (sadb_supported_t *) 26360Sstevel@tonic-gate (pfkey_msg_mp->b_rptr + sizeof (*samsg)); 26370Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_auth + 1); 26380Sstevel@tonic-gate 26390Sstevel@tonic-gate ASSERT(((ulong_t)saalg & 0x7) == 0); 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate numalgs_snap = 0; 26420Sstevel@tonic-gate for (i = 0; 26430Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); i++) { 26440Sstevel@tonic-gate if (authalgs[i] == NULL || !ALG_VALID(authalgs[i])) 26450Sstevel@tonic-gate continue; 26460Sstevel@tonic-gate 26470Sstevel@tonic-gate saalg->sadb_alg_id = authalgs[i]->alg_id; 26480Sstevel@tonic-gate saalg->sadb_alg_ivlen = 0; 26490Sstevel@tonic-gate saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits; 26500Sstevel@tonic-gate saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits; 26510Sstevel@tonic-gate saalg->sadb_x_alg_defincr = authalgs[i]->alg_ef_default; 26520Sstevel@tonic-gate saalg->sadb_x_alg_increment = 26530Sstevel@tonic-gate authalgs[i]->alg_increment; 26540Sstevel@tonic-gate numalgs_snap++; 26550Sstevel@tonic-gate saalg++; 26560Sstevel@tonic-gate } 26570Sstevel@tonic-gate ASSERT(numalgs_snap == num_aalgs); 26580Sstevel@tonic-gate #ifdef DEBUG 26590Sstevel@tonic-gate /* 26600Sstevel@tonic-gate * Reality check to make sure I snagged all of the 26610Sstevel@tonic-gate * algorithms. 26620Sstevel@tonic-gate */ 26630Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 26640Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) { 26650Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 26660Sstevel@tonic-gate "Missed aalg #%d.\n", i); 26670Sstevel@tonic-gate } 26680Sstevel@tonic-gate } 26690Sstevel@tonic-gate #endif /* DEBUG */ 26700Sstevel@tonic-gate } else { 26710Sstevel@tonic-gate saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg)); 26720Sstevel@tonic-gate } 26730Sstevel@tonic-gate 26740Sstevel@tonic-gate if (num_ealgs != 0) { 26750Sstevel@tonic-gate sasupp_encr = (sadb_supported_t *)saalg; 26760Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_encr + 1); 26770Sstevel@tonic-gate 26780Sstevel@tonic-gate numalgs_snap = 0; 26790Sstevel@tonic-gate for (i = 0; 26800Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) { 26810Sstevel@tonic-gate if (encralgs[i] == NULL || !ALG_VALID(encralgs[i])) 26820Sstevel@tonic-gate continue; 26830Sstevel@tonic-gate saalg->sadb_alg_id = encralgs[i]->alg_id; 26840Sstevel@tonic-gate saalg->sadb_alg_ivlen = encralgs[i]->alg_datalen; 26850Sstevel@tonic-gate saalg->sadb_alg_minbits = encralgs[i]->alg_ef_minbits; 26860Sstevel@tonic-gate saalg->sadb_alg_maxbits = encralgs[i]->alg_ef_maxbits; 26870Sstevel@tonic-gate saalg->sadb_x_alg_defincr = encralgs[i]->alg_ef_default; 26880Sstevel@tonic-gate saalg->sadb_x_alg_increment = 26890Sstevel@tonic-gate encralgs[i]->alg_increment; 26900Sstevel@tonic-gate numalgs_snap++; 26910Sstevel@tonic-gate saalg++; 26920Sstevel@tonic-gate } 26930Sstevel@tonic-gate ASSERT(numalgs_snap == num_ealgs); 26940Sstevel@tonic-gate #ifdef DEBUG 26950Sstevel@tonic-gate /* 26960Sstevel@tonic-gate * Reality check to make sure I snagged all of the 26970Sstevel@tonic-gate * algorithms. 26980Sstevel@tonic-gate */ 26990Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 27000Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) { 27010Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 27020Sstevel@tonic-gate "Missed ealg #%d.\n", i); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate } 27050Sstevel@tonic-gate #endif /* DEBUG */ 27060Sstevel@tonic-gate } 27070Sstevel@tonic-gate 27080Sstevel@tonic-gate current_aalgs = num_aalgs; 27090Sstevel@tonic-gate current_ealgs = num_ealgs; 27100Sstevel@tonic-gate 27110Sstevel@tonic-gate mutex_exit(&alg_lock); 27120Sstevel@tonic-gate 27130Sstevel@tonic-gate /* Now fill the rest of the SADB_REGISTER message. */ 27140Sstevel@tonic-gate 27150Sstevel@tonic-gate samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr; 27160Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2; 27170Sstevel@tonic-gate samsg->sadb_msg_type = SADB_REGISTER; 27180Sstevel@tonic-gate samsg->sadb_msg_errno = 0; 27190Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 27200Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(allocsize); 27210Sstevel@tonic-gate samsg->sadb_msg_reserved = 0; 27220Sstevel@tonic-gate /* 27230Sstevel@tonic-gate * Assume caller has sufficient sequence/pid number info. If it's one 27240Sstevel@tonic-gate * from me over a new alg., I could give two hoots about sequence. 27250Sstevel@tonic-gate */ 27260Sstevel@tonic-gate samsg->sadb_msg_seq = sequence; 27270Sstevel@tonic-gate samsg->sadb_msg_pid = pid; 27280Sstevel@tonic-gate 27290Sstevel@tonic-gate if (sasupp_auth != NULL) { 27300Sstevel@tonic-gate sasupp_auth->sadb_supported_len = 27310Sstevel@tonic-gate SADB_8TO64(sizeof (*sasupp_auth) + 27320Sstevel@tonic-gate sizeof (*saalg) * current_aalgs); 27330Sstevel@tonic-gate sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 27340Sstevel@tonic-gate sasupp_auth->sadb_supported_reserved = 0; 27350Sstevel@tonic-gate } 27360Sstevel@tonic-gate 27370Sstevel@tonic-gate if (sasupp_encr != NULL) { 27380Sstevel@tonic-gate sasupp_encr->sadb_supported_len = 27390Sstevel@tonic-gate SADB_8TO64(sizeof (*sasupp_encr) + 27400Sstevel@tonic-gate sizeof (*saalg) * current_ealgs); 27410Sstevel@tonic-gate sasupp_encr->sadb_supported_exttype = 27420Sstevel@tonic-gate SADB_EXT_SUPPORTED_ENCRYPT; 27430Sstevel@tonic-gate sasupp_encr->sadb_supported_reserved = 0; 27440Sstevel@tonic-gate } 27450Sstevel@tonic-gate 27460Sstevel@tonic-gate if (esp_pfkey_q != NULL) 27470Sstevel@tonic-gate putnext(esp_pfkey_q, keysock_out_mp); 27480Sstevel@tonic-gate else { 27490Sstevel@tonic-gate freemsg(keysock_out_mp); 27500Sstevel@tonic-gate return (B_FALSE); 27510Sstevel@tonic-gate } 27520Sstevel@tonic-gate 27530Sstevel@tonic-gate return (B_TRUE); 27540Sstevel@tonic-gate } 27550Sstevel@tonic-gate 27560Sstevel@tonic-gate /* 27570Sstevel@tonic-gate * Invoked when the algorithm table changes. Causes SADB_REGISTER 27580Sstevel@tonic-gate * messages continaining the current list of algorithms to be 27590Sstevel@tonic-gate * sent up to the ESP listeners. 27600Sstevel@tonic-gate */ 27610Sstevel@tonic-gate void 27620Sstevel@tonic-gate ipsecesp_algs_changed(void) 27630Sstevel@tonic-gate { 27640Sstevel@tonic-gate /* 27650Sstevel@tonic-gate * Time to send a PF_KEY SADB_REGISTER message to ESP listeners 27660Sstevel@tonic-gate * everywhere. (The function itself checks for NULL esp_pfkey_q.) 27670Sstevel@tonic-gate */ 27680Sstevel@tonic-gate (void) esp_register_out(0, 0, 0); 27690Sstevel@tonic-gate } 27700Sstevel@tonic-gate 27710Sstevel@tonic-gate /* 27720Sstevel@tonic-gate * taskq_dispatch handler. 27730Sstevel@tonic-gate */ 27740Sstevel@tonic-gate static void 27750Sstevel@tonic-gate inbound_task(void *arg) 27760Sstevel@tonic-gate { 27770Sstevel@tonic-gate esph_t *esph; 27780Sstevel@tonic-gate mblk_t *mp = (mblk_t *)arg; 27790Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr; 27800Sstevel@tonic-gate int ipsec_rc; 27810Sstevel@tonic-gate 27820Sstevel@tonic-gate esp2dbg(("in ESP inbound_task")); 27830Sstevel@tonic-gate 27840Sstevel@tonic-gate esph = ipsec_inbound_esp_sa(mp); 27850Sstevel@tonic-gate if (esph == NULL) 27860Sstevel@tonic-gate return; 27870Sstevel@tonic-gate ASSERT(ii->ipsec_in_esp_sa != NULL); 27880Sstevel@tonic-gate ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(mp, esph); 27890Sstevel@tonic-gate if (ipsec_rc != IPSEC_STATUS_SUCCESS) 27900Sstevel@tonic-gate return; 27910Sstevel@tonic-gate ip_fanout_proto_again(mp, NULL, NULL, NULL); 27920Sstevel@tonic-gate } 27930Sstevel@tonic-gate 27940Sstevel@tonic-gate /* 27950Sstevel@tonic-gate * Now that weak-key passed, actually ADD the security association, and 27960Sstevel@tonic-gate * send back a reply ADD message. 27970Sstevel@tonic-gate */ 27980Sstevel@tonic-gate static int 27990Sstevel@tonic-gate esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi) 28000Sstevel@tonic-gate { 2801691Ssommerfe isaf_t *primary, *secondary, *inbound, *outbound; 28020Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 28030Sstevel@tonic-gate sadb_address_t *dstext = 28040Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 28050Sstevel@tonic-gate struct sockaddr_in *dst; 28060Sstevel@tonic-gate struct sockaddr_in6 *dst6; 28070Sstevel@tonic-gate boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE; 28080Sstevel@tonic-gate uint32_t *dstaddr; 28090Sstevel@tonic-gate ipsa_t *larval = NULL; 28100Sstevel@tonic-gate ipsacq_t *acqrec; 28110Sstevel@tonic-gate iacqf_t *acq_bucket; 28120Sstevel@tonic-gate mblk_t *acq_msgs = NULL; 28130Sstevel@tonic-gate int rc; 28140Sstevel@tonic-gate sadb_t *sp; 28150Sstevel@tonic-gate int outhash; 28160Sstevel@tonic-gate mblk_t *lpkt; 28170Sstevel@tonic-gate 28180Sstevel@tonic-gate /* 28190Sstevel@tonic-gate * Locate the appropriate table(s). 28200Sstevel@tonic-gate */ 28210Sstevel@tonic-gate 28220Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 28230Sstevel@tonic-gate dst6 = (struct sockaddr_in6 *)dst; 28240Sstevel@tonic-gate is_ipv4 = (dst->sin_family == AF_INET); 28250Sstevel@tonic-gate if (is_ipv4) { 28260Sstevel@tonic-gate sp = &esp_sadb.s_v4; 28270Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst->sin_addr); 2828564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr); 28290Sstevel@tonic-gate } else { 28300Sstevel@tonic-gate sp = &esp_sadb.s_v6; 28310Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst6->sin6_addr); 2832564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr); 28330Sstevel@tonic-gate } 2834691Ssommerfe 2835564Ssommerfe inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi); 2836691Ssommerfe outbound = &sp->sdb_of[outhash]; 2837691Ssommerfe 28380Sstevel@tonic-gate switch (ksi->ks_in_dsttype) { 28390Sstevel@tonic-gate case KS_IN_ADDR_MBCAST: 28400Sstevel@tonic-gate clone = B_TRUE; /* All mcast SAs can be bidirectional */ 28410Sstevel@tonic-gate /* FALLTHRU */ 28420Sstevel@tonic-gate case KS_IN_ADDR_ME: 28430Sstevel@tonic-gate primary = inbound; 2844691Ssommerfe secondary = outbound; 28450Sstevel@tonic-gate /* 28460Sstevel@tonic-gate * If the source address is either one of mine, or unspecified 28470Sstevel@tonic-gate * (which is best summed up by saying "not 'not mine'"), 28480Sstevel@tonic-gate * then the association is potentially bi-directional, 28490Sstevel@tonic-gate * in that it can be used for inbound traffic and outbound 28500Sstevel@tonic-gate * traffic. The best example of such an SA is a multicast 28510Sstevel@tonic-gate * SA (which allows me to receive the outbound traffic). 28520Sstevel@tonic-gate */ 28530Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME) 28540Sstevel@tonic-gate clone = B_TRUE; 28550Sstevel@tonic-gate is_inbound = B_TRUE; 28560Sstevel@tonic-gate break; 28570Sstevel@tonic-gate case KS_IN_ADDR_NOTME: 2858691Ssommerfe primary = outbound; 28590Sstevel@tonic-gate secondary = inbound; 28600Sstevel@tonic-gate /* 28610Sstevel@tonic-gate * If the source address literally not mine (either 28620Sstevel@tonic-gate * unspecified or not mine), then this SA may have an 28630Sstevel@tonic-gate * address that WILL be mine after some configuration. 28640Sstevel@tonic-gate * We pay the price for this by making it a bi-directional 28650Sstevel@tonic-gate * SA. 28660Sstevel@tonic-gate */ 28670Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_ME) 28680Sstevel@tonic-gate clone = B_TRUE; 28690Sstevel@tonic-gate break; 28700Sstevel@tonic-gate default: 28710Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 28720Sstevel@tonic-gate return (EINVAL); 28730Sstevel@tonic-gate } 28740Sstevel@tonic-gate 28750Sstevel@tonic-gate /* 28760Sstevel@tonic-gate * Find a ACQUIRE list entry if possible. If we've added an SA that 28770Sstevel@tonic-gate * suits the needs of an ACQUIRE list entry, we can eliminate the 28780Sstevel@tonic-gate * ACQUIRE list entry and transmit the enqueued packets. Use the 28790Sstevel@tonic-gate * high-bit of the sequence number to queue it. Key off destination 28800Sstevel@tonic-gate * addr, and change acqrec's state. 28810Sstevel@tonic-gate */ 28820Sstevel@tonic-gate 28830Sstevel@tonic-gate if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) { 28840Sstevel@tonic-gate acq_bucket = &sp->sdb_acq[outhash]; 28850Sstevel@tonic-gate mutex_enter(&acq_bucket->iacqf_lock); 28860Sstevel@tonic-gate for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL; 28870Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) { 28880Sstevel@tonic-gate mutex_enter(&acqrec->ipsacq_lock); 28890Sstevel@tonic-gate /* 28900Sstevel@tonic-gate * Q: I only check sequence. Should I check dst? 28910Sstevel@tonic-gate * A: Yes, check dest because those are the packets 28920Sstevel@tonic-gate * that are queued up. 28930Sstevel@tonic-gate */ 28940Sstevel@tonic-gate if (acqrec->ipsacq_seq == samsg->sadb_msg_seq && 28950Sstevel@tonic-gate IPSA_ARE_ADDR_EQUAL(dstaddr, 28960Sstevel@tonic-gate acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam)) 28970Sstevel@tonic-gate break; 28980Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 28990Sstevel@tonic-gate } 29000Sstevel@tonic-gate if (acqrec != NULL) { 29010Sstevel@tonic-gate /* 29020Sstevel@tonic-gate * AHA! I found an ACQUIRE record for this SA. 29030Sstevel@tonic-gate * Grab the msg list, and free the acquire record. 29040Sstevel@tonic-gate * I already am holding the lock for this record, 29050Sstevel@tonic-gate * so all I have to do is free it. 29060Sstevel@tonic-gate */ 29070Sstevel@tonic-gate acq_msgs = acqrec->ipsacq_mp; 29080Sstevel@tonic-gate acqrec->ipsacq_mp = NULL; 29090Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 29100Sstevel@tonic-gate sadb_destroy_acquire(acqrec); 29110Sstevel@tonic-gate } 29120Sstevel@tonic-gate mutex_exit(&acq_bucket->iacqf_lock); 29130Sstevel@tonic-gate } 29140Sstevel@tonic-gate 29150Sstevel@tonic-gate /* 29160Sstevel@tonic-gate * Find PF_KEY message, and see if I'm an update. If so, find entry 29170Sstevel@tonic-gate * in larval list (if there). 29180Sstevel@tonic-gate */ 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_UPDATE) { 29210Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 29220Sstevel@tonic-gate larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi, 29230Sstevel@tonic-gate ALL_ZEROES_PTR, dstaddr, dst->sin_family); 29240Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 29250Sstevel@tonic-gate 29260Sstevel@tonic-gate if (larval == NULL) { 29270Sstevel@tonic-gate esp0dbg(("Larval update, but larval disappeared.\n")); 29280Sstevel@tonic-gate return (ESRCH); 29290Sstevel@tonic-gate } /* Else sadb_common_add unlinks it for me! */ 29300Sstevel@tonic-gate } 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate lpkt = NULL; 29330Sstevel@tonic-gate if (larval != NULL) 29340Sstevel@tonic-gate lpkt = sadb_clear_lpkt(larval); 29350Sstevel@tonic-gate 29360Sstevel@tonic-gate rc = sadb_common_add(esp_sadb.s_ip_q, esp_pfkey_q, mp, samsg, ksi, 29370Sstevel@tonic-gate primary, secondary, larval, clone, is_inbound); 29380Sstevel@tonic-gate 29390Sstevel@tonic-gate if (rc == 0 && lpkt != NULL) { 29400Sstevel@tonic-gate rc = !taskq_dispatch(esp_taskq, inbound_task, 29410Sstevel@tonic-gate (void *) lpkt, TQ_NOSLEEP); 29420Sstevel@tonic-gate } 29430Sstevel@tonic-gate 29440Sstevel@tonic-gate if (rc != 0) { 29450Sstevel@tonic-gate ip_drop_packet(lpkt, B_TRUE, NULL, NULL, 29460Sstevel@tonic-gate &ipdrops_sadb_inlarval_timeout, &esp_dropper); 29470Sstevel@tonic-gate } 29480Sstevel@tonic-gate 29490Sstevel@tonic-gate /* 29500Sstevel@tonic-gate * How much more stack will I create with all of these 29510Sstevel@tonic-gate * esp_outbound() calls? 29520Sstevel@tonic-gate */ 29530Sstevel@tonic-gate 29540Sstevel@tonic-gate while (acq_msgs != NULL) { 29550Sstevel@tonic-gate mblk_t *mp = acq_msgs; 29560Sstevel@tonic-gate 29570Sstevel@tonic-gate acq_msgs = acq_msgs->b_next; 29580Sstevel@tonic-gate mp->b_next = NULL; 29590Sstevel@tonic-gate if (rc == 0) { 29600Sstevel@tonic-gate if (ipsec_outbound_sa(mp, IPPROTO_ESP)) { 29610Sstevel@tonic-gate ((ipsec_out_t *)(mp->b_rptr))-> 29620Sstevel@tonic-gate ipsec_out_esp_done = B_TRUE; 29630Sstevel@tonic-gate if (esp_outbound(mp) == IPSEC_STATUS_SUCCESS) { 29640Sstevel@tonic-gate ipha_t *ipha = (ipha_t *) 29650Sstevel@tonic-gate mp->b_cont->b_rptr; 29660Sstevel@tonic-gate 29670Sstevel@tonic-gate /* do AH processing if needed */ 29680Sstevel@tonic-gate if (!esp_do_outbound_ah(mp)) 29690Sstevel@tonic-gate continue; 29700Sstevel@tonic-gate 29710Sstevel@tonic-gate /* finish IPsec processing */ 29720Sstevel@tonic-gate if (is_ipv4) { 29730Sstevel@tonic-gate ip_wput_ipsec_out(NULL, mp, 29740Sstevel@tonic-gate ipha, NULL, NULL); 29750Sstevel@tonic-gate } else { 29760Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 29770Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, 29780Sstevel@tonic-gate mp, ip6h, NULL, NULL); 29790Sstevel@tonic-gate } 29800Sstevel@tonic-gate } 29810Sstevel@tonic-gate continue; 29820Sstevel@tonic-gate } 29830Sstevel@tonic-gate } 29840Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 29850Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 29860Sstevel@tonic-gate &ipdrops_sadb_acquire_timeout, &esp_dropper); 29870Sstevel@tonic-gate } 29880Sstevel@tonic-gate 29890Sstevel@tonic-gate return (rc); 29900Sstevel@tonic-gate } 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate /* 29930Sstevel@tonic-gate * Add new ESP security association. This may become a generic AH/ESP 29940Sstevel@tonic-gate * routine eventually. 29950Sstevel@tonic-gate */ 29960Sstevel@tonic-gate static int 29970Sstevel@tonic-gate esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 29980Sstevel@tonic-gate { 29990Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 30000Sstevel@tonic-gate sadb_address_t *srcext = 30010Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 30020Sstevel@tonic-gate sadb_address_t *dstext = 30030Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 30040Sstevel@tonic-gate sadb_address_t *nttext_loc = 30050Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC]; 30060Sstevel@tonic-gate sadb_address_t *nttext_rem = 30070Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM]; 30080Sstevel@tonic-gate sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH]; 30090Sstevel@tonic-gate sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT]; 30100Sstevel@tonic-gate struct sockaddr_in *src, *dst; 30110Sstevel@tonic-gate struct sockaddr_in *natt_loc, *natt_rem; 30120Sstevel@tonic-gate struct sockaddr_in6 *natt_loc6, *natt_rem6; 30130Sstevel@tonic-gate 30140Sstevel@tonic-gate sadb_lifetime_t *soft = 30150Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT]; 30160Sstevel@tonic-gate sadb_lifetime_t *hard = 30170Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD]; 30180Sstevel@tonic-gate 30190Sstevel@tonic-gate /* I need certain extensions present for an ADD message. */ 30200Sstevel@tonic-gate if (srcext == NULL) { 30210Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC; 30220Sstevel@tonic-gate return (EINVAL); 30230Sstevel@tonic-gate } 30240Sstevel@tonic-gate if (dstext == NULL) { 30250Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 30260Sstevel@tonic-gate return (EINVAL); 30270Sstevel@tonic-gate } 30280Sstevel@tonic-gate if (assoc == NULL) { 30290Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 30300Sstevel@tonic-gate return (EINVAL); 30310Sstevel@tonic-gate } 30320Sstevel@tonic-gate if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) { 30330Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY; 30340Sstevel@tonic-gate return (EINVAL); 30350Sstevel@tonic-gate } 30360Sstevel@tonic-gate 30370Sstevel@tonic-gate src = (struct sockaddr_in *)(srcext + 1); 30380Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 30390Sstevel@tonic-gate natt_loc = (struct sockaddr_in *)(nttext_loc + 1); 30400Sstevel@tonic-gate natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1); 30410Sstevel@tonic-gate natt_rem = (struct sockaddr_in *)(nttext_rem + 1); 30420Sstevel@tonic-gate natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1); 30430Sstevel@tonic-gate 30440Sstevel@tonic-gate /* Sundry ADD-specific reality checks. */ 30450Sstevel@tonic-gate /* XXX STATS : Logging/stats here? */ 30460Sstevel@tonic-gate if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) { 30470Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE; 30480Sstevel@tonic-gate return (EINVAL); 30490Sstevel@tonic-gate } 30500Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) { 30510Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 30520Sstevel@tonic-gate return (EINVAL); 30530Sstevel@tonic-gate } 30540Sstevel@tonic-gate 30550Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NULL && 30560Sstevel@tonic-gate assoc->sadb_sa_auth == SADB_AALG_NONE) { 30570Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 30580Sstevel@tonic-gate return (EINVAL); 30590Sstevel@tonic-gate } 30600Sstevel@tonic-gate 30610Sstevel@tonic-gate if (assoc->sadb_sa_flags & ~(SADB_SAFLAGS_NOREPLAY | 30620Sstevel@tonic-gate SADB_X_SAFLAGS_NATT_LOC | SADB_X_SAFLAGS_NATT_REM)) { 30630Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS; 30640Sstevel@tonic-gate return (EINVAL); 30650Sstevel@tonic-gate } 30660Sstevel@tonic-gate 30670Sstevel@tonic-gate if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) { 30680Sstevel@tonic-gate return (EINVAL); 30690Sstevel@tonic-gate } 30700Sstevel@tonic-gate if (src->sin_family != dst->sin_family) { 30710Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH; 30720Sstevel@tonic-gate return (EINVAL); 30730Sstevel@tonic-gate } 30740Sstevel@tonic-gate 30750Sstevel@tonic-gate 30760Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) { 30770Sstevel@tonic-gate if (nttext_loc == NULL) { 30780Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC; 30790Sstevel@tonic-gate return (EINVAL); 30800Sstevel@tonic-gate } 30810Sstevel@tonic-gate 30820Sstevel@tonic-gate if (natt_loc->sin_family == AF_INET6 && 30830Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) { 30840Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC; 30850Sstevel@tonic-gate return (EINVAL); 30860Sstevel@tonic-gate } 30870Sstevel@tonic-gate } 30880Sstevel@tonic-gate 30890Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) { 30900Sstevel@tonic-gate if (nttext_rem == NULL) { 30910Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM; 30920Sstevel@tonic-gate return (EINVAL); 30930Sstevel@tonic-gate } 30940Sstevel@tonic-gate if (natt_rem->sin_family == AF_INET6 && 30950Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) { 30960Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM; 30970Sstevel@tonic-gate return (EINVAL); 30980Sstevel@tonic-gate } 30990Sstevel@tonic-gate } 31000Sstevel@tonic-gate 31010Sstevel@tonic-gate 31020Sstevel@tonic-gate /* Stuff I don't support, for now. XXX Diagnostic? */ 31030Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL || 31040Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) 31050Sstevel@tonic-gate return (EOPNOTSUPP); 31060Sstevel@tonic-gate 31070Sstevel@tonic-gate /* 31080Sstevel@tonic-gate * XXX Policy : I'm not checking identities or sensitivity 31090Sstevel@tonic-gate * labels at this time, but if I did, I'd do them here, before I sent 31100Sstevel@tonic-gate * the weak key check up to the algorithm. 31110Sstevel@tonic-gate */ 31120Sstevel@tonic-gate 31130Sstevel@tonic-gate mutex_enter(&alg_lock); 31140Sstevel@tonic-gate 31150Sstevel@tonic-gate /* 31160Sstevel@tonic-gate * First locate the authentication algorithm. 31170Sstevel@tonic-gate */ 31180Sstevel@tonic-gate if (akey != NULL) { 31190Sstevel@tonic-gate ipsec_alginfo_t *aalg; 31200Sstevel@tonic-gate 31210Sstevel@tonic-gate aalg = ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth]; 31220Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) { 31230Sstevel@tonic-gate mutex_exit(&alg_lock); 31240Sstevel@tonic-gate esp1dbg(("Couldn't find auth alg #%d.\n", 31250Sstevel@tonic-gate assoc->sadb_sa_auth)); 31260Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 31270Sstevel@tonic-gate return (EINVAL); 31280Sstevel@tonic-gate } 3129*2810Smarkfen 3130*2810Smarkfen /* 3131*2810Smarkfen * Sanity check key sizes. 3132*2810Smarkfen * Note: It's not possible to use SADB_AALG_NONE because 3133*2810Smarkfen * this auth_alg is not defined with ALG_FLAG_VALID. If this 3134*2810Smarkfen * ever changes, the same check for SADB_AALG_NONE and 3135*2810Smarkfen * a auth_key != NULL should be made here ( see below). 3136*2810Smarkfen */ 31370Sstevel@tonic-gate if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) { 31380Sstevel@tonic-gate mutex_exit(&alg_lock); 31390Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS; 31400Sstevel@tonic-gate return (EINVAL); 31410Sstevel@tonic-gate } 3142*2810Smarkfen ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 31430Sstevel@tonic-gate 31440Sstevel@tonic-gate /* check key and fix parity if needed */ 31450Sstevel@tonic-gate if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE, 31460Sstevel@tonic-gate diagnostic) != 0) { 31470Sstevel@tonic-gate mutex_exit(&alg_lock); 31480Sstevel@tonic-gate return (EINVAL); 31490Sstevel@tonic-gate } 31500Sstevel@tonic-gate } 31510Sstevel@tonic-gate 31520Sstevel@tonic-gate /* 31530Sstevel@tonic-gate * Then locate the encryption algorithm. 31540Sstevel@tonic-gate */ 31550Sstevel@tonic-gate if (ekey != NULL) { 31560Sstevel@tonic-gate ipsec_alginfo_t *ealg; 31570Sstevel@tonic-gate 31580Sstevel@tonic-gate ealg = ipsec_alglists[IPSEC_ALG_ENCR][assoc->sadb_sa_encrypt]; 31590Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) { 31600Sstevel@tonic-gate mutex_exit(&alg_lock); 31610Sstevel@tonic-gate esp1dbg(("Couldn't find encr alg #%d.\n", 31620Sstevel@tonic-gate assoc->sadb_sa_encrypt)); 31630Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 31640Sstevel@tonic-gate return (EINVAL); 31650Sstevel@tonic-gate } 3166*2810Smarkfen 3167*2810Smarkfen /* 3168*2810Smarkfen * Sanity check key sizes. If the encryption algorithm is 3169*2810Smarkfen * SADB_EALG_NULL but the encryption key is NOT 3170*2810Smarkfen * NULL then complain. 3171*2810Smarkfen */ 3172*2810Smarkfen if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) || 3173*2810Smarkfen (!ipsec_valid_key_size(ekey->sadb_key_bits, ealg))) { 31740Sstevel@tonic-gate mutex_exit(&alg_lock); 31750Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS; 31760Sstevel@tonic-gate return (EINVAL); 31770Sstevel@tonic-gate } 3178*2810Smarkfen ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 31790Sstevel@tonic-gate 31800Sstevel@tonic-gate /* check key */ 31810Sstevel@tonic-gate if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE, 31820Sstevel@tonic-gate diagnostic) != 0) { 31830Sstevel@tonic-gate mutex_exit(&alg_lock); 31840Sstevel@tonic-gate return (EINVAL); 31850Sstevel@tonic-gate } 31860Sstevel@tonic-gate } 31870Sstevel@tonic-gate mutex_exit(&alg_lock); 31880Sstevel@tonic-gate 31890Sstevel@tonic-gate return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi)); 31900Sstevel@tonic-gate } 31910Sstevel@tonic-gate 31920Sstevel@tonic-gate /* 31930Sstevel@tonic-gate * Update a security association. Updates come in two varieties. The first 31940Sstevel@tonic-gate * is an update of lifetimes on a non-larval SA. The second is an update of 31950Sstevel@tonic-gate * a larval SA, which ends up looking a lot more like an add. 31960Sstevel@tonic-gate */ 31970Sstevel@tonic-gate static int 31980Sstevel@tonic-gate esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 31990Sstevel@tonic-gate { 32000Sstevel@tonic-gate sadb_address_t *dstext = 32010Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 32020Sstevel@tonic-gate struct sockaddr_in *sin; 32030Sstevel@tonic-gate 32040Sstevel@tonic-gate if (dstext == NULL) { 32050Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 32060Sstevel@tonic-gate return (EINVAL); 32070Sstevel@tonic-gate } 32080Sstevel@tonic-gate 32090Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 32100Sstevel@tonic-gate return (sadb_update_sa(mp, ksi, 32110Sstevel@tonic-gate (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 : &esp_sadb.s_v4, 32120Sstevel@tonic-gate diagnostic, esp_pfkey_q, esp_add_sa)); 32130Sstevel@tonic-gate } 32140Sstevel@tonic-gate 32150Sstevel@tonic-gate /* 32160Sstevel@tonic-gate * Delete a security association. This is REALLY likely to be code common to 32170Sstevel@tonic-gate * both AH and ESP. Find the association, then unlink it. 32180Sstevel@tonic-gate */ 32190Sstevel@tonic-gate static int 32200Sstevel@tonic-gate esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 32210Sstevel@tonic-gate { 32220Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 32230Sstevel@tonic-gate sadb_address_t *dstext = 32240Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 32250Sstevel@tonic-gate sadb_address_t *srcext = 32260Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 32270Sstevel@tonic-gate struct sockaddr_in *sin; 32280Sstevel@tonic-gate 32290Sstevel@tonic-gate if (assoc == NULL) { 32300Sstevel@tonic-gate if (dstext != NULL) { 32310Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 32320Sstevel@tonic-gate } else if (srcext != NULL) { 32330Sstevel@tonic-gate sin = (struct sockaddr_in *)(srcext + 1); 32340Sstevel@tonic-gate } else { 32350Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 32360Sstevel@tonic-gate return (EINVAL); 32370Sstevel@tonic-gate } 32380Sstevel@tonic-gate return sadb_purge_sa(mp, ksi, 32390Sstevel@tonic-gate (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 : 32400Sstevel@tonic-gate &esp_sadb.s_v4, 32410Sstevel@tonic-gate diagnostic, esp_pfkey_q, esp_sadb.s_ip_q); 32420Sstevel@tonic-gate } 32430Sstevel@tonic-gate 32440Sstevel@tonic-gate return (sadb_del_sa(mp, ksi, &esp_sadb, diagnostic, esp_pfkey_q)); 32450Sstevel@tonic-gate } 32460Sstevel@tonic-gate 32470Sstevel@tonic-gate /* 32480Sstevel@tonic-gate * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP 32490Sstevel@tonic-gate * messages. 32500Sstevel@tonic-gate */ 32510Sstevel@tonic-gate static void 32520Sstevel@tonic-gate esp_dump(mblk_t *mp, keysock_in_t *ksi) 32530Sstevel@tonic-gate { 32540Sstevel@tonic-gate int error; 32550Sstevel@tonic-gate sadb_msg_t *samsg; 32560Sstevel@tonic-gate 32570Sstevel@tonic-gate /* 32580Sstevel@tonic-gate * Dump each fanout, bailing if error is non-zero. 32590Sstevel@tonic-gate */ 32600Sstevel@tonic-gate 32610Sstevel@tonic-gate error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v4); 32620Sstevel@tonic-gate if (error != 0) 32630Sstevel@tonic-gate goto bail; 32640Sstevel@tonic-gate 32650Sstevel@tonic-gate error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v6); 32660Sstevel@tonic-gate bail: 32670Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 32680Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 32690Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 32700Sstevel@tonic-gate sadb_pfkey_echo(esp_pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi, 32710Sstevel@tonic-gate NULL); 32720Sstevel@tonic-gate } 32730Sstevel@tonic-gate 32740Sstevel@tonic-gate /* 32750Sstevel@tonic-gate * ESP parsing of PF_KEY messages. Keysock did most of the really silly 32760Sstevel@tonic-gate * error cases. What I receive is a fully-formed, syntactically legal 32770Sstevel@tonic-gate * PF_KEY message. I then need to check semantics... 32780Sstevel@tonic-gate * 32790Sstevel@tonic-gate * This code may become common to AH and ESP. Stay tuned. 32800Sstevel@tonic-gate * 32810Sstevel@tonic-gate * I also make the assumption that db_ref's are cool. If this assumption 32820Sstevel@tonic-gate * is wrong, this means that someone other than keysock or me has been 32830Sstevel@tonic-gate * mucking with PF_KEY messages. 32840Sstevel@tonic-gate */ 32850Sstevel@tonic-gate static void 32860Sstevel@tonic-gate esp_parse_pfkey(mblk_t *mp) 32870Sstevel@tonic-gate { 32880Sstevel@tonic-gate mblk_t *msg = mp->b_cont; 32890Sstevel@tonic-gate sadb_msg_t *samsg; 32900Sstevel@tonic-gate keysock_in_t *ksi; 32910Sstevel@tonic-gate int error; 32920Sstevel@tonic-gate int diagnostic = SADB_X_DIAGNOSTIC_NONE; 32930Sstevel@tonic-gate 32940Sstevel@tonic-gate ASSERT(msg != NULL); 32950Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr; 32960Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 32970Sstevel@tonic-gate 32980Sstevel@tonic-gate /* 32990Sstevel@tonic-gate * If applicable, convert unspecified AF_INET6 to unspecified 33000Sstevel@tonic-gate * AF_INET. 33010Sstevel@tonic-gate */ 33020Sstevel@tonic-gate sadb_srcaddrfix(ksi); 33030Sstevel@tonic-gate 33040Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 33050Sstevel@tonic-gate case SADB_ADD: 33060Sstevel@tonic-gate error = esp_add_sa(mp, ksi, &diagnostic); 33070Sstevel@tonic-gate if (error != 0) { 33080Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 33090Sstevel@tonic-gate ksi->ks_in_serial); 33100Sstevel@tonic-gate } 33110Sstevel@tonic-gate /* else esp_add_sa() took care of things. */ 33120Sstevel@tonic-gate break; 33130Sstevel@tonic-gate case SADB_DELETE: 33140Sstevel@tonic-gate error = esp_del_sa(mp, ksi, &diagnostic); 33150Sstevel@tonic-gate if (error != 0) { 33160Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 33170Sstevel@tonic-gate ksi->ks_in_serial); 33180Sstevel@tonic-gate } 33190Sstevel@tonic-gate /* Else esp_del_sa() took care of things. */ 33200Sstevel@tonic-gate break; 33210Sstevel@tonic-gate case SADB_GET: 33220Sstevel@tonic-gate error = sadb_get_sa(mp, ksi, &esp_sadb, &diagnostic, 33230Sstevel@tonic-gate esp_pfkey_q); 33240Sstevel@tonic-gate if (error != 0) { 33250Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 33260Sstevel@tonic-gate ksi->ks_in_serial); 33270Sstevel@tonic-gate } 33280Sstevel@tonic-gate /* Else sadb_get_sa() took care of things. */ 33290Sstevel@tonic-gate break; 33300Sstevel@tonic-gate case SADB_FLUSH: 33310Sstevel@tonic-gate sadbp_flush(&esp_sadb); 33320Sstevel@tonic-gate sadb_pfkey_echo(esp_pfkey_q, mp, samsg, ksi, NULL); 33330Sstevel@tonic-gate break; 33340Sstevel@tonic-gate case SADB_REGISTER: 33350Sstevel@tonic-gate /* 33360Sstevel@tonic-gate * Hmmm, let's do it! Check for extensions (there should 33370Sstevel@tonic-gate * be none), extract the fields, call esp_register_out(), 33380Sstevel@tonic-gate * then either free or report an error. 33390Sstevel@tonic-gate * 33400Sstevel@tonic-gate * Keysock takes care of the PF_KEY bookkeeping for this. 33410Sstevel@tonic-gate */ 33420Sstevel@tonic-gate if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid, 33430Sstevel@tonic-gate ksi->ks_in_serial)) { 33440Sstevel@tonic-gate freemsg(mp); 33450Sstevel@tonic-gate } else { 33460Sstevel@tonic-gate /* 33470Sstevel@tonic-gate * Only way this path hits is if there is a memory 33480Sstevel@tonic-gate * failure. It will not return B_FALSE because of 33490Sstevel@tonic-gate * lack of esp_pfkey_q if I am in wput(). 33500Sstevel@tonic-gate */ 33510Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic, 33520Sstevel@tonic-gate ksi->ks_in_serial); 33530Sstevel@tonic-gate } 33540Sstevel@tonic-gate break; 33550Sstevel@tonic-gate case SADB_UPDATE: 33560Sstevel@tonic-gate /* 33570Sstevel@tonic-gate * Find a larval, if not there, find a full one and get 33580Sstevel@tonic-gate * strict. 33590Sstevel@tonic-gate */ 33600Sstevel@tonic-gate error = esp_update_sa(mp, ksi, &diagnostic); 33610Sstevel@tonic-gate if (error != 0) { 33620Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic, 33630Sstevel@tonic-gate ksi->ks_in_serial); 33640Sstevel@tonic-gate } 33650Sstevel@tonic-gate /* else esp_update_sa() took care of things. */ 33660Sstevel@tonic-gate break; 33670Sstevel@tonic-gate case SADB_GETSPI: 33680Sstevel@tonic-gate /* 33690Sstevel@tonic-gate * Reserve a new larval entry. 33700Sstevel@tonic-gate */ 33710Sstevel@tonic-gate esp_getspi(mp, ksi); 33720Sstevel@tonic-gate break; 33730Sstevel@tonic-gate case SADB_ACQUIRE: 33740Sstevel@tonic-gate /* 33750Sstevel@tonic-gate * Find larval and/or ACQUIRE record and kill it (them), I'm 33760Sstevel@tonic-gate * most likely an error. Inbound ACQUIRE messages should only 33770Sstevel@tonic-gate * have the base header. 33780Sstevel@tonic-gate */ 33790Sstevel@tonic-gate sadb_in_acquire(samsg, &esp_sadb, esp_pfkey_q); 33800Sstevel@tonic-gate freemsg(mp); 33810Sstevel@tonic-gate break; 33820Sstevel@tonic-gate case SADB_DUMP: 33830Sstevel@tonic-gate /* 33840Sstevel@tonic-gate * Dump all entries. 33850Sstevel@tonic-gate */ 33860Sstevel@tonic-gate esp_dump(mp, ksi); 33870Sstevel@tonic-gate /* esp_dump will take care of the return message, etc. */ 33880Sstevel@tonic-gate break; 33890Sstevel@tonic-gate case SADB_EXPIRE: 33900Sstevel@tonic-gate /* Should never reach me. */ 33910Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EOPNOTSUPP, diagnostic, 33920Sstevel@tonic-gate ksi->ks_in_serial); 33930Sstevel@tonic-gate break; 33940Sstevel@tonic-gate default: 33950Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, 33960Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial); 33970Sstevel@tonic-gate break; 33980Sstevel@tonic-gate } 33990Sstevel@tonic-gate } 34000Sstevel@tonic-gate 34010Sstevel@tonic-gate /* 34020Sstevel@tonic-gate * Handle case where PF_KEY says it can't find a keysock for one of my 34030Sstevel@tonic-gate * ACQUIRE messages. 34040Sstevel@tonic-gate */ 34050Sstevel@tonic-gate static void 34060Sstevel@tonic-gate esp_keysock_no_socket(mblk_t *mp) 34070Sstevel@tonic-gate { 34080Sstevel@tonic-gate sadb_msg_t *samsg; 34090Sstevel@tonic-gate keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr; 34100Sstevel@tonic-gate 34110Sstevel@tonic-gate if (mp->b_cont == NULL) { 34120Sstevel@tonic-gate freemsg(mp); 34130Sstevel@tonic-gate return; 34140Sstevel@tonic-gate } 34150Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 34160Sstevel@tonic-gate 34170Sstevel@tonic-gate /* 34180Sstevel@tonic-gate * If keysock can't find any registered, delete the acquire record 34190Sstevel@tonic-gate * immediately, and handle errors. 34200Sstevel@tonic-gate */ 34210Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_ACQUIRE) { 34220Sstevel@tonic-gate samsg->sadb_msg_errno = kse->ks_err_errno; 34230Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); 34240Sstevel@tonic-gate /* 34250Sstevel@tonic-gate * Use the write-side of the esp_pfkey_q, in case there is 34260Sstevel@tonic-gate * no esp_sadb.s_ip_q. 34270Sstevel@tonic-gate */ 34280Sstevel@tonic-gate sadb_in_acquire(samsg, &esp_sadb, WR(esp_pfkey_q)); 34290Sstevel@tonic-gate } 34300Sstevel@tonic-gate 34310Sstevel@tonic-gate freemsg(mp); 34320Sstevel@tonic-gate } 34330Sstevel@tonic-gate 34340Sstevel@tonic-gate /* 34350Sstevel@tonic-gate * First-cut reality check for an inbound PF_KEY message. 34360Sstevel@tonic-gate */ 34370Sstevel@tonic-gate static boolean_t 34380Sstevel@tonic-gate esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi) 34390Sstevel@tonic-gate { 34400Sstevel@tonic-gate int diagnostic; 34410Sstevel@tonic-gate 34420Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) { 34430Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT; 34440Sstevel@tonic-gate goto badmsg; 34450Sstevel@tonic-gate } 34460Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL || 34470Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) { 34480Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT; 34490Sstevel@tonic-gate goto badmsg; 34500Sstevel@tonic-gate } 34510Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_MBCAST) { 34520Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC; 34530Sstevel@tonic-gate goto badmsg; 34540Sstevel@tonic-gate } 34550Sstevel@tonic-gate if (ksi->ks_in_dsttype == KS_IN_ADDR_UNSPEC) { 34560Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 34570Sstevel@tonic-gate goto badmsg; 34580Sstevel@tonic-gate } 34590Sstevel@tonic-gate 34600Sstevel@tonic-gate return (B_FALSE); /* False ==> no failures */ 34610Sstevel@tonic-gate 34620Sstevel@tonic-gate badmsg: 34630Sstevel@tonic-gate sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic, 34640Sstevel@tonic-gate ksi->ks_in_serial); 34650Sstevel@tonic-gate return (B_TRUE); /* True ==> failures */ 34660Sstevel@tonic-gate } 34670Sstevel@tonic-gate 34680Sstevel@tonic-gate /* 34690Sstevel@tonic-gate * ESP module write put routine. 34700Sstevel@tonic-gate */ 34710Sstevel@tonic-gate static void 34720Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp) 34730Sstevel@tonic-gate { 34740Sstevel@tonic-gate ipsec_info_t *ii; 34750Sstevel@tonic-gate keysock_in_t *ksi; 34760Sstevel@tonic-gate int rc; 34770Sstevel@tonic-gate struct iocblk *iocp; 34780Sstevel@tonic-gate 34790Sstevel@tonic-gate esp3dbg(("In esp_wput().\n")); 34800Sstevel@tonic-gate 34810Sstevel@tonic-gate /* NOTE: Each case must take care of freeing or passing mp. */ 34820Sstevel@tonic-gate switch (mp->b_datap->db_type) { 34830Sstevel@tonic-gate case M_CTL: 34840Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) { 34850Sstevel@tonic-gate /* Not big enough message. */ 34860Sstevel@tonic-gate freemsg(mp); 34870Sstevel@tonic-gate break; 34880Sstevel@tonic-gate } 34890Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 34900Sstevel@tonic-gate 34910Sstevel@tonic-gate switch (ii->ipsec_info_type) { 34920Sstevel@tonic-gate case KEYSOCK_OUT_ERR: 34930Sstevel@tonic-gate esp1dbg(("Got KEYSOCK_OUT_ERR message.\n")); 34940Sstevel@tonic-gate esp_keysock_no_socket(mp); 34950Sstevel@tonic-gate break; 34960Sstevel@tonic-gate case KEYSOCK_IN: 34970Sstevel@tonic-gate ESP_BUMP_STAT(keysock_in); 34980Sstevel@tonic-gate esp3dbg(("Got KEYSOCK_IN message.\n")); 34990Sstevel@tonic-gate ksi = (keysock_in_t *)ii; 35000Sstevel@tonic-gate /* 35010Sstevel@tonic-gate * Some common reality checks. 35020Sstevel@tonic-gate */ 35030Sstevel@tonic-gate 35040Sstevel@tonic-gate if (esp_pfkey_reality_failures(mp, ksi)) 35050Sstevel@tonic-gate return; 35060Sstevel@tonic-gate 35070Sstevel@tonic-gate /* 35080Sstevel@tonic-gate * Use 'q' instead of esp_sadb.s_ip_q, since 35090Sstevel@tonic-gate * it's the write side already, and it'll go 35100Sstevel@tonic-gate * down to IP. Use esp_pfkey_q because we 35110Sstevel@tonic-gate * wouldn't get here if that weren't set, and 35120Sstevel@tonic-gate * the RD(q) has been done already. 35130Sstevel@tonic-gate */ 35140Sstevel@tonic-gate if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) { 35150Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 35160Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC], 35170Sstevel@tonic-gate ksi->ks_in_serial); 35180Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 35190Sstevel@tonic-gate return; 35200Sstevel@tonic-gate else 35210Sstevel@tonic-gate ksi->ks_in_srctype = rc; 35220Sstevel@tonic-gate } 35230Sstevel@tonic-gate if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) { 35240Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 35250Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_DST], 35260Sstevel@tonic-gate ksi->ks_in_serial); 35270Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 35280Sstevel@tonic-gate return; 35290Sstevel@tonic-gate else 35300Sstevel@tonic-gate ksi->ks_in_dsttype = rc; 35310Sstevel@tonic-gate } 35320Sstevel@tonic-gate /* 35330Sstevel@tonic-gate * XXX Proxy may be a different address family. 35340Sstevel@tonic-gate */ 35350Sstevel@tonic-gate if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) { 35360Sstevel@tonic-gate rc = sadb_addrcheck(q, esp_pfkey_q, mp, 35370Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_ADDRESS_PROXY], 35380Sstevel@tonic-gate ksi->ks_in_serial); 35390Sstevel@tonic-gate if (rc == KS_IN_ADDR_UNKNOWN) 35400Sstevel@tonic-gate return; 35410Sstevel@tonic-gate else 35420Sstevel@tonic-gate ksi->ks_in_proxytype = rc; 35430Sstevel@tonic-gate } 35440Sstevel@tonic-gate esp_parse_pfkey(mp); 35450Sstevel@tonic-gate break; 35460Sstevel@tonic-gate case KEYSOCK_HELLO: 35470Sstevel@tonic-gate sadb_keysock_hello(&esp_pfkey_q, q, mp, 35480Sstevel@tonic-gate esp_ager, &esp_event, SADB_SATYPE_ESP); 35490Sstevel@tonic-gate break; 35500Sstevel@tonic-gate default: 35510Sstevel@tonic-gate esp2dbg(("Got M_CTL from above of 0x%x.\n", 35520Sstevel@tonic-gate ii->ipsec_info_type)); 35530Sstevel@tonic-gate freemsg(mp); 35540Sstevel@tonic-gate break; 35550Sstevel@tonic-gate } 35560Sstevel@tonic-gate break; 35570Sstevel@tonic-gate case M_IOCTL: 35580Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 35590Sstevel@tonic-gate switch (iocp->ioc_cmd) { 35600Sstevel@tonic-gate case ND_SET: 35610Sstevel@tonic-gate case ND_GET: 35620Sstevel@tonic-gate if (nd_getset(q, ipsecesp_g_nd, mp)) { 35630Sstevel@tonic-gate qreply(q, mp); 35640Sstevel@tonic-gate return; 35650Sstevel@tonic-gate } else { 35660Sstevel@tonic-gate iocp->ioc_error = ENOENT; 35670Sstevel@tonic-gate } 35680Sstevel@tonic-gate /* FALLTHRU */ 35690Sstevel@tonic-gate default: 35700Sstevel@tonic-gate /* We really don't support any other ioctls, do we? */ 35710Sstevel@tonic-gate 35720Sstevel@tonic-gate /* Return EINVAL */ 35730Sstevel@tonic-gate if (iocp->ioc_error != ENOENT) 35740Sstevel@tonic-gate iocp->ioc_error = EINVAL; 35750Sstevel@tonic-gate iocp->ioc_count = 0; 35760Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 35770Sstevel@tonic-gate qreply(q, mp); 35780Sstevel@tonic-gate return; 35790Sstevel@tonic-gate } 35800Sstevel@tonic-gate default: 35810Sstevel@tonic-gate esp3dbg(("Got default message, type %d, passing to IP.\n", 35820Sstevel@tonic-gate mp->b_datap->db_type)); 35830Sstevel@tonic-gate putnext(q, mp); 35840Sstevel@tonic-gate } 35850Sstevel@tonic-gate } 35860Sstevel@tonic-gate 35870Sstevel@tonic-gate /* 35880Sstevel@tonic-gate * Process an outbound ESP packet that can be accelerated by a IPsec 35890Sstevel@tonic-gate * hardware acceleration capable Provider. 35900Sstevel@tonic-gate * The caller already inserted and initialized the ESP header. 35910Sstevel@tonic-gate * This function allocates a tagging M_CTL, and adds room at the end 35920Sstevel@tonic-gate * of the packet to hold the ICV if authentication is needed. 35930Sstevel@tonic-gate * 35940Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 35950Sstevel@tonic-gate * mblk chain ipsec_out. 35960Sstevel@tonic-gate */ 35970Sstevel@tonic-gate static ipsec_status_t 35980Sstevel@tonic-gate esp_outbound_accelerated(mblk_t *ipsec_out, uint_t icv_len) 35990Sstevel@tonic-gate { 36000Sstevel@tonic-gate ipsec_out_t *io; 36010Sstevel@tonic-gate mblk_t *lastmp; 36020Sstevel@tonic-gate 36030Sstevel@tonic-gate ESP_BUMP_STAT(out_accelerated); 36040Sstevel@tonic-gate 36050Sstevel@tonic-gate io = (ipsec_out_t *)ipsec_out->b_rptr; 36060Sstevel@tonic-gate 36070Sstevel@tonic-gate /* mark packet as being accelerated in IPSEC_OUT */ 36080Sstevel@tonic-gate ASSERT(io->ipsec_out_accelerated == B_FALSE); 36090Sstevel@tonic-gate io->ipsec_out_accelerated = B_TRUE; 36100Sstevel@tonic-gate 36110Sstevel@tonic-gate /* 36120Sstevel@tonic-gate * add room at the end of the packet for the ICV if needed 36130Sstevel@tonic-gate */ 36140Sstevel@tonic-gate if (icv_len > 0) { 36150Sstevel@tonic-gate /* go to last mblk */ 36160Sstevel@tonic-gate lastmp = ipsec_out; /* For following while loop. */ 36170Sstevel@tonic-gate do { 36180Sstevel@tonic-gate lastmp = lastmp->b_cont; 36190Sstevel@tonic-gate } while (lastmp->b_cont != NULL); 36200Sstevel@tonic-gate 36210Sstevel@tonic-gate /* if not enough available room, allocate new mblk */ 36220Sstevel@tonic-gate if ((lastmp->b_wptr + icv_len) > lastmp->b_datap->db_lim) { 36230Sstevel@tonic-gate lastmp->b_cont = allocb(icv_len, BPRI_HI); 36240Sstevel@tonic-gate if (lastmp->b_cont == NULL) { 36250Sstevel@tonic-gate ESP_BUMP_STAT(out_discards); 36260Sstevel@tonic-gate ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 36270Sstevel@tonic-gate &ipdrops_esp_nomem, &esp_dropper); 36280Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 36290Sstevel@tonic-gate } 36300Sstevel@tonic-gate lastmp = lastmp->b_cont; 36310Sstevel@tonic-gate } 36320Sstevel@tonic-gate lastmp->b_wptr += icv_len; 36330Sstevel@tonic-gate } 36340Sstevel@tonic-gate 36350Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 36360Sstevel@tonic-gate } 36370Sstevel@tonic-gate 36380Sstevel@tonic-gate /* 36390Sstevel@tonic-gate * Process an inbound accelerated ESP packet. 36400Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 36410Sstevel@tonic-gate * mblk chain ipsec_in. 36420Sstevel@tonic-gate */ 36430Sstevel@tonic-gate static ipsec_status_t 36440Sstevel@tonic-gate esp_inbound_accelerated(mblk_t *ipsec_in, mblk_t *data_mp, boolean_t isv4, 36450Sstevel@tonic-gate ipsa_t *assoc) 36460Sstevel@tonic-gate { 36470Sstevel@tonic-gate ipsec_in_t *ii; 36480Sstevel@tonic-gate mblk_t *hada_mp; 36490Sstevel@tonic-gate uint32_t icv_len = 0; 36500Sstevel@tonic-gate da_ipsec_t *hada; 36510Sstevel@tonic-gate ipha_t *ipha; 36520Sstevel@tonic-gate ip6_t *ip6h; 36530Sstevel@tonic-gate kstat_named_t *counter; 36540Sstevel@tonic-gate 36550Sstevel@tonic-gate ESP_BUMP_STAT(in_accelerated); 36560Sstevel@tonic-gate 36570Sstevel@tonic-gate ii = (ipsec_in_t *)ipsec_in->b_rptr; 36580Sstevel@tonic-gate hada_mp = ii->ipsec_in_da; 36590Sstevel@tonic-gate ASSERT(hada_mp != NULL); 36600Sstevel@tonic-gate hada = (da_ipsec_t *)hada_mp->b_rptr; 36610Sstevel@tonic-gate 36620Sstevel@tonic-gate /* 36630Sstevel@tonic-gate * We only support one level of decapsulation in hardware, so 36640Sstevel@tonic-gate * nuke the pointer. 36650Sstevel@tonic-gate */ 36660Sstevel@tonic-gate ii->ipsec_in_da = NULL; 36670Sstevel@tonic-gate ii->ipsec_in_accelerated = B_FALSE; 36680Sstevel@tonic-gate 36690Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 36700Sstevel@tonic-gate /* 36710Sstevel@tonic-gate * ESP with authentication. We expect the Provider to have 36720Sstevel@tonic-gate * computed the ICV and placed it in the hardware acceleration 36730Sstevel@tonic-gate * data attributes. 36740Sstevel@tonic-gate * 36750Sstevel@tonic-gate * Extract ICV length from attributes M_CTL and sanity check 36760Sstevel@tonic-gate * its value. We allow the mblk to be smaller than da_ipsec_t 36770Sstevel@tonic-gate * for a small ICV, as long as the entire ICV fits within the 36780Sstevel@tonic-gate * mblk. 36790Sstevel@tonic-gate * 36800Sstevel@tonic-gate * Also ensures that the ICV length computed by Provider 36810Sstevel@tonic-gate * corresponds to the ICV length of the agorithm specified by 36820Sstevel@tonic-gate * the SA. 36830Sstevel@tonic-gate */ 36840Sstevel@tonic-gate icv_len = hada->da_icv_len; 36850Sstevel@tonic-gate if ((icv_len != assoc->ipsa_mac_len) || 36860Sstevel@tonic-gate (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) < 36870Sstevel@tonic-gate (sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) { 36880Sstevel@tonic-gate esp0dbg(("esp_inbound_accelerated: " 36890Sstevel@tonic-gate "ICV len (%u) incorrect or mblk too small (%u)\n", 36900Sstevel@tonic-gate icv_len, (uint32_t)(MBLKL(hada_mp)))); 36910Sstevel@tonic-gate counter = &ipdrops_esp_bad_auth; 36920Sstevel@tonic-gate goto esp_in_discard; 36930Sstevel@tonic-gate } 36940Sstevel@tonic-gate } 36950Sstevel@tonic-gate 36960Sstevel@tonic-gate /* get pointers to IP header */ 36970Sstevel@tonic-gate if (isv4) { 36980Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 36990Sstevel@tonic-gate } else { 37000Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 37010Sstevel@tonic-gate } 37020Sstevel@tonic-gate 37030Sstevel@tonic-gate /* 37040Sstevel@tonic-gate * Compare ICV in ESP packet vs ICV computed by adapter. 37050Sstevel@tonic-gate * We also remove the ICV from the end of the packet since 37060Sstevel@tonic-gate * it will no longer be needed. 37070Sstevel@tonic-gate * 37080Sstevel@tonic-gate * Assume that esp_inbound() already ensured that the pkt 37090Sstevel@tonic-gate * was in one mblk. 37100Sstevel@tonic-gate */ 37110Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 37120Sstevel@tonic-gate data_mp->b_wptr -= icv_len; 37130Sstevel@tonic-gate /* adjust IP header */ 37140Sstevel@tonic-gate if (isv4) 37150Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - icv_len); 37160Sstevel@tonic-gate else 37170Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - icv_len); 37180Sstevel@tonic-gate if (icv_len && bcmp(hada->da_icv, data_mp->b_wptr, icv_len)) { 37190Sstevel@tonic-gate int af; 37200Sstevel@tonic-gate void *addr; 37210Sstevel@tonic-gate 37220Sstevel@tonic-gate if (isv4) { 37230Sstevel@tonic-gate addr = &ipha->ipha_dst; 37240Sstevel@tonic-gate af = AF_INET; 37250Sstevel@tonic-gate } else { 37260Sstevel@tonic-gate addr = &ip6h->ip6_dst; 37270Sstevel@tonic-gate af = AF_INET6; 37280Sstevel@tonic-gate } 37290Sstevel@tonic-gate 37300Sstevel@tonic-gate /* 37310Sstevel@tonic-gate * Log the event. Don't print to the console, block 37320Sstevel@tonic-gate * potential denial-of-service attack. 37330Sstevel@tonic-gate */ 37340Sstevel@tonic-gate ESP_BUMP_STAT(bad_auth); 37350Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 37360Sstevel@tonic-gate "ESP Authentication failed spi %x, dst_addr %s", 37370Sstevel@tonic-gate assoc->ipsa_spi, addr, af); 37380Sstevel@tonic-gate counter = &ipdrops_esp_bad_auth; 37390Sstevel@tonic-gate goto esp_in_discard; 37400Sstevel@tonic-gate } 37410Sstevel@tonic-gate 37420Sstevel@tonic-gate esp3dbg(("esp_inbound_accelerated: ESP authentication succeeded, " 37430Sstevel@tonic-gate "checking replay\n")); 37440Sstevel@tonic-gate 37450Sstevel@tonic-gate ipsec_in->b_cont = data_mp; 37460Sstevel@tonic-gate 37470Sstevel@tonic-gate /* 37480Sstevel@tonic-gate * Remove ESP header and padding from packet. 37490Sstevel@tonic-gate */ 37500Sstevel@tonic-gate if (!esp_strip_header(data_mp, ii->ipsec_in_v4, assoc->ipsa_iv_len, 37510Sstevel@tonic-gate &counter)) { 37520Sstevel@tonic-gate esp1dbg(("esp_inbound_accelerated: " 37530Sstevel@tonic-gate "esp_strip_header() failed\n")); 37540Sstevel@tonic-gate goto esp_in_discard; 37550Sstevel@tonic-gate } 37560Sstevel@tonic-gate 37570Sstevel@tonic-gate freeb(hada_mp); 37580Sstevel@tonic-gate 37590Sstevel@tonic-gate /* 37600Sstevel@tonic-gate * Account for usage.. 37610Sstevel@tonic-gate */ 37620Sstevel@tonic-gate if (!esp_age_bytes(assoc, msgdsize(data_mp), B_TRUE)) { 37630Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 37640Sstevel@tonic-gate ESP_BUMP_STAT(bytes_expired); 37650Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 37660Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 37670Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 37680Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 37690Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 37700Sstevel@tonic-gate &ipdrops_esp_bytes_expire, &esp_dropper); 37710Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 37720Sstevel@tonic-gate } 37730Sstevel@tonic-gate 37740Sstevel@tonic-gate /* done processing the packet */ 37750Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 37760Sstevel@tonic-gate 37770Sstevel@tonic-gate esp_in_discard: 37780Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 37790Sstevel@tonic-gate freeb(hada_mp); 37800Sstevel@tonic-gate 37810Sstevel@tonic-gate ipsec_in->b_cont = data_mp; /* For ip_drop_packet()'s sake... */ 37820Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, &esp_dropper); 37830Sstevel@tonic-gate 37840Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 37850Sstevel@tonic-gate } 37860Sstevel@tonic-gate 37870Sstevel@tonic-gate /* 37880Sstevel@tonic-gate * Wrapper to allow IP to trigger an ESP association failure message 37890Sstevel@tonic-gate * during inbound SA selection. 37900Sstevel@tonic-gate */ 37910Sstevel@tonic-gate void 37920Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt, 37930Sstevel@tonic-gate uint32_t spi, void *addr, int af) 37940Sstevel@tonic-gate { 37950Sstevel@tonic-gate if (ipsecesp_log_unknown_spi) { 37960Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi, 37970Sstevel@tonic-gate addr, af); 37980Sstevel@tonic-gate } 37990Sstevel@tonic-gate 38000Sstevel@tonic-gate ip_drop_packet(mp, B_TRUE, NULL, NULL, &ipdrops_esp_no_sa, 38010Sstevel@tonic-gate &esp_dropper); 38020Sstevel@tonic-gate } 38030Sstevel@tonic-gate 38040Sstevel@tonic-gate /* 38050Sstevel@tonic-gate * Initialize the ESP input and output processing functions. 38060Sstevel@tonic-gate */ 38070Sstevel@tonic-gate void 38080Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa) 38090Sstevel@tonic-gate { 38100Sstevel@tonic-gate if (sa->ipsa_output_func == NULL) 38110Sstevel@tonic-gate sa->ipsa_output_func = esp_outbound; 38120Sstevel@tonic-gate if (sa->ipsa_input_func == NULL) 38130Sstevel@tonic-gate sa->ipsa_input_func = esp_inbound; 38140Sstevel@tonic-gate } 3815