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 /* 226352Swy83408 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/stream.h> 280Sstevel@tonic-gate #include <sys/stropts.h> 290Sstevel@tonic-gate #include <sys/errno.h> 300Sstevel@tonic-gate #include <sys/strlog.h> 310Sstevel@tonic-gate #include <sys/tihdr.h> 320Sstevel@tonic-gate #include <sys/socket.h> 330Sstevel@tonic-gate #include <sys/ddi.h> 340Sstevel@tonic-gate #include <sys/sunddi.h> 350Sstevel@tonic-gate #include <sys/kmem.h> 363448Sdh155122 #include <sys/zone.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/cmn_err.h> 390Sstevel@tonic-gate #include <sys/vtrace.h> 400Sstevel@tonic-gate #include <sys/debug.h> 410Sstevel@tonic-gate #include <sys/atomic.h> 420Sstevel@tonic-gate #include <sys/strsun.h> 430Sstevel@tonic-gate #include <sys/random.h> 440Sstevel@tonic-gate #include <netinet/in.h> 450Sstevel@tonic-gate #include <net/if.h> 460Sstevel@tonic-gate #include <netinet/ip6.h> 470Sstevel@tonic-gate #include <net/pfkeyv2.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate #include <inet/common.h> 500Sstevel@tonic-gate #include <inet/mi.h> 510Sstevel@tonic-gate #include <inet/nd.h> 520Sstevel@tonic-gate #include <inet/ip.h> 534987Sdanmcd #include <inet/ip_impl.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> 663448Sdh155122 #include <sys/note.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #include <sys/iphada.h> 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * Table of ND variables supported by ipsecesp. These are loaded into 720Sstevel@tonic-gate * ipsecesp_g_nd in ipsecesp_init_nd. 730Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 740Sstevel@tonic-gate */ 753448Sdh155122 static ipsecespparam_t lcl_param_arr[] = { 760Sstevel@tonic-gate /* min max value name */ 770Sstevel@tonic-gate { 0, 3, 0, "ipsecesp_debug"}, 780Sstevel@tonic-gate { 125, 32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"}, 790Sstevel@tonic-gate { 1, 10, 1, "ipsecesp_reap_delay"}, 800Sstevel@tonic-gate { 1, SADB_MAX_REPLAY, 64, "ipsecesp_replay_size"}, 810Sstevel@tonic-gate { 1, 300, 15, "ipsecesp_acquire_timeout"}, 820Sstevel@tonic-gate { 1, 1800, 90, "ipsecesp_larval_timeout"}, 830Sstevel@tonic-gate /* Default lifetime values for ACQUIRE messages. */ 840Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_bytes"}, 850Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_bytes"}, 860Sstevel@tonic-gate { 0, 0xffffffffU, 24000, "ipsecesp_default_soft_addtime"}, 870Sstevel@tonic-gate { 0, 0xffffffffU, 28800, "ipsecesp_default_hard_addtime"}, 880Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_usetime"}, 890Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_usetime"}, 900Sstevel@tonic-gate { 0, 1, 0, "ipsecesp_log_unknown_spi"}, 910Sstevel@tonic-gate { 0, 2, 1, "ipsecesp_padding_check"}, 924987Sdanmcd { 0, 600, 20, "ipsecesp_nat_keepalive_interval"}, 930Sstevel@tonic-gate }; 943448Sdh155122 #define ipsecesp_debug ipsecesp_params[0].ipsecesp_param_value 953448Sdh155122 #define ipsecesp_age_interval ipsecesp_params[1].ipsecesp_param_value 963448Sdh155122 #define ipsecesp_age_int_max ipsecesp_params[1].ipsecesp_param_max 973448Sdh155122 #define ipsecesp_reap_delay ipsecesp_params[2].ipsecesp_param_value 983448Sdh155122 #define ipsecesp_replay_size ipsecesp_params[3].ipsecesp_param_value 993448Sdh155122 #define ipsecesp_acquire_timeout \ 1003448Sdh155122 ipsecesp_params[4].ipsecesp_param_value 1013448Sdh155122 #define ipsecesp_larval_timeout \ 1023448Sdh155122 ipsecesp_params[5].ipsecesp_param_value 1033448Sdh155122 #define ipsecesp_default_soft_bytes \ 1043448Sdh155122 ipsecesp_params[6].ipsecesp_param_value 1053448Sdh155122 #define ipsecesp_default_hard_bytes \ 1063448Sdh155122 ipsecesp_params[7].ipsecesp_param_value 1073448Sdh155122 #define ipsecesp_default_soft_addtime \ 1083448Sdh155122 ipsecesp_params[8].ipsecesp_param_value 1093448Sdh155122 #define ipsecesp_default_hard_addtime \ 1103448Sdh155122 ipsecesp_params[9].ipsecesp_param_value 1113448Sdh155122 #define ipsecesp_default_soft_usetime \ 1123448Sdh155122 ipsecesp_params[10].ipsecesp_param_value 1133448Sdh155122 #define ipsecesp_default_hard_usetime \ 1143448Sdh155122 ipsecesp_params[11].ipsecesp_param_value 1153448Sdh155122 #define ipsecesp_log_unknown_spi \ 1163448Sdh155122 ipsecesp_params[12].ipsecesp_param_value 1173448Sdh155122 #define ipsecesp_padding_check \ 1183448Sdh155122 ipsecesp_params[13].ipsecesp_param_value 1194987Sdanmcd /* For ipsecesp_nat_keepalive_interval, see ipsecesp.h. */ 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate #define esp0dbg(a) printf a 1220Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 1233448Sdh155122 #define esp1dbg(espstack, a) if (espstack->ipsecesp_debug != 0) printf a 1243448Sdh155122 #define esp2dbg(espstack, a) if (espstack->ipsecesp_debug > 1) printf a 1253448Sdh155122 #define esp3dbg(espstack, a) if (espstack->ipsecesp_debug > 2) printf a 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *); 1280Sstevel@tonic-gate static int ipsecesp_close(queue_t *); 1290Sstevel@tonic-gate static void ipsecesp_rput(queue_t *, mblk_t *); 1300Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *); 1313448Sdh155122 static void *ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns); 1323448Sdh155122 static void ipsecesp_stack_fini(netstackid_t stackid, void *arg); 1333448Sdh155122 static void esp_send_acquire(ipsacq_t *, mblk_t *, netstack_t *); 1340Sstevel@tonic-gate 1354987Sdanmcd static void esp_prepare_udp(netstack_t *, mblk_t *, ipha_t *); 1360Sstevel@tonic-gate static ipsec_status_t esp_outbound_accelerated(mblk_t *, uint_t); 1370Sstevel@tonic-gate static ipsec_status_t esp_inbound_accelerated(mblk_t *, mblk_t *, 1380Sstevel@tonic-gate boolean_t, ipsa_t *); 1390Sstevel@tonic-gate 1403448Sdh155122 static boolean_t esp_register_out(uint32_t, uint32_t, uint_t, 1413448Sdh155122 ipsecesp_stack_t *); 1420Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t, 1433448Sdh155122 kstat_named_t **, ipsecesp_stack_t *); 1440Sstevel@tonic-gate static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t); 1450Sstevel@tonic-gate static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *, 1460Sstevel@tonic-gate uint_t); 147*8392SHuafeng.Lv@Sun.COM extern void (*cl_inet_getspi)(netstackid_t, uint8_t, uint8_t *, size_t, 148*8392SHuafeng.Lv@Sun.COM void *); 1497749SThejaswini.Singarajipura@Sun.COM 1503448Sdh155122 /* Setable in /etc/system */ 1513448Sdh155122 uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE; 1523448Sdh155122 1530Sstevel@tonic-gate static struct module_info info = { 1540Sstevel@tonic-gate 5137, "ipsecesp", 0, INFPSZ, 65536, 1024 1550Sstevel@tonic-gate }; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate static struct qinit rinit = { 1580Sstevel@tonic-gate (pfi_t)ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1590Sstevel@tonic-gate NULL 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate static struct qinit winit = { 1630Sstevel@tonic-gate (pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1640Sstevel@tonic-gate NULL 1650Sstevel@tonic-gate }; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate struct streamtab ipsecespinfo = { 1680Sstevel@tonic-gate &rinit, &winit, NULL, NULL 1690Sstevel@tonic-gate }; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static taskq_t *esp_taskq; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now. 1750Sstevel@tonic-gate * 1760Sstevel@tonic-gate * Question: Do I need this, given that all instance's esps->esps_wq point 1770Sstevel@tonic-gate * to IP? 1780Sstevel@tonic-gate * 1790Sstevel@tonic-gate * Answer: Yes, because I need to know which queue is BOUND to 1800Sstevel@tonic-gate * IPPROTO_ESP 1810Sstevel@tonic-gate */ 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 1883448Sdh155122 typedef struct esp_kstats_s { 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; 2087066Sdanmcd kstat_named_t esp_stat_sa_port_renumbers; 2090Sstevel@tonic-gate } esp_kstats_t; 2100Sstevel@tonic-gate 2113448Sdh155122 /* 2123448Sdh155122 * espstack->esp_kstats is equal to espstack->esp_ksp->ks_data if 2133448Sdh155122 * kstat_create_netstack for espstack->esp_ksp succeeds, but when it 2143448Sdh155122 * fails, it will be NULL. Note this is done for all stack instances, 2153448Sdh155122 * so it *could* fail. hence a non-NULL checking is done for 2163448Sdh155122 * ESP_BUMP_STAT and ESP_DEBUMP_STAT 2173448Sdh155122 */ 2183448Sdh155122 #define ESP_BUMP_STAT(espstack, x) \ 2193448Sdh155122 do { \ 2203448Sdh155122 if (espstack->esp_kstats != NULL) \ 2213448Sdh155122 (espstack->esp_kstats->esp_stat_ ## x).value.ui64++; \ 2223448Sdh155122 _NOTE(CONSTCOND) \ 2233448Sdh155122 } while (0) 2243448Sdh155122 2253448Sdh155122 #define ESP_DEBUMP_STAT(espstack, x) \ 2263448Sdh155122 do { \ 2273448Sdh155122 if (espstack->esp_kstats != NULL) \ 2283448Sdh155122 (espstack->esp_kstats->esp_stat_ ## x).value.ui64--; \ 2293448Sdh155122 _NOTE(CONSTCOND) \ 2303448Sdh155122 } while (0) 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate static int esp_kstat_update(kstat_t *, int); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate static boolean_t 2353448Sdh155122 esp_kstat_init(ipsecesp_stack_t *espstack, netstackid_t stackid) 2360Sstevel@tonic-gate { 2373448Sdh155122 espstack->esp_ksp = kstat_create_netstack("ipsecesp", 0, "esp_stat", 2383448Sdh155122 "net", KSTAT_TYPE_NAMED, 2393448Sdh155122 sizeof (esp_kstats_t) / sizeof (kstat_named_t), 2403448Sdh155122 KSTAT_FLAG_PERSISTENT, stackid); 2413448Sdh155122 2423448Sdh155122 if (espstack->esp_ksp == NULL || espstack->esp_ksp->ks_data == NULL) 2430Sstevel@tonic-gate return (B_FALSE); 2440Sstevel@tonic-gate 2453448Sdh155122 espstack->esp_kstats = espstack->esp_ksp->ks_data; 2463448Sdh155122 2473448Sdh155122 espstack->esp_ksp->ks_update = esp_kstat_update; 2483448Sdh155122 espstack->esp_ksp->ks_private = (void *)(uintptr_t)stackid; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate #define K64 KSTAT_DATA_UINT64 2513448Sdh155122 #define KI(x) kstat_named_init(&(espstack->esp_kstats->esp_stat_##x), #x, K64) 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate KI(num_aalgs); 2540Sstevel@tonic-gate KI(num_ealgs); 2550Sstevel@tonic-gate KI(good_auth); 2560Sstevel@tonic-gate KI(bad_auth); 2570Sstevel@tonic-gate KI(bad_padding); 2580Sstevel@tonic-gate KI(replay_failures); 2590Sstevel@tonic-gate KI(replay_early_failures); 2600Sstevel@tonic-gate KI(keysock_in); 2610Sstevel@tonic-gate KI(out_requests); 2620Sstevel@tonic-gate KI(acquire_requests); 2630Sstevel@tonic-gate KI(bytes_expired); 2640Sstevel@tonic-gate KI(out_discards); 2650Sstevel@tonic-gate KI(in_accelerated); 2660Sstevel@tonic-gate KI(out_accelerated); 2670Sstevel@tonic-gate KI(noaccel); 2680Sstevel@tonic-gate KI(crypto_sync); 2690Sstevel@tonic-gate KI(crypto_async); 2700Sstevel@tonic-gate KI(crypto_failures); 2710Sstevel@tonic-gate KI(bad_decrypt); 2727066Sdanmcd KI(sa_port_renumbers); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate #undef KI 2750Sstevel@tonic-gate #undef K64 2760Sstevel@tonic-gate 2773448Sdh155122 kstat_install(espstack->esp_ksp); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate return (B_TRUE); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate static int 2830Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate esp_kstats_t *ekp; 2863448Sdh155122 netstackid_t stackid = (zoneid_t)(uintptr_t)kp->ks_private; 2873448Sdh155122 netstack_t *ns; 2883448Sdh155122 ipsec_stack_t *ipss; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 2910Sstevel@tonic-gate return (EIO); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (rw == KSTAT_WRITE) 2940Sstevel@tonic-gate return (EACCES); 2950Sstevel@tonic-gate 2963448Sdh155122 ns = netstack_find_by_stackid(stackid); 2973448Sdh155122 if (ns == NULL) 2983448Sdh155122 return (-1); 2993448Sdh155122 ipss = ns->netstack_ipsec; 3003448Sdh155122 if (ipss == NULL) { 3013448Sdh155122 netstack_rele(ns); 3023448Sdh155122 return (-1); 3033448Sdh155122 } 3040Sstevel@tonic-gate ekp = (esp_kstats_t *)kp->ks_data; 3053448Sdh155122 3063448Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 3073448Sdh155122 ekp->esp_stat_num_aalgs.value.ui64 = 3083448Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_AUTH]; 3093448Sdh155122 ekp->esp_stat_num_ealgs.value.ui64 = 3103448Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_ENCR]; 3113448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 3123448Sdh155122 3133448Sdh155122 netstack_rele(ns); 3140Sstevel@tonic-gate return (0); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate #ifdef DEBUG 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * Debug routine, useful to see pre-encryption data. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate static char * 3220Sstevel@tonic-gate dump_msg(mblk_t *mp) 3230Sstevel@tonic-gate { 3240Sstevel@tonic-gate char tmp_str[3], tmp_line[256]; 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate while (mp != NULL) { 3270Sstevel@tonic-gate unsigned char *ptr; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate printf("mblk address 0x%p, length %ld, db_ref %d " 3300Sstevel@tonic-gate "type %d, base 0x%p, lim 0x%p\n", 3310Sstevel@tonic-gate (void *) mp, (long)(mp->b_wptr - mp->b_rptr), 3320Sstevel@tonic-gate mp->b_datap->db_ref, mp->b_datap->db_type, 3330Sstevel@tonic-gate (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim); 3340Sstevel@tonic-gate ptr = mp->b_rptr; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate tmp_line[0] = '\0'; 3370Sstevel@tonic-gate while (ptr < mp->b_wptr) { 3380Sstevel@tonic-gate uint_t diff; 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate diff = (ptr - mp->b_rptr); 3410Sstevel@tonic-gate if (!(diff & 0x1f)) { 3420Sstevel@tonic-gate if (strlen(tmp_line) > 0) { 3430Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3440Sstevel@tonic-gate tmp_line[0] = '\0'; 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate if (!(diff & 0x3)) 3480Sstevel@tonic-gate (void) strcat(tmp_line, " "); 3490Sstevel@tonic-gate (void) sprintf(tmp_str, "%02x", *ptr); 3500Sstevel@tonic-gate (void) strcat(tmp_line, tmp_str); 3510Sstevel@tonic-gate ptr++; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate if (strlen(tmp_line) > 0) 3540Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate mp = mp->b_cont; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate return ("\n"); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate #else /* DEBUG */ 3630Sstevel@tonic-gate static char * 3640Sstevel@tonic-gate dump_msg(mblk_t *mp) 3650Sstevel@tonic-gate { 3660Sstevel@tonic-gate printf("Find value of mp %p.\n", mp); 3670Sstevel@tonic-gate return ("\n"); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate #endif /* DEBUG */ 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate /* 3720Sstevel@tonic-gate * Don't have to lock age_interval, as only one thread will access it at 3730Sstevel@tonic-gate * a time, because I control the one function that does with timeout(). 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate static void 3763448Sdh155122 esp_ager(void *arg) 3770Sstevel@tonic-gate { 3783448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg; 3793448Sdh155122 netstack_t *ns = espstack->ipsecesp_netstack; 3800Sstevel@tonic-gate hrtime_t begin = gethrtime(); 3810Sstevel@tonic-gate 3823448Sdh155122 sadb_ager(&espstack->esp_sadb.s_v4, espstack->esp_pfkey_q, 3833448Sdh155122 espstack->esp_sadb.s_ip_q, espstack->ipsecesp_reap_delay, ns); 3843448Sdh155122 sadb_ager(&espstack->esp_sadb.s_v6, espstack->esp_pfkey_q, 3853448Sdh155122 espstack->esp_sadb.s_ip_q, espstack->ipsecesp_reap_delay, ns); 3863448Sdh155122 3873448Sdh155122 espstack->esp_event = sadb_retimeout(begin, espstack->esp_pfkey_q, 3883448Sdh155122 esp_ager, espstack, 3893448Sdh155122 &espstack->ipsecesp_age_interval, espstack->ipsecesp_age_int_max, 3903448Sdh155122 info.mi_idnum); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Get an ESP NDD parameter. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate /* ARGSUSED */ 3970Sstevel@tonic-gate static int 3980Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr) 3990Sstevel@tonic-gate queue_t *q; 4000Sstevel@tonic-gate mblk_t *mp; 4010Sstevel@tonic-gate caddr_t cp; 4020Sstevel@tonic-gate cred_t *cr; 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 4050Sstevel@tonic-gate uint_t value; 4063448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 4073448Sdh155122 4083448Sdh155122 mutex_enter(&espstack->ipsecesp_param_lock); 4090Sstevel@tonic-gate value = ipsecesppa->ipsecesp_param_value; 4103448Sdh155122 mutex_exit(&espstack->ipsecesp_param_lock); 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 4130Sstevel@tonic-gate return (0); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * This routine sets an NDD variable in a ipsecespparam_t structure. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate /* ARGSUSED */ 4200Sstevel@tonic-gate static int 4210Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr) 4220Sstevel@tonic-gate queue_t *q; 4230Sstevel@tonic-gate mblk_t *mp; 4240Sstevel@tonic-gate char *value; 4250Sstevel@tonic-gate caddr_t cp; 4260Sstevel@tonic-gate cred_t *cr; 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate ulong_t new_value; 4290Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 4303448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * Fail the request if the new value does not lie within the 4340Sstevel@tonic-gate * required bounds. 4350Sstevel@tonic-gate */ 4360Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 4370Sstevel@tonic-gate new_value < ipsecesppa->ipsecesp_param_min || 4380Sstevel@tonic-gate new_value > ipsecesppa->ipsecesp_param_max) { 4390Sstevel@tonic-gate return (EINVAL); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* Set the new value */ 4433448Sdh155122 mutex_enter(&espstack->ipsecesp_param_lock); 4440Sstevel@tonic-gate ipsecesppa->ipsecesp_param_value = new_value; 4453448Sdh155122 mutex_exit(&espstack->ipsecesp_param_lock); 4460Sstevel@tonic-gate return (0); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Using lifetime NDD variables, fill in an extended combination's 4510Sstevel@tonic-gate * lifetime information. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate void 4543448Sdh155122 ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb, netstack_t *ns) 4550Sstevel@tonic-gate { 4563448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 4573448Sdh155122 4583448Sdh155122 ecomb->sadb_x_ecomb_soft_bytes = espstack->ipsecesp_default_soft_bytes; 4593448Sdh155122 ecomb->sadb_x_ecomb_hard_bytes = espstack->ipsecesp_default_hard_bytes; 4603448Sdh155122 ecomb->sadb_x_ecomb_soft_addtime = 4613448Sdh155122 espstack->ipsecesp_default_soft_addtime; 4623448Sdh155122 ecomb->sadb_x_ecomb_hard_addtime = 4633448Sdh155122 espstack->ipsecesp_default_hard_addtime; 4643448Sdh155122 ecomb->sadb_x_ecomb_soft_usetime = 4653448Sdh155122 espstack->ipsecesp_default_soft_usetime; 4663448Sdh155122 ecomb->sadb_x_ecomb_hard_usetime = 4673448Sdh155122 espstack->ipsecesp_default_hard_usetime; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate /* 4710Sstevel@tonic-gate * Initialize things for ESP at module load time. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate boolean_t 4740Sstevel@tonic-gate ipsecesp_ddi_init(void) 4750Sstevel@tonic-gate { 4763448Sdh155122 esp_taskq = taskq_create("esp_taskq", 1, minclsyspri, 4773448Sdh155122 IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0); 4783448Sdh155122 4793448Sdh155122 /* 4803448Sdh155122 * We want to be informed each time a stack is created or 4813448Sdh155122 * destroyed in the kernel, so we can maintain the 4823448Sdh155122 * set of ipsecesp_stack_t's. 4833448Sdh155122 */ 4843448Sdh155122 netstack_register(NS_IPSECESP, ipsecesp_stack_init, NULL, 4853448Sdh155122 ipsecesp_stack_fini); 4863448Sdh155122 4873448Sdh155122 return (B_TRUE); 4883448Sdh155122 } 4893448Sdh155122 4903448Sdh155122 /* 4913448Sdh155122 * Walk through the param array specified registering each element with the 4923448Sdh155122 * named dispatch handler. 4933448Sdh155122 */ 4943448Sdh155122 static boolean_t 4953448Sdh155122 ipsecesp_param_register(IDP *ndp, ipsecespparam_t *espp, int cnt) 4963448Sdh155122 { 4973448Sdh155122 for (; cnt-- > 0; espp++) { 4980Sstevel@tonic-gate if (espp->ipsecesp_param_name != NULL && 4990Sstevel@tonic-gate espp->ipsecesp_param_name[0]) { 5003448Sdh155122 if (!nd_load(ndp, 5013448Sdh155122 espp->ipsecesp_param_name, 5020Sstevel@tonic-gate ipsecesp_param_get, ipsecesp_param_set, 5030Sstevel@tonic-gate (caddr_t)espp)) { 5043448Sdh155122 nd_free(ndp); 5050Sstevel@tonic-gate return (B_FALSE); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate return (B_TRUE); 5100Sstevel@tonic-gate } 5113448Sdh155122 /* 5123448Sdh155122 * Initialize things for ESP for each stack instance 5133448Sdh155122 */ 5143448Sdh155122 static void * 5153448Sdh155122 ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns) 5163448Sdh155122 { 5173448Sdh155122 ipsecesp_stack_t *espstack; 5183448Sdh155122 ipsecespparam_t *espp; 5193448Sdh155122 5203448Sdh155122 espstack = (ipsecesp_stack_t *)kmem_zalloc(sizeof (*espstack), 5213448Sdh155122 KM_SLEEP); 5223448Sdh155122 espstack->ipsecesp_netstack = ns; 5233448Sdh155122 5243448Sdh155122 espp = (ipsecespparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 5253448Sdh155122 espstack->ipsecesp_params = espp; 5263448Sdh155122 bcopy(lcl_param_arr, espp, sizeof (lcl_param_arr)); 5273448Sdh155122 5283448Sdh155122 (void) ipsecesp_param_register(&espstack->ipsecesp_g_nd, espp, 5293448Sdh155122 A_CNT(lcl_param_arr)); 5303448Sdh155122 5313448Sdh155122 (void) esp_kstat_init(espstack, stackid); 5323448Sdh155122 5333448Sdh155122 espstack->esp_sadb.s_acquire_timeout = 5343448Sdh155122 &espstack->ipsecesp_acquire_timeout; 5353448Sdh155122 espstack->esp_sadb.s_acqfn = esp_send_acquire; 5363448Sdh155122 sadbp_init("ESP", &espstack->esp_sadb, SADB_SATYPE_ESP, esp_hash_size, 5373448Sdh155122 espstack->ipsecesp_netstack); 5383448Sdh155122 5393448Sdh155122 mutex_init(&espstack->ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0); 5403448Sdh155122 5413448Sdh155122 ip_drop_register(&espstack->esp_dropper, "IPsec ESP"); 5423448Sdh155122 return (espstack); 5433448Sdh155122 } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * Destroy things for ESP at module unload time. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate void 5490Sstevel@tonic-gate ipsecesp_ddi_destroy(void) 5500Sstevel@tonic-gate { 5513448Sdh155122 netstack_unregister(NS_IPSECESP); 5520Sstevel@tonic-gate taskq_destroy(esp_taskq); 5533448Sdh155122 } 5543448Sdh155122 5553448Sdh155122 /* 5563448Sdh155122 * Destroy things for ESP for one stack instance 5573448Sdh155122 */ 5583448Sdh155122 static void 5593448Sdh155122 ipsecesp_stack_fini(netstackid_t stackid, void *arg) 5603448Sdh155122 { 5613448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg; 5623448Sdh155122 5633448Sdh155122 if (espstack->esp_pfkey_q != NULL) { 5643448Sdh155122 (void) quntimeout(espstack->esp_pfkey_q, espstack->esp_event); 5653448Sdh155122 } 5663448Sdh155122 espstack->esp_sadb.s_acqfn = NULL; 5673448Sdh155122 espstack->esp_sadb.s_acquire_timeout = NULL; 5683448Sdh155122 sadbp_destroy(&espstack->esp_sadb, espstack->ipsecesp_netstack); 5693448Sdh155122 ip_drop_unregister(&espstack->esp_dropper); 5703448Sdh155122 mutex_destroy(&espstack->ipsecesp_param_lock); 5713448Sdh155122 nd_free(&espstack->ipsecesp_g_nd); 5723448Sdh155122 5733448Sdh155122 kmem_free(espstack->ipsecesp_params, sizeof (lcl_param_arr)); 5743448Sdh155122 espstack->ipsecesp_params = NULL; 5753448Sdh155122 kstat_delete_netstack(espstack->esp_ksp, stackid); 5763448Sdh155122 espstack->esp_ksp = NULL; 5773448Sdh155122 espstack->esp_kstats = NULL; 5783448Sdh155122 kmem_free(espstack, sizeof (*espstack)); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * ESP module open routine. 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate /* ARGSUSED */ 5850Sstevel@tonic-gate static int 5860Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 5870Sstevel@tonic-gate { 5883448Sdh155122 netstack_t *ns; 5893448Sdh155122 ipsecesp_stack_t *espstack; 5903448Sdh155122 5917118Ssommerfe if (secpolicy_ip_config(credp, B_FALSE) != 0) 5920Sstevel@tonic-gate return (EPERM); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (q->q_ptr != NULL) 5950Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if (sflag != MODOPEN) 5980Sstevel@tonic-gate return (EINVAL); 5990Sstevel@tonic-gate 6003448Sdh155122 ns = netstack_find_by_cred(credp); 6013448Sdh155122 ASSERT(ns != NULL); 6023448Sdh155122 espstack = ns->netstack_ipsecesp; 6033448Sdh155122 ASSERT(espstack != NULL); 6043448Sdh155122 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * ASSUMPTIONS (because I'm MT_OCEXCL): 6070Sstevel@tonic-gate * 6080Sstevel@tonic-gate * * I'm being pushed on top of IP for all my opens (incl. #1). 6090Sstevel@tonic-gate * * Only ipsecesp_open() can write into esp_sadb.s_ip_q. 6100Sstevel@tonic-gate * * Because of this, I can check lazily for esp_sadb.s_ip_q. 6110Sstevel@tonic-gate * 6120Sstevel@tonic-gate * If these assumptions are wrong, I'm in BIG trouble... 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate 6153448Sdh155122 q->q_ptr = espstack; 6163448Sdh155122 WR(q)->q_ptr = q->q_ptr; 6173448Sdh155122 6183448Sdh155122 if (espstack->esp_sadb.s_ip_q == NULL) { 6190Sstevel@tonic-gate struct T_unbind_req *tur; 6200Sstevel@tonic-gate 6213448Sdh155122 espstack->esp_sadb.s_ip_q = WR(q); 6220Sstevel@tonic-gate /* Allocate an unbind... */ 6233448Sdh155122 espstack->esp_ip_unbind = allocb(sizeof (struct T_unbind_req), 6243448Sdh155122 BPRI_HI); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * Send down T_BIND_REQ to bind IPPROTO_ESP. 6280Sstevel@tonic-gate * Handle the ACK here in ESP. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate qprocson(q); 6313448Sdh155122 if (espstack->esp_ip_unbind == NULL || 6323448Sdh155122 !sadb_t_bind_req(espstack->esp_sadb.s_ip_q, IPPROTO_ESP)) { 6333448Sdh155122 if (espstack->esp_ip_unbind != NULL) { 6343448Sdh155122 freeb(espstack->esp_ip_unbind); 6353448Sdh155122 espstack->esp_ip_unbind = NULL; 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate q->q_ptr = NULL; 6383448Sdh155122 netstack_rele(espstack->ipsecesp_netstack); 6390Sstevel@tonic-gate return (ENOMEM); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6423448Sdh155122 espstack->esp_ip_unbind->b_datap->db_type = M_PROTO; 6433448Sdh155122 tur = (struct T_unbind_req *)espstack->esp_ip_unbind->b_rptr; 6440Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 6450Sstevel@tonic-gate } else { 6460Sstevel@tonic-gate qprocson(q); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * For now, there's not much I can do. I'll be getting a message 6510Sstevel@tonic-gate * passed down to me from keysock (in my wput), and a T_BIND_ACK 6520Sstevel@tonic-gate * up from IP (in my rput). 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate return (0); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * ESP module close routine. 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate static int 6620Sstevel@tonic-gate ipsecesp_close(queue_t *q) 6630Sstevel@tonic-gate { 6643448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 6653448Sdh155122 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * If esp_sadb.s_ip_q is attached to this instance, send a 6680Sstevel@tonic-gate * T_UNBIND_REQ to IP for the instance before doing 6690Sstevel@tonic-gate * a qprocsoff(). 6700Sstevel@tonic-gate */ 6713448Sdh155122 if (WR(q) == espstack->esp_sadb.s_ip_q && 6723448Sdh155122 espstack->esp_ip_unbind != NULL) { 6733448Sdh155122 putnext(WR(q), espstack->esp_ip_unbind); 6743448Sdh155122 espstack->esp_ip_unbind = NULL; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * Clean up q_ptr, if needed. 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate qprocsoff(q); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* Keysock queue check is safe, because of OCEXCL perimeter. */ 6830Sstevel@tonic-gate 6843448Sdh155122 if (q == espstack->esp_pfkey_q) { 6853448Sdh155122 esp1dbg(espstack, 6863448Sdh155122 ("ipsecesp_close: Ummm... keysock is closing ESP.\n")); 6873448Sdh155122 espstack->esp_pfkey_q = NULL; 6880Sstevel@tonic-gate /* Detach qtimeouts. */ 6893448Sdh155122 (void) quntimeout(q, espstack->esp_event); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate 6923448Sdh155122 if (WR(q) == espstack->esp_sadb.s_ip_q) { 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * If the esp_sadb.s_ip_q is attached to this instance, find 6950Sstevel@tonic-gate * another. The OCEXCL outer perimeter helps us here. 6960Sstevel@tonic-gate */ 6973448Sdh155122 espstack->esp_sadb.s_ip_q = NULL; 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * Find a replacement queue for esp_sadb.s_ip_q. 7010Sstevel@tonic-gate */ 7023448Sdh155122 if (espstack->esp_pfkey_q != NULL && 7033448Sdh155122 espstack->esp_pfkey_q != RD(q)) { 7040Sstevel@tonic-gate /* 7050Sstevel@tonic-gate * See if we can use the pfkey_q. 7060Sstevel@tonic-gate */ 7073448Sdh155122 espstack->esp_sadb.s_ip_q = WR(espstack->esp_pfkey_q); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7103448Sdh155122 if (espstack->esp_sadb.s_ip_q == NULL || 7113448Sdh155122 !sadb_t_bind_req(espstack->esp_sadb.s_ip_q, IPPROTO_ESP)) { 7123448Sdh155122 esp1dbg(espstack, ("ipsecesp: Can't reassign ip_q.\n")); 7133448Sdh155122 espstack->esp_sadb.s_ip_q = NULL; 7140Sstevel@tonic-gate } else { 7153448Sdh155122 espstack->esp_ip_unbind = 7163448Sdh155122 allocb(sizeof (struct T_unbind_req), BPRI_HI); 7173448Sdh155122 7183448Sdh155122 if (espstack->esp_ip_unbind != NULL) { 7190Sstevel@tonic-gate struct T_unbind_req *tur; 7200Sstevel@tonic-gate 7213448Sdh155122 espstack->esp_ip_unbind->b_datap->db_type = 7223448Sdh155122 M_PROTO; 7230Sstevel@tonic-gate tur = (struct T_unbind_req *) 7243448Sdh155122 espstack->esp_ip_unbind->b_rptr; 7250Sstevel@tonic-gate tur->PRIM_type = T_UNBIND_REQ; 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate /* If it's NULL, I can't do much here. */ 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7313448Sdh155122 netstack_rele(espstack->ipsecesp_netstack); 7320Sstevel@tonic-gate return (0); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* 7360Sstevel@tonic-gate * Add a number of bytes to what the SA has protected so far. Return 7370Sstevel@tonic-gate * B_TRUE if the SA can still protect that many bytes. 7380Sstevel@tonic-gate * 7390Sstevel@tonic-gate * Caller must REFRELE the passed-in assoc. This function must REFRELE 7400Sstevel@tonic-gate * any obtained peer SA. 7410Sstevel@tonic-gate */ 7420Sstevel@tonic-gate static boolean_t 7430Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound) 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 7460Sstevel@tonic-gate isaf_t *bucket; 7470Sstevel@tonic-gate boolean_t inrc, outrc, isv6; 7480Sstevel@tonic-gate sadb_t *sp; 7490Sstevel@tonic-gate int outhash; 7503448Sdh155122 netstack_t *ns = assoc->ipsa_netstack; 7513448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate /* No peer? No problem! */ 7540Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 7553448Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, assoc, bytes, 7560Sstevel@tonic-gate B_TRUE)); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 7610Sstevel@tonic-gate * There might be a race for this, but if it's a real race, two 7620Sstevel@tonic-gate * expire messages may occur. We limit this by only sending the 7630Sstevel@tonic-gate * expire message on one of the peers, we'll pick the inbound 7640Sstevel@tonic-gate * arbitrarily. 7650Sstevel@tonic-gate * 7660Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 7670Sstevel@tonic-gate * reconsider. 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 7710Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 7723448Sdh155122 sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate if (inbound) { 7750Sstevel@tonic-gate inassoc = assoc; 7760Sstevel@tonic-gate if (isv6) { 777564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 7780Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 7790Sstevel@tonic-gate } else { 780564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 7814987Sdanmcd &inassoc->ipsa_dstaddr)); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 7840Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 7850Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 7860Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 7870Sstevel@tonic-gate inassoc->ipsa_addrfam); 7880Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 7890Sstevel@tonic-gate if (outassoc == NULL) { 7900Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 7910Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 7920Sstevel@tonic-gate "can't find peer for inbound.\n")); 7933448Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, inassoc, 7940Sstevel@tonic-gate bytes, B_TRUE)); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate } else { 7970Sstevel@tonic-gate outassoc = assoc; 798564Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 7990Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 8000Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 8010Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 8020Sstevel@tonic-gate outassoc->ipsa_addrfam); 8030Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 8040Sstevel@tonic-gate if (inassoc == NULL) { 8050Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 8060Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 8070Sstevel@tonic-gate "can't find peer for outbound.\n")); 8083448Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, outassoc, 8090Sstevel@tonic-gate bytes, B_TRUE)); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate 8133448Sdh155122 inrc = sadb_age_bytes(espstack->esp_pfkey_q, inassoc, bytes, B_TRUE); 8143448Sdh155122 outrc = sadb_age_bytes(espstack->esp_pfkey_q, outassoc, bytes, B_FALSE); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * REFRELE any peer SA. 8180Sstevel@tonic-gate * 8190Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 8200Sstevel@tonic-gate * them in { }. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate if (inbound) { 8230Sstevel@tonic-gate IPSA_REFRELE(outassoc); 8240Sstevel@tonic-gate } else { 8250Sstevel@tonic-gate IPSA_REFRELE(inassoc); 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate return (inrc && outrc); 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * Do incoming NAT-T manipulations for packet. 8330Sstevel@tonic-gate */ 8340Sstevel@tonic-gate static ipsec_status_t 8350Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 8380Sstevel@tonic-gate tcpha_t *tcph; 8390Sstevel@tonic-gate udpha_t *udpha; 8400Sstevel@tonic-gate /* Initialize to our inbound cksum adjustment... */ 8410Sstevel@tonic-gate uint32_t sum = assoc->ipsa_inbound_cksum; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate switch (ipha->ipha_protocol) { 8440Sstevel@tonic-gate case IPPROTO_TCP: 8450Sstevel@tonic-gate tcph = (tcpha_t *)(data_mp->b_rptr + 8460Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate #define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16) 8490Sstevel@tonic-gate sum += ~ntohs(tcph->tha_sum) & 0xFFFF; 8500Sstevel@tonic-gate DOWN_SUM(sum); 8510Sstevel@tonic-gate DOWN_SUM(sum); 8520Sstevel@tonic-gate tcph->tha_sum = ~htons(sum); 8530Sstevel@tonic-gate break; 8540Sstevel@tonic-gate case IPPROTO_UDP: 8550Sstevel@tonic-gate udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha)); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate if (udpha->uha_checksum != 0) { 8580Sstevel@tonic-gate /* Adujst if the inbound one was not zero. */ 8590Sstevel@tonic-gate sum += ~ntohs(udpha->uha_checksum) & 0xFFFF; 8600Sstevel@tonic-gate DOWN_SUM(sum); 8610Sstevel@tonic-gate DOWN_SUM(sum); 8620Sstevel@tonic-gate udpha->uha_checksum = ~htons(sum); 8630Sstevel@tonic-gate if (udpha->uha_checksum == 0) 8640Sstevel@tonic-gate udpha->uha_checksum = 0xFFFF; 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate #undef DOWN_SUM 8670Sstevel@tonic-gate break; 8680Sstevel@tonic-gate case IPPROTO_IP: 8690Sstevel@tonic-gate /* 8700Sstevel@tonic-gate * This case is only an issue for self-encapsulated 8710Sstevel@tonic-gate * packets. So for now, fall through. 8720Sstevel@tonic-gate */ 8730Sstevel@tonic-gate break; 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate /* 8803192Sdanmcd * Strip ESP header, check padding, and fix IP header. 8810Sstevel@tonic-gate * Returns B_TRUE on success, B_FALSE if an error occured. 8820Sstevel@tonic-gate */ 8830Sstevel@tonic-gate static boolean_t 8840Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen, 8853448Sdh155122 kstat_named_t **counter, ipsecesp_stack_t *espstack) 8860Sstevel@tonic-gate { 8870Sstevel@tonic-gate ipha_t *ipha; 8880Sstevel@tonic-gate ip6_t *ip6h; 8890Sstevel@tonic-gate uint_t divpoint; 8900Sstevel@tonic-gate mblk_t *scratch; 8910Sstevel@tonic-gate uint8_t nexthdr, padlen; 8920Sstevel@tonic-gate uint8_t lastpad; 8933448Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 8943192Sdanmcd uint8_t *lastbyte; 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * Strip ESP data and fix IP header. 8980Sstevel@tonic-gate * 8990Sstevel@tonic-gate * XXX In case the beginning of esp_inbound() changes to not do a 9000Sstevel@tonic-gate * pullup, this part of the code can remain unchanged. 9010Sstevel@tonic-gate */ 9020Sstevel@tonic-gate if (isv4) { 9030Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t)); 9040Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 9050Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) + 9060Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 9070Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 9080Sstevel@tonic-gate } else { 9090Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t)); 9100Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 9110Sstevel@tonic-gate divpoint = ip_hdr_length_v6(data_mp, ip6h); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate scratch = data_mp; 9150Sstevel@tonic-gate while (scratch->b_cont != NULL) 9160Sstevel@tonic-gate scratch = scratch->b_cont; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3); 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * "Next header" and padding length are the last two bytes in the 9220Sstevel@tonic-gate * ESP-protected datagram, thus the explicit - 1 and - 2. 9230Sstevel@tonic-gate * lastpad is the last byte of the padding, which can be used for 9240Sstevel@tonic-gate * a quick check to see if the padding is correct. 9250Sstevel@tonic-gate */ 9263192Sdanmcd lastbyte = scratch->b_wptr - 1; 9273192Sdanmcd nexthdr = *lastbyte--; 9283192Sdanmcd padlen = *lastbyte--; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate if (isv4) { 9310Sstevel@tonic-gate /* Fix part of the IP header. */ 9320Sstevel@tonic-gate ipha->ipha_protocol = nexthdr; 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Reality check the padlen. The explicit - 2 is for the 9350Sstevel@tonic-gate * padding length and the next-header bytes. 9360Sstevel@tonic-gate */ 9370Sstevel@tonic-gate if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 - 9380Sstevel@tonic-gate sizeof (esph_t) - ivlen) { 9393448Sdh155122 ESP_BUMP_STAT(espstack, bad_decrypt); 9403448Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 9413448Sdh155122 info.mi_idnum, 0, 0, 9423448Sdh155122 SL_ERROR | SL_WARN, 9433192Sdanmcd "Corrupt ESP packet (padlen too big).\n"); 9443448Sdh155122 esp1dbg(espstack, ("padlen (%d) is greater than:\n", 9454987Sdanmcd padlen)); 9463448Sdh155122 esp1dbg(espstack, ("pkt len(%d) - ip hdr - esp " 9473448Sdh155122 "hdr - ivlen(%d) = %d.\n", 9483448Sdh155122 ntohs(ipha->ipha_length), ivlen, 9490Sstevel@tonic-gate (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) - 9503448Sdh155122 2 - sizeof (esph_t) - ivlen))); 9513448Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padlen); 9520Sstevel@tonic-gate return (B_FALSE); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 9570Sstevel@tonic-gate * padding length and the next-header bytes. 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen - 9600Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 9610Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 9620Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 9630Sstevel@tonic-gate } else { 9640Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_ESP) { 9650Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 9660Sstevel@tonic-gate } else { 9670Sstevel@tonic-gate ip6_pkt_t ipp; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 9700Sstevel@tonic-gate (void) ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 9710Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL) { 9720Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt = nexthdr; 9730Sstevel@tonic-gate } else if (ipp.ipp_rthdr != NULL) { 9740Sstevel@tonic-gate ipp.ipp_rthdr->ip6r_nxt = nexthdr; 9750Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 9760Sstevel@tonic-gate ipp.ipp_hopopts->ip6h_nxt = nexthdr; 9770Sstevel@tonic-gate } else { 9780Sstevel@tonic-gate /* Panic a DEBUG kernel. */ 9790Sstevel@tonic-gate ASSERT(ipp.ipp_hopopts != NULL); 9800Sstevel@tonic-gate /* Otherwise, pretend it's IP + ESP. */ 9810Sstevel@tonic-gate cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n"); 9820Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) - 9870Sstevel@tonic-gate ivlen) { 9883448Sdh155122 ESP_BUMP_STAT(espstack, bad_decrypt); 9893448Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 9903448Sdh155122 info.mi_idnum, 0, 0, 9913448Sdh155122 SL_ERROR | SL_WARN, 9923192Sdanmcd "Corrupt ESP packet (v6 padlen too big).\n"); 9933448Sdh155122 esp1dbg(espstack, ("padlen (%d) is greater than:\n", 9944987Sdanmcd padlen)); 9954987Sdanmcd esp1dbg(espstack, 9964987Sdanmcd ("pkt len(%u) - ip hdr - esp hdr - ivlen(%d) = " 9974987Sdanmcd "%u.\n", (unsigned)(ntohs(ip6h->ip6_plen) 9984987Sdanmcd + sizeof (ip6_t)), ivlen, 9994987Sdanmcd (unsigned)(ntohs(ip6h->ip6_plen) - 2 - 10004987Sdanmcd sizeof (esph_t) - ivlen))); 10013448Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padlen); 10020Sstevel@tonic-gate return (B_FALSE); 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate /* 10070Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 10080Sstevel@tonic-gate * padding length and the next-header bytes. IPv6 is nice, 10090Sstevel@tonic-gate * because there's no hdr checksum! 10100Sstevel@tonic-gate */ 10110Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen - 10120Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10153448Sdh155122 if (espstack->ipsecesp_padding_check > 0 && padlen > 0) { 10163192Sdanmcd /* 10173192Sdanmcd * Weak padding check: compare last-byte to length, they 10183192Sdanmcd * should be equal. 10193192Sdanmcd */ 10203192Sdanmcd lastpad = *lastbyte--; 10213192Sdanmcd 10223192Sdanmcd if (padlen != lastpad) { 10233448Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 10243448Sdh155122 info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 10253192Sdanmcd "Corrupt ESP packet (lastpad != padlen).\n"); 10263448Sdh155122 esp1dbg(espstack, 10273448Sdh155122 ("lastpad (%d) not equal to padlen (%d):\n", 10283448Sdh155122 lastpad, padlen)); 10293448Sdh155122 ESP_BUMP_STAT(espstack, bad_padding); 10303448Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padding); 10313192Sdanmcd return (B_FALSE); 10323192Sdanmcd } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate /* 10353192Sdanmcd * Strong padding check: Check all pad bytes to see that 10363192Sdanmcd * they're ascending. Go backwards using a descending counter 10373192Sdanmcd * to verify. padlen == 1 is checked by previous block, so 10383192Sdanmcd * only bother if we've more than 1 byte of padding. 10393192Sdanmcd * Consequently, start the check one byte before the location 10403192Sdanmcd * of "lastpad". 10410Sstevel@tonic-gate */ 10423448Sdh155122 if (espstack->ipsecesp_padding_check > 1) { 10433192Sdanmcd /* 10443192Sdanmcd * This assert may have to become an if and a pullup 10453192Sdanmcd * if we start accepting multi-dblk mblks. For now, 10463192Sdanmcd * though, any packet here will have been pulled up in 10473192Sdanmcd * esp_inbound. 10483192Sdanmcd */ 10493192Sdanmcd ASSERT(MBLKL(scratch) >= lastpad + 3); 10503192Sdanmcd 10513192Sdanmcd /* 10523192Sdanmcd * Use "--lastpad" because we already checked the very 10533192Sdanmcd * last pad byte previously. 10543192Sdanmcd */ 10553192Sdanmcd while (--lastpad != 0) { 10563192Sdanmcd if (lastpad != *lastbyte) { 10573448Sdh155122 ipsec_rl_strlog( 10583448Sdh155122 espstack->ipsecesp_netstack, 10593448Sdh155122 info.mi_idnum, 0, 0, 10603192Sdanmcd SL_ERROR | SL_WARN, "Corrupt ESP " 10613192Sdanmcd "packet (bad padding).\n"); 10623448Sdh155122 esp1dbg(espstack, 10633448Sdh155122 ("padding not in correct" 10643448Sdh155122 " format:\n")); 10653448Sdh155122 ESP_BUMP_STAT(espstack, bad_padding); 10663448Sdh155122 *counter = DROPPER(ipss, 10673448Sdh155122 ipds_esp_bad_padding); 10683192Sdanmcd return (B_FALSE); 10693192Sdanmcd } 10703192Sdanmcd lastbyte--; 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate /* Trim off the padding. */ 10760Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 10770Sstevel@tonic-gate data_mp->b_wptr -= (padlen + 2); 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* 10800Sstevel@tonic-gate * Remove the ESP header. 10810Sstevel@tonic-gate * 10820Sstevel@tonic-gate * The above assertions about data_mp's size will make this work. 10830Sstevel@tonic-gate * 10840Sstevel@tonic-gate * XXX Question: If I send up and get back a contiguous mblk, 10850Sstevel@tonic-gate * would it be quicker to bcopy over, or keep doing the dupb stuff? 10860Sstevel@tonic-gate * I go with copying for now. 10870Sstevel@tonic-gate */ 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) && 10900Sstevel@tonic-gate IS_P2ALIGNED(ivlen, sizeof (uint32_t))) { 10910Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 10920Sstevel@tonic-gate uint32_t *src, *dst; 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate src = (uint32_t *)(start + divpoint); 10950Sstevel@tonic-gate dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen); 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) && 10980Sstevel@tonic-gate IS_P2ALIGNED(src, sizeof (uint32_t))); 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate do { 11010Sstevel@tonic-gate src--; 11020Sstevel@tonic-gate dst--; 11030Sstevel@tonic-gate *dst = *src; 11040Sstevel@tonic-gate } while (src != (uint32_t *)start); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate data_mp->b_rptr = (uchar_t *)dst; 11070Sstevel@tonic-gate } else { 11080Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 11090Sstevel@tonic-gate uint8_t *src, *dst; 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate src = start + divpoint; 11120Sstevel@tonic-gate dst = src + sizeof (esph_t) + ivlen; 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate do { 11150Sstevel@tonic-gate src--; 11160Sstevel@tonic-gate dst--; 11170Sstevel@tonic-gate *dst = *src; 11180Sstevel@tonic-gate } while (src != start); 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate data_mp->b_rptr = dst; 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11233448Sdh155122 esp2dbg(espstack, ("data_mp after inbound ESP adjustment:\n")); 11243448Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate return (B_TRUE); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* 11300Sstevel@tonic-gate * Updating use times can be tricky business if the ipsa_haspeer flag is 11310Sstevel@tonic-gate * set. This function is called once in an SA's lifetime. 11320Sstevel@tonic-gate * 11330Sstevel@tonic-gate * Caller has to REFRELE "assoc" which is passed in. This function has 11340Sstevel@tonic-gate * to REFRELE any peer SA that is obtained. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate static void 11370Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 11400Sstevel@tonic-gate isaf_t *bucket; 11410Sstevel@tonic-gate sadb_t *sp; 11420Sstevel@tonic-gate int outhash; 11430Sstevel@tonic-gate boolean_t isv6; 11443448Sdh155122 netstack_t *ns = assoc->ipsa_netstack; 11453448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate /* No peer? No problem! */ 11480Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 11490Sstevel@tonic-gate sadb_set_usetime(assoc); 11500Sstevel@tonic-gate return; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 11550Sstevel@tonic-gate * There might be a race for this, but if it's a real race, the times 11560Sstevel@tonic-gate * will be out-of-synch by at most a second, and since our time 11570Sstevel@tonic-gate * granularity is a second, this won't be a problem. 11580Sstevel@tonic-gate * 11590Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 11600Sstevel@tonic-gate * reconsider. 11610Sstevel@tonic-gate */ 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 11640Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 11653448Sdh155122 sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4; 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate if (inbound) { 11680Sstevel@tonic-gate inassoc = assoc; 11690Sstevel@tonic-gate if (isv6) { 1170564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 11710Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 11720Sstevel@tonic-gate } else { 1173564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 11744987Sdanmcd &inassoc->ipsa_dstaddr)); 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 11770Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 11780Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 11790Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 11800Sstevel@tonic-gate inassoc->ipsa_addrfam); 11810Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 11820Sstevel@tonic-gate if (outassoc == NULL) { 11830Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 11840Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 11850Sstevel@tonic-gate "can't find peer for inbound.\n")); 11860Sstevel@tonic-gate sadb_set_usetime(inassoc); 11870Sstevel@tonic-gate return; 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate } else { 11900Sstevel@tonic-gate outassoc = assoc; 1191564Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 11920Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 11930Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 11940Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 11950Sstevel@tonic-gate outassoc->ipsa_addrfam); 11960Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 11970Sstevel@tonic-gate if (inassoc == NULL) { 11980Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 11990Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 12000Sstevel@tonic-gate "can't find peer for outbound.\n")); 12010Sstevel@tonic-gate sadb_set_usetime(outassoc); 12020Sstevel@tonic-gate return; 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate /* Update usetime on both. */ 12070Sstevel@tonic-gate sadb_set_usetime(inassoc); 12080Sstevel@tonic-gate sadb_set_usetime(outassoc); 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate /* 12110Sstevel@tonic-gate * REFRELE any peer SA. 12120Sstevel@tonic-gate * 12130Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 12140Sstevel@tonic-gate * them in { }. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate if (inbound) { 12170Sstevel@tonic-gate IPSA_REFRELE(outassoc); 12180Sstevel@tonic-gate } else { 12190Sstevel@tonic-gate IPSA_REFRELE(inassoc); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate /* 12240Sstevel@tonic-gate * Handle ESP inbound data for IPv4 and IPv6. 12250Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 12260Sstevel@tonic-gate * mblk chain ipsec_in_mp. 12270Sstevel@tonic-gate */ 12280Sstevel@tonic-gate ipsec_status_t 12290Sstevel@tonic-gate esp_inbound(mblk_t *ipsec_in_mp, void *arg) 12300Sstevel@tonic-gate { 12310Sstevel@tonic-gate mblk_t *data_mp = ipsec_in_mp->b_cont; 12320Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 12330Sstevel@tonic-gate esph_t *esph = (esph_t *)arg; 12340Sstevel@tonic-gate ipsa_t *ipsa = ii->ipsec_in_esp_sa; 12353448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 12363448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 12373448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * We may wish to check replay in-range-only here as an optimization. 12410Sstevel@tonic-gate * Include the reality check of ipsa->ipsa_replay > 12420Sstevel@tonic-gate * ipsa->ipsa_replay_wsize for times when it's the first N packets, 12430Sstevel@tonic-gate * where N == ipsa->ipsa_replay_wsize. 12440Sstevel@tonic-gate * 12450Sstevel@tonic-gate * Another check that may come here later is the "collision" check. 12460Sstevel@tonic-gate * If legitimate packets flow quickly enough, this won't be a problem, 12470Sstevel@tonic-gate * but collisions may cause authentication algorithm crunching to 12480Sstevel@tonic-gate * take place when it doesn't need to. 12490Sstevel@tonic-gate */ 12500Sstevel@tonic-gate if (!sadb_replay_peek(ipsa, esph->esph_replay)) { 12513448Sdh155122 ESP_BUMP_STAT(espstack, replay_early_failures); 12523448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 12550Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 12560Sstevel@tonic-gate */ 12570Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 12583448Sdh155122 DROPPER(ipss, ipds_esp_early_replay), 12593448Sdh155122 &espstack->esp_dropper); 12600Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate /* 12640Sstevel@tonic-gate * Has this packet already been processed by a hardware 12650Sstevel@tonic-gate * IPsec accelerator? 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate if (ii->ipsec_in_accelerated) { 12680Sstevel@tonic-gate ipsec_status_t rv; 12693448Sdh155122 esp3dbg(espstack, 12703448Sdh155122 ("esp_inbound: pkt processed by ill=%d isv6=%d\n", 12710Sstevel@tonic-gate ii->ipsec_in_ill_index, !ii->ipsec_in_v4)); 12720Sstevel@tonic-gate rv = esp_inbound_accelerated(ipsec_in_mp, 12730Sstevel@tonic-gate data_mp, ii->ipsec_in_v4, ipsa); 12740Sstevel@tonic-gate return (rv); 12750Sstevel@tonic-gate } 12763448Sdh155122 ESP_BUMP_STAT(espstack, noaccel); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12790Sstevel@tonic-gate * Adjust the IP header's payload length to reflect the removal 12800Sstevel@tonic-gate * of the ICV. 12810Sstevel@tonic-gate */ 12820Sstevel@tonic-gate if (!ii->ipsec_in_v4) { 12830Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 12840Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - 12850Sstevel@tonic-gate ipsa->ipsa_mac_len); 12860Sstevel@tonic-gate } else { 12870Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 12880Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - 12890Sstevel@tonic-gate ipsa->ipsa_mac_len); 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate /* submit the request to the crypto framework */ 12930Sstevel@tonic-gate return (esp_submit_req_inbound(ipsec_in_mp, ipsa, 12940Sstevel@tonic-gate (uint8_t *)esph - data_mp->b_rptr)); 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate /* 12980Sstevel@tonic-gate * Perform the really difficult work of inserting the proposed situation. 12990Sstevel@tonic-gate * Called while holding the algorithm lock. 13000Sstevel@tonic-gate */ 13010Sstevel@tonic-gate static void 13020Sstevel@tonic-gate esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs) 13030Sstevel@tonic-gate { 13040Sstevel@tonic-gate sadb_comb_t *comb = (sadb_comb_t *)(prop + 1); 13050Sstevel@tonic-gate ipsec_out_t *io; 13060Sstevel@tonic-gate ipsec_action_t *ap; 13070Sstevel@tonic-gate ipsec_prot_t *prot; 13083448Sdh155122 netstack_t *ns; 13093448Sdh155122 ipsecesp_stack_t *espstack; 13103448Sdh155122 ipsec_stack_t *ipss; 13113448Sdh155122 13120Sstevel@tonic-gate io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr; 13130Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 13143448Sdh155122 ns = io->ipsec_out_ns; 13153448Sdh155122 espstack = ns->netstack_ipsecesp; 13163448Sdh155122 ipss = ns->netstack_ipsec; 13173448Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock)); 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; 13200Sstevel@tonic-gate prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t)); 13210Sstevel@tonic-gate *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ 13220Sstevel@tonic-gate 13233448Sdh155122 prop->sadb_prop_replay = espstack->ipsecesp_replay_size; 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * Based upon algorithm properties, and what-not, prioritize 13270Sstevel@tonic-gate * a proposal. If the IPSEC_OUT message has an algorithm specified, 13280Sstevel@tonic-gate * use it first and foremost. 13290Sstevel@tonic-gate * 13300Sstevel@tonic-gate * For each action in policy list 13310Sstevel@tonic-gate * Add combination. If I've hit limit, return. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate for (ap = acqrec->ipsacq_act; ap != NULL; 13350Sstevel@tonic-gate ap = ap->ipa_next) { 13360Sstevel@tonic-gate ipsec_alginfo_t *ealg = NULL; 13370Sstevel@tonic-gate ipsec_alginfo_t *aalg = NULL; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) 13400Sstevel@tonic-gate continue; 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate prot = &ap->ipa_act.ipa_apply; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if (!(prot->ipp_use_esp)) 13450Sstevel@tonic-gate continue; 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate if (prot->ipp_esp_auth_alg != 0) { 13483448Sdh155122 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] 13490Sstevel@tonic-gate [prot->ipp_esp_auth_alg]; 13500Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) 13510Sstevel@tonic-gate continue; 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate ASSERT(prot->ipp_encr_alg > 0); 13553448Sdh155122 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR] 13563448Sdh155122 [prot->ipp_encr_alg]; 13570Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) 13580Sstevel@tonic-gate continue; 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate comb->sadb_comb_flags = 0; 13610Sstevel@tonic-gate comb->sadb_comb_reserved = 0; 13620Sstevel@tonic-gate comb->sadb_comb_encrypt = ealg->alg_id; 13632751Sdanmcd comb->sadb_comb_encrypt_minbits = 13642751Sdanmcd MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits); 13652751Sdanmcd comb->sadb_comb_encrypt_maxbits = 13662751Sdanmcd MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits); 13670Sstevel@tonic-gate if (aalg == NULL) { 13680Sstevel@tonic-gate comb->sadb_comb_auth = 0; 13690Sstevel@tonic-gate comb->sadb_comb_auth_minbits = 0; 13700Sstevel@tonic-gate comb->sadb_comb_auth_maxbits = 0; 13710Sstevel@tonic-gate } else { 13720Sstevel@tonic-gate comb->sadb_comb_auth = aalg->alg_id; 13732751Sdanmcd comb->sadb_comb_auth_minbits = 13742751Sdanmcd MAX(prot->ipp_espa_minbits, aalg->alg_ef_minbits); 13752751Sdanmcd comb->sadb_comb_auth_maxbits = 13762751Sdanmcd MIN(prot->ipp_espa_maxbits, aalg->alg_ef_maxbits); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate /* 13800Sstevel@tonic-gate * The following may be based on algorithm 13810Sstevel@tonic-gate * properties, but in the meantime, we just pick 13820Sstevel@tonic-gate * some good, sensible numbers. Key mgmt. can 13830Sstevel@tonic-gate * (and perhaps should) be the place to finalize 13840Sstevel@tonic-gate * such decisions. 13850Sstevel@tonic-gate */ 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * No limits on allocations, since we really don't 13890Sstevel@tonic-gate * support that concept currently. 13900Sstevel@tonic-gate */ 13910Sstevel@tonic-gate comb->sadb_comb_soft_allocations = 0; 13920Sstevel@tonic-gate comb->sadb_comb_hard_allocations = 0; 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate /* 13950Sstevel@tonic-gate * These may want to come from policy rule.. 13960Sstevel@tonic-gate */ 13973448Sdh155122 comb->sadb_comb_soft_bytes = 13983448Sdh155122 espstack->ipsecesp_default_soft_bytes; 13993448Sdh155122 comb->sadb_comb_hard_bytes = 14003448Sdh155122 espstack->ipsecesp_default_hard_bytes; 14013448Sdh155122 comb->sadb_comb_soft_addtime = 14023448Sdh155122 espstack->ipsecesp_default_soft_addtime; 14033448Sdh155122 comb->sadb_comb_hard_addtime = 14043448Sdh155122 espstack->ipsecesp_default_hard_addtime; 14053448Sdh155122 comb->sadb_comb_soft_usetime = 14063448Sdh155122 espstack->ipsecesp_default_soft_usetime; 14073448Sdh155122 comb->sadb_comb_hard_usetime = 14083448Sdh155122 espstack->ipsecesp_default_hard_usetime; 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); 14110Sstevel@tonic-gate if (--combs == 0) 14120Sstevel@tonic-gate break; /* out of space.. */ 14130Sstevel@tonic-gate comb++; 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * Prepare and actually send the SADB_ACQUIRE message to PF_KEY. 14190Sstevel@tonic-gate */ 14200Sstevel@tonic-gate static void 14213448Sdh155122 esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns) 14220Sstevel@tonic-gate { 14233055Sdanmcd uint_t combs; 14240Sstevel@tonic-gate sadb_msg_t *samsg; 14250Sstevel@tonic-gate sadb_prop_t *prop; 14263055Sdanmcd mblk_t *pfkeymp, *msgmp; 14273448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 14283448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 14293448Sdh155122 14303448Sdh155122 ESP_BUMP_STAT(espstack, acquire_requests); 14313448Sdh155122 14327073Spwernau if (espstack->esp_pfkey_q == NULL) { 14337073Spwernau mutex_exit(&acqrec->ipsacq_lock); 14343055Sdanmcd return; 14357073Spwernau } 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate /* Set up ACQUIRE. */ 14383448Sdh155122 pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP, 14393448Sdh155122 ns->netstack_ipsec); 14403055Sdanmcd if (pfkeymp == NULL) { 14410Sstevel@tonic-gate esp0dbg(("sadb_setup_acquire failed.\n")); 14427073Spwernau mutex_exit(&acqrec->ipsacq_lock); 14433055Sdanmcd return; 14440Sstevel@tonic-gate } 14453448Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock)); 14463448Sdh155122 combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] * 14473448Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_ENCR]; 14483055Sdanmcd msgmp = pfkeymp->b_cont; 14493055Sdanmcd samsg = (sadb_msg_t *)(msgmp->b_rptr); 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate /* Insert proposal here. */ 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len); 14540Sstevel@tonic-gate esp_insert_prop(prop, acqrec, combs); 14550Sstevel@tonic-gate samsg->sadb_msg_len += prop->sadb_prop_len; 14560Sstevel@tonic-gate msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len); 14570Sstevel@tonic-gate 14583448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate /* 14610Sstevel@tonic-gate * Must mutex_exit() before sending PF_KEY message up, in 14620Sstevel@tonic-gate * order to avoid recursive mutex_enter() if there are no registered 14630Sstevel@tonic-gate * listeners. 14640Sstevel@tonic-gate * 14650Sstevel@tonic-gate * Once I've sent the message, I'm cool anyway. 14660Sstevel@tonic-gate */ 14670Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 14683055Sdanmcd if (extended != NULL) { 14693448Sdh155122 putnext(espstack->esp_pfkey_q, extended); 14700Sstevel@tonic-gate } 14713448Sdh155122 putnext(espstack->esp_pfkey_q, pfkeymp); 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate /* 14750Sstevel@tonic-gate * Handle the SADB_GETSPI message. Create a larval SA. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate static void 14783448Sdh155122 esp_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack) 14790Sstevel@tonic-gate { 14800Sstevel@tonic-gate ipsa_t *newbie, *target; 14810Sstevel@tonic-gate isaf_t *outbound, *inbound; 14820Sstevel@tonic-gate int rc, diagnostic; 14830Sstevel@tonic-gate sadb_sa_t *assoc; 14840Sstevel@tonic-gate keysock_out_t *kso; 14850Sstevel@tonic-gate uint32_t newspi; 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate /* 14880Sstevel@tonic-gate * Randomly generate a proposed SPI value 14890Sstevel@tonic-gate */ 14907749SThejaswini.Singarajipura@Sun.COM if (cl_inet_getspi != NULL) { 1491*8392SHuafeng.Lv@Sun.COM cl_inet_getspi(espstack->ipsecesp_netstack->netstack_stackid, 1492*8392SHuafeng.Lv@Sun.COM IPPROTO_ESP, (uint8_t *)&newspi, sizeof (uint32_t), NULL); 14937749SThejaswini.Singarajipura@Sun.COM } else { 14947749SThejaswini.Singarajipura@Sun.COM (void) random_get_pseudo_bytes((uint8_t *)&newspi, 14957749SThejaswini.Singarajipura@Sun.COM sizeof (uint32_t)); 14967749SThejaswini.Singarajipura@Sun.COM } 14973448Sdh155122 newbie = sadb_getspi(ksi, newspi, &diagnostic, 14987749SThejaswini.Singarajipura@Sun.COM espstack->ipsecesp_netstack, IPPROTO_ESP); 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate if (newbie == NULL) { 15013448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, diagnostic, 15020Sstevel@tonic-gate ksi->ks_in_serial); 15030Sstevel@tonic-gate return; 15040Sstevel@tonic-gate } else if (newbie == (ipsa_t *)-1) { 15053448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic, 15060Sstevel@tonic-gate ksi->ks_in_serial); 15070Sstevel@tonic-gate return; 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate /* 15110Sstevel@tonic-gate * XXX - We may randomly collide. We really should recover from this. 15120Sstevel@tonic-gate * Unfortunately, that could require spending way-too-much-time 15130Sstevel@tonic-gate * in here. For now, let the user retry. 15140Sstevel@tonic-gate */ 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate if (newbie->ipsa_addrfam == AF_INET6) { 15173448Sdh155122 outbound = OUTBOUND_BUCKET_V6(&espstack->esp_sadb.s_v6, 1518564Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 15193448Sdh155122 inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v6, 15203448Sdh155122 newbie->ipsa_spi); 15210Sstevel@tonic-gate } else { 15220Sstevel@tonic-gate ASSERT(newbie->ipsa_addrfam == AF_INET); 15233448Sdh155122 outbound = OUTBOUND_BUCKET_V4(&espstack->esp_sadb.s_v4, 1524564Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 15253448Sdh155122 inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v4, 15263448Sdh155122 newbie->ipsa_spi); 15270Sstevel@tonic-gate } 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate mutex_enter(&outbound->isaf_lock); 15300Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate /* 15330Sstevel@tonic-gate * Check for collisions (i.e. did sadb_getspi() return with something 15340Sstevel@tonic-gate * that already exists?). 15350Sstevel@tonic-gate * 15360Sstevel@tonic-gate * Try outbound first. Even though SADB_GETSPI is traditionally 15370Sstevel@tonic-gate * for inbound SAs, you never know what a user might do. 15380Sstevel@tonic-gate */ 15390Sstevel@tonic-gate target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi, 15400Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam); 15410Sstevel@tonic-gate if (target == NULL) { 15420Sstevel@tonic-gate target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi, 15430Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, 15440Sstevel@tonic-gate newbie->ipsa_addrfam); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * I don't have collisions elsewhere! 15490Sstevel@tonic-gate * (Nor will I because I'm still holding inbound/outbound locks.) 15500Sstevel@tonic-gate */ 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate if (target != NULL) { 15530Sstevel@tonic-gate rc = EEXIST; 15540Sstevel@tonic-gate IPSA_REFRELE(target); 15550Sstevel@tonic-gate } else { 15560Sstevel@tonic-gate /* 15570Sstevel@tonic-gate * sadb_insertassoc() also checks for collisions, so 15580Sstevel@tonic-gate * if there's a colliding entry, rc will be set 15590Sstevel@tonic-gate * to EEXIST. 15600Sstevel@tonic-gate */ 15610Sstevel@tonic-gate rc = sadb_insertassoc(newbie, inbound); 15624987Sdanmcd newbie->ipsa_hardexpiretime = gethrestime_sec(); 15633448Sdh155122 newbie->ipsa_hardexpiretime += 15643448Sdh155122 espstack->ipsecesp_larval_timeout; 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate /* 15680Sstevel@tonic-gate * Can exit outbound mutex. Hold inbound until we're done 15690Sstevel@tonic-gate * with newbie. 15700Sstevel@tonic-gate */ 15710Sstevel@tonic-gate mutex_exit(&outbound->isaf_lock); 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate if (rc != 0) { 15740Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 15750Sstevel@tonic-gate IPSA_REFRELE(newbie); 15763448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, rc, 15773448Sdh155122 SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial); 15780Sstevel@tonic-gate return; 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate 15820Sstevel@tonic-gate /* Can write here because I'm still holding the bucket lock. */ 15830Sstevel@tonic-gate newbie->ipsa_type = SADB_SATYPE_ESP; 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate /* 15866668Smarkfen * Construct successful return message. We have one thing going 15870Sstevel@tonic-gate * for us in PF_KEY v2. That's the fact that 15880Sstevel@tonic-gate * sizeof (sadb_spirange_t) == sizeof (sadb_sa_t) 15890Sstevel@tonic-gate */ 15900Sstevel@tonic-gate assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE]; 15910Sstevel@tonic-gate assoc->sadb_sa_exttype = SADB_EXT_SA; 15920Sstevel@tonic-gate assoc->sadb_sa_spi = newbie->ipsa_spi; 15930Sstevel@tonic-gate *((uint64_t *)(&assoc->sadb_sa_replay)) = 0; 15940Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 15950Sstevel@tonic-gate 15960Sstevel@tonic-gate /* Convert KEYSOCK_IN to KEYSOCK_OUT. */ 15970Sstevel@tonic-gate kso = (keysock_out_t *)ksi; 15980Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso); 15990Sstevel@tonic-gate kso->ks_out_serial = ksi->ks_in_serial; 16000Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT; 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate /* 16030Sstevel@tonic-gate * Can safely putnext() to esp_pfkey_q, because this is a turnaround 16040Sstevel@tonic-gate * from the esp_pfkey_q. 16050Sstevel@tonic-gate */ 16063448Sdh155122 putnext(espstack->esp_pfkey_q, mp); 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate /* 16100Sstevel@tonic-gate * Insert the ESP header into a packet. Duplicate an mblk, and insert a newly 16110Sstevel@tonic-gate * allocated mblk with the ESP header in between the two. 16120Sstevel@tonic-gate */ 16130Sstevel@tonic-gate static boolean_t 16143448Sdh155122 esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint, 16153448Sdh155122 ipsecesp_stack_t *espstack) 16160Sstevel@tonic-gate { 16170Sstevel@tonic-gate mblk_t *split_mp = mp; 16180Sstevel@tonic-gate uint_t wheretodiv = divpoint; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) { 16210Sstevel@tonic-gate wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr); 16220Sstevel@tonic-gate split_mp = split_mp->b_cont; 16230Sstevel@tonic-gate ASSERT(split_mp != NULL); 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) { 16270Sstevel@tonic-gate mblk_t *scratch; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate /* "scratch" is the 2nd half, split_mp is the first. */ 16300Sstevel@tonic-gate scratch = dupb(split_mp); 16310Sstevel@tonic-gate if (scratch == NULL) { 16323448Sdh155122 esp1dbg(espstack, 16333448Sdh155122 ("esp_insert_esp: can't allocate scratch.\n")); 16340Sstevel@tonic-gate return (B_FALSE); 16350Sstevel@tonic-gate } 16360Sstevel@tonic-gate /* NOTE: dupb() doesn't set b_cont appropriately. */ 16370Sstevel@tonic-gate scratch->b_cont = split_mp->b_cont; 16380Sstevel@tonic-gate scratch->b_rptr += wheretodiv; 16390Sstevel@tonic-gate split_mp->b_wptr = split_mp->b_rptr + wheretodiv; 16400Sstevel@tonic-gate split_mp->b_cont = scratch; 16410Sstevel@tonic-gate } 16420Sstevel@tonic-gate /* 16430Sstevel@tonic-gate * At this point, split_mp is exactly "wheretodiv" bytes long, and 16440Sstevel@tonic-gate * holds the end of the pre-ESP part of the datagram. 16450Sstevel@tonic-gate */ 16460Sstevel@tonic-gate esp_mp->b_cont = split_mp->b_cont; 16470Sstevel@tonic-gate split_mp->b_cont = esp_mp; 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate return (B_TRUE); 16500Sstevel@tonic-gate } 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate /* 16537066Sdanmcd * Section 7 of RFC 3947 says: 16547066Sdanmcd * 16557066Sdanmcd * 7. Recovering from the Expiring NAT Mappings 16567066Sdanmcd * 16577066Sdanmcd * There are cases where NAT box decides to remove mappings that are still 16587066Sdanmcd * alive (for example, when the keepalive interval is too long, or when the 16597066Sdanmcd * NAT box is rebooted). To recover from this, ends that are NOT behind 16607066Sdanmcd * NAT SHOULD use the last valid UDP encapsulated IKE or IPsec packet from 16617066Sdanmcd * the other end to determine which IP and port addresses should be used. 16627066Sdanmcd * The host behind dynamic NAT MUST NOT do this, as otherwise it opens a 16637066Sdanmcd * DoS attack possibility because the IP address or port of the other host 16647066Sdanmcd * will not change (it is not behind NAT). 16657066Sdanmcd * 16667066Sdanmcd * Keepalives cannot be used for these purposes, as they are not 16677066Sdanmcd * authenticated, but any IKE authenticated IKE packet or ESP packet can be 16687066Sdanmcd * used to detect whether the IP address or the port has changed. 16697066Sdanmcd * 16707066Sdanmcd * The following function will check an SA and its explicitly-set pair to see 16717066Sdanmcd * if the NAT-T remote port matches the received packet (which must have 16727066Sdanmcd * passed ESP authentication, see esp_in_done() for the caller context). If 16737066Sdanmcd * there is a mismatch, the SAs are updated. It is not important if we race 16747066Sdanmcd * with a transmitting thread, as if there is a transmitting thread, it will 16757066Sdanmcd * merely emit a packet that will most-likely be dropped. 16767066Sdanmcd * 16777066Sdanmcd * "ports" are ordered src,dst, and assoc is an inbound SA, where src should 16787066Sdanmcd * match ipsa_remote_nat_port and dst should match ipsa_local_nat_port. 16797066Sdanmcd */ 16807066Sdanmcd #ifdef _LITTLE_ENDIAN 16817066Sdanmcd #define FIRST_16(x) ((x) & 0xFFFF) 16827066Sdanmcd #define NEXT_16(x) (((x) >> 16) & 0xFFFF) 16837066Sdanmcd #else 16847066Sdanmcd #define FIRST_16(x) (((x) >> 16) & 0xFFFF) 16857066Sdanmcd #define NEXT_16(x) ((x) & 0xFFFF) 16867066Sdanmcd #endif 16877066Sdanmcd static void 16887066Sdanmcd esp_port_freshness(uint32_t ports, ipsa_t *assoc) 16897066Sdanmcd { 16907066Sdanmcd uint16_t remote = FIRST_16(ports); 16917066Sdanmcd uint16_t local = NEXT_16(ports); 16927066Sdanmcd ipsa_t *outbound_peer; 16937066Sdanmcd isaf_t *bucket; 16947066Sdanmcd ipsecesp_stack_t *espstack = assoc->ipsa_netstack->netstack_ipsecesp; 16957066Sdanmcd 16967066Sdanmcd /* We found a conn_t, therefore local != 0. */ 16977066Sdanmcd ASSERT(local != 0); 16987066Sdanmcd /* Assume an IPv4 SA. */ 16997066Sdanmcd ASSERT(assoc->ipsa_addrfam == AF_INET); 17007066Sdanmcd 17017066Sdanmcd /* 17027066Sdanmcd * On-the-wire rport == 0 means something's very wrong. 17037066Sdanmcd * An unpaired SA is also useless to us. 17047066Sdanmcd * If we are behind the NAT, don't bother. 17057066Sdanmcd * A zero local NAT port defaults to 4500, so check that too. 17067066Sdanmcd * And, of course, if the ports already match, we don't need to 17077066Sdanmcd * bother. 17087066Sdanmcd */ 17097066Sdanmcd if (remote == 0 || assoc->ipsa_otherspi == 0 || 17107066Sdanmcd (assoc->ipsa_flags & IPSA_F_BEHIND_NAT) || 17117066Sdanmcd (assoc->ipsa_remote_nat_port == 0 && 17127066Sdanmcd remote == htons(IPPORT_IKE_NATT)) || 17137066Sdanmcd remote == assoc->ipsa_remote_nat_port) 17147066Sdanmcd return; 17157066Sdanmcd 17167066Sdanmcd /* Try and snag the peer. NOTE: Assume IPv4 for now. */ 17177066Sdanmcd bucket = OUTBOUND_BUCKET_V4(&(espstack->esp_sadb.s_v4), 17187066Sdanmcd assoc->ipsa_srcaddr[0]); 17197066Sdanmcd mutex_enter(&bucket->isaf_lock); 17207066Sdanmcd outbound_peer = ipsec_getassocbyspi(bucket, assoc->ipsa_otherspi, 17217066Sdanmcd assoc->ipsa_dstaddr, assoc->ipsa_srcaddr, AF_INET); 17227066Sdanmcd mutex_exit(&bucket->isaf_lock); 17237066Sdanmcd 17247066Sdanmcd /* We probably lost a race to a deleting or expiring thread. */ 17257066Sdanmcd if (outbound_peer == NULL) 17267066Sdanmcd return; 17277066Sdanmcd 17287066Sdanmcd /* 17297066Sdanmcd * Hold the mutexes for both SAs so we don't race another inbound 17307066Sdanmcd * thread. A lock-entry order shouldn't matter, since all other 17317066Sdanmcd * per-ipsa locks are individually held-then-released. 17327066Sdanmcd * 17337066Sdanmcd * Luckily, this has nothing to do with the remote-NAT address, 17347066Sdanmcd * so we don't have to re-scribble the cached-checksum differential. 17357066Sdanmcd */ 17367066Sdanmcd mutex_enter(&outbound_peer->ipsa_lock); 17377066Sdanmcd mutex_enter(&assoc->ipsa_lock); 17387066Sdanmcd outbound_peer->ipsa_remote_nat_port = assoc->ipsa_remote_nat_port = 17397066Sdanmcd remote; 17407066Sdanmcd mutex_exit(&assoc->ipsa_lock); 17417066Sdanmcd mutex_exit(&outbound_peer->ipsa_lock); 17427066Sdanmcd IPSA_REFRELE(outbound_peer); 17437066Sdanmcd ESP_BUMP_STAT(espstack, sa_port_renumbers); 17447066Sdanmcd } 17457066Sdanmcd /* 17460Sstevel@tonic-gate * Finish processing of an inbound ESP packet after processing by the 17470Sstevel@tonic-gate * crypto framework. 17480Sstevel@tonic-gate * - Remove the ESP header. 17490Sstevel@tonic-gate * - Send packet back to IP. 17500Sstevel@tonic-gate * If authentication was performed on the packet, this function is called 17510Sstevel@tonic-gate * only if the authentication succeeded. 17520Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 17530Sstevel@tonic-gate * mblk chain ipsec_in_mp. 17540Sstevel@tonic-gate */ 17550Sstevel@tonic-gate static ipsec_status_t 17560Sstevel@tonic-gate esp_in_done(mblk_t *ipsec_in_mp) 17570Sstevel@tonic-gate { 17580Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 17590Sstevel@tonic-gate mblk_t *data_mp; 17600Sstevel@tonic-gate ipsa_t *assoc; 17610Sstevel@tonic-gate uint_t espstart; 17620Sstevel@tonic-gate uint32_t ivlen = 0; 17630Sstevel@tonic-gate uint_t processed_len; 17640Sstevel@tonic-gate esph_t *esph; 17650Sstevel@tonic-gate kstat_named_t *counter; 17660Sstevel@tonic-gate boolean_t is_natt; 17673448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 17683448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 17693448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate assoc = ii->ipsec_in_esp_sa; 17720Sstevel@tonic-gate ASSERT(assoc != NULL); 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate /* get the pointer to the ESP header */ 17770Sstevel@tonic-gate if (assoc->ipsa_encr_alg == SADB_EALG_NULL) { 17780Sstevel@tonic-gate /* authentication-only ESP */ 17790Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset; 17800Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length; 17810Sstevel@tonic-gate } else { 17820Sstevel@tonic-gate /* encryption present */ 17830Sstevel@tonic-gate ivlen = assoc->ipsa_iv_len; 17840Sstevel@tonic-gate if (assoc->ipsa_auth_alg == SADB_AALG_NONE) { 17850Sstevel@tonic-gate /* encryption-only ESP */ 17860Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_data.cd_offset - 17874987Sdanmcd sizeof (esph_t) - assoc->ipsa_iv_len; 17880Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_data.cd_length + 17894987Sdanmcd ivlen; 17900Sstevel@tonic-gate } else { 17910Sstevel@tonic-gate /* encryption with authentication */ 17920Sstevel@tonic-gate espstart = ii->ipsec_in_crypto_dual_data.dd_offset1; 17930Sstevel@tonic-gate processed_len = ii->ipsec_in_crypto_dual_data.dd_len2 + 17940Sstevel@tonic-gate ivlen; 17950Sstevel@tonic-gate } 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate data_mp = ipsec_in_mp->b_cont; 17990Sstevel@tonic-gate esph = (esph_t *)(data_mp->b_rptr + espstart); 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 18020Sstevel@tonic-gate /* authentication passed if we reach this point */ 18033448Sdh155122 ESP_BUMP_STAT(espstack, good_auth); 18040Sstevel@tonic-gate data_mp->b_wptr -= assoc->ipsa_mac_len; 18050Sstevel@tonic-gate 18060Sstevel@tonic-gate /* 18070Sstevel@tonic-gate * Check replay window here! 18080Sstevel@tonic-gate * For right now, assume keysock will set the replay window 18090Sstevel@tonic-gate * size to zero for SAs that have an unspecified sender. 18100Sstevel@tonic-gate * This may change... 18110Sstevel@tonic-gate */ 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate if (!sadb_replay_check(assoc, esph->esph_replay)) { 18140Sstevel@tonic-gate /* 18150Sstevel@tonic-gate * Log the event. As of now we print out an event. 18160Sstevel@tonic-gate * Do not print the replay failure number, or else 18170Sstevel@tonic-gate * syslog cannot collate the error messages. Printing 18180Sstevel@tonic-gate * the replay number that failed opens a denial-of- 18190Sstevel@tonic-gate * service attack. 18200Sstevel@tonic-gate */ 18210Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 18220Sstevel@tonic-gate SL_ERROR | SL_WARN, 18230Sstevel@tonic-gate "Replay failed for ESP spi 0x%x, dst %s.\n", 18240Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, 18253448Sdh155122 assoc->ipsa_addrfam, espstack->ipsecesp_netstack); 18263448Sdh155122 ESP_BUMP_STAT(espstack, replay_failures); 18273448Sdh155122 counter = DROPPER(ipss, ipds_esp_replay); 18280Sstevel@tonic-gate goto drop_and_bail; 18290Sstevel@tonic-gate } 18307066Sdanmcd 18317066Sdanmcd if (is_natt) 18327066Sdanmcd esp_port_freshness(ii->ipsec_in_esp_udp_ports, assoc); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate 18354987Sdanmcd esp_set_usetime(assoc, B_TRUE); 18364987Sdanmcd 18370Sstevel@tonic-gate if (!esp_age_bytes(assoc, processed_len, B_TRUE)) { 18380Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 18390Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 18400Sstevel@tonic-gate SL_ERROR | SL_WARN, 18410Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 18423448Sdh155122 assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam, 18433448Sdh155122 espstack->ipsecesp_netstack); 18443448Sdh155122 ESP_BUMP_STAT(espstack, bytes_expired); 18453448Sdh155122 counter = DROPPER(ipss, ipds_esp_bytes_expire); 18460Sstevel@tonic-gate goto drop_and_bail; 18470Sstevel@tonic-gate } 18480Sstevel@tonic-gate 18490Sstevel@tonic-gate /* 18500Sstevel@tonic-gate * Remove ESP header and padding from packet. I hope the compiler 18510Sstevel@tonic-gate * spews "branch, predict taken" code for this. 18520Sstevel@tonic-gate */ 18530Sstevel@tonic-gate 18543448Sdh155122 if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter, 18554987Sdanmcd espstack)) { 18560Sstevel@tonic-gate if (is_natt) 18570Sstevel@tonic-gate return (esp_fix_natt_checksums(data_mp, assoc)); 18587885Sdanmcd@sun.com 18597885Sdanmcd@sun.com if (assoc->ipsa_state == IPSA_STATE_IDLE) { 18607885Sdanmcd@sun.com /* 18617885Sdanmcd@sun.com * Cluster buffering case. Tell caller that we're 18627885Sdanmcd@sun.com * handling the packet. 18637885Sdanmcd@sun.com */ 18647885Sdanmcd@sun.com sadb_buf_pkt(assoc, ipsec_in_mp, ns); 18657885Sdanmcd@sun.com return (IPSEC_STATUS_PENDING); 18667885Sdanmcd@sun.com } 18677885Sdanmcd@sun.com 18680Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 18690Sstevel@tonic-gate } 18700Sstevel@tonic-gate 18713448Sdh155122 esp1dbg(espstack, ("esp_in_done: esp_strip_header() failed\n")); 18720Sstevel@tonic-gate drop_and_bail: 18733448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 18740Sstevel@tonic-gate /* 18750Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN message's 18760Sstevel@tonic-gate * ii->ipsec_in_rill_index. 18770Sstevel@tonic-gate */ 18783448Sdh155122 ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, counter, 18793448Sdh155122 &espstack->esp_dropper); 18800Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate /* 18840Sstevel@tonic-gate * Called upon failing the inbound ICV check. The message passed as 18850Sstevel@tonic-gate * argument is freed. 18860Sstevel@tonic-gate */ 18870Sstevel@tonic-gate static void 18880Sstevel@tonic-gate esp_log_bad_auth(mblk_t *ipsec_in) 18890Sstevel@tonic-gate { 18900Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr; 18910Sstevel@tonic-gate ipsa_t *assoc = ii->ipsec_in_esp_sa; 18923448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 18933448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 18943448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 18950Sstevel@tonic-gate 18960Sstevel@tonic-gate /* 18970Sstevel@tonic-gate * Log the event. Don't print to the console, block 18980Sstevel@tonic-gate * potential denial-of-service attack. 18990Sstevel@tonic-gate */ 19003448Sdh155122 ESP_BUMP_STAT(espstack, bad_auth); 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 19030Sstevel@tonic-gate "ESP Authentication failed for spi 0x%x, dst %s.\n", 19043448Sdh155122 assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam, 19053448Sdh155122 espstack->ipsecesp_netstack); 19063448Sdh155122 19073448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 19080Sstevel@tonic-gate /* 19090Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 19100Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 19110Sstevel@tonic-gate */ 19123448Sdh155122 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 19133448Sdh155122 DROPPER(ipss, ipds_esp_bad_auth), 19143448Sdh155122 &espstack->esp_dropper); 19150Sstevel@tonic-gate } 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate /* 19190Sstevel@tonic-gate * Invoked for outbound packets after ESP processing. If the packet 19200Sstevel@tonic-gate * also requires AH, performs the AH SA selection and AH processing. 19210Sstevel@tonic-gate * Returns B_TRUE if the AH processing was not needed or if it was 19220Sstevel@tonic-gate * performed successfully. Returns B_FALSE and consumes the passed mblk 19230Sstevel@tonic-gate * if AH processing was required but could not be performed. 19240Sstevel@tonic-gate */ 19250Sstevel@tonic-gate static boolean_t 19260Sstevel@tonic-gate esp_do_outbound_ah(mblk_t *ipsec_mp) 19270Sstevel@tonic-gate { 19280Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 19290Sstevel@tonic-gate ipsec_status_t ipsec_rc; 19300Sstevel@tonic-gate ipsec_action_t *ap; 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate ap = io->ipsec_out_act; 19330Sstevel@tonic-gate if (ap == NULL) { 19340Sstevel@tonic-gate ipsec_policy_t *pp = io->ipsec_out_policy; 19350Sstevel@tonic-gate ap = pp->ipsp_act; 19360Sstevel@tonic-gate } 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate if (!ap->ipa_want_ah) 19390Sstevel@tonic-gate return (B_TRUE); 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_done == B_FALSE); 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate if (io->ipsec_out_ah_sa == NULL) { 19440Sstevel@tonic-gate if (!ipsec_outbound_sa(ipsec_mp, IPPROTO_AH)) { 19450Sstevel@tonic-gate sadb_acquire(ipsec_mp, io, B_TRUE, B_FALSE); 19460Sstevel@tonic-gate return (B_FALSE); 19470Sstevel@tonic-gate } 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate ASSERT(io->ipsec_out_ah_sa != NULL); 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate io->ipsec_out_ah_done = B_TRUE; 19520Sstevel@tonic-gate ipsec_rc = io->ipsec_out_ah_sa->ipsa_output_func(ipsec_mp); 19530Sstevel@tonic-gate return (ipsec_rc == IPSEC_STATUS_SUCCESS); 19540Sstevel@tonic-gate } 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate 19570Sstevel@tonic-gate /* 19580Sstevel@tonic-gate * Kernel crypto framework callback invoked after completion of async 19590Sstevel@tonic-gate * crypto requests. 19600Sstevel@tonic-gate */ 19610Sstevel@tonic-gate static void 19620Sstevel@tonic-gate esp_kcf_callback(void *arg, int status) 19630Sstevel@tonic-gate { 19640Sstevel@tonic-gate mblk_t *ipsec_mp = (mblk_t *)arg; 19650Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 19664987Sdanmcd ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 19670Sstevel@tonic-gate boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN); 19683448Sdh155122 netstackid_t stackid; 19693448Sdh155122 netstack_t *ns, *ns_arg; 19703448Sdh155122 ipsecesp_stack_t *espstack; 19713448Sdh155122 ipsec_stack_t *ipss; 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL); 19740Sstevel@tonic-gate 19753448Sdh155122 if (is_inbound) { 19763448Sdh155122 stackid = ii->ipsec_in_stackid; 19773448Sdh155122 ns_arg = ii->ipsec_in_ns; 19783448Sdh155122 } else { 19793448Sdh155122 stackid = io->ipsec_out_stackid; 19803448Sdh155122 ns_arg = io->ipsec_out_ns; 19813448Sdh155122 } 19823448Sdh155122 19833448Sdh155122 /* 19843448Sdh155122 * Verify that the netstack is still around; could have vanished 19853448Sdh155122 * while kEf was doing its work. 19863448Sdh155122 */ 19873448Sdh155122 ns = netstack_find_by_stackid(stackid); 19883448Sdh155122 if (ns == NULL || ns != ns_arg) { 19893448Sdh155122 /* Disappeared on us */ 19903448Sdh155122 if (ns != NULL) 19913448Sdh155122 netstack_rele(ns); 19923448Sdh155122 freemsg(ipsec_mp); 19933448Sdh155122 return; 19943448Sdh155122 } 19953448Sdh155122 19963448Sdh155122 espstack = ns->netstack_ipsecesp; 19973448Sdh155122 ipss = ns->netstack_ipsec; 19983448Sdh155122 19990Sstevel@tonic-gate if (status == CRYPTO_SUCCESS) { 20000Sstevel@tonic-gate if (is_inbound) { 20013448Sdh155122 if (esp_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) { 20023448Sdh155122 netstack_rele(ns); 20030Sstevel@tonic-gate return; 20043448Sdh155122 } 20050Sstevel@tonic-gate /* finish IPsec processing */ 20060Sstevel@tonic-gate ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL); 20070Sstevel@tonic-gate } else { 20080Sstevel@tonic-gate /* 20090Sstevel@tonic-gate * If a ICV was computed, it was stored by the 20100Sstevel@tonic-gate * crypto framework at the end of the packet. 20110Sstevel@tonic-gate */ 20120Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr; 20130Sstevel@tonic-gate 20144987Sdanmcd esp_set_usetime(io->ipsec_out_esp_sa, B_FALSE); 20154987Sdanmcd /* NAT-T packet. */ 20164987Sdanmcd if (ipha->ipha_protocol == IPPROTO_UDP) 20174987Sdanmcd esp_prepare_udp(ns, ipsec_mp->b_cont, ipha); 20184987Sdanmcd 20190Sstevel@tonic-gate /* do AH processing if needed */ 20203448Sdh155122 if (!esp_do_outbound_ah(ipsec_mp)) { 20213448Sdh155122 netstack_rele(ns); 20220Sstevel@tonic-gate return; 20233448Sdh155122 } 20240Sstevel@tonic-gate /* finish IPsec processing */ 20250Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IP_VERSION) { 20260Sstevel@tonic-gate ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, 20270Sstevel@tonic-gate NULL); 20280Sstevel@tonic-gate } else { 20290Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 20300Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h, 20310Sstevel@tonic-gate NULL, NULL); 20320Sstevel@tonic-gate } 20330Sstevel@tonic-gate } 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate } else if (status == CRYPTO_INVALID_MAC) { 20360Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate } else { 20393448Sdh155122 esp1dbg(espstack, 20403448Sdh155122 ("esp_kcf_callback: crypto failed with 0x%x\n", 20410Sstevel@tonic-gate status)); 20423448Sdh155122 ESP_BUMP_STAT(espstack, crypto_failures); 20430Sstevel@tonic-gate if (is_inbound) 20443448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 20450Sstevel@tonic-gate else 20463448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 20470Sstevel@tonic-gate ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL, 20483448Sdh155122 DROPPER(ipss, ipds_esp_crypto_failed), 20493448Sdh155122 &espstack->esp_dropper); 20500Sstevel@tonic-gate } 20513448Sdh155122 netstack_rele(ns); 20520Sstevel@tonic-gate } 20530Sstevel@tonic-gate 20540Sstevel@tonic-gate /* 20550Sstevel@tonic-gate * Invoked on crypto framework failure during inbound and outbound processing. 20560Sstevel@tonic-gate */ 20570Sstevel@tonic-gate static void 20583448Sdh155122 esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc, 20593448Sdh155122 ipsecesp_stack_t *espstack) 20600Sstevel@tonic-gate { 20613448Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 20623448Sdh155122 20633448Sdh155122 esp1dbg(espstack, ("crypto failed for %s ESP with 0x%x\n", 20640Sstevel@tonic-gate is_inbound ? "inbound" : "outbound", kef_rc)); 20653448Sdh155122 ip_drop_packet(mp, is_inbound, NULL, NULL, 20663448Sdh155122 DROPPER(ipss, ipds_esp_crypto_failed), 20673448Sdh155122 &espstack->esp_dropper); 20683448Sdh155122 ESP_BUMP_STAT(espstack, crypto_failures); 20690Sstevel@tonic-gate if (is_inbound) 20703448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 20710Sstevel@tonic-gate else 20723448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 20730Sstevel@tonic-gate } 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate #define ESP_INIT_CALLREQ(_cr) { \ 20760Sstevel@tonic-gate (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED; \ 20770Sstevel@tonic-gate (_cr)->cr_callback_arg = ipsec_mp; \ 20780Sstevel@tonic-gate (_cr)->cr_callback_func = esp_kcf_callback; \ 20790Sstevel@tonic-gate } 20800Sstevel@tonic-gate 20810Sstevel@tonic-gate #define ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \ 20820Sstevel@tonic-gate (mac)->cd_format = CRYPTO_DATA_RAW; \ 20830Sstevel@tonic-gate (mac)->cd_offset = 0; \ 20840Sstevel@tonic-gate (mac)->cd_length = icvlen; \ 20850Sstevel@tonic-gate (mac)->cd_raw.iov_base = (char *)icvbuf; \ 20860Sstevel@tonic-gate (mac)->cd_raw.iov_len = icvlen; \ 20870Sstevel@tonic-gate } 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DATA(data, mp, off, len) { \ 20900Sstevel@tonic-gate if (MBLKL(mp) >= (len) + (off)) { \ 20910Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_RAW; \ 20920Sstevel@tonic-gate (data)->cd_raw.iov_base = (char *)(mp)->b_rptr; \ 20930Sstevel@tonic-gate (data)->cd_raw.iov_len = MBLKL(mp); \ 20940Sstevel@tonic-gate (data)->cd_offset = off; \ 20950Sstevel@tonic-gate } else { \ 20960Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_MBLK; \ 20970Sstevel@tonic-gate (data)->cd_mp = mp; \ 20980Sstevel@tonic-gate (data)->cd_offset = off; \ 20990Sstevel@tonic-gate } \ 21000Sstevel@tonic-gate (data)->cd_length = len; \ 21010Sstevel@tonic-gate } 21020Sstevel@tonic-gate 21030Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) { \ 21040Sstevel@tonic-gate (data)->dd_format = CRYPTO_DATA_MBLK; \ 21050Sstevel@tonic-gate (data)->dd_mp = mp; \ 21060Sstevel@tonic-gate (data)->dd_len1 = len1; \ 21070Sstevel@tonic-gate (data)->dd_offset1 = off1; \ 21080Sstevel@tonic-gate (data)->dd_len2 = len2; \ 21090Sstevel@tonic-gate (data)->dd_offset2 = off2; \ 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate static ipsec_status_t 21130Sstevel@tonic-gate esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset) 21140Sstevel@tonic-gate { 21150Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 21160Sstevel@tonic-gate boolean_t do_auth; 21170Sstevel@tonic-gate uint_t auth_offset, msg_len, auth_len; 21180Sstevel@tonic-gate crypto_call_req_t call_req; 21190Sstevel@tonic-gate mblk_t *esp_mp; 21200Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 21210Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 21220Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 21230Sstevel@tonic-gate boolean_t do_encr; 21240Sstevel@tonic-gate uint_t encr_offset, encr_len; 21250Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 21260Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 21273448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 21283448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 21293448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 21300Sstevel@tonic-gate 21310Sstevel@tonic-gate ASSERT(ii->ipsec_in_type == IPSEC_IN); 21320Sstevel@tonic-gate 21333448Sdh155122 /* 21343448Sdh155122 * In case kEF queues and calls back, keep netstackid_t for 21353448Sdh155122 * verification that the IP instance is still around in 21363448Sdh155122 * esp_kcf_callback(). 21373448Sdh155122 */ 21383448Sdh155122 ii->ipsec_in_stackid = ns->netstack_stackid; 21393448Sdh155122 21400Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 21410Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate /* 21440Sstevel@tonic-gate * An inbound packet is of the form: 21450Sstevel@tonic-gate * IPSEC_IN -> [IP,options,ESP,IV,data,ICV,pad] 21460Sstevel@tonic-gate */ 21470Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont; 21480Sstevel@tonic-gate msg_len = MBLKL(esp_mp); 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 21510Sstevel@tonic-gate 21520Sstevel@tonic-gate if (do_auth) { 21530Sstevel@tonic-gate /* force asynchronous processing? */ 21543448Sdh155122 if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 21550Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 21560Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 21570Sstevel@tonic-gate 21580Sstevel@tonic-gate /* authentication context template */ 21590Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 21600Sstevel@tonic-gate auth_ctx_tmpl); 21610Sstevel@tonic-gate 21620Sstevel@tonic-gate /* ICV to be verified */ 21630Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac, 21640Sstevel@tonic-gate icv_len, esp_mp->b_wptr - icv_len); 21650Sstevel@tonic-gate 21660Sstevel@tonic-gate /* authentication starts at the ESP header */ 21670Sstevel@tonic-gate auth_offset = esph_offset; 21680Sstevel@tonic-gate auth_len = msg_len - auth_offset - icv_len; 21690Sstevel@tonic-gate if (!do_encr) { 21700Sstevel@tonic-gate /* authentication only */ 21710Sstevel@tonic-gate /* initialize input data argument */ 21720Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 21730Sstevel@tonic-gate esp_mp, auth_offset, auth_len); 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate /* call the crypto framework */ 21760Sstevel@tonic-gate kef_rc = crypto_mac_verify(&assoc->ipsa_amech, 21770Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 21780Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 21790Sstevel@tonic-gate &ii->ipsec_in_crypto_mac, &call_req); 21800Sstevel@tonic-gate } 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate if (do_encr) { 21840Sstevel@tonic-gate /* force asynchronous processing? */ 21853448Sdh155122 if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 21860Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 21870Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 21880Sstevel@tonic-gate 21890Sstevel@tonic-gate /* encryption template */ 21900Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 21910Sstevel@tonic-gate encr_ctx_tmpl); 21920Sstevel@tonic-gate 21930Sstevel@tonic-gate /* skip IV, since it is passed separately */ 21940Sstevel@tonic-gate encr_offset = esph_offset + sizeof (esph_t) + iv_len; 21950Sstevel@tonic-gate encr_len = msg_len - encr_offset; 21960Sstevel@tonic-gate 21970Sstevel@tonic-gate if (!do_auth) { 21980Sstevel@tonic-gate /* decryption only */ 21990Sstevel@tonic-gate /* initialize input data argument */ 22000Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, 22010Sstevel@tonic-gate esp_mp, encr_offset, encr_len); 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate /* specify IV */ 22040Sstevel@tonic-gate ii->ipsec_in_crypto_data.cd_miscdata = 22050Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 22060Sstevel@tonic-gate esph_offset; 22070Sstevel@tonic-gate 22080Sstevel@tonic-gate /* call the crypto framework */ 22090Sstevel@tonic-gate kef_rc = crypto_decrypt(&assoc->ipsa_emech, 22100Sstevel@tonic-gate &ii->ipsec_in_crypto_data, 22110Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 22120Sstevel@tonic-gate NULL, &call_req); 22130Sstevel@tonic-gate } 22140Sstevel@tonic-gate } 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate if (do_auth && do_encr) { 22170Sstevel@tonic-gate /* dual operation */ 22180Sstevel@tonic-gate /* initialize input data argument */ 22190Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&ii->ipsec_in_crypto_dual_data, 22200Sstevel@tonic-gate esp_mp, auth_offset, auth_len, 22210Sstevel@tonic-gate encr_offset, encr_len - icv_len); 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate /* specify IV */ 22240Sstevel@tonic-gate ii->ipsec_in_crypto_dual_data.dd_miscdata = 22250Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 22260Sstevel@tonic-gate 22270Sstevel@tonic-gate /* call the framework */ 22280Sstevel@tonic-gate kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech, 22290Sstevel@tonic-gate &assoc->ipsa_emech, &ii->ipsec_in_crypto_dual_data, 22300Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey, 22310Sstevel@tonic-gate auth_ctx_tmpl, encr_ctx_tmpl, &ii->ipsec_in_crypto_mac, 22320Sstevel@tonic-gate NULL, &call_req); 22330Sstevel@tonic-gate } 22340Sstevel@tonic-gate 22350Sstevel@tonic-gate switch (kef_rc) { 22360Sstevel@tonic-gate case CRYPTO_SUCCESS: 22373448Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 22380Sstevel@tonic-gate return (esp_in_done(ipsec_mp)); 22390Sstevel@tonic-gate case CRYPTO_QUEUED: 22400Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 22413448Sdh155122 ESP_BUMP_STAT(espstack, crypto_async); 22420Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 22430Sstevel@tonic-gate case CRYPTO_INVALID_MAC: 22443448Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 22450Sstevel@tonic-gate esp_log_bad_auth(ipsec_mp); 22460Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 22470Sstevel@tonic-gate } 22480Sstevel@tonic-gate 22493448Sdh155122 esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc, espstack); 22500Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 22510Sstevel@tonic-gate } 22520Sstevel@tonic-gate 22534987Sdanmcd /* 22544987Sdanmcd * Compute the IP and UDP checksums -- common code for both keepalives and 22554987Sdanmcd * actual ESP-in-UDP packets. Be flexible with multiple mblks because ESP 22564987Sdanmcd * uses mblk-insertion to insert the UDP header. 22574987Sdanmcd * TODO - If there is an easy way to prep a packet for HW checksums, make 22584987Sdanmcd * it happen here. 22594987Sdanmcd */ 22604987Sdanmcd static void 22614987Sdanmcd esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha) 22624987Sdanmcd { 22634987Sdanmcd int offset; 22644987Sdanmcd uint32_t cksum; 22654987Sdanmcd uint16_t *arr; 22664987Sdanmcd mblk_t *udpmp = mp; 22676352Swy83408 uint_t hlen = IPH_HDR_LENGTH(ipha); 22684987Sdanmcd 22694987Sdanmcd ASSERT(MBLKL(mp) >= sizeof (ipha_t)); 22704987Sdanmcd 22714987Sdanmcd ipha->ipha_hdr_checksum = 0; 22724987Sdanmcd ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 22734987Sdanmcd 22744987Sdanmcd if (ns->netstack_udp->us_do_checksum) { 22754987Sdanmcd ASSERT(MBLKL(udpmp) >= sizeof (udpha_t)); 22764987Sdanmcd /* arr points to the IP header. */ 22774987Sdanmcd arr = (uint16_t *)ipha; 22784987Sdanmcd IP_STAT(ns->netstack_ip, ip_out_sw_cksum); 22794987Sdanmcd IP_STAT_UPDATE(ns->netstack_ip, ip_udp_out_sw_cksum_bytes, 22806352Swy83408 ntohs(htons(ipha->ipha_length) - hlen)); 22814987Sdanmcd /* arr[6-9] are the IP addresses. */ 22824987Sdanmcd cksum = IP_UDP_CSUM_COMP + arr[6] + arr[7] + arr[8] + arr[9] + 22836352Swy83408 ntohs(htons(ipha->ipha_length) - hlen); 22846352Swy83408 cksum = IP_CSUM(mp, hlen, cksum); 22856352Swy83408 offset = hlen + UDP_CHECKSUM_OFFSET; 22864987Sdanmcd while (offset >= MBLKL(udpmp)) { 22874987Sdanmcd offset -= MBLKL(udpmp); 22884987Sdanmcd udpmp = udpmp->b_cont; 22894987Sdanmcd } 22904987Sdanmcd /* arr points to the UDP header's checksum field. */ 22914987Sdanmcd arr = (uint16_t *)(udpmp->b_rptr + offset); 22924987Sdanmcd *arr = cksum; 22934987Sdanmcd } 22944987Sdanmcd } 22954987Sdanmcd 22964987Sdanmcd /* 22974987Sdanmcd * Send a one-byte UDP NAT-T keepalive. Construct an IPSEC_OUT too that'll 22984987Sdanmcd * get fed into esp_send_udp/ip_wput_ipsec_out. 22994987Sdanmcd */ 23004987Sdanmcd void 23014987Sdanmcd ipsecesp_send_keepalive(ipsa_t *assoc) 23024987Sdanmcd { 23034987Sdanmcd mblk_t *mp = NULL, *ipsec_mp = NULL; 23044987Sdanmcd ipha_t *ipha; 23054987Sdanmcd udpha_t *udpha; 23064987Sdanmcd ipsec_out_t *io; 23074987Sdanmcd 23087373Ssommerfeld@sun.com ASSERT(MUTEX_NOT_HELD(&assoc->ipsa_lock)); 23094987Sdanmcd 23104987Sdanmcd mp = allocb(sizeof (ipha_t) + sizeof (udpha_t) + 1, BPRI_HI); 23114987Sdanmcd if (mp == NULL) 23124987Sdanmcd return; 23134987Sdanmcd ipha = (ipha_t *)mp->b_rptr; 23144987Sdanmcd ipha->ipha_version_and_hdr_length = IP_SIMPLE_HDR_VERSION; 23154987Sdanmcd ipha->ipha_type_of_service = 0; 23164987Sdanmcd ipha->ipha_length = htons(sizeof (ipha_t) + sizeof (udpha_t) + 1); 23174987Sdanmcd /* Use the low-16 of the SPI so we have some clue where it came from. */ 23184987Sdanmcd ipha->ipha_ident = *(((uint16_t *)(&assoc->ipsa_spi)) + 1); 23194987Sdanmcd ipha->ipha_fragment_offset_and_flags = 0; /* Too small to fragment! */ 23204987Sdanmcd ipha->ipha_ttl = 0xFF; 23214987Sdanmcd ipha->ipha_protocol = IPPROTO_UDP; 23224987Sdanmcd ipha->ipha_hdr_checksum = 0; 23234987Sdanmcd ipha->ipha_src = assoc->ipsa_srcaddr[0]; 23244987Sdanmcd ipha->ipha_dst = assoc->ipsa_dstaddr[0]; 23254987Sdanmcd udpha = (udpha_t *)(ipha + 1); 23264987Sdanmcd udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ? 23274987Sdanmcd assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT); 23284987Sdanmcd udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ? 23294987Sdanmcd assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT); 23304987Sdanmcd udpha->uha_length = htons(sizeof (udpha_t) + 1); 23314987Sdanmcd udpha->uha_checksum = 0; 23324987Sdanmcd mp->b_wptr = (uint8_t *)(udpha + 1); 23334987Sdanmcd *(mp->b_wptr++) = 0xFF; 23344987Sdanmcd 23354987Sdanmcd ipsec_mp = ipsec_alloc_ipsec_out(assoc->ipsa_netstack); 23364987Sdanmcd if (ipsec_mp == NULL) { 23374987Sdanmcd freeb(mp); 23384987Sdanmcd return; 23394987Sdanmcd } 23404987Sdanmcd ipsec_mp->b_cont = mp; 23414987Sdanmcd io = (ipsec_out_t *)ipsec_mp->b_rptr; 23424987Sdanmcd io->ipsec_out_zoneid = 23434987Sdanmcd netstackid_to_zoneid(assoc->ipsa_netstack->netstack_stackid); 23444987Sdanmcd 23454987Sdanmcd esp_prepare_udp(assoc->ipsa_netstack, mp, ipha); 23464987Sdanmcd ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, NULL); 23474987Sdanmcd } 23484987Sdanmcd 23490Sstevel@tonic-gate static ipsec_status_t 23500Sstevel@tonic-gate esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf, 23510Sstevel@tonic-gate uint_t payload_len) 23520Sstevel@tonic-gate { 23530Sstevel@tonic-gate ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 23540Sstevel@tonic-gate uint_t auth_len; 23550Sstevel@tonic-gate crypto_call_req_t call_req; 23560Sstevel@tonic-gate mblk_t *esp_mp; 23570Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 23580Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 23590Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 23600Sstevel@tonic-gate boolean_t do_auth; 23610Sstevel@tonic-gate boolean_t do_encr; 23620Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 23630Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 23640Sstevel@tonic-gate boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 23650Sstevel@tonic-gate size_t esph_offset = (is_natt ? UDPH_SIZE : 0); 23663448Sdh155122 netstack_t *ns = io->ipsec_out_ns; 23673448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 23683448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 23693448Sdh155122 23703448Sdh155122 esp3dbg(espstack, ("esp_submit_req_outbound:%s", 23714987Sdanmcd is_natt ? "natt" : "not natt")); 23720Sstevel@tonic-gate 23730Sstevel@tonic-gate ASSERT(io->ipsec_out_type == IPSEC_OUT); 23740Sstevel@tonic-gate 23753448Sdh155122 /* 23763448Sdh155122 * In case kEF queues and calls back, keep netstackid_t for 23773448Sdh155122 * verification that the IP instance is still around in 23783448Sdh155122 * esp_kcf_callback(). 23793448Sdh155122 */ 23803448Sdh155122 io->ipsec_out_stackid = ns->netstack_stackid; 23813448Sdh155122 23820Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 23830Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 23840Sstevel@tonic-gate 23850Sstevel@tonic-gate /* 23860Sstevel@tonic-gate * Outbound IPsec packets are of the form: 23870Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV] 23880Sstevel@tonic-gate * unless it's NATT, then it's 23890Sstevel@tonic-gate * IPSEC_OUT -> [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV] 23900Sstevel@tonic-gate * Get a pointer to the mblk containing the ESP header. 23910Sstevel@tonic-gate */ 23920Sstevel@tonic-gate ASSERT(ipsec_mp->b_cont != NULL && ipsec_mp->b_cont->b_cont != NULL); 23930Sstevel@tonic-gate esp_mp = ipsec_mp->b_cont->b_cont; 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate ESP_INIT_CALLREQ(&call_req); 23960Sstevel@tonic-gate 23970Sstevel@tonic-gate if (do_auth) { 23980Sstevel@tonic-gate /* force asynchronous processing? */ 23993448Sdh155122 if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == 24000Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 24010Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 24020Sstevel@tonic-gate 24030Sstevel@tonic-gate /* authentication context template */ 24040Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 24050Sstevel@tonic-gate auth_ctx_tmpl); 24060Sstevel@tonic-gate 24070Sstevel@tonic-gate /* where to store the computed mac */ 24080Sstevel@tonic-gate ESP_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac, 24090Sstevel@tonic-gate icv_len, icv_buf); 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate /* authentication starts at the ESP header */ 2412134Sdanmcd auth_len = payload_len + iv_len + sizeof (esph_t); 24130Sstevel@tonic-gate if (!do_encr) { 24140Sstevel@tonic-gate /* authentication only */ 24150Sstevel@tonic-gate /* initialize input data argument */ 24160Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 24170Sstevel@tonic-gate esp_mp, esph_offset, auth_len); 24180Sstevel@tonic-gate 24190Sstevel@tonic-gate /* call the crypto framework */ 24200Sstevel@tonic-gate kef_rc = crypto_mac(&assoc->ipsa_amech, 24210Sstevel@tonic-gate &io->ipsec_out_crypto_data, 24220Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 24230Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 24240Sstevel@tonic-gate } 24250Sstevel@tonic-gate } 24260Sstevel@tonic-gate 24270Sstevel@tonic-gate if (do_encr) { 24280Sstevel@tonic-gate /* force asynchronous processing? */ 24293448Sdh155122 if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] == 24300Sstevel@tonic-gate IPSEC_ALGS_EXEC_ASYNC) 24310Sstevel@tonic-gate call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE; 24320Sstevel@tonic-gate 24330Sstevel@tonic-gate /* encryption context template */ 24340Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 24350Sstevel@tonic-gate encr_ctx_tmpl); 24360Sstevel@tonic-gate 24370Sstevel@tonic-gate if (!do_auth) { 24380Sstevel@tonic-gate /* encryption only, skip mblk that contains ESP hdr */ 24390Sstevel@tonic-gate /* initialize input data argument */ 24400Sstevel@tonic-gate ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, 24410Sstevel@tonic-gate esp_mp->b_cont, 0, payload_len); 24420Sstevel@tonic-gate 24430Sstevel@tonic-gate /* specify IV */ 24440Sstevel@tonic-gate io->ipsec_out_crypto_data.cd_miscdata = 24450Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + 24460Sstevel@tonic-gate esph_offset; 24470Sstevel@tonic-gate 24480Sstevel@tonic-gate /* call the crypto framework */ 24490Sstevel@tonic-gate kef_rc = crypto_encrypt(&assoc->ipsa_emech, 24500Sstevel@tonic-gate &io->ipsec_out_crypto_data, 24510Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 24520Sstevel@tonic-gate NULL, &call_req); 24530Sstevel@tonic-gate } 24540Sstevel@tonic-gate } 24550Sstevel@tonic-gate 24560Sstevel@tonic-gate if (do_auth && do_encr) { 24570Sstevel@tonic-gate /* 24580Sstevel@tonic-gate * Encryption and authentication: 24590Sstevel@tonic-gate * Pass the pointer to the mblk chain starting at the ESP 24600Sstevel@tonic-gate * header to the framework. Skip the ESP header mblk 24610Sstevel@tonic-gate * for encryption, which is reflected by an encryption 24620Sstevel@tonic-gate * offset equal to the length of that mblk. Start 24630Sstevel@tonic-gate * the authentication at the ESP header, i.e. use an 24640Sstevel@tonic-gate * authentication offset of zero. 24650Sstevel@tonic-gate */ 24660Sstevel@tonic-gate ESP_INIT_CRYPTO_DUAL_DATA(&io->ipsec_out_crypto_dual_data, 24670Sstevel@tonic-gate esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len); 24680Sstevel@tonic-gate 24690Sstevel@tonic-gate /* specify IV */ 24700Sstevel@tonic-gate io->ipsec_out_crypto_dual_data.dd_miscdata = 24710Sstevel@tonic-gate (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset; 24720Sstevel@tonic-gate 24730Sstevel@tonic-gate /* call the framework */ 24740Sstevel@tonic-gate kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech, 24750Sstevel@tonic-gate &assoc->ipsa_amech, NULL, 24760Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey, 24770Sstevel@tonic-gate encr_ctx_tmpl, auth_ctx_tmpl, 24780Sstevel@tonic-gate &io->ipsec_out_crypto_dual_data, 24790Sstevel@tonic-gate &io->ipsec_out_crypto_mac, &call_req); 24800Sstevel@tonic-gate } 24810Sstevel@tonic-gate 24820Sstevel@tonic-gate switch (kef_rc) { 24830Sstevel@tonic-gate case CRYPTO_SUCCESS: 24843448Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 24854987Sdanmcd esp_set_usetime(assoc, B_FALSE); 24864987Sdanmcd if (is_natt) 24874987Sdanmcd esp_prepare_udp(ns, ipsec_mp->b_cont, 24884987Sdanmcd (ipha_t *)ipsec_mp->b_cont->b_rptr); 24890Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 24900Sstevel@tonic-gate case CRYPTO_QUEUED: 24910Sstevel@tonic-gate /* esp_kcf_callback() will be invoked on completion */ 24923448Sdh155122 ESP_BUMP_STAT(espstack, crypto_async); 24930Sstevel@tonic-gate return (IPSEC_STATUS_PENDING); 24940Sstevel@tonic-gate } 24950Sstevel@tonic-gate 24963448Sdh155122 esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc, espstack); 24970Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 24980Sstevel@tonic-gate } 24990Sstevel@tonic-gate 25000Sstevel@tonic-gate /* 25010Sstevel@tonic-gate * Handle outbound IPsec processing for IPv4 and IPv6 25020Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 25030Sstevel@tonic-gate * mblk chain ipsec_in_mp. 25040Sstevel@tonic-gate */ 25050Sstevel@tonic-gate static ipsec_status_t 25060Sstevel@tonic-gate esp_outbound(mblk_t *mp) 25070Sstevel@tonic-gate { 25080Sstevel@tonic-gate mblk_t *ipsec_out_mp, *data_mp, *espmp, *tailmp; 25090Sstevel@tonic-gate ipsec_out_t *io; 25100Sstevel@tonic-gate ipha_t *ipha; 25110Sstevel@tonic-gate ip6_t *ip6h; 25120Sstevel@tonic-gate esph_t *esph; 25130Sstevel@tonic-gate uint_t af; 25140Sstevel@tonic-gate uint8_t *nhp; 25150Sstevel@tonic-gate uintptr_t divpoint, datalen, adj, padlen, i, alloclen; 25160Sstevel@tonic-gate uintptr_t esplen = sizeof (esph_t); 25170Sstevel@tonic-gate uint8_t protocol; 25180Sstevel@tonic-gate ipsa_t *assoc; 25193192Sdanmcd uint_t iv_len, mac_len = 0; 25200Sstevel@tonic-gate uchar_t *icv_buf; 25210Sstevel@tonic-gate udpha_t *udpha; 25220Sstevel@tonic-gate boolean_t is_natt = B_FALSE; 25233448Sdh155122 netstack_t *ns; 25243448Sdh155122 ipsecesp_stack_t *espstack; 25253448Sdh155122 ipsec_stack_t *ipss; 25260Sstevel@tonic-gate 25270Sstevel@tonic-gate ipsec_out_mp = mp; 25280Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 25290Sstevel@tonic-gate 25303448Sdh155122 io = (ipsec_out_t *)ipsec_out_mp->b_rptr; 25313448Sdh155122 ns = io->ipsec_out_ns; 25323448Sdh155122 espstack = ns->netstack_ipsecesp; 25333448Sdh155122 ipss = ns->netstack_ipsec; 25343448Sdh155122 25353448Sdh155122 ESP_BUMP_STAT(espstack, out_requests); 25363448Sdh155122 25370Sstevel@tonic-gate /* 25380Sstevel@tonic-gate * <sigh> We have to copy the message here, because TCP (for example) 25390Sstevel@tonic-gate * keeps a dupb() of the message lying around for retransmission. 25400Sstevel@tonic-gate * Since ESP changes the whole of the datagram, we have to create our 25410Sstevel@tonic-gate * own copy lest we clobber TCP's data. Since we have to copy anyway, 25420Sstevel@tonic-gate * we might as well make use of msgpullup() and get the mblk into one 25430Sstevel@tonic-gate * contiguous piece! 25440Sstevel@tonic-gate */ 25450Sstevel@tonic-gate ipsec_out_mp->b_cont = msgpullup(data_mp, -1); 25460Sstevel@tonic-gate if (ipsec_out_mp->b_cont == NULL) { 25470Sstevel@tonic-gate esp0dbg(("esp_outbound: msgpullup() failed, " 25480Sstevel@tonic-gate "dropping packet.\n")); 25490Sstevel@tonic-gate ipsec_out_mp->b_cont = data_mp; 25500Sstevel@tonic-gate /* 25510Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 25520Sstevel@tonic-gate * pass it to ip_drop_packet(). 25530Sstevel@tonic-gate */ 25540Sstevel@tonic-gate ip_drop_packet(ipsec_out_mp, B_FALSE, NULL, NULL, 25553448Sdh155122 DROPPER(ipss, ipds_esp_nomem), 25563448Sdh155122 &espstack->esp_dropper); 25570Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 25580Sstevel@tonic-gate } else { 25590Sstevel@tonic-gate freemsg(data_mp); 25600Sstevel@tonic-gate data_mp = ipsec_out_mp->b_cont; 25610Sstevel@tonic-gate } 25620Sstevel@tonic-gate 25630Sstevel@tonic-gate /* 25640Sstevel@tonic-gate * Reality check.... 25650Sstevel@tonic-gate */ 25660Sstevel@tonic-gate 25670Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */ 25680Sstevel@tonic-gate 25690Sstevel@tonic-gate if (io->ipsec_out_v4) { 25700Sstevel@tonic-gate af = AF_INET; 25710Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 25720Sstevel@tonic-gate datalen = ntohs(ipha->ipha_length) - divpoint; 25730Sstevel@tonic-gate nhp = (uint8_t *)&ipha->ipha_protocol; 25740Sstevel@tonic-gate } else { 25750Sstevel@tonic-gate ip6_pkt_t ipp; 25760Sstevel@tonic-gate 25770Sstevel@tonic-gate af = AF_INET6; 25780Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 25790Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 25800Sstevel@tonic-gate divpoint = ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL); 25810Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL && 25820Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) { 25830Sstevel@tonic-gate /* 25840Sstevel@tonic-gate * Destination options are tricky. If we get in here, 25850Sstevel@tonic-gate * then we have a terminal header following the 25860Sstevel@tonic-gate * destination options. We need to adjust backwards 25870Sstevel@tonic-gate * so we insert ESP BEFORE the destination options 25880Sstevel@tonic-gate * bag. (So that the dstopts get encrypted!) 25890Sstevel@tonic-gate * 25900Sstevel@tonic-gate * Since this is for outbound packets only, we know 25910Sstevel@tonic-gate * that non-terminal destination options only precede 25920Sstevel@tonic-gate * routing headers. 25930Sstevel@tonic-gate */ 25940Sstevel@tonic-gate divpoint -= ipp.ipp_dstoptslen; 25950Sstevel@tonic-gate } 25960Sstevel@tonic-gate datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint; 25970Sstevel@tonic-gate 25980Sstevel@tonic-gate if (ipp.ipp_rthdr != NULL) { 25990Sstevel@tonic-gate nhp = &ipp.ipp_rthdr->ip6r_nxt; 26000Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 26010Sstevel@tonic-gate nhp = &ipp.ipp_hopopts->ip6h_nxt; 26020Sstevel@tonic-gate } else { 26030Sstevel@tonic-gate ASSERT(divpoint == sizeof (ip6_t)); 26040Sstevel@tonic-gate /* It's probably IP + ESP. */ 26050Sstevel@tonic-gate nhp = &ip6h->ip6_nxt; 26060Sstevel@tonic-gate } 26070Sstevel@tonic-gate } 26080Sstevel@tonic-gate assoc = io->ipsec_out_esp_sa; 26090Sstevel@tonic-gate ASSERT(assoc != NULL); 26100Sstevel@tonic-gate 26110Sstevel@tonic-gate if (assoc->ipsa_auth_alg != SADB_AALG_NONE) 26120Sstevel@tonic-gate mac_len = assoc->ipsa_mac_len; 26130Sstevel@tonic-gate 26140Sstevel@tonic-gate if (assoc->ipsa_flags & IPSA_F_NATT) { 26150Sstevel@tonic-gate /* wedge in fake UDP */ 26160Sstevel@tonic-gate is_natt = B_TRUE; 26170Sstevel@tonic-gate esplen += UDPH_SIZE; 26180Sstevel@tonic-gate } 26190Sstevel@tonic-gate 26200Sstevel@tonic-gate /* 26210Sstevel@tonic-gate * Set up ESP header and encryption padding for ENCR PI request. 26220Sstevel@tonic-gate */ 26230Sstevel@tonic-gate 26243192Sdanmcd /* Determine the padding length. Pad to 4-bytes for no-encryption. */ 26250Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) { 26263192Sdanmcd iv_len = assoc->ipsa_iv_len; 26273192Sdanmcd 26283192Sdanmcd /* 26293192Sdanmcd * Include the two additional bytes (hence the - 2) for the 26303192Sdanmcd * padding length and the next header. Take this into account 26313192Sdanmcd * when calculating the actual length of the padding. 26323192Sdanmcd */ 26333192Sdanmcd ASSERT(ISP2(iv_len)); 26343192Sdanmcd padlen = ((unsigned)(iv_len - datalen - 2)) & (iv_len - 1); 26350Sstevel@tonic-gate } else { 26363192Sdanmcd iv_len = 0; 26373192Sdanmcd padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) & 26383192Sdanmcd (sizeof (uint32_t) - 1); 26390Sstevel@tonic-gate } 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate /* Allocate ESP header and IV. */ 26420Sstevel@tonic-gate esplen += iv_len; 26430Sstevel@tonic-gate 26440Sstevel@tonic-gate /* 26450Sstevel@tonic-gate * Update association byte-count lifetimes. Don't forget to take 26460Sstevel@tonic-gate * into account the padding length and next-header (hence the + 2). 2647134Sdanmcd * 26480Sstevel@tonic-gate * Use the amount of data fed into the "encryption algorithm". This 26490Sstevel@tonic-gate * is the IV, the data length, the padding length, and the final two 26500Sstevel@tonic-gate * bytes (padlen, and next-header). 26510Sstevel@tonic-gate * 26520Sstevel@tonic-gate */ 26530Sstevel@tonic-gate 2654134Sdanmcd if (!esp_age_bytes(assoc, datalen + padlen + iv_len + 2, B_FALSE)) { 26550Sstevel@tonic-gate /* 26560Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 26570Sstevel@tonic-gate * pass it to ip_drop_packet(). 26580Sstevel@tonic-gate */ 26590Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 26603448Sdh155122 DROPPER(ipss, ipds_esp_bytes_expire), 26613448Sdh155122 &espstack->esp_dropper); 26620Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 26630Sstevel@tonic-gate } 26640Sstevel@tonic-gate 26650Sstevel@tonic-gate espmp = allocb(esplen, BPRI_HI); 26660Sstevel@tonic-gate if (espmp == NULL) { 26673448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 26683448Sdh155122 esp1dbg(espstack, ("esp_outbound: can't allocate espmp.\n")); 26690Sstevel@tonic-gate /* 26700Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 26710Sstevel@tonic-gate * pass it to ip_drop_packet(). 26720Sstevel@tonic-gate */ 26733448Sdh155122 ip_drop_packet(mp, B_FALSE, NULL, NULL, 26743448Sdh155122 DROPPER(ipss, ipds_esp_nomem), 26753448Sdh155122 &espstack->esp_dropper); 26760Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 26770Sstevel@tonic-gate } 26780Sstevel@tonic-gate espmp->b_wptr += esplen; 26790Sstevel@tonic-gate esph = (esph_t *)espmp->b_rptr; 26800Sstevel@tonic-gate 26810Sstevel@tonic-gate if (is_natt) { 26823448Sdh155122 esp3dbg(espstack, ("esp_outbound: NATT")); 26830Sstevel@tonic-gate 26840Sstevel@tonic-gate udpha = (udpha_t *)espmp->b_rptr; 26854987Sdanmcd udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ? 26864987Sdanmcd assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT); 26874987Sdanmcd udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ? 26884987Sdanmcd assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT); 26890Sstevel@tonic-gate /* 26904987Sdanmcd * Set the checksum to 0, so that the esp_prepare_udp() call 26910Sstevel@tonic-gate * can do the right thing. 26920Sstevel@tonic-gate */ 26930Sstevel@tonic-gate udpha->uha_checksum = 0; 26940Sstevel@tonic-gate esph = (esph_t *)(udpha + 1); 26950Sstevel@tonic-gate } 26960Sstevel@tonic-gate 26970Sstevel@tonic-gate esph->esph_spi = assoc->ipsa_spi; 26980Sstevel@tonic-gate 26990Sstevel@tonic-gate esph->esph_replay = htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1)); 27000Sstevel@tonic-gate if (esph->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) { 27010Sstevel@tonic-gate /* 27020Sstevel@tonic-gate * XXX We have replay counter wrapping. 27030Sstevel@tonic-gate * We probably want to nuke this SA (and its peer). 27040Sstevel@tonic-gate */ 27050Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 27060Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 27070Sstevel@tonic-gate "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n", 27083448Sdh155122 esph->esph_spi, assoc->ipsa_dstaddr, af, 27093448Sdh155122 espstack->ipsecesp_netstack); 27103448Sdh155122 27113448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 27120Sstevel@tonic-gate sadb_replay_delete(assoc); 27130Sstevel@tonic-gate /* 27140Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 27150Sstevel@tonic-gate * pass it to ip_drop_packet(). 27160Sstevel@tonic-gate */ 27173448Sdh155122 ip_drop_packet(mp, B_FALSE, NULL, NULL, 27183448Sdh155122 DROPPER(ipss, ipds_esp_replay), 27193448Sdh155122 &espstack->esp_dropper); 27200Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 27210Sstevel@tonic-gate } 27220Sstevel@tonic-gate 27230Sstevel@tonic-gate /* 27240Sstevel@tonic-gate * Set the IV to a random quantity. We do not require the 27250Sstevel@tonic-gate * highest quality random bits, but for best security with CBC 27260Sstevel@tonic-gate * mode ciphers, the value must be unlikely to repeat and also 27270Sstevel@tonic-gate * must not be known in advance to an adversary capable of 27280Sstevel@tonic-gate * influencing the plaintext. 27290Sstevel@tonic-gate */ 27300Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)(esph + 1), iv_len); 27310Sstevel@tonic-gate 27320Sstevel@tonic-gate /* Fix the IP header. */ 27330Sstevel@tonic-gate alloclen = padlen + 2 + mac_len; 27340Sstevel@tonic-gate adj = alloclen + (espmp->b_wptr - espmp->b_rptr); 27350Sstevel@tonic-gate 27360Sstevel@tonic-gate protocol = *nhp; 27370Sstevel@tonic-gate 27380Sstevel@tonic-gate if (io->ipsec_out_v4) { 27390Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj); 27400Sstevel@tonic-gate if (is_natt) { 27410Sstevel@tonic-gate *nhp = IPPROTO_UDP; 27420Sstevel@tonic-gate udpha->uha_length = htons(ntohs(ipha->ipha_length) - 27430Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 27440Sstevel@tonic-gate } else { 27450Sstevel@tonic-gate *nhp = IPPROTO_ESP; 27460Sstevel@tonic-gate } 27470Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 27480Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 27490Sstevel@tonic-gate } else { 27500Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj); 27510Sstevel@tonic-gate *nhp = IPPROTO_ESP; 27520Sstevel@tonic-gate } 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate /* I've got the two ESP mblks, now insert them. */ 27550Sstevel@tonic-gate 27563448Sdh155122 esp2dbg(espstack, ("data_mp before outbound ESP adjustment:\n")); 27573448Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 27583448Sdh155122 27593448Sdh155122 if (!esp_insert_esp(data_mp, espmp, divpoint, espstack)) { 27603448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 27610Sstevel@tonic-gate /* NOTE: esp_insert_esp() only fails if there's no memory. */ 27620Sstevel@tonic-gate /* 27630Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 27640Sstevel@tonic-gate * pass it to ip_drop_packet(). 27650Sstevel@tonic-gate */ 27663448Sdh155122 ip_drop_packet(mp, B_FALSE, NULL, NULL, 27673448Sdh155122 DROPPER(ipss, ipds_esp_nomem), 27683448Sdh155122 &espstack->esp_dropper); 27690Sstevel@tonic-gate freeb(espmp); 27700Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 27710Sstevel@tonic-gate } 27720Sstevel@tonic-gate 27730Sstevel@tonic-gate /* Append padding (and leave room for ICV). */ 27740Sstevel@tonic-gate for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont) 27750Sstevel@tonic-gate ; 27760Sstevel@tonic-gate if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) { 27770Sstevel@tonic-gate tailmp->b_cont = allocb(alloclen, BPRI_HI); 27780Sstevel@tonic-gate if (tailmp->b_cont == NULL) { 27793448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 27800Sstevel@tonic-gate esp0dbg(("esp_outbound: Can't allocate tailmp.\n")); 27810Sstevel@tonic-gate /* 27820Sstevel@tonic-gate * TODO: Find the outbound IRE for this packet and 27830Sstevel@tonic-gate * pass it to ip_drop_packet(). 27840Sstevel@tonic-gate */ 27850Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 27863448Sdh155122 DROPPER(ipss, ipds_esp_nomem), 27873448Sdh155122 &espstack->esp_dropper); 27880Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 27890Sstevel@tonic-gate } 27900Sstevel@tonic-gate tailmp = tailmp->b_cont; 27910Sstevel@tonic-gate } 27920Sstevel@tonic-gate 27930Sstevel@tonic-gate /* 27940Sstevel@tonic-gate * If there's padding, N bytes of padding must be of the form 0x1, 27950Sstevel@tonic-gate * 0x2, 0x3... 0xN. 27960Sstevel@tonic-gate */ 27970Sstevel@tonic-gate for (i = 0; i < padlen; ) { 27980Sstevel@tonic-gate i++; 27990Sstevel@tonic-gate *tailmp->b_wptr++ = i; 28000Sstevel@tonic-gate } 28010Sstevel@tonic-gate *tailmp->b_wptr++ = i; 28020Sstevel@tonic-gate *tailmp->b_wptr++ = protocol; 28030Sstevel@tonic-gate 28043448Sdh155122 esp2dbg(espstack, ("data_Mp before encryption:\n")); 28053448Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 28060Sstevel@tonic-gate 28070Sstevel@tonic-gate /* 28080Sstevel@tonic-gate * The packet is eligible for hardware acceleration if the 28090Sstevel@tonic-gate * following conditions are satisfied: 28100Sstevel@tonic-gate * 28110Sstevel@tonic-gate * 1. the packet will not be fragmented 28120Sstevel@tonic-gate * 2. the provider supports the algorithms specified by SA 28130Sstevel@tonic-gate * 3. there is no pending control message being exchanged 28140Sstevel@tonic-gate * 4. snoop is not attached 28150Sstevel@tonic-gate * 5. the destination address is not a multicast address 28160Sstevel@tonic-gate * 28170Sstevel@tonic-gate * All five of these conditions are checked by IP prior to 28180Sstevel@tonic-gate * sending the packet to ESP. 28190Sstevel@tonic-gate * 28200Sstevel@tonic-gate * But We, and We Alone, can, nay MUST check if the packet 28210Sstevel@tonic-gate * is over NATT, and then disqualify it from hardware 28220Sstevel@tonic-gate * acceleration. 28230Sstevel@tonic-gate */ 28240Sstevel@tonic-gate 28250Sstevel@tonic-gate if (io->ipsec_out_is_capab_ill && !(assoc->ipsa_flags & IPSA_F_NATT)) { 28260Sstevel@tonic-gate return (esp_outbound_accelerated(ipsec_out_mp, mac_len)); 28270Sstevel@tonic-gate } 28283448Sdh155122 ESP_BUMP_STAT(espstack, noaccel); 28290Sstevel@tonic-gate 28300Sstevel@tonic-gate /* 28310Sstevel@tonic-gate * Okay. I've set up the pre-encryption ESP. Let's do it! 28320Sstevel@tonic-gate */ 28330Sstevel@tonic-gate 28340Sstevel@tonic-gate if (mac_len > 0) { 28350Sstevel@tonic-gate ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim); 28360Sstevel@tonic-gate icv_buf = tailmp->b_wptr; 28370Sstevel@tonic-gate tailmp->b_wptr += mac_len; 28380Sstevel@tonic-gate } else { 28390Sstevel@tonic-gate icv_buf = NULL; 28400Sstevel@tonic-gate } 28410Sstevel@tonic-gate 28420Sstevel@tonic-gate return (esp_submit_req_outbound(ipsec_out_mp, assoc, icv_buf, 28430Sstevel@tonic-gate datalen + padlen + 2)); 28440Sstevel@tonic-gate } 28450Sstevel@tonic-gate 28460Sstevel@tonic-gate /* 28470Sstevel@tonic-gate * IP calls this to validate the ICMP errors that 28480Sstevel@tonic-gate * we got from the network. 28490Sstevel@tonic-gate */ 28500Sstevel@tonic-gate ipsec_status_t 28510Sstevel@tonic-gate ipsecesp_icmp_error(mblk_t *ipsec_mp) 28520Sstevel@tonic-gate { 28533448Sdh155122 ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 28543448Sdh155122 boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN); 28553448Sdh155122 netstack_t *ns; 28563448Sdh155122 ipsecesp_stack_t *espstack; 28573448Sdh155122 ipsec_stack_t *ipss; 28583448Sdh155122 28593448Sdh155122 if (is_inbound) { 28603448Sdh155122 ns = ii->ipsec_in_ns; 28613448Sdh155122 } else { 28623448Sdh155122 ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 28633448Sdh155122 28643448Sdh155122 ns = io->ipsec_out_ns; 28653448Sdh155122 } 28663448Sdh155122 espstack = ns->netstack_ipsecesp; 28673448Sdh155122 ipss = ns->netstack_ipsec; 28683448Sdh155122 28690Sstevel@tonic-gate /* 28700Sstevel@tonic-gate * Unless we get an entire packet back, this function is useless. 28710Sstevel@tonic-gate * Why? 28720Sstevel@tonic-gate * 28730Sstevel@tonic-gate * 1.) Partial packets are useless, because the "next header" 28740Sstevel@tonic-gate * is at the end of the decrypted ESP packet. Without the 28750Sstevel@tonic-gate * whole packet, this is useless. 28760Sstevel@tonic-gate * 28770Sstevel@tonic-gate * 2.) If we every use a stateful cipher, such as a stream or a 28780Sstevel@tonic-gate * one-time pad, we can't do anything. 28790Sstevel@tonic-gate * 28800Sstevel@tonic-gate * Since the chances of us getting an entire packet back are very 28810Sstevel@tonic-gate * very small, we discard here. 28820Sstevel@tonic-gate */ 28833448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 28843448Sdh155122 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, 28853448Sdh155122 DROPPER(ipss, ipds_esp_icmp), 28863448Sdh155122 &espstack->esp_dropper); 28870Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 28880Sstevel@tonic-gate } 28890Sstevel@tonic-gate 28900Sstevel@tonic-gate /* 28910Sstevel@tonic-gate * ESP module read put routine. 28920Sstevel@tonic-gate */ 28930Sstevel@tonic-gate /* ARGSUSED */ 28940Sstevel@tonic-gate static void 28950Sstevel@tonic-gate ipsecesp_rput(queue_t *q, mblk_t *mp) 28960Sstevel@tonic-gate { 28973448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 28983448Sdh155122 28993055Sdanmcd ASSERT(mp->b_datap->db_type != M_CTL); /* No more IRE_DB_REQ. */ 29003448Sdh155122 29010Sstevel@tonic-gate switch (mp->b_datap->db_type) { 29020Sstevel@tonic-gate case M_PROTO: 29030Sstevel@tonic-gate case M_PCPROTO: 29040Sstevel@tonic-gate /* TPI message of some sort. */ 29050Sstevel@tonic-gate switch (*((t_scalar_t *)mp->b_rptr)) { 29060Sstevel@tonic-gate case T_BIND_ACK: 29073448Sdh155122 esp3dbg(espstack, 29083448Sdh155122 ("Thank you IP from ESP for T_BIND_ACK\n")); 29090Sstevel@tonic-gate break; 29100Sstevel@tonic-gate case T_ERROR_ACK: 29110Sstevel@tonic-gate cmn_err(CE_WARN, 29120Sstevel@tonic-gate "ipsecesp: ESP received T_ERROR_ACK from IP."); 29130Sstevel@tonic-gate /* 29140Sstevel@tonic-gate * Make esp_sadb.s_ip_q NULL, and in the 29150Sstevel@tonic-gate * future, perhaps try again. 29160Sstevel@tonic-gate */ 29173448Sdh155122 espstack->esp_sadb.s_ip_q = NULL; 29180Sstevel@tonic-gate break; 29190Sstevel@tonic-gate case T_OK_ACK: 29200Sstevel@tonic-gate /* Probably from a (rarely sent) T_UNBIND_REQ. */ 29210Sstevel@tonic-gate break; 29220Sstevel@tonic-gate default: 29230Sstevel@tonic-gate esp0dbg(("Unknown M_{,PC}PROTO message.\n")); 29240Sstevel@tonic-gate } 29250Sstevel@tonic-gate freemsg(mp); 29260Sstevel@tonic-gate break; 29270Sstevel@tonic-gate default: 29280Sstevel@tonic-gate /* For now, passthru message. */ 29293448Sdh155122 esp2dbg(espstack, ("ESP got unknown mblk type %d.\n", 29300Sstevel@tonic-gate mp->b_datap->db_type)); 29310Sstevel@tonic-gate putnext(q, mp); 29320Sstevel@tonic-gate } 29330Sstevel@tonic-gate } 29340Sstevel@tonic-gate 29350Sstevel@tonic-gate /* 29360Sstevel@tonic-gate * Construct an SADB_REGISTER message with the current algorithms. 29370Sstevel@tonic-gate */ 29380Sstevel@tonic-gate static boolean_t 29393448Sdh155122 esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial, 29403448Sdh155122 ipsecesp_stack_t *espstack) 29410Sstevel@tonic-gate { 29420Sstevel@tonic-gate mblk_t *pfkey_msg_mp, *keysock_out_mp; 29430Sstevel@tonic-gate sadb_msg_t *samsg; 29440Sstevel@tonic-gate sadb_supported_t *sasupp_auth = NULL; 29450Sstevel@tonic-gate sadb_supported_t *sasupp_encr = NULL; 29460Sstevel@tonic-gate sadb_alg_t *saalg; 29470Sstevel@tonic-gate uint_t allocsize = sizeof (*samsg); 29480Sstevel@tonic-gate uint_t i, numalgs_snap; 29490Sstevel@tonic-gate int current_aalgs; 29500Sstevel@tonic-gate ipsec_alginfo_t **authalgs; 29510Sstevel@tonic-gate uint_t num_aalgs; 29520Sstevel@tonic-gate int current_ealgs; 29530Sstevel@tonic-gate ipsec_alginfo_t **encralgs; 29540Sstevel@tonic-gate uint_t num_ealgs; 29553448Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 29560Sstevel@tonic-gate 29570Sstevel@tonic-gate /* Allocate the KEYSOCK_OUT. */ 29580Sstevel@tonic-gate keysock_out_mp = sadb_keysock_out(serial); 29590Sstevel@tonic-gate if (keysock_out_mp == NULL) { 29600Sstevel@tonic-gate esp0dbg(("esp_register_out: couldn't allocate mblk.\n")); 29610Sstevel@tonic-gate return (B_FALSE); 29620Sstevel@tonic-gate } 29630Sstevel@tonic-gate 29640Sstevel@tonic-gate /* 29650Sstevel@tonic-gate * Allocate the PF_KEY message that follows KEYSOCK_OUT. 29660Sstevel@tonic-gate */ 29670Sstevel@tonic-gate 29683448Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 29690Sstevel@tonic-gate 29700Sstevel@tonic-gate /* 29710Sstevel@tonic-gate * Fill SADB_REGISTER message's algorithm descriptors. Hold 29720Sstevel@tonic-gate * down the lock while filling it. 29730Sstevel@tonic-gate * 29740Sstevel@tonic-gate * Return only valid algorithms, so the number of algorithms 29750Sstevel@tonic-gate * to send up may be less than the number of algorithm entries 29760Sstevel@tonic-gate * in the table. 29770Sstevel@tonic-gate */ 29783448Sdh155122 authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH]; 29790Sstevel@tonic-gate for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 29800Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 29810Sstevel@tonic-gate num_aalgs++; 29820Sstevel@tonic-gate 29830Sstevel@tonic-gate if (num_aalgs != 0) { 29840Sstevel@tonic-gate allocsize += (num_aalgs * sizeof (*saalg)); 29850Sstevel@tonic-gate allocsize += sizeof (*sasupp_auth); 29860Sstevel@tonic-gate } 29873448Sdh155122 encralgs = ipss->ipsec_alglists[IPSEC_ALG_ENCR]; 29880Sstevel@tonic-gate for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 29890Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) 29900Sstevel@tonic-gate num_ealgs++; 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate if (num_ealgs != 0) { 29930Sstevel@tonic-gate allocsize += (num_ealgs * sizeof (*saalg)); 29940Sstevel@tonic-gate allocsize += sizeof (*sasupp_encr); 29950Sstevel@tonic-gate } 29960Sstevel@tonic-gate keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI); 29970Sstevel@tonic-gate if (keysock_out_mp->b_cont == NULL) { 29983448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 29990Sstevel@tonic-gate freemsg(keysock_out_mp); 30000Sstevel@tonic-gate return (B_FALSE); 30010Sstevel@tonic-gate } 30020Sstevel@tonic-gate 30030Sstevel@tonic-gate pfkey_msg_mp = keysock_out_mp->b_cont; 30040Sstevel@tonic-gate pfkey_msg_mp->b_wptr += allocsize; 30050Sstevel@tonic-gate if (num_aalgs != 0) { 30060Sstevel@tonic-gate sasupp_auth = (sadb_supported_t *) 30070Sstevel@tonic-gate (pfkey_msg_mp->b_rptr + sizeof (*samsg)); 30080Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_auth + 1); 30090Sstevel@tonic-gate 30100Sstevel@tonic-gate ASSERT(((ulong_t)saalg & 0x7) == 0); 30110Sstevel@tonic-gate 30120Sstevel@tonic-gate numalgs_snap = 0; 30130Sstevel@tonic-gate for (i = 0; 30143448Sdh155122 ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); 30153448Sdh155122 i++) { 30160Sstevel@tonic-gate if (authalgs[i] == NULL || !ALG_VALID(authalgs[i])) 30170Sstevel@tonic-gate continue; 30180Sstevel@tonic-gate 30190Sstevel@tonic-gate saalg->sadb_alg_id = authalgs[i]->alg_id; 30200Sstevel@tonic-gate saalg->sadb_alg_ivlen = 0; 30210Sstevel@tonic-gate saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits; 30220Sstevel@tonic-gate saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits; 30230Sstevel@tonic-gate saalg->sadb_x_alg_defincr = authalgs[i]->alg_ef_default; 30240Sstevel@tonic-gate saalg->sadb_x_alg_increment = 30250Sstevel@tonic-gate authalgs[i]->alg_increment; 30260Sstevel@tonic-gate numalgs_snap++; 30270Sstevel@tonic-gate saalg++; 30280Sstevel@tonic-gate } 30290Sstevel@tonic-gate ASSERT(numalgs_snap == num_aalgs); 30300Sstevel@tonic-gate #ifdef DEBUG 30310Sstevel@tonic-gate /* 30320Sstevel@tonic-gate * Reality check to make sure I snagged all of the 30330Sstevel@tonic-gate * algorithms. 30340Sstevel@tonic-gate */ 30350Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 30360Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) { 30370Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 30380Sstevel@tonic-gate "Missed aalg #%d.\n", i); 30390Sstevel@tonic-gate } 30400Sstevel@tonic-gate } 30410Sstevel@tonic-gate #endif /* DEBUG */ 30420Sstevel@tonic-gate } else { 30430Sstevel@tonic-gate saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg)); 30440Sstevel@tonic-gate } 30450Sstevel@tonic-gate 30460Sstevel@tonic-gate if (num_ealgs != 0) { 30470Sstevel@tonic-gate sasupp_encr = (sadb_supported_t *)saalg; 30480Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_encr + 1); 30490Sstevel@tonic-gate 30500Sstevel@tonic-gate numalgs_snap = 0; 30510Sstevel@tonic-gate for (i = 0; 30520Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) { 30530Sstevel@tonic-gate if (encralgs[i] == NULL || !ALG_VALID(encralgs[i])) 30540Sstevel@tonic-gate continue; 30550Sstevel@tonic-gate saalg->sadb_alg_id = encralgs[i]->alg_id; 30560Sstevel@tonic-gate saalg->sadb_alg_ivlen = encralgs[i]->alg_datalen; 30570Sstevel@tonic-gate saalg->sadb_alg_minbits = encralgs[i]->alg_ef_minbits; 30580Sstevel@tonic-gate saalg->sadb_alg_maxbits = encralgs[i]->alg_ef_maxbits; 30590Sstevel@tonic-gate saalg->sadb_x_alg_defincr = encralgs[i]->alg_ef_default; 30600Sstevel@tonic-gate saalg->sadb_x_alg_increment = 30610Sstevel@tonic-gate encralgs[i]->alg_increment; 30620Sstevel@tonic-gate numalgs_snap++; 30630Sstevel@tonic-gate saalg++; 30640Sstevel@tonic-gate } 30650Sstevel@tonic-gate ASSERT(numalgs_snap == num_ealgs); 30660Sstevel@tonic-gate #ifdef DEBUG 30670Sstevel@tonic-gate /* 30680Sstevel@tonic-gate * Reality check to make sure I snagged all of the 30690Sstevel@tonic-gate * algorithms. 30700Sstevel@tonic-gate */ 30710Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 30720Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) { 30730Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 30740Sstevel@tonic-gate "Missed ealg #%d.\n", i); 30750Sstevel@tonic-gate } 30760Sstevel@tonic-gate } 30770Sstevel@tonic-gate #endif /* DEBUG */ 30780Sstevel@tonic-gate } 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate current_aalgs = num_aalgs; 30810Sstevel@tonic-gate current_ealgs = num_ealgs; 30820Sstevel@tonic-gate 30833448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 30840Sstevel@tonic-gate 30850Sstevel@tonic-gate /* Now fill the rest of the SADB_REGISTER message. */ 30860Sstevel@tonic-gate 30870Sstevel@tonic-gate samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr; 30880Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2; 30890Sstevel@tonic-gate samsg->sadb_msg_type = SADB_REGISTER; 30900Sstevel@tonic-gate samsg->sadb_msg_errno = 0; 30910Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 30920Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(allocsize); 30930Sstevel@tonic-gate samsg->sadb_msg_reserved = 0; 30940Sstevel@tonic-gate /* 30950Sstevel@tonic-gate * Assume caller has sufficient sequence/pid number info. If it's one 30960Sstevel@tonic-gate * from me over a new alg., I could give two hoots about sequence. 30970Sstevel@tonic-gate */ 30980Sstevel@tonic-gate samsg->sadb_msg_seq = sequence; 30990Sstevel@tonic-gate samsg->sadb_msg_pid = pid; 31000Sstevel@tonic-gate 31010Sstevel@tonic-gate if (sasupp_auth != NULL) { 31024987Sdanmcd sasupp_auth->sadb_supported_len = SADB_8TO64( 31034987Sdanmcd sizeof (*sasupp_auth) + sizeof (*saalg) * current_aalgs); 31040Sstevel@tonic-gate sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 31050Sstevel@tonic-gate sasupp_auth->sadb_supported_reserved = 0; 31060Sstevel@tonic-gate } 31070Sstevel@tonic-gate 31080Sstevel@tonic-gate if (sasupp_encr != NULL) { 31094987Sdanmcd sasupp_encr->sadb_supported_len = SADB_8TO64( 31104987Sdanmcd sizeof (*sasupp_encr) + sizeof (*saalg) * current_ealgs); 31110Sstevel@tonic-gate sasupp_encr->sadb_supported_exttype = 31120Sstevel@tonic-gate SADB_EXT_SUPPORTED_ENCRYPT; 31130Sstevel@tonic-gate sasupp_encr->sadb_supported_reserved = 0; 31140Sstevel@tonic-gate } 31150Sstevel@tonic-gate 31163448Sdh155122 if (espstack->esp_pfkey_q != NULL) 31173448Sdh155122 putnext(espstack->esp_pfkey_q, keysock_out_mp); 31180Sstevel@tonic-gate else { 31190Sstevel@tonic-gate freemsg(keysock_out_mp); 31200Sstevel@tonic-gate return (B_FALSE); 31210Sstevel@tonic-gate } 31220Sstevel@tonic-gate 31230Sstevel@tonic-gate return (B_TRUE); 31240Sstevel@tonic-gate } 31250Sstevel@tonic-gate 31260Sstevel@tonic-gate /* 31270Sstevel@tonic-gate * Invoked when the algorithm table changes. Causes SADB_REGISTER 31280Sstevel@tonic-gate * messages continaining the current list of algorithms to be 31290Sstevel@tonic-gate * sent up to the ESP listeners. 31300Sstevel@tonic-gate */ 31310Sstevel@tonic-gate void 31323448Sdh155122 ipsecesp_algs_changed(netstack_t *ns) 31330Sstevel@tonic-gate { 31343448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 31353448Sdh155122 31360Sstevel@tonic-gate /* 31370Sstevel@tonic-gate * Time to send a PF_KEY SADB_REGISTER message to ESP listeners 31380Sstevel@tonic-gate * everywhere. (The function itself checks for NULL esp_pfkey_q.) 31390Sstevel@tonic-gate */ 31403448Sdh155122 (void) esp_register_out(0, 0, 0, espstack); 31410Sstevel@tonic-gate } 31420Sstevel@tonic-gate 31430Sstevel@tonic-gate /* 31440Sstevel@tonic-gate * taskq_dispatch handler. 31450Sstevel@tonic-gate */ 31460Sstevel@tonic-gate static void 31470Sstevel@tonic-gate inbound_task(void *arg) 31480Sstevel@tonic-gate { 31490Sstevel@tonic-gate esph_t *esph; 31500Sstevel@tonic-gate mblk_t *mp = (mblk_t *)arg; 31510Sstevel@tonic-gate ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr; 31523448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 31533448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 31540Sstevel@tonic-gate int ipsec_rc; 31550Sstevel@tonic-gate 31563448Sdh155122 esp2dbg(espstack, ("in ESP inbound_task")); 31573448Sdh155122 ASSERT(espstack != NULL); 31583448Sdh155122 31593448Sdh155122 esph = ipsec_inbound_esp_sa(mp, ns); 31600Sstevel@tonic-gate if (esph == NULL) 31610Sstevel@tonic-gate return; 31620Sstevel@tonic-gate ASSERT(ii->ipsec_in_esp_sa != NULL); 31630Sstevel@tonic-gate ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(mp, esph); 31640Sstevel@tonic-gate if (ipsec_rc != IPSEC_STATUS_SUCCESS) 31650Sstevel@tonic-gate return; 31660Sstevel@tonic-gate ip_fanout_proto_again(mp, NULL, NULL, NULL); 31670Sstevel@tonic-gate } 31680Sstevel@tonic-gate 31690Sstevel@tonic-gate /* 31700Sstevel@tonic-gate * Now that weak-key passed, actually ADD the security association, and 31710Sstevel@tonic-gate * send back a reply ADD message. 31720Sstevel@tonic-gate */ 31730Sstevel@tonic-gate static int 31743055Sdanmcd esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi, 31753448Sdh155122 int *diagnostic, ipsecesp_stack_t *espstack) 31760Sstevel@tonic-gate { 31776668Smarkfen isaf_t *primary = NULL, *secondary, *inbound, *outbound; 31780Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 31790Sstevel@tonic-gate sadb_address_t *dstext = 31800Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 31810Sstevel@tonic-gate struct sockaddr_in *dst; 31820Sstevel@tonic-gate struct sockaddr_in6 *dst6; 31830Sstevel@tonic-gate boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE; 31840Sstevel@tonic-gate uint32_t *dstaddr; 31850Sstevel@tonic-gate ipsa_t *larval = NULL; 31860Sstevel@tonic-gate ipsacq_t *acqrec; 31870Sstevel@tonic-gate iacqf_t *acq_bucket; 31880Sstevel@tonic-gate mblk_t *acq_msgs = NULL; 31890Sstevel@tonic-gate int rc; 31900Sstevel@tonic-gate sadb_t *sp; 31910Sstevel@tonic-gate int outhash; 31920Sstevel@tonic-gate mblk_t *lpkt; 31933448Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 31940Sstevel@tonic-gate 31950Sstevel@tonic-gate /* 31960Sstevel@tonic-gate * Locate the appropriate table(s). 31970Sstevel@tonic-gate */ 31980Sstevel@tonic-gate 31990Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 32000Sstevel@tonic-gate dst6 = (struct sockaddr_in6 *)dst; 32010Sstevel@tonic-gate is_ipv4 = (dst->sin_family == AF_INET); 32020Sstevel@tonic-gate if (is_ipv4) { 32033448Sdh155122 sp = &espstack->esp_sadb.s_v4; 32040Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst->sin_addr); 3205564Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr); 32060Sstevel@tonic-gate } else { 32073448Sdh155122 sp = &espstack->esp_sadb.s_v6; 32080Sstevel@tonic-gate dstaddr = (uint32_t *)(&dst6->sin6_addr); 3209564Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr); 32100Sstevel@tonic-gate } 3211691Ssommerfe 3212564Ssommerfe inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi); 3213691Ssommerfe outbound = &sp->sdb_of[outhash]; 3214691Ssommerfe 32156668Smarkfen /* 32166668Smarkfen * Use the direction flags provided by the KMD to determine 32176668Smarkfen * if the inbound or outbound table should be the primary 32186668Smarkfen * for this SA. If these flags were absent then make this 32196668Smarkfen * decision based on the addresses. 32206668Smarkfen */ 32216668Smarkfen if (assoc->sadb_sa_flags & IPSA_F_INBOUND) { 32220Sstevel@tonic-gate primary = inbound; 3223691Ssommerfe secondary = outbound; 32246668Smarkfen is_inbound = B_TRUE; 32256668Smarkfen if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) 32266668Smarkfen clone = B_TRUE; 32276668Smarkfen } else { 32286668Smarkfen if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) { 32296668Smarkfen primary = outbound; 32306668Smarkfen secondary = inbound; 32316668Smarkfen } 32326668Smarkfen } 32336668Smarkfen 32346668Smarkfen if (primary == NULL) { 32356668Smarkfen /* 32366668Smarkfen * The KMD did not set a direction flag, determine which 32376668Smarkfen * table to insert the SA into based on addresses. 32386668Smarkfen */ 32396668Smarkfen switch (ksi->ks_in_dsttype) { 32406668Smarkfen case KS_IN_ADDR_MBCAST: 32416668Smarkfen clone = B_TRUE; /* All mcast SAs can be bidirectional */ 32426668Smarkfen assoc->sadb_sa_flags |= IPSA_F_OUTBOUND; 32436668Smarkfen /* FALLTHRU */ 32440Sstevel@tonic-gate /* 32450Sstevel@tonic-gate * If the source address is either one of mine, or unspecified 32460Sstevel@tonic-gate * (which is best summed up by saying "not 'not mine'"), 32470Sstevel@tonic-gate * then the association is potentially bi-directional, 32480Sstevel@tonic-gate * in that it can be used for inbound traffic and outbound 32490Sstevel@tonic-gate * traffic. The best example of such an SA is a multicast 32500Sstevel@tonic-gate * SA (which allows me to receive the outbound traffic). 32510Sstevel@tonic-gate */ 32526668Smarkfen case KS_IN_ADDR_ME: 32536668Smarkfen assoc->sadb_sa_flags |= IPSA_F_INBOUND; 32546668Smarkfen primary = inbound; 32556668Smarkfen secondary = outbound; 32566668Smarkfen if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME) 32576668Smarkfen clone = B_TRUE; 32586668Smarkfen is_inbound = B_TRUE; 32596668Smarkfen break; 32600Sstevel@tonic-gate /* 32610Sstevel@tonic-gate * If the source address literally not mine (either 32620Sstevel@tonic-gate * unspecified or not mine), then this SA may have an 32630Sstevel@tonic-gate * address that WILL be mine after some configuration. 32640Sstevel@tonic-gate * We pay the price for this by making it a bi-directional 32650Sstevel@tonic-gate * SA. 32660Sstevel@tonic-gate */ 32676668Smarkfen case KS_IN_ADDR_NOTME: 32686668Smarkfen assoc->sadb_sa_flags |= IPSA_F_OUTBOUND; 32696668Smarkfen primary = outbound; 32706668Smarkfen secondary = inbound; 32716668Smarkfen if (ksi->ks_in_srctype != KS_IN_ADDR_ME) { 32726668Smarkfen assoc->sadb_sa_flags |= IPSA_F_INBOUND; 32736668Smarkfen clone = B_TRUE; 32746668Smarkfen } 32756668Smarkfen break; 32766668Smarkfen default: 32776668Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 32786668Smarkfen return (EINVAL); 32796668Smarkfen } 32800Sstevel@tonic-gate } 32810Sstevel@tonic-gate 32820Sstevel@tonic-gate /* 32830Sstevel@tonic-gate * Find a ACQUIRE list entry if possible. If we've added an SA that 32840Sstevel@tonic-gate * suits the needs of an ACQUIRE list entry, we can eliminate the 32850Sstevel@tonic-gate * ACQUIRE list entry and transmit the enqueued packets. Use the 32860Sstevel@tonic-gate * high-bit of the sequence number to queue it. Key off destination 32870Sstevel@tonic-gate * addr, and change acqrec's state. 32880Sstevel@tonic-gate */ 32890Sstevel@tonic-gate 32900Sstevel@tonic-gate if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) { 32910Sstevel@tonic-gate acq_bucket = &sp->sdb_acq[outhash]; 32920Sstevel@tonic-gate mutex_enter(&acq_bucket->iacqf_lock); 32930Sstevel@tonic-gate for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL; 32940Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) { 32950Sstevel@tonic-gate mutex_enter(&acqrec->ipsacq_lock); 32960Sstevel@tonic-gate /* 32970Sstevel@tonic-gate * Q: I only check sequence. Should I check dst? 32980Sstevel@tonic-gate * A: Yes, check dest because those are the packets 32990Sstevel@tonic-gate * that are queued up. 33000Sstevel@tonic-gate */ 33010Sstevel@tonic-gate if (acqrec->ipsacq_seq == samsg->sadb_msg_seq && 33020Sstevel@tonic-gate IPSA_ARE_ADDR_EQUAL(dstaddr, 33034987Sdanmcd acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam)) 33040Sstevel@tonic-gate break; 33050Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 33060Sstevel@tonic-gate } 33070Sstevel@tonic-gate if (acqrec != NULL) { 33080Sstevel@tonic-gate /* 33090Sstevel@tonic-gate * AHA! I found an ACQUIRE record for this SA. 33100Sstevel@tonic-gate * Grab the msg list, and free the acquire record. 33110Sstevel@tonic-gate * I already am holding the lock for this record, 33120Sstevel@tonic-gate * so all I have to do is free it. 33130Sstevel@tonic-gate */ 33140Sstevel@tonic-gate acq_msgs = acqrec->ipsacq_mp; 33150Sstevel@tonic-gate acqrec->ipsacq_mp = NULL; 33160Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 33173448Sdh155122 sadb_destroy_acquire(acqrec, 33183448Sdh155122 espstack->ipsecesp_netstack); 33190Sstevel@tonic-gate } 33200Sstevel@tonic-gate mutex_exit(&acq_bucket->iacqf_lock); 33210Sstevel@tonic-gate } 33220Sstevel@tonic-gate 33230Sstevel@tonic-gate /* 33240Sstevel@tonic-gate * Find PF_KEY message, and see if I'm an update. If so, find entry 33250Sstevel@tonic-gate * in larval list (if there). 33260Sstevel@tonic-gate */ 33270Sstevel@tonic-gate 33280Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_UPDATE) { 33290Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 33300Sstevel@tonic-gate larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi, 33310Sstevel@tonic-gate ALL_ZEROES_PTR, dstaddr, dst->sin_family); 33320Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 33330Sstevel@tonic-gate 33347110Sdanmcd if ((larval == NULL) || 33357110Sdanmcd (larval->ipsa_state != IPSA_STATE_LARVAL)) { 33366668Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND; 33377110Sdanmcd if (larval != NULL) { 33387110Sdanmcd IPSA_REFRELE(larval); 33397110Sdanmcd } 33400Sstevel@tonic-gate esp0dbg(("Larval update, but larval disappeared.\n")); 33410Sstevel@tonic-gate return (ESRCH); 33420Sstevel@tonic-gate } /* Else sadb_common_add unlinks it for me! */ 33430Sstevel@tonic-gate } 33440Sstevel@tonic-gate 33450Sstevel@tonic-gate lpkt = NULL; 33460Sstevel@tonic-gate if (larval != NULL) 33470Sstevel@tonic-gate lpkt = sadb_clear_lpkt(larval); 33480Sstevel@tonic-gate 33493448Sdh155122 rc = sadb_common_add(espstack->esp_sadb.s_ip_q, espstack->esp_pfkey_q, 33503448Sdh155122 mp, samsg, ksi, primary, secondary, larval, clone, is_inbound, 33516668Smarkfen diagnostic, espstack->ipsecesp_netstack, &espstack->esp_sadb); 33520Sstevel@tonic-gate 33530Sstevel@tonic-gate if (rc == 0 && lpkt != NULL) { 33540Sstevel@tonic-gate rc = !taskq_dispatch(esp_taskq, inbound_task, 33554987Sdanmcd (void *) lpkt, TQ_NOSLEEP); 33560Sstevel@tonic-gate } 33570Sstevel@tonic-gate 33580Sstevel@tonic-gate if (rc != 0) { 33590Sstevel@tonic-gate ip_drop_packet(lpkt, B_TRUE, NULL, NULL, 33603448Sdh155122 DROPPER(ipss, ipds_sadb_inlarval_timeout), 33613448Sdh155122 &espstack->esp_dropper); 33620Sstevel@tonic-gate } 33630Sstevel@tonic-gate 33640Sstevel@tonic-gate /* 33650Sstevel@tonic-gate * How much more stack will I create with all of these 33660Sstevel@tonic-gate * esp_outbound() calls? 33670Sstevel@tonic-gate */ 33680Sstevel@tonic-gate 33690Sstevel@tonic-gate while (acq_msgs != NULL) { 33700Sstevel@tonic-gate mblk_t *mp = acq_msgs; 33710Sstevel@tonic-gate 33720Sstevel@tonic-gate acq_msgs = acq_msgs->b_next; 33730Sstevel@tonic-gate mp->b_next = NULL; 33740Sstevel@tonic-gate if (rc == 0) { 33750Sstevel@tonic-gate if (ipsec_outbound_sa(mp, IPPROTO_ESP)) { 33760Sstevel@tonic-gate ((ipsec_out_t *)(mp->b_rptr))-> 33770Sstevel@tonic-gate ipsec_out_esp_done = B_TRUE; 33780Sstevel@tonic-gate if (esp_outbound(mp) == IPSEC_STATUS_SUCCESS) { 33793055Sdanmcd ipha_t *ipha; 33800Sstevel@tonic-gate 33810Sstevel@tonic-gate /* do AH processing if needed */ 33820Sstevel@tonic-gate if (!esp_do_outbound_ah(mp)) 33830Sstevel@tonic-gate continue; 33840Sstevel@tonic-gate 33853055Sdanmcd ipha = (ipha_t *)mp->b_cont->b_rptr; 33863055Sdanmcd 33870Sstevel@tonic-gate /* finish IPsec processing */ 33880Sstevel@tonic-gate if (is_ipv4) { 33890Sstevel@tonic-gate ip_wput_ipsec_out(NULL, mp, 33900Sstevel@tonic-gate ipha, NULL, NULL); 33910Sstevel@tonic-gate } else { 33920Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)ipha; 33930Sstevel@tonic-gate ip_wput_ipsec_out_v6(NULL, 33940Sstevel@tonic-gate mp, ip6h, NULL, NULL); 33950Sstevel@tonic-gate } 33960Sstevel@tonic-gate } 33970Sstevel@tonic-gate continue; 33980Sstevel@tonic-gate } 33990Sstevel@tonic-gate } 34003448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 34010Sstevel@tonic-gate ip_drop_packet(mp, B_FALSE, NULL, NULL, 34023448Sdh155122 DROPPER(ipss, ipds_sadb_acquire_timeout), 34033448Sdh155122 &espstack->esp_dropper); 34040Sstevel@tonic-gate } 34050Sstevel@tonic-gate 34060Sstevel@tonic-gate return (rc); 34070Sstevel@tonic-gate } 34080Sstevel@tonic-gate 34090Sstevel@tonic-gate /* 34100Sstevel@tonic-gate * Add new ESP security association. This may become a generic AH/ESP 34110Sstevel@tonic-gate * routine eventually. 34120Sstevel@tonic-gate */ 34130Sstevel@tonic-gate static int 34143448Sdh155122 esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns) 34150Sstevel@tonic-gate { 34160Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 34170Sstevel@tonic-gate sadb_address_t *srcext = 34180Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 34190Sstevel@tonic-gate sadb_address_t *dstext = 34200Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 34213055Sdanmcd sadb_address_t *isrcext = 34223055Sdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC]; 34233055Sdanmcd sadb_address_t *idstext = 34243055Sdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST]; 34250Sstevel@tonic-gate sadb_address_t *nttext_loc = 34260Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC]; 34270Sstevel@tonic-gate sadb_address_t *nttext_rem = 34280Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM]; 34290Sstevel@tonic-gate sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH]; 34300Sstevel@tonic-gate sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT]; 34310Sstevel@tonic-gate struct sockaddr_in *src, *dst; 34320Sstevel@tonic-gate struct sockaddr_in *natt_loc, *natt_rem; 34330Sstevel@tonic-gate struct sockaddr_in6 *natt_loc6, *natt_rem6; 34340Sstevel@tonic-gate sadb_lifetime_t *soft = 34350Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT]; 34360Sstevel@tonic-gate sadb_lifetime_t *hard = 34370Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD]; 34387749SThejaswini.Singarajipura@Sun.COM sadb_lifetime_t *idle = 34397749SThejaswini.Singarajipura@Sun.COM (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE]; 34403448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 34413448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 34420Sstevel@tonic-gate 34430Sstevel@tonic-gate /* I need certain extensions present for an ADD message. */ 34440Sstevel@tonic-gate if (srcext == NULL) { 34450Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC; 34460Sstevel@tonic-gate return (EINVAL); 34470Sstevel@tonic-gate } 34480Sstevel@tonic-gate if (dstext == NULL) { 34490Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 34500Sstevel@tonic-gate return (EINVAL); 34510Sstevel@tonic-gate } 34523055Sdanmcd if (isrcext == NULL && idstext != NULL) { 34533055Sdanmcd *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC; 34543055Sdanmcd return (EINVAL); 34553055Sdanmcd } 34563055Sdanmcd if (isrcext != NULL && idstext == NULL) { 34573055Sdanmcd *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST; 34583055Sdanmcd return (EINVAL); 34593055Sdanmcd } 34600Sstevel@tonic-gate if (assoc == NULL) { 34610Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 34620Sstevel@tonic-gate return (EINVAL); 34630Sstevel@tonic-gate } 34640Sstevel@tonic-gate if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) { 34650Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY; 34660Sstevel@tonic-gate return (EINVAL); 34670Sstevel@tonic-gate } 34680Sstevel@tonic-gate 34690Sstevel@tonic-gate src = (struct sockaddr_in *)(srcext + 1); 34700Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 34710Sstevel@tonic-gate natt_loc = (struct sockaddr_in *)(nttext_loc + 1); 34720Sstevel@tonic-gate natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1); 34730Sstevel@tonic-gate natt_rem = (struct sockaddr_in *)(nttext_rem + 1); 34740Sstevel@tonic-gate natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1); 34750Sstevel@tonic-gate 34760Sstevel@tonic-gate /* Sundry ADD-specific reality checks. */ 34770Sstevel@tonic-gate /* XXX STATS : Logging/stats here? */ 34787749SThejaswini.Singarajipura@Sun.COM 34797749SThejaswini.Singarajipura@Sun.COM if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) && 34807749SThejaswini.Singarajipura@Sun.COM (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) { 34810Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE; 34820Sstevel@tonic-gate return (EINVAL); 34830Sstevel@tonic-gate } 34840Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) { 34850Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 34860Sstevel@tonic-gate return (EINVAL); 34870Sstevel@tonic-gate } 34880Sstevel@tonic-gate 34890Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NULL && 34900Sstevel@tonic-gate assoc->sadb_sa_auth == SADB_AALG_NONE) { 34910Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 34920Sstevel@tonic-gate return (EINVAL); 34930Sstevel@tonic-gate } 34940Sstevel@tonic-gate 34957110Sdanmcd if (assoc->sadb_sa_flags & ~espstack->esp_sadb.s_addflags) { 34960Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS; 34970Sstevel@tonic-gate return (EINVAL); 34980Sstevel@tonic-gate } 34990Sstevel@tonic-gate 35007749SThejaswini.Singarajipura@Sun.COM if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) { 35010Sstevel@tonic-gate return (EINVAL); 35020Sstevel@tonic-gate } 35033055Sdanmcd ASSERT(src->sin_family == dst->sin_family); 35040Sstevel@tonic-gate 35050Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) { 35060Sstevel@tonic-gate if (nttext_loc == NULL) { 35070Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC; 35080Sstevel@tonic-gate return (EINVAL); 35090Sstevel@tonic-gate } 35100Sstevel@tonic-gate 35110Sstevel@tonic-gate if (natt_loc->sin_family == AF_INET6 && 35120Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) { 35130Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC; 35140Sstevel@tonic-gate return (EINVAL); 35150Sstevel@tonic-gate } 35160Sstevel@tonic-gate } 35170Sstevel@tonic-gate 35180Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) { 35190Sstevel@tonic-gate if (nttext_rem == NULL) { 35200Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM; 35210Sstevel@tonic-gate return (EINVAL); 35220Sstevel@tonic-gate } 35230Sstevel@tonic-gate if (natt_rem->sin_family == AF_INET6 && 35240Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) { 35250Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM; 35260Sstevel@tonic-gate return (EINVAL); 35270Sstevel@tonic-gate } 35280Sstevel@tonic-gate } 35290Sstevel@tonic-gate 35300Sstevel@tonic-gate 35310Sstevel@tonic-gate /* Stuff I don't support, for now. XXX Diagnostic? */ 35320Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL || 35330Sstevel@tonic-gate ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) 35340Sstevel@tonic-gate return (EOPNOTSUPP); 35350Sstevel@tonic-gate 35360Sstevel@tonic-gate /* 35370Sstevel@tonic-gate * XXX Policy : I'm not checking identities or sensitivity 35380Sstevel@tonic-gate * labels at this time, but if I did, I'd do them here, before I sent 35390Sstevel@tonic-gate * the weak key check up to the algorithm. 35400Sstevel@tonic-gate */ 35410Sstevel@tonic-gate 35423448Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 35430Sstevel@tonic-gate 35440Sstevel@tonic-gate /* 35450Sstevel@tonic-gate * First locate the authentication algorithm. 35460Sstevel@tonic-gate */ 35470Sstevel@tonic-gate if (akey != NULL) { 35480Sstevel@tonic-gate ipsec_alginfo_t *aalg; 35490Sstevel@tonic-gate 35503448Sdh155122 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] 35513448Sdh155122 [assoc->sadb_sa_auth]; 35520Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) { 35533448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 35543448Sdh155122 esp1dbg(espstack, ("Couldn't find auth alg #%d.\n", 35550Sstevel@tonic-gate assoc->sadb_sa_auth)); 35560Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 35570Sstevel@tonic-gate return (EINVAL); 35580Sstevel@tonic-gate } 35592810Smarkfen 35602810Smarkfen /* 35612810Smarkfen * Sanity check key sizes. 35622810Smarkfen * Note: It's not possible to use SADB_AALG_NONE because 35632810Smarkfen * this auth_alg is not defined with ALG_FLAG_VALID. If this 35642810Smarkfen * ever changes, the same check for SADB_AALG_NONE and 35652810Smarkfen * a auth_key != NULL should be made here ( see below). 35662810Smarkfen */ 35670Sstevel@tonic-gate if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) { 35683448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 35690Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS; 35700Sstevel@tonic-gate return (EINVAL); 35710Sstevel@tonic-gate } 35722810Smarkfen ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 35730Sstevel@tonic-gate 35740Sstevel@tonic-gate /* check key and fix parity if needed */ 35750Sstevel@tonic-gate if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE, 35760Sstevel@tonic-gate diagnostic) != 0) { 35773448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 35780Sstevel@tonic-gate return (EINVAL); 35790Sstevel@tonic-gate } 35800Sstevel@tonic-gate } 35810Sstevel@tonic-gate 35820Sstevel@tonic-gate /* 35830Sstevel@tonic-gate * Then locate the encryption algorithm. 35840Sstevel@tonic-gate */ 35850Sstevel@tonic-gate if (ekey != NULL) { 35860Sstevel@tonic-gate ipsec_alginfo_t *ealg; 35870Sstevel@tonic-gate 35883448Sdh155122 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR] 35893448Sdh155122 [assoc->sadb_sa_encrypt]; 35900Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) { 35913448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 35923448Sdh155122 esp1dbg(espstack, ("Couldn't find encr alg #%d.\n", 35930Sstevel@tonic-gate assoc->sadb_sa_encrypt)); 35940Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 35950Sstevel@tonic-gate return (EINVAL); 35960Sstevel@tonic-gate } 35972810Smarkfen 35982810Smarkfen /* 35992810Smarkfen * Sanity check key sizes. If the encryption algorithm is 36002810Smarkfen * SADB_EALG_NULL but the encryption key is NOT 36012810Smarkfen * NULL then complain. 36022810Smarkfen */ 36032810Smarkfen if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) || 36042810Smarkfen (!ipsec_valid_key_size(ekey->sadb_key_bits, ealg))) { 36053448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 36060Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS; 36070Sstevel@tonic-gate return (EINVAL); 36080Sstevel@tonic-gate } 36092810Smarkfen ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 36100Sstevel@tonic-gate 36110Sstevel@tonic-gate /* check key */ 36120Sstevel@tonic-gate if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE, 36130Sstevel@tonic-gate diagnostic) != 0) { 36143448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 36150Sstevel@tonic-gate return (EINVAL); 36160Sstevel@tonic-gate } 36170Sstevel@tonic-gate } 36183448Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 36190Sstevel@tonic-gate 36203055Sdanmcd return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi, 36214987Sdanmcd diagnostic, espstack)); 36220Sstevel@tonic-gate } 36230Sstevel@tonic-gate 36240Sstevel@tonic-gate /* 36250Sstevel@tonic-gate * Update a security association. Updates come in two varieties. The first 36260Sstevel@tonic-gate * is an update of lifetimes on a non-larval SA. The second is an update of 36270Sstevel@tonic-gate * a larval SA, which ends up looking a lot more like an add. 36280Sstevel@tonic-gate */ 36290Sstevel@tonic-gate static int 36303448Sdh155122 esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, 36316668Smarkfen ipsecesp_stack_t *espstack, uint8_t sadb_msg_type) 36320Sstevel@tonic-gate { 36337749SThejaswini.Singarajipura@Sun.COM sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 36347749SThejaswini.Singarajipura@Sun.COM mblk_t *buf_pkt; 36357749SThejaswini.Singarajipura@Sun.COM int rcode; 36367749SThejaswini.Singarajipura@Sun.COM 36370Sstevel@tonic-gate sadb_address_t *dstext = 36380Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 36390Sstevel@tonic-gate 36400Sstevel@tonic-gate if (dstext == NULL) { 36410Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 36420Sstevel@tonic-gate return (EINVAL); 36430Sstevel@tonic-gate } 36440Sstevel@tonic-gate 36457749SThejaswini.Singarajipura@Sun.COM rcode = sadb_update_sa(mp, ksi, &buf_pkt, &espstack->esp_sadb, 36467749SThejaswini.Singarajipura@Sun.COM diagnostic, espstack->esp_pfkey_q, esp_add_sa, 36477749SThejaswini.Singarajipura@Sun.COM espstack->ipsecesp_netstack, sadb_msg_type); 36487749SThejaswini.Singarajipura@Sun.COM 36497749SThejaswini.Singarajipura@Sun.COM if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) || 36507749SThejaswini.Singarajipura@Sun.COM (rcode != 0)) { 36517749SThejaswini.Singarajipura@Sun.COM return (rcode); 36527749SThejaswini.Singarajipura@Sun.COM } 36537749SThejaswini.Singarajipura@Sun.COM 36547749SThejaswini.Singarajipura@Sun.COM HANDLE_BUF_PKT(esp_taskq, 36557749SThejaswini.Singarajipura@Sun.COM espstack->ipsecesp_netstack->netstack_ipsec, 36567749SThejaswini.Singarajipura@Sun.COM espstack->esp_dropper, buf_pkt); 36577749SThejaswini.Singarajipura@Sun.COM 36587749SThejaswini.Singarajipura@Sun.COM return (rcode); 36590Sstevel@tonic-gate } 36600Sstevel@tonic-gate 36610Sstevel@tonic-gate /* 36620Sstevel@tonic-gate * Delete a security association. This is REALLY likely to be code common to 36630Sstevel@tonic-gate * both AH and ESP. Find the association, then unlink it. 36640Sstevel@tonic-gate */ 36650Sstevel@tonic-gate static int 36663448Sdh155122 esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, 36676668Smarkfen ipsecesp_stack_t *espstack, uint8_t sadb_msg_type) 36680Sstevel@tonic-gate { 36690Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 36700Sstevel@tonic-gate sadb_address_t *dstext = 36710Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 36720Sstevel@tonic-gate sadb_address_t *srcext = 36730Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 36740Sstevel@tonic-gate struct sockaddr_in *sin; 36750Sstevel@tonic-gate 36760Sstevel@tonic-gate if (assoc == NULL) { 36770Sstevel@tonic-gate if (dstext != NULL) { 36780Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 36790Sstevel@tonic-gate } else if (srcext != NULL) { 36800Sstevel@tonic-gate sin = (struct sockaddr_in *)(srcext + 1); 36810Sstevel@tonic-gate } else { 36820Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 36830Sstevel@tonic-gate return (EINVAL); 36840Sstevel@tonic-gate } 36853055Sdanmcd return (sadb_purge_sa(mp, ksi, 36863448Sdh155122 (sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 : 36873448Sdh155122 &espstack->esp_sadb.s_v4, espstack->esp_pfkey_q, 36883448Sdh155122 espstack->esp_sadb.s_ip_q)); 36890Sstevel@tonic-gate } 36900Sstevel@tonic-gate 36916668Smarkfen return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic, 36926668Smarkfen espstack->esp_pfkey_q, sadb_msg_type)); 36930Sstevel@tonic-gate } 36940Sstevel@tonic-gate 36950Sstevel@tonic-gate /* 36960Sstevel@tonic-gate * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP 36970Sstevel@tonic-gate * messages. 36980Sstevel@tonic-gate */ 36990Sstevel@tonic-gate static void 37003448Sdh155122 esp_dump(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack) 37010Sstevel@tonic-gate { 37020Sstevel@tonic-gate int error; 37030Sstevel@tonic-gate sadb_msg_t *samsg; 37040Sstevel@tonic-gate 37050Sstevel@tonic-gate /* 37060Sstevel@tonic-gate * Dump each fanout, bailing if error is non-zero. 37070Sstevel@tonic-gate */ 37080Sstevel@tonic-gate 37097749SThejaswini.Singarajipura@Sun.COM error = sadb_dump(espstack->esp_pfkey_q, mp, ksi, 37103448Sdh155122 &espstack->esp_sadb.s_v4); 37110Sstevel@tonic-gate if (error != 0) 37120Sstevel@tonic-gate goto bail; 37130Sstevel@tonic-gate 37147749SThejaswini.Singarajipura@Sun.COM error = sadb_dump(espstack->esp_pfkey_q, mp, ksi, 37153448Sdh155122 &espstack->esp_sadb.s_v6); 37160Sstevel@tonic-gate bail: 37170Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 37180Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 37190Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 37203448Sdh155122 sadb_pfkey_echo(espstack->esp_pfkey_q, mp, 37213448Sdh155122 (sadb_msg_t *)mp->b_cont->b_rptr, ksi, NULL); 37220Sstevel@tonic-gate } 37230Sstevel@tonic-gate 37240Sstevel@tonic-gate /* 37253055Sdanmcd * First-cut reality check for an inbound PF_KEY message. 37263055Sdanmcd */ 37273055Sdanmcd static boolean_t 37283448Sdh155122 esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi, 37293448Sdh155122 ipsecesp_stack_t *espstack) 37303055Sdanmcd { 37313055Sdanmcd int diagnostic; 37323055Sdanmcd 37333055Sdanmcd if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) { 37343055Sdanmcd diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT; 37353055Sdanmcd goto badmsg; 37363055Sdanmcd } 37373055Sdanmcd if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL || 37383055Sdanmcd ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) { 37393055Sdanmcd diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT; 37403055Sdanmcd goto badmsg; 37413055Sdanmcd } 37423055Sdanmcd return (B_FALSE); /* False ==> no failures */ 37433055Sdanmcd 37443055Sdanmcd badmsg: 37453448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic, 37463055Sdanmcd ksi->ks_in_serial); 37473055Sdanmcd return (B_TRUE); /* True ==> failures */ 37483055Sdanmcd } 37493055Sdanmcd 37503055Sdanmcd /* 37510Sstevel@tonic-gate * ESP parsing of PF_KEY messages. Keysock did most of the really silly 37520Sstevel@tonic-gate * error cases. What I receive is a fully-formed, syntactically legal 37530Sstevel@tonic-gate * PF_KEY message. I then need to check semantics... 37540Sstevel@tonic-gate * 37550Sstevel@tonic-gate * This code may become common to AH and ESP. Stay tuned. 37560Sstevel@tonic-gate * 37570Sstevel@tonic-gate * I also make the assumption that db_ref's are cool. If this assumption 37580Sstevel@tonic-gate * is wrong, this means that someone other than keysock or me has been 37590Sstevel@tonic-gate * mucking with PF_KEY messages. 37600Sstevel@tonic-gate */ 37610Sstevel@tonic-gate static void 37623448Sdh155122 esp_parse_pfkey(mblk_t *mp, ipsecesp_stack_t *espstack) 37630Sstevel@tonic-gate { 37640Sstevel@tonic-gate mblk_t *msg = mp->b_cont; 37650Sstevel@tonic-gate sadb_msg_t *samsg; 37660Sstevel@tonic-gate keysock_in_t *ksi; 37670Sstevel@tonic-gate int error; 37680Sstevel@tonic-gate int diagnostic = SADB_X_DIAGNOSTIC_NONE; 37690Sstevel@tonic-gate 37700Sstevel@tonic-gate ASSERT(msg != NULL); 37713448Sdh155122 37720Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr; 37730Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 37740Sstevel@tonic-gate 37750Sstevel@tonic-gate /* 37760Sstevel@tonic-gate * If applicable, convert unspecified AF_INET6 to unspecified 37773055Sdanmcd * AF_INET. And do other address reality checks. 37780Sstevel@tonic-gate */ 37793448Sdh155122 if (!sadb_addrfix(ksi, espstack->esp_pfkey_q, mp, 37803448Sdh155122 espstack->ipsecesp_netstack) || 37813448Sdh155122 esp_pfkey_reality_failures(mp, ksi, espstack)) { 37823055Sdanmcd return; 37833055Sdanmcd } 37840Sstevel@tonic-gate 37850Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 37860Sstevel@tonic-gate case SADB_ADD: 37873448Sdh155122 error = esp_add_sa(mp, ksi, &diagnostic, 37883448Sdh155122 espstack->ipsecesp_netstack); 37890Sstevel@tonic-gate if (error != 0) { 37903448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 37913448Sdh155122 diagnostic, ksi->ks_in_serial); 37920Sstevel@tonic-gate } 37930Sstevel@tonic-gate /* else esp_add_sa() took care of things. */ 37940Sstevel@tonic-gate break; 37950Sstevel@tonic-gate case SADB_DELETE: 37966668Smarkfen case SADB_X_DELPAIR: 37977749SThejaswini.Singarajipura@Sun.COM case SADB_X_DELPAIR_STATE: 37986668Smarkfen error = esp_del_sa(mp, ksi, &diagnostic, espstack, 37996668Smarkfen samsg->sadb_msg_type); 38000Sstevel@tonic-gate if (error != 0) { 38013448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 38023448Sdh155122 diagnostic, ksi->ks_in_serial); 38030Sstevel@tonic-gate } 38040Sstevel@tonic-gate /* Else esp_del_sa() took care of things. */ 38050Sstevel@tonic-gate break; 38060Sstevel@tonic-gate case SADB_GET: 38076668Smarkfen error = sadb_delget_sa(mp, ksi, &espstack->esp_sadb, 38086668Smarkfen &diagnostic, espstack->esp_pfkey_q, samsg->sadb_msg_type); 38090Sstevel@tonic-gate if (error != 0) { 38103448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 38113448Sdh155122 diagnostic, ksi->ks_in_serial); 38120Sstevel@tonic-gate } 38130Sstevel@tonic-gate /* Else sadb_get_sa() took care of things. */ 38140Sstevel@tonic-gate break; 38150Sstevel@tonic-gate case SADB_FLUSH: 38163448Sdh155122 sadbp_flush(&espstack->esp_sadb, espstack->ipsecesp_netstack); 38173448Sdh155122 sadb_pfkey_echo(espstack->esp_pfkey_q, mp, samsg, ksi, NULL); 38180Sstevel@tonic-gate break; 38190Sstevel@tonic-gate case SADB_REGISTER: 38200Sstevel@tonic-gate /* 38210Sstevel@tonic-gate * Hmmm, let's do it! Check for extensions (there should 38220Sstevel@tonic-gate * be none), extract the fields, call esp_register_out(), 38230Sstevel@tonic-gate * then either free or report an error. 38240Sstevel@tonic-gate * 38250Sstevel@tonic-gate * Keysock takes care of the PF_KEY bookkeeping for this. 38260Sstevel@tonic-gate */ 38270Sstevel@tonic-gate if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid, 38283448Sdh155122 ksi->ks_in_serial, espstack)) { 38290Sstevel@tonic-gate freemsg(mp); 38300Sstevel@tonic-gate } else { 38310Sstevel@tonic-gate /* 38320Sstevel@tonic-gate * Only way this path hits is if there is a memory 38330Sstevel@tonic-gate * failure. It will not return B_FALSE because of 38340Sstevel@tonic-gate * lack of esp_pfkey_q if I am in wput(). 38350Sstevel@tonic-gate */ 38363448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, 38373448Sdh155122 diagnostic, ksi->ks_in_serial); 38380Sstevel@tonic-gate } 38390Sstevel@tonic-gate break; 38400Sstevel@tonic-gate case SADB_UPDATE: 38416668Smarkfen case SADB_X_UPDATEPAIR: 38420Sstevel@tonic-gate /* 38430Sstevel@tonic-gate * Find a larval, if not there, find a full one and get 38440Sstevel@tonic-gate * strict. 38450Sstevel@tonic-gate */ 38466668Smarkfen error = esp_update_sa(mp, ksi, &diagnostic, espstack, 38476668Smarkfen samsg->sadb_msg_type); 38480Sstevel@tonic-gate if (error != 0) { 38493448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 38503448Sdh155122 diagnostic, ksi->ks_in_serial); 38510Sstevel@tonic-gate } 38520Sstevel@tonic-gate /* else esp_update_sa() took care of things. */ 38530Sstevel@tonic-gate break; 38540Sstevel@tonic-gate case SADB_GETSPI: 38550Sstevel@tonic-gate /* 38560Sstevel@tonic-gate * Reserve a new larval entry. 38570Sstevel@tonic-gate */ 38583448Sdh155122 esp_getspi(mp, ksi, espstack); 38590Sstevel@tonic-gate break; 38600Sstevel@tonic-gate case SADB_ACQUIRE: 38610Sstevel@tonic-gate /* 38620Sstevel@tonic-gate * Find larval and/or ACQUIRE record and kill it (them), I'm 38630Sstevel@tonic-gate * most likely an error. Inbound ACQUIRE messages should only 38640Sstevel@tonic-gate * have the base header. 38650Sstevel@tonic-gate */ 38663448Sdh155122 sadb_in_acquire(samsg, &espstack->esp_sadb, 38673448Sdh155122 espstack->esp_pfkey_q, espstack->ipsecesp_netstack); 38680Sstevel@tonic-gate freemsg(mp); 38690Sstevel@tonic-gate break; 38700Sstevel@tonic-gate case SADB_DUMP: 38710Sstevel@tonic-gate /* 38720Sstevel@tonic-gate * Dump all entries. 38730Sstevel@tonic-gate */ 38743448Sdh155122 esp_dump(mp, ksi, espstack); 38750Sstevel@tonic-gate /* esp_dump will take care of the return message, etc. */ 38760Sstevel@tonic-gate break; 38770Sstevel@tonic-gate case SADB_EXPIRE: 38780Sstevel@tonic-gate /* Should never reach me. */ 38793448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EOPNOTSUPP, 38803448Sdh155122 diagnostic, ksi->ks_in_serial); 38810Sstevel@tonic-gate break; 38820Sstevel@tonic-gate default: 38833448Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, 38840Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial); 38850Sstevel@tonic-gate break; 38860Sstevel@tonic-gate } 38870Sstevel@tonic-gate } 38880Sstevel@tonic-gate 38890Sstevel@tonic-gate /* 38900Sstevel@tonic-gate * Handle case where PF_KEY says it can't find a keysock for one of my 38910Sstevel@tonic-gate * ACQUIRE messages. 38920Sstevel@tonic-gate */ 38930Sstevel@tonic-gate static void 38943448Sdh155122 esp_keysock_no_socket(mblk_t *mp, ipsecesp_stack_t *espstack) 38950Sstevel@tonic-gate { 38960Sstevel@tonic-gate sadb_msg_t *samsg; 38970Sstevel@tonic-gate keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr; 38980Sstevel@tonic-gate 38990Sstevel@tonic-gate if (mp->b_cont == NULL) { 39000Sstevel@tonic-gate freemsg(mp); 39010Sstevel@tonic-gate return; 39020Sstevel@tonic-gate } 39030Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 39040Sstevel@tonic-gate 39050Sstevel@tonic-gate /* 39060Sstevel@tonic-gate * If keysock can't find any registered, delete the acquire record 39070Sstevel@tonic-gate * immediately, and handle errors. 39080Sstevel@tonic-gate */ 39090Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_ACQUIRE) { 39100Sstevel@tonic-gate samsg->sadb_msg_errno = kse->ks_err_errno; 39110Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); 39120Sstevel@tonic-gate /* 39130Sstevel@tonic-gate * Use the write-side of the esp_pfkey_q, in case there is 39140Sstevel@tonic-gate * no esp_sadb.s_ip_q. 39150Sstevel@tonic-gate */ 39163448Sdh155122 sadb_in_acquire(samsg, &espstack->esp_sadb, 39173448Sdh155122 WR(espstack->esp_pfkey_q), espstack->ipsecesp_netstack); 39180Sstevel@tonic-gate } 39190Sstevel@tonic-gate 39200Sstevel@tonic-gate freemsg(mp); 39210Sstevel@tonic-gate } 39220Sstevel@tonic-gate 39230Sstevel@tonic-gate /* 39240Sstevel@tonic-gate * ESP module write put routine. 39250Sstevel@tonic-gate */ 39260Sstevel@tonic-gate static void 39270Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp) 39280Sstevel@tonic-gate { 39290Sstevel@tonic-gate ipsec_info_t *ii; 39300Sstevel@tonic-gate struct iocblk *iocp; 39313448Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 39323448Sdh155122 39333448Sdh155122 esp3dbg(espstack, ("In esp_wput().\n")); 39340Sstevel@tonic-gate 39350Sstevel@tonic-gate /* NOTE: Each case must take care of freeing or passing mp. */ 39360Sstevel@tonic-gate switch (mp->b_datap->db_type) { 39370Sstevel@tonic-gate case M_CTL: 39380Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) { 39390Sstevel@tonic-gate /* Not big enough message. */ 39400Sstevel@tonic-gate freemsg(mp); 39410Sstevel@tonic-gate break; 39420Sstevel@tonic-gate } 39430Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 39440Sstevel@tonic-gate 39450Sstevel@tonic-gate switch (ii->ipsec_info_type) { 39460Sstevel@tonic-gate case KEYSOCK_OUT_ERR: 39473448Sdh155122 esp1dbg(espstack, ("Got KEYSOCK_OUT_ERR message.\n")); 39483448Sdh155122 esp_keysock_no_socket(mp, espstack); 39490Sstevel@tonic-gate break; 39500Sstevel@tonic-gate case KEYSOCK_IN: 39513448Sdh155122 ESP_BUMP_STAT(espstack, keysock_in); 39523448Sdh155122 esp3dbg(espstack, ("Got KEYSOCK_IN message.\n")); 39533055Sdanmcd 39543055Sdanmcd /* Parse the message. */ 39553448Sdh155122 esp_parse_pfkey(mp, espstack); 39560Sstevel@tonic-gate break; 39570Sstevel@tonic-gate case KEYSOCK_HELLO: 39583448Sdh155122 sadb_keysock_hello(&espstack->esp_pfkey_q, q, mp, 39593448Sdh155122 esp_ager, (void *)espstack, &espstack->esp_event, 39603448Sdh155122 SADB_SATYPE_ESP); 39610Sstevel@tonic-gate break; 39620Sstevel@tonic-gate default: 39633448Sdh155122 esp2dbg(espstack, ("Got M_CTL from above of 0x%x.\n", 39640Sstevel@tonic-gate ii->ipsec_info_type)); 39650Sstevel@tonic-gate freemsg(mp); 39660Sstevel@tonic-gate break; 39670Sstevel@tonic-gate } 39680Sstevel@tonic-gate break; 39690Sstevel@tonic-gate case M_IOCTL: 39700Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 39710Sstevel@tonic-gate switch (iocp->ioc_cmd) { 39720Sstevel@tonic-gate case ND_SET: 39730Sstevel@tonic-gate case ND_GET: 39743448Sdh155122 if (nd_getset(q, espstack->ipsecesp_g_nd, mp)) { 39750Sstevel@tonic-gate qreply(q, mp); 39760Sstevel@tonic-gate return; 39770Sstevel@tonic-gate } else { 39780Sstevel@tonic-gate iocp->ioc_error = ENOENT; 39790Sstevel@tonic-gate } 39800Sstevel@tonic-gate /* FALLTHRU */ 39810Sstevel@tonic-gate default: 39820Sstevel@tonic-gate /* We really don't support any other ioctls, do we? */ 39830Sstevel@tonic-gate 39840Sstevel@tonic-gate /* Return EINVAL */ 39850Sstevel@tonic-gate if (iocp->ioc_error != ENOENT) 39860Sstevel@tonic-gate iocp->ioc_error = EINVAL; 39870Sstevel@tonic-gate iocp->ioc_count = 0; 39880Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 39890Sstevel@tonic-gate qreply(q, mp); 39900Sstevel@tonic-gate return; 39910Sstevel@tonic-gate } 39920Sstevel@tonic-gate default: 39933448Sdh155122 esp3dbg(espstack, 39943448Sdh155122 ("Got default message, type %d, passing to IP.\n", 39950Sstevel@tonic-gate mp->b_datap->db_type)); 39960Sstevel@tonic-gate putnext(q, mp); 39970Sstevel@tonic-gate } 39980Sstevel@tonic-gate } 39990Sstevel@tonic-gate 40000Sstevel@tonic-gate /* 40010Sstevel@tonic-gate * Process an outbound ESP packet that can be accelerated by a IPsec 40020Sstevel@tonic-gate * hardware acceleration capable Provider. 40030Sstevel@tonic-gate * The caller already inserted and initialized the ESP header. 40040Sstevel@tonic-gate * This function allocates a tagging M_CTL, and adds room at the end 40050Sstevel@tonic-gate * of the packet to hold the ICV if authentication is needed. 40060Sstevel@tonic-gate * 40070Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 40080Sstevel@tonic-gate * mblk chain ipsec_out. 40090Sstevel@tonic-gate */ 40100Sstevel@tonic-gate static ipsec_status_t 40110Sstevel@tonic-gate esp_outbound_accelerated(mblk_t *ipsec_out, uint_t icv_len) 40120Sstevel@tonic-gate { 40130Sstevel@tonic-gate ipsec_out_t *io; 40140Sstevel@tonic-gate mblk_t *lastmp; 40153448Sdh155122 netstack_t *ns; 40163448Sdh155122 ipsecesp_stack_t *espstack; 40173448Sdh155122 ipsec_stack_t *ipss; 40180Sstevel@tonic-gate 40190Sstevel@tonic-gate io = (ipsec_out_t *)ipsec_out->b_rptr; 40203448Sdh155122 ns = io->ipsec_out_ns; 40213448Sdh155122 espstack = ns->netstack_ipsecesp; 40223448Sdh155122 ipss = ns->netstack_ipsec; 40233448Sdh155122 40243448Sdh155122 ESP_BUMP_STAT(espstack, out_accelerated); 40250Sstevel@tonic-gate 40260Sstevel@tonic-gate /* mark packet as being accelerated in IPSEC_OUT */ 40270Sstevel@tonic-gate ASSERT(io->ipsec_out_accelerated == B_FALSE); 40280Sstevel@tonic-gate io->ipsec_out_accelerated = B_TRUE; 40290Sstevel@tonic-gate 40300Sstevel@tonic-gate /* 40310Sstevel@tonic-gate * add room at the end of the packet for the ICV if needed 40320Sstevel@tonic-gate */ 40330Sstevel@tonic-gate if (icv_len > 0) { 40340Sstevel@tonic-gate /* go to last mblk */ 40350Sstevel@tonic-gate lastmp = ipsec_out; /* For following while loop. */ 40360Sstevel@tonic-gate do { 40370Sstevel@tonic-gate lastmp = lastmp->b_cont; 40380Sstevel@tonic-gate } while (lastmp->b_cont != NULL); 40390Sstevel@tonic-gate 40400Sstevel@tonic-gate /* if not enough available room, allocate new mblk */ 40410Sstevel@tonic-gate if ((lastmp->b_wptr + icv_len) > lastmp->b_datap->db_lim) { 40420Sstevel@tonic-gate lastmp->b_cont = allocb(icv_len, BPRI_HI); 40430Sstevel@tonic-gate if (lastmp->b_cont == NULL) { 40443448Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 40450Sstevel@tonic-gate ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 40463448Sdh155122 DROPPER(ipss, ipds_esp_nomem), 40473448Sdh155122 &espstack->esp_dropper); 40480Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 40490Sstevel@tonic-gate } 40500Sstevel@tonic-gate lastmp = lastmp->b_cont; 40510Sstevel@tonic-gate } 40520Sstevel@tonic-gate lastmp->b_wptr += icv_len; 40530Sstevel@tonic-gate } 40540Sstevel@tonic-gate 40550Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 40560Sstevel@tonic-gate } 40570Sstevel@tonic-gate 40580Sstevel@tonic-gate /* 40590Sstevel@tonic-gate * Process an inbound accelerated ESP packet. 40600Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 40610Sstevel@tonic-gate * mblk chain ipsec_in. 40620Sstevel@tonic-gate */ 40630Sstevel@tonic-gate static ipsec_status_t 40640Sstevel@tonic-gate esp_inbound_accelerated(mblk_t *ipsec_in, mblk_t *data_mp, boolean_t isv4, 40650Sstevel@tonic-gate ipsa_t *assoc) 40660Sstevel@tonic-gate { 40673448Sdh155122 ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr; 40680Sstevel@tonic-gate mblk_t *hada_mp; 40690Sstevel@tonic-gate uint32_t icv_len = 0; 40700Sstevel@tonic-gate da_ipsec_t *hada; 40710Sstevel@tonic-gate ipha_t *ipha; 40720Sstevel@tonic-gate ip6_t *ip6h; 40730Sstevel@tonic-gate kstat_named_t *counter; 40743448Sdh155122 netstack_t *ns = ii->ipsec_in_ns; 40753448Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 40763448Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 40773448Sdh155122 40783448Sdh155122 ESP_BUMP_STAT(espstack, in_accelerated); 40793448Sdh155122 40800Sstevel@tonic-gate hada_mp = ii->ipsec_in_da; 40810Sstevel@tonic-gate ASSERT(hada_mp != NULL); 40820Sstevel@tonic-gate hada = (da_ipsec_t *)hada_mp->b_rptr; 40830Sstevel@tonic-gate 40840Sstevel@tonic-gate /* 40850Sstevel@tonic-gate * We only support one level of decapsulation in hardware, so 40860Sstevel@tonic-gate * nuke the pointer. 40870Sstevel@tonic-gate */ 40880Sstevel@tonic-gate ii->ipsec_in_da = NULL; 40890Sstevel@tonic-gate ii->ipsec_in_accelerated = B_FALSE; 40900Sstevel@tonic-gate 40910Sstevel@tonic-gate if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) { 40920Sstevel@tonic-gate /* 40930Sstevel@tonic-gate * ESP with authentication. We expect the Provider to have 40940Sstevel@tonic-gate * computed the ICV and placed it in the hardware acceleration 40950Sstevel@tonic-gate * data attributes. 40960Sstevel@tonic-gate * 40970Sstevel@tonic-gate * Extract ICV length from attributes M_CTL and sanity check 40980Sstevel@tonic-gate * its value. We allow the mblk to be smaller than da_ipsec_t 40990Sstevel@tonic-gate * for a small ICV, as long as the entire ICV fits within the 41000Sstevel@tonic-gate * mblk. 41010Sstevel@tonic-gate * 41020Sstevel@tonic-gate * Also ensures that the ICV length computed by Provider 41030Sstevel@tonic-gate * corresponds to the ICV length of the agorithm specified by 41040Sstevel@tonic-gate * the SA. 41050Sstevel@tonic-gate */ 41060Sstevel@tonic-gate icv_len = hada->da_icv_len; 41070Sstevel@tonic-gate if ((icv_len != assoc->ipsa_mac_len) || 41080Sstevel@tonic-gate (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) < 41094987Sdanmcd (sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) { 41100Sstevel@tonic-gate esp0dbg(("esp_inbound_accelerated: " 41110Sstevel@tonic-gate "ICV len (%u) incorrect or mblk too small (%u)\n", 41120Sstevel@tonic-gate icv_len, (uint32_t)(MBLKL(hada_mp)))); 41133448Sdh155122 counter = DROPPER(ipss, ipds_esp_bad_auth); 41140Sstevel@tonic-gate goto esp_in_discard; 41150Sstevel@tonic-gate } 41160Sstevel@tonic-gate } 41170Sstevel@tonic-gate 41180Sstevel@tonic-gate /* get pointers to IP header */ 41190Sstevel@tonic-gate if (isv4) { 41200Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 41210Sstevel@tonic-gate } else { 41220Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 41230Sstevel@tonic-gate } 41240Sstevel@tonic-gate 41250Sstevel@tonic-gate /* 41260Sstevel@tonic-gate * Compare ICV in ESP packet vs ICV computed by adapter. 41270Sstevel@tonic-gate * We also remove the ICV from the end of the packet since 41280Sstevel@tonic-gate * it will no longer be needed. 41290Sstevel@tonic-gate * 41300Sstevel@tonic-gate * Assume that esp_inbound() already ensured that the pkt 41310Sstevel@tonic-gate * was in one mblk. 41320Sstevel@tonic-gate */ 41330Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 41340Sstevel@tonic-gate data_mp->b_wptr -= icv_len; 41350Sstevel@tonic-gate /* adjust IP header */ 41360Sstevel@tonic-gate if (isv4) 41370Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - icv_len); 41380Sstevel@tonic-gate else 41390Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - icv_len); 41400Sstevel@tonic-gate if (icv_len && bcmp(hada->da_icv, data_mp->b_wptr, icv_len)) { 41410Sstevel@tonic-gate int af; 41420Sstevel@tonic-gate void *addr; 41430Sstevel@tonic-gate 41440Sstevel@tonic-gate if (isv4) { 41450Sstevel@tonic-gate addr = &ipha->ipha_dst; 41460Sstevel@tonic-gate af = AF_INET; 41470Sstevel@tonic-gate } else { 41480Sstevel@tonic-gate addr = &ip6h->ip6_dst; 41490Sstevel@tonic-gate af = AF_INET6; 41500Sstevel@tonic-gate } 41510Sstevel@tonic-gate 41520Sstevel@tonic-gate /* 41530Sstevel@tonic-gate * Log the event. Don't print to the console, block 41540Sstevel@tonic-gate * potential denial-of-service attack. 41550Sstevel@tonic-gate */ 41563448Sdh155122 ESP_BUMP_STAT(espstack, bad_auth); 41570Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 41580Sstevel@tonic-gate "ESP Authentication failed spi %x, dst_addr %s", 41593448Sdh155122 assoc->ipsa_spi, addr, af, espstack->ipsecesp_netstack); 41603448Sdh155122 counter = DROPPER(ipss, ipds_esp_bad_auth); 41610Sstevel@tonic-gate goto esp_in_discard; 41620Sstevel@tonic-gate } 41630Sstevel@tonic-gate 41643448Sdh155122 esp3dbg(espstack, ("esp_inbound_accelerated: ESP authentication " 41654987Sdanmcd "succeeded, checking replay\n")); 41660Sstevel@tonic-gate 41670Sstevel@tonic-gate ipsec_in->b_cont = data_mp; 41680Sstevel@tonic-gate 41690Sstevel@tonic-gate /* 41700Sstevel@tonic-gate * Remove ESP header and padding from packet. 41710Sstevel@tonic-gate */ 41720Sstevel@tonic-gate if (!esp_strip_header(data_mp, ii->ipsec_in_v4, assoc->ipsa_iv_len, 41734987Sdanmcd &counter, espstack)) { 41743448Sdh155122 esp1dbg(espstack, ("esp_inbound_accelerated: " 41750Sstevel@tonic-gate "esp_strip_header() failed\n")); 41760Sstevel@tonic-gate goto esp_in_discard; 41770Sstevel@tonic-gate } 41780Sstevel@tonic-gate 41790Sstevel@tonic-gate freeb(hada_mp); 41800Sstevel@tonic-gate 41810Sstevel@tonic-gate /* 41820Sstevel@tonic-gate * Account for usage.. 41830Sstevel@tonic-gate */ 41840Sstevel@tonic-gate if (!esp_age_bytes(assoc, msgdsize(data_mp), B_TRUE)) { 41850Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 41863448Sdh155122 ESP_BUMP_STAT(espstack, bytes_expired); 41873448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 41880Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 41890Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 41903448Sdh155122 assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam, 41913448Sdh155122 espstack->ipsecesp_netstack); 41920Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 41933448Sdh155122 DROPPER(ipss, ipds_esp_bytes_expire), 41943448Sdh155122 &espstack->esp_dropper); 41950Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 41960Sstevel@tonic-gate } 41970Sstevel@tonic-gate 41980Sstevel@tonic-gate /* done processing the packet */ 41990Sstevel@tonic-gate return (IPSEC_STATUS_SUCCESS); 42000Sstevel@tonic-gate 42010Sstevel@tonic-gate esp_in_discard: 42023448Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 42030Sstevel@tonic-gate freeb(hada_mp); 42040Sstevel@tonic-gate 42050Sstevel@tonic-gate ipsec_in->b_cont = data_mp; /* For ip_drop_packet()'s sake... */ 42063448Sdh155122 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, 42073448Sdh155122 &espstack->esp_dropper); 42080Sstevel@tonic-gate 42090Sstevel@tonic-gate return (IPSEC_STATUS_FAILED); 42100Sstevel@tonic-gate } 42110Sstevel@tonic-gate 42120Sstevel@tonic-gate /* 42130Sstevel@tonic-gate * Wrapper to allow IP to trigger an ESP association failure message 42140Sstevel@tonic-gate * during inbound SA selection. 42150Sstevel@tonic-gate */ 42160Sstevel@tonic-gate void 42170Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt, 42183448Sdh155122 uint32_t spi, void *addr, int af, ipsecesp_stack_t *espstack) 42190Sstevel@tonic-gate { 42203448Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 42213448Sdh155122 42223448Sdh155122 if (espstack->ipsecesp_log_unknown_spi) { 42230Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi, 42243448Sdh155122 addr, af, espstack->ipsecesp_netstack); 42250Sstevel@tonic-gate } 42260Sstevel@tonic-gate 42273448Sdh155122 ip_drop_packet(mp, B_TRUE, NULL, NULL, 42283448Sdh155122 DROPPER(ipss, ipds_esp_no_sa), 42293448Sdh155122 &espstack->esp_dropper); 42300Sstevel@tonic-gate } 42310Sstevel@tonic-gate 42320Sstevel@tonic-gate /* 42330Sstevel@tonic-gate * Initialize the ESP input and output processing functions. 42340Sstevel@tonic-gate */ 42350Sstevel@tonic-gate void 42360Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa) 42370Sstevel@tonic-gate { 42380Sstevel@tonic-gate if (sa->ipsa_output_func == NULL) 42390Sstevel@tonic-gate sa->ipsa_output_func = esp_outbound; 42400Sstevel@tonic-gate if (sa->ipsa_input_func == NULL) 42410Sstevel@tonic-gate sa->ipsa_input_func = esp_inbound; 42420Sstevel@tonic-gate } 4243