17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51dc8613eSdanmcd * Common Development and Distribution License (the "License").
61dc8613eSdanmcd * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22b9c2bf66SDan McDonald * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <sys/param.h>
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/stream.h>
297c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
307c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
317c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
33f4b3ec61Sdh155122 #include <sys/zone.h>
347c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
367c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2
377c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
387c478bd9Sstevel@tonic-gate #include <sys/timod.h>
397c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
407c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
437c478bd9Sstevel@tonic-gate #include <sys/file.h>
447c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
457c478bd9Sstevel@tonic-gate #include <sys/debug.h>
467c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
487c478bd9Sstevel@tonic-gate #include <sys/proc.h>
497c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
507c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
517c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
527c478bd9Sstevel@tonic-gate #include <sys/policy.h>
53f4b3ec61Sdh155122 #include <sys/disp.h>
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate #include <sys/socket.h>
567c478bd9Sstevel@tonic-gate #include <netinet/in.h>
577c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #include <inet/common.h>
607c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
617c478bd9Sstevel@tonic-gate #include <inet/ip.h>
620f1702c5SYu Xiangning #include <inet/proto_set.h>
637c478bd9Sstevel@tonic-gate #include <inet/nd.h>
647c478bd9Sstevel@tonic-gate #include <inet/optcom.h>
657c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h>
667c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
677c478bd9Sstevel@tonic-gate #include <inet/keysock.h>
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate * This is a transport provider for the PF_KEY key mangement socket.
737c478bd9Sstevel@tonic-gate * (See RFC 2367 for details.)
747c478bd9Sstevel@tonic-gate * Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN
757c478bd9Sstevel@tonic-gate * messages (see ipsec_info.h), and passed to the appropriate consumer.
767c478bd9Sstevel@tonic-gate * Upstream messages are generated for all open PF_KEY sockets, when
777c478bd9Sstevel@tonic-gate * appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled)
787c478bd9Sstevel@tonic-gate * in reply to downstream messages.
797c478bd9Sstevel@tonic-gate *
807c478bd9Sstevel@tonic-gate * Upstream messages must be created asynchronously for the following
817c478bd9Sstevel@tonic-gate * situations:
827c478bd9Sstevel@tonic-gate *
837c478bd9Sstevel@tonic-gate * 1.) A keysock consumer requires an SA, and there is currently none.
847c478bd9Sstevel@tonic-gate * 2.) An SA expires, either hard or soft lifetime.
857c478bd9Sstevel@tonic-gate * 3.) Other events a consumer deems fit.
867c478bd9Sstevel@tonic-gate *
877c478bd9Sstevel@tonic-gate * The MT model of this is PERMOD, with shared put procedures. Two types of
887c478bd9Sstevel@tonic-gate * messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send
897c478bd9Sstevel@tonic-gate * down the *multiple* messages they create.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate static vmem_t *keysock_vmem; /* for minor numbers. */
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate #define KEYSOCK_MAX_CONSUMERS 256
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */
977c478bd9Sstevel@tonic-gate static struct T_info_ack keysock_g_t_info_ack = {
987c478bd9Sstevel@tonic-gate T_INFO_ACK,
997c478bd9Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */
1007c478bd9Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */
1017c478bd9Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */
1027c478bd9Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */
1037c478bd9Sstevel@tonic-gate 0, /* ADDR_size. */
1047c478bd9Sstevel@tonic-gate 0, /* OPT_size. No user-settable options */
1057c478bd9Sstevel@tonic-gate 64 * 1024, /* TIDU_size. keysock allows maximum size messages. */
1067c478bd9Sstevel@tonic-gate T_COTS, /* SERV_type. keysock supports connection oriented. */
1077c478bd9Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from keysock_state. */
1087c478bd9Sstevel@tonic-gate (XPG4_1) /* Provider flags */
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */
112f4b3ec61Sdh155122 typedef struct keysockparam_s {
1137c478bd9Sstevel@tonic-gate uint_t keysock_param_min;
1147c478bd9Sstevel@tonic-gate uint_t keysock_param_max;
1157c478bd9Sstevel@tonic-gate uint_t keysock_param_value;
1167c478bd9Sstevel@tonic-gate char *keysock_param_name;
1177c478bd9Sstevel@tonic-gate } keysockparam_t;
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate * Table of NDD variables supported by keysock. These are loaded into
1217c478bd9Sstevel@tonic-gate * keysock_g_nd in keysock_init_nd.
1227c478bd9Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time.
1237c478bd9Sstevel@tonic-gate */
124f4b3ec61Sdh155122 static keysockparam_t lcl_param_arr[] = {
1257c478bd9Sstevel@tonic-gate /* min max value name */
1267c478bd9Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_xmit_hiwat"},
1277c478bd9Sstevel@tonic-gate { 0, 65536, 1024, "keysock_xmit_lowat"},
1287c478bd9Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_recv_hiwat"},
1297c478bd9Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "keysock_max_buf"},
1307c478bd9Sstevel@tonic-gate { 0, 3, 0, "keysock_debug"},
1317c478bd9Sstevel@tonic-gate };
132f4b3ec61Sdh155122 #define keystack_xmit_hiwat keystack_params[0].keysock_param_value
133f4b3ec61Sdh155122 #define keystack_xmit_lowat keystack_params[1].keysock_param_value
134f4b3ec61Sdh155122 #define keystack_recv_hiwat keystack_params[2].keysock_param_value
135f4b3ec61Sdh155122 #define keystack_max_buf keystack_params[3].keysock_param_value
136f4b3ec61Sdh155122 #define keystack_debug keystack_params[4].keysock_param_value
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate #define ks0dbg(a) printf a
1397c478bd9Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */
140f4b3ec61Sdh155122 #define ks1dbg(keystack, a) if (keystack->keystack_debug != 0) printf a
141f4b3ec61Sdh155122 #define ks2dbg(keystack, a) if (keystack->keystack_debug > 1) printf a
142f4b3ec61Sdh155122 #define ks3dbg(keystack, a) if (keystack->keystack_debug > 2) printf a
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate static int keysock_close(queue_t *);
1457c478bd9Sstevel@tonic-gate static int keysock_open(queue_t *, dev_t *, int, int, cred_t *);
1467c478bd9Sstevel@tonic-gate static void keysock_wput(queue_t *, mblk_t *);
1477c478bd9Sstevel@tonic-gate static void keysock_rput(queue_t *, mblk_t *);
1487c478bd9Sstevel@tonic-gate static void keysock_rsrv(queue_t *);
1497c478bd9Sstevel@tonic-gate static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t,
150f4b3ec61Sdh155122 keysock_consumer_t *, boolean_t, keysock_stack_t *);
151f4b3ec61Sdh155122 static void *keysock_stack_init(netstackid_t stackid, netstack_t *ns);
152f4b3ec61Sdh155122 static void keysock_stack_fini(netstackid_t stackid, void *arg);
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate static struct module_info info = {
1557c478bd9Sstevel@tonic-gate 5138, "keysock", 1, INFPSZ, 512, 128
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate static struct qinit rinit = {
1597c478bd9Sstevel@tonic-gate (pfi_t)keysock_rput, (pfi_t)keysock_rsrv, keysock_open, keysock_close,
1607c478bd9Sstevel@tonic-gate NULL, &info
1617c478bd9Sstevel@tonic-gate };
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate static struct qinit winit = {
1647c478bd9Sstevel@tonic-gate (pfi_t)keysock_wput, NULL, NULL, NULL, NULL, &info
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate struct streamtab keysockinfo = {
1687c478bd9Sstevel@tonic-gate &rinit, &winit
1697c478bd9Sstevel@tonic-gate };
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate extern struct modlinkage *keysock_modlp;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * Plumb IPsec.
1757c478bd9Sstevel@tonic-gate *
1767c478bd9Sstevel@tonic-gate * NOTE: New "default" modules will need to be loaded here if needed before
1777c478bd9Sstevel@tonic-gate * boot time.
1787c478bd9Sstevel@tonic-gate */
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /* Keep these in global space to keep the lint from complaining. */
1817c478bd9Sstevel@tonic-gate static char *IPSECESP = "ipsecesp";
1827c478bd9Sstevel@tonic-gate static char *IPSECESPDEV = "/devices/pseudo/ipsecesp@0:ipsecesp";
1837c478bd9Sstevel@tonic-gate static char *IPSECAH = "ipsecah";
1847c478bd9Sstevel@tonic-gate static char *IPSECAHDEV = "/devices/pseudo/ipsecah@0:ipsecah";
1857c478bd9Sstevel@tonic-gate static char *IP6DEV = "/devices/pseudo/ip6@0:ip6";
1867c478bd9Sstevel@tonic-gate static char *KEYSOCK = "keysock";
1877c478bd9Sstevel@tonic-gate static char *STRMOD = "strmod";
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate * Load the other ipsec modules and plumb them together.
1917c478bd9Sstevel@tonic-gate */
1927c478bd9Sstevel@tonic-gate int
keysock_plumb_ipsec(netstack_t * ns)193f4b3ec61Sdh155122 keysock_plumb_ipsec(netstack_t *ns)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate ldi_handle_t lh, ip6_lh = NULL;
1967c478bd9Sstevel@tonic-gate ldi_ident_t li = NULL;
1977c478bd9Sstevel@tonic-gate int err = 0;
1987c478bd9Sstevel@tonic-gate int muxid, rval;
1997c478bd9Sstevel@tonic-gate boolean_t esp_present = B_TRUE;
200f4b3ec61Sdh155122 cred_t *cr;
201f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock;
2027c478bd9Sstevel@tonic-gate
203f4b3ec61Sdh155122 #ifdef NS_DEBUG
204f4b3ec61Sdh155122 (void) printf("keysock_plumb_ipsec(%d)\n",
205f4b3ec61Sdh155122 ns->netstack_stackid);
206f4b3ec61Sdh155122 #endif
2077c478bd9Sstevel@tonic-gate
208f4b3ec61Sdh155122 keystack->keystack_plumbed = 0; /* we're trying again.. */
2097c478bd9Sstevel@tonic-gate
210f4b3ec61Sdh155122 cr = zone_get_kcred(netstackid_to_zoneid(
211f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_stackid));
212f4b3ec61Sdh155122 ASSERT(cr != NULL);
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate * Load up the drivers (AH/ESP).
2157c478bd9Sstevel@tonic-gate *
2167c478bd9Sstevel@tonic-gate * I do this separately from the actual plumbing in case this function
2177c478bd9Sstevel@tonic-gate * ever gets called from a diskless boot before the root filesystem is
2187c478bd9Sstevel@tonic-gate * up. I don't have to worry about "keysock" because, well, if I'm
2197c478bd9Sstevel@tonic-gate * here, keysock must've loaded successfully.
2207c478bd9Sstevel@tonic-gate */
2217c478bd9Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECAH) == NULL) {
2227c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: AH failed to attach.\n"));
2237c478bd9Sstevel@tonic-gate goto bail;
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECESP) == NULL) {
2267c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: ESP failed to attach.\n"));
2277c478bd9Sstevel@tonic-gate esp_present = B_FALSE;
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate * Set up the IP streams for AH and ESP, as well as tacking keysock
2327c478bd9Sstevel@tonic-gate * on top of them. Assume keysock has set the autopushes up already.
2337c478bd9Sstevel@tonic-gate */
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /* Open IP. */
2367c478bd9Sstevel@tonic-gate err = ldi_ident_from_mod(keysock_modlp, &li);
2377c478bd9Sstevel@tonic-gate if (err) {
2387c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: lid_ident_from_mod failed (err %d).\n",
2397c478bd9Sstevel@tonic-gate err));
2407c478bd9Sstevel@tonic-gate goto bail;
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate
243f4b3ec61Sdh155122 err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, cr, &ip6_lh, li);
2447c478bd9Sstevel@tonic-gate if (err) {
2457c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of IP6 failed (err %d).\n", err));
2467c478bd9Sstevel@tonic-gate goto bail;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate /* PLINK KEYSOCK/AH */
250f4b3ec61Sdh155122 err = ldi_open_by_name(IPSECAHDEV, FREAD|FWRITE, cr, &lh, li);
2517c478bd9Sstevel@tonic-gate if (err) {
2527c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of AH failed (err %d).\n", err));
2537c478bd9Sstevel@tonic-gate goto bail;
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate err = ldi_ioctl(lh,
256f4b3ec61Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval);
2577c478bd9Sstevel@tonic-gate if (err) {
2587c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Push of KEYSOCK onto AH failed (err %d).\n",
2597c478bd9Sstevel@tonic-gate err));
260f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2617c478bd9Sstevel@tonic-gate goto bail;
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh,
264f4b3ec61Sdh155122 FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid);
2657c478bd9Sstevel@tonic-gate if (err) {
2667c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: PLINK of KEYSOCK/AH failed (err %d).\n", err));
267f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2687c478bd9Sstevel@tonic-gate goto bail;
2697c478bd9Sstevel@tonic-gate }
270f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /* PLINK KEYSOCK/ESP */
2737c478bd9Sstevel@tonic-gate if (esp_present) {
2747c478bd9Sstevel@tonic-gate err = ldi_open_by_name(IPSECESPDEV,
275f4b3ec61Sdh155122 FREAD|FWRITE, cr, &lh, li);
2767c478bd9Sstevel@tonic-gate if (err) {
2777c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of ESP failed (err %d).\n", err));
2787c478bd9Sstevel@tonic-gate goto bail;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate err = ldi_ioctl(lh,
281f4b3ec61Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval);
2827c478bd9Sstevel@tonic-gate if (err) {
2837c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: "
2847c478bd9Sstevel@tonic-gate "Push of KEYSOCK onto ESP failed (err %d).\n",
2857c478bd9Sstevel@tonic-gate err));
286f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2877c478bd9Sstevel@tonic-gate goto bail;
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh,
290f4b3ec61Sdh155122 FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid);
2917c478bd9Sstevel@tonic-gate if (err) {
2927c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: "
2937c478bd9Sstevel@tonic-gate "PLINK of KEYSOCK/ESP failed (err %d).\n", err));
294f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2957c478bd9Sstevel@tonic-gate goto bail;
2967c478bd9Sstevel@tonic-gate }
297f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate bail:
301f4b3ec61Sdh155122 keystack->keystack_plumbed = (err == 0) ? 1 : -1;
3027c478bd9Sstevel@tonic-gate if (ip6_lh != NULL) {
303f4b3ec61Sdh155122 (void) ldi_close(ip6_lh, FREAD|FWRITE, cr);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate if (li != NULL)
3067c478bd9Sstevel@tonic-gate ldi_ident_release(li);
307f4b3ec61Sdh155122 #ifdef NS_DEBUG
308f4b3ec61Sdh155122 (void) printf("keysock_plumb_ipsec -> %d\n",
309f4b3ec61Sdh155122 keystack->keystack_plumbed);
310f4b3ec61Sdh155122 #endif
311f4b3ec61Sdh155122 crfree(cr);
3127c478bd9Sstevel@tonic-gate return (err);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate /* ARGSUSED */
3167c478bd9Sstevel@tonic-gate static int
keysock_param_get(q,mp,cp,cr)3177c478bd9Sstevel@tonic-gate keysock_param_get(q, mp, cp, cr)
3187c478bd9Sstevel@tonic-gate queue_t *q;
3197c478bd9Sstevel@tonic-gate mblk_t *mp;
3207c478bd9Sstevel@tonic-gate caddr_t cp;
3217c478bd9Sstevel@tonic-gate cred_t *cr;
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp;
3247c478bd9Sstevel@tonic-gate uint_t value;
325f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr;
326f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
3277c478bd9Sstevel@tonic-gate
328f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_param_lock);
3297c478bd9Sstevel@tonic-gate value = keysockpa->keysock_param_value;
330f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock);
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value);
3337c478bd9Sstevel@tonic-gate return (0);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate /* This routine sets an NDD variable in a keysockparam_t structure. */
3377c478bd9Sstevel@tonic-gate /* ARGSUSED */
3387c478bd9Sstevel@tonic-gate static int
keysock_param_set(q,mp,value,cp,cr)3397c478bd9Sstevel@tonic-gate keysock_param_set(q, mp, value, cp, cr)
3407c478bd9Sstevel@tonic-gate queue_t *q;
3417c478bd9Sstevel@tonic-gate mblk_t *mp;
3427c478bd9Sstevel@tonic-gate char *value;
3437c478bd9Sstevel@tonic-gate caddr_t cp;
3447c478bd9Sstevel@tonic-gate cred_t *cr;
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate ulong_t new_value;
3477c478bd9Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp;
348f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr;
349f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate /* Convert the value from a string into a long integer. */
3527c478bd9Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0)
3537c478bd9Sstevel@tonic-gate return (EINVAL);
3547c478bd9Sstevel@tonic-gate
355f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_param_lock);
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the
3587c478bd9Sstevel@tonic-gate * required bounds.
3597c478bd9Sstevel@tonic-gate */
3607c478bd9Sstevel@tonic-gate if (new_value < keysockpa->keysock_param_min ||
3617c478bd9Sstevel@tonic-gate new_value > keysockpa->keysock_param_max) {
362f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock);
3637c478bd9Sstevel@tonic-gate return (EINVAL);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate /* Set the new value */
3677c478bd9Sstevel@tonic-gate keysockpa->keysock_param_value = new_value;
368f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock);
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate return (0);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate /*
374f4b3ec61Sdh155122 * Initialize keysock at module load time
3757c478bd9Sstevel@tonic-gate */
3767c478bd9Sstevel@tonic-gate boolean_t
keysock_ddi_init(void)3777c478bd9Sstevel@tonic-gate keysock_ddi_init(void)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate keysock_max_optsize = optcom_max_optsize(
3807c478bd9Sstevel@tonic-gate keysock_opt_obj.odb_opt_des_arr, keysock_opt_obj.odb_opt_arr_cnt);
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate keysock_vmem = vmem_create("keysock", (void *)1, MAXMIN, 1,
3837c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
3847c478bd9Sstevel@tonic-gate
385f4b3ec61Sdh155122 /*
386f4b3ec61Sdh155122 * We want to be informed each time a stack is created or
387f4b3ec61Sdh155122 * destroyed in the kernel, so we can maintain the
388f4b3ec61Sdh155122 * set of keysock_stack_t's.
389f4b3ec61Sdh155122 */
390f4b3ec61Sdh155122 netstack_register(NS_KEYSOCK, keysock_stack_init, NULL,
391f4b3ec61Sdh155122 keysock_stack_fini);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate return (B_TRUE);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /*
397f4b3ec61Sdh155122 * Walk through the param array specified registering each element with the
398f4b3ec61Sdh155122 * named dispatch handler.
399f4b3ec61Sdh155122 */
400f4b3ec61Sdh155122 static boolean_t
keysock_param_register(IDP * ndp,keysockparam_t * ksp,int cnt)401f4b3ec61Sdh155122 keysock_param_register(IDP *ndp, keysockparam_t *ksp, int cnt)
402f4b3ec61Sdh155122 {
403f4b3ec61Sdh155122 for (; cnt-- > 0; ksp++) {
404f4b3ec61Sdh155122 if (ksp->keysock_param_name != NULL &&
405f4b3ec61Sdh155122 ksp->keysock_param_name[0]) {
406f4b3ec61Sdh155122 if (!nd_load(ndp,
407f4b3ec61Sdh155122 ksp->keysock_param_name,
408f4b3ec61Sdh155122 keysock_param_get, keysock_param_set,
409f4b3ec61Sdh155122 (caddr_t)ksp)) {
410f4b3ec61Sdh155122 nd_free(ndp);
411f4b3ec61Sdh155122 return (B_FALSE);
412f4b3ec61Sdh155122 }
413f4b3ec61Sdh155122 }
414f4b3ec61Sdh155122 }
415f4b3ec61Sdh155122 return (B_TRUE);
416f4b3ec61Sdh155122 }
417f4b3ec61Sdh155122
418f4b3ec61Sdh155122 /*
419f4b3ec61Sdh155122 * Initialize keysock for one stack instance
420f4b3ec61Sdh155122 */
421f4b3ec61Sdh155122 /* ARGSUSED */
422f4b3ec61Sdh155122 static void *
keysock_stack_init(netstackid_t stackid,netstack_t * ns)423f4b3ec61Sdh155122 keysock_stack_init(netstackid_t stackid, netstack_t *ns)
424f4b3ec61Sdh155122 {
425f4b3ec61Sdh155122 keysock_stack_t *keystack;
426f4b3ec61Sdh155122 keysockparam_t *ksp;
427f4b3ec61Sdh155122
428f4b3ec61Sdh155122 keystack = (keysock_stack_t *)kmem_zalloc(sizeof (*keystack), KM_SLEEP);
429f4b3ec61Sdh155122 keystack->keystack_netstack = ns;
430f4b3ec61Sdh155122
431f4b3ec61Sdh155122 keystack->keystack_acquire_seq = 0xffffffff;
432f4b3ec61Sdh155122
433f4b3ec61Sdh155122 ksp = (keysockparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
434f4b3ec61Sdh155122 keystack->keystack_params = ksp;
435f4b3ec61Sdh155122 bcopy(lcl_param_arr, ksp, sizeof (lcl_param_arr));
436f4b3ec61Sdh155122
437f4b3ec61Sdh155122 (void) keysock_param_register(&keystack->keystack_g_nd, ksp,
438f4b3ec61Sdh155122 A_CNT(lcl_param_arr));
439f4b3ec61Sdh155122
440f4b3ec61Sdh155122 mutex_init(&keystack->keystack_list_lock, NULL, MUTEX_DEFAULT, NULL);
441f4b3ec61Sdh155122 mutex_init(&keystack->keystack_consumers_lock,
442f4b3ec61Sdh155122 NULL, MUTEX_DEFAULT, NULL);
443f4b3ec61Sdh155122 mutex_init(&keystack->keystack_param_lock, NULL, MUTEX_DEFAULT, NULL);
444f4b3ec61Sdh155122 return (keystack);
445f4b3ec61Sdh155122 }
446f4b3ec61Sdh155122
447f4b3ec61Sdh155122 /*
4487c478bd9Sstevel@tonic-gate * Free NDD variable space, and other destructors, for keysock.
4497c478bd9Sstevel@tonic-gate */
4507c478bd9Sstevel@tonic-gate void
keysock_ddi_destroy(void)4517c478bd9Sstevel@tonic-gate keysock_ddi_destroy(void)
4527c478bd9Sstevel@tonic-gate {
453f4b3ec61Sdh155122 netstack_unregister(NS_KEYSOCK);
4547c478bd9Sstevel@tonic-gate vmem_destroy(keysock_vmem);
455f4b3ec61Sdh155122 }
456f4b3ec61Sdh155122
457f4b3ec61Sdh155122 /*
458f4b3ec61Sdh155122 * Remove one stack instance from keysock
459f4b3ec61Sdh155122 */
460f4b3ec61Sdh155122 /* ARGSUSED */
461f4b3ec61Sdh155122 static void
keysock_stack_fini(netstackid_t stackid,void * arg)462f4b3ec61Sdh155122 keysock_stack_fini(netstackid_t stackid, void *arg)
463f4b3ec61Sdh155122 {
464f4b3ec61Sdh155122 keysock_stack_t *keystack = (keysock_stack_t *)arg;
465f4b3ec61Sdh155122
466f4b3ec61Sdh155122 nd_free(&keystack->keystack_g_nd);
467f4b3ec61Sdh155122 kmem_free(keystack->keystack_params, sizeof (lcl_param_arr));
468f4b3ec61Sdh155122 keystack->keystack_params = NULL;
469f4b3ec61Sdh155122
470f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_list_lock);
471f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_consumers_lock);
472f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_param_lock);
473f4b3ec61Sdh155122
474f4b3ec61Sdh155122 kmem_free(keystack, sizeof (*keystack));
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate * Close routine for keysock.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate static int
keysock_close(queue_t * q)4817c478bd9Sstevel@tonic-gate keysock_close(queue_t *q)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate keysock_t *ks;
4847c478bd9Sstevel@tonic-gate keysock_consumer_t *kc;
4857c478bd9Sstevel@tonic-gate void *ptr = q->q_ptr;
4867c478bd9Sstevel@tonic-gate int size;
487f4b3ec61Sdh155122 keysock_stack_t *keystack;
488f4b3ec61Sdh155122
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate qprocsoff(q);
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /* Safe assumption. */
4937c478bd9Sstevel@tonic-gate ASSERT(ptr != NULL);
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate if (WR(q)->q_next) {
4967c478bd9Sstevel@tonic-gate kc = (keysock_consumer_t *)ptr;
497f4b3ec61Sdh155122 keystack = kc->kc_keystack;
498f4b3ec61Sdh155122
499f4b3ec61Sdh155122 ks1dbg(keystack, ("Module close, removing a consumer (%d).\n",
5007c478bd9Sstevel@tonic-gate kc->kc_sa_type));
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate * Because of PERMOD open/close exclusive perimeter, I
5037c478bd9Sstevel@tonic-gate * can inspect KC_FLUSHING w/o locking down kc->kc_lock.
5047c478bd9Sstevel@tonic-gate */
5057c478bd9Sstevel@tonic-gate if (kc->kc_flags & KC_FLUSHING) {
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate * If this decrement was the last one, send
5087c478bd9Sstevel@tonic-gate * down the next pending one, if any.
5097c478bd9Sstevel@tonic-gate *
5107c478bd9Sstevel@tonic-gate * With a PERMOD perimeter, the mutexes ops aren't
5117c478bd9Sstevel@tonic-gate * really necessary, but if we ever loosen up, we will
5127c478bd9Sstevel@tonic-gate * have this bit covered already.
5137c478bd9Sstevel@tonic-gate */
514f4b3ec61Sdh155122 keystack->keystack_flushdump--;
515f4b3ec61Sdh155122 if (keystack->keystack_flushdump == 0) {
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate * The flush/dump terminated by having a
5187c478bd9Sstevel@tonic-gate * consumer go away. I need to send up to the
5197c478bd9Sstevel@tonic-gate * appropriate keysock all of the relevant
5207c478bd9Sstevel@tonic-gate * information. Unfortunately, I don't
5217c478bd9Sstevel@tonic-gate * have that handy.
5227c478bd9Sstevel@tonic-gate */
5237c478bd9Sstevel@tonic-gate ks0dbg(("Consumer went away while flushing or"
5247c478bd9Sstevel@tonic-gate " dumping.\n"));
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate size = sizeof (keysock_consumer_t);
528f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock);
529f4b3ec61Sdh155122 keystack->keystack_consumers[kc->kc_sa_type] = NULL;
530f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock);
5317c478bd9Sstevel@tonic-gate mutex_destroy(&kc->kc_lock);
532f4b3ec61Sdh155122 netstack_rele(kc->kc_keystack->keystack_netstack);
5337c478bd9Sstevel@tonic-gate } else {
5347c478bd9Sstevel@tonic-gate ks = (keysock_t *)ptr;
535f4b3ec61Sdh155122 keystack = ks->keysock_keystack;
536f4b3ec61Sdh155122
537f4b3ec61Sdh155122 ks3dbg(keystack,
538f4b3ec61Sdh155122 ("Driver close, PF_KEY socket is going away.\n"));
5397c478bd9Sstevel@tonic-gate if ((ks->keysock_flags & KEYSOCK_EXTENDED) != 0)
540*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&keystack->keystack_num_extended);
5417c478bd9Sstevel@tonic-gate size = sizeof (keysock_t);
542f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock);
5437c478bd9Sstevel@tonic-gate *(ks->keysock_ptpn) = ks->keysock_next;
5447c478bd9Sstevel@tonic-gate if (ks->keysock_next != NULL)
5457c478bd9Sstevel@tonic-gate ks->keysock_next->keysock_ptpn = ks->keysock_ptpn;
546f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock);
5477c478bd9Sstevel@tonic-gate mutex_destroy(&ks->keysock_lock);
5481dc8613eSdanmcd vmem_free(keysock_vmem, (void *)(uintptr_t)ks->keysock_serial,
5491dc8613eSdanmcd 1);
550f4b3ec61Sdh155122 netstack_rele(ks->keysock_keystack->keystack_netstack);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /* Now I'm free. */
5547c478bd9Sstevel@tonic-gate kmem_free(ptr, size);
5557c478bd9Sstevel@tonic-gate return (0);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate * Open routine for keysock.
5597c478bd9Sstevel@tonic-gate */
5607c478bd9Sstevel@tonic-gate /* ARGSUSED */
5617c478bd9Sstevel@tonic-gate static int
keysock_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)5627c478bd9Sstevel@tonic-gate keysock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate keysock_t *ks;
5657c478bd9Sstevel@tonic-gate keysock_consumer_t *kc;
5667c478bd9Sstevel@tonic-gate mblk_t *mp;
5677c478bd9Sstevel@tonic-gate ipsec_info_t *ii;
568f4b3ec61Sdh155122 netstack_t *ns;
569f4b3ec61Sdh155122 keysock_stack_t *keystack;
5707c478bd9Sstevel@tonic-gate
571f4b3ec61Sdh155122 if (secpolicy_ip_config(credp, B_FALSE) != 0) {
5727c478bd9Sstevel@tonic-gate /* Privilege debugging will log the error */
5737c478bd9Sstevel@tonic-gate return (EPERM);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL)
5777c478bd9Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */
5787c478bd9Sstevel@tonic-gate
579f4b3ec61Sdh155122 ns = netstack_find_by_cred(credp);
580f4b3ec61Sdh155122 ASSERT(ns != NULL);
581f4b3ec61Sdh155122 keystack = ns->netstack_keysock;
582f4b3ec61Sdh155122 ASSERT(keystack != NULL);
583f4b3ec61Sdh155122
584f4b3ec61Sdh155122 ks3dbg(keystack, ("Entering keysock open.\n"));
585f4b3ec61Sdh155122
586f4b3ec61Sdh155122 if (keystack->keystack_plumbed < 1) {
587f4b3ec61Sdh155122 netstack_t *ns = keystack->keystack_netstack;
588f4b3ec61Sdh155122
589f4b3ec61Sdh155122 keystack->keystack_plumbed = 0;
590f4b3ec61Sdh155122 #ifdef NS_DEBUG
591f4b3ec61Sdh155122 printf("keysock_open(%d) - plumb\n",
592f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_stackid);
593f4b3ec61Sdh155122 #endif
5947c478bd9Sstevel@tonic-gate /*
5957c478bd9Sstevel@tonic-gate * Don't worry about ipsec_failure being true here.
5967c478bd9Sstevel@tonic-gate * (See ip.c). An open of keysock should try and force
5977c478bd9Sstevel@tonic-gate * the issue. Maybe it was a transient failure.
5987c478bd9Sstevel@tonic-gate */
599f4b3ec61Sdh155122 ipsec_loader_loadnow(ns->netstack_ipsec);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate if (sflag & MODOPEN) {
6037c478bd9Sstevel@tonic-gate /* Initialize keysock_consumer state here. */
6047c478bd9Sstevel@tonic-gate kc = kmem_zalloc(sizeof (keysock_consumer_t), KM_NOSLEEP);
605f4b3ec61Sdh155122 if (kc == NULL) {
606f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack);
6077c478bd9Sstevel@tonic-gate return (ENOMEM);
608f4b3ec61Sdh155122 }
6097c478bd9Sstevel@tonic-gate mutex_init(&kc->kc_lock, NULL, MUTEX_DEFAULT, 0);
6107c478bd9Sstevel@tonic-gate kc->kc_rq = q;
6117c478bd9Sstevel@tonic-gate kc->kc_wq = WR(q);
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate q->q_ptr = kc;
6147c478bd9Sstevel@tonic-gate WR(q)->q_ptr = kc;
6157c478bd9Sstevel@tonic-gate
616f4b3ec61Sdh155122 kc->kc_keystack = keystack;
6177c478bd9Sstevel@tonic-gate qprocson(q);
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate * Send down initial message to whatever I was pushed on top
6217c478bd9Sstevel@tonic-gate * of asking for its consumer type. The reply will set it.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /* Allocate it. */
6257c478bd9Sstevel@tonic-gate mp = allocb(sizeof (ipsec_info_t), BPRI_HI);
6267c478bd9Sstevel@tonic-gate if (mp == NULL) {
627f4b3ec61Sdh155122 ks1dbg(keystack, (
6287c478bd9Sstevel@tonic-gate "keysock_open: Cannot allocate KEYSOCK_HELLO.\n"));
6297c478bd9Sstevel@tonic-gate /* Do I need to set these to null? */
6307c478bd9Sstevel@tonic-gate q->q_ptr = NULL;
6317c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL;
6327c478bd9Sstevel@tonic-gate mutex_destroy(&kc->kc_lock);
6337c478bd9Sstevel@tonic-gate kmem_free(kc, sizeof (*kc));
634f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack);
6357c478bd9Sstevel@tonic-gate return (ENOMEM);
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate /* If I allocated okay, putnext to what I was pushed atop. */
6397c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (ipsec_info_t);
6407c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_CTL;
6417c478bd9Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr;
6427c478bd9Sstevel@tonic-gate ii->ipsec_info_type = KEYSOCK_HELLO;
6437c478bd9Sstevel@tonic-gate /* Length only of type/len. */
6447c478bd9Sstevel@tonic-gate ii->ipsec_info_len = sizeof (ii->ipsec_allu);
645f4b3ec61Sdh155122 ks2dbg(keystack, ("Ready to putnext KEYSOCK_HELLO.\n"));
6467c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, mp);
6477c478bd9Sstevel@tonic-gate } else {
6487c478bd9Sstevel@tonic-gate minor_t ksminor;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate /* Initialize keysock state. */
6517c478bd9Sstevel@tonic-gate
652f4b3ec61Sdh155122 ks2dbg(keystack, ("Made it into PF_KEY socket open.\n"));
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate ksminor = (minor_t)(uintptr_t)
6557c478bd9Sstevel@tonic-gate vmem_alloc(keysock_vmem, 1, VM_NOSLEEP);
656f4b3ec61Sdh155122 if (ksminor == 0) {
657f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack);
6587c478bd9Sstevel@tonic-gate return (ENOMEM);
659f4b3ec61Sdh155122 }
6607c478bd9Sstevel@tonic-gate ks = kmem_zalloc(sizeof (keysock_t), KM_NOSLEEP);
6617c478bd9Sstevel@tonic-gate if (ks == NULL) {
6627c478bd9Sstevel@tonic-gate vmem_free(keysock_vmem, (void *)(uintptr_t)ksminor, 1);
663f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack);
6647c478bd9Sstevel@tonic-gate return (ENOMEM);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate mutex_init(&ks->keysock_lock, NULL, MUTEX_DEFAULT, 0);
6687c478bd9Sstevel@tonic-gate ks->keysock_rq = q;
6697c478bd9Sstevel@tonic-gate ks->keysock_wq = WR(q);
6707c478bd9Sstevel@tonic-gate ks->keysock_state = TS_UNBND;
6717c478bd9Sstevel@tonic-gate ks->keysock_serial = ksminor;
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate q->q_ptr = ks;
6747c478bd9Sstevel@tonic-gate WR(q)->q_ptr = ks;
675f4b3ec61Sdh155122 ks->keysock_keystack = keystack;
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate * The receive hiwat is only looked at on the stream head
6797c478bd9Sstevel@tonic-gate * queue. Store in q_hiwat in order to return on SO_RCVBUF
6807c478bd9Sstevel@tonic-gate * getsockopts.
6817c478bd9Sstevel@tonic-gate */
6827c478bd9Sstevel@tonic-gate
683f4b3ec61Sdh155122 q->q_hiwat = keystack->keystack_recv_hiwat;
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate * The transmit hiwat/lowat is only looked at on IP's queue.
6877c478bd9Sstevel@tonic-gate * Store in q_hiwat/q_lowat in order to return on
6887c478bd9Sstevel@tonic-gate * SO_SNDBUF/SO_SNDLOWAT getsockopts.
6897c478bd9Sstevel@tonic-gate */
6907c478bd9Sstevel@tonic-gate
691f4b3ec61Sdh155122 WR(q)->q_hiwat = keystack->keystack_xmit_hiwat;
692f4b3ec61Sdh155122 WR(q)->q_lowat = keystack->keystack_xmit_lowat;
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), ksminor);
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate * Thread keysock into the global keysock list.
6987c478bd9Sstevel@tonic-gate */
699f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock);
700f4b3ec61Sdh155122 ks->keysock_next = keystack->keystack_list;
701f4b3ec61Sdh155122 ks->keysock_ptpn = &keystack->keystack_list;
702f4b3ec61Sdh155122 if (keystack->keystack_list != NULL) {
703f4b3ec61Sdh155122 keystack->keystack_list->keysock_ptpn =
704f4b3ec61Sdh155122 &ks->keysock_next;
705f4b3ec61Sdh155122 }
706f4b3ec61Sdh155122 keystack->keystack_list = ks;
707f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock);
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate qprocson(q);
7100f1702c5SYu Xiangning (void) proto_set_rx_hiwat(q, NULL,
7110f1702c5SYu Xiangning keystack->keystack_recv_hiwat);
7127c478bd9Sstevel@tonic-gate /*
7137c478bd9Sstevel@tonic-gate * Wait outside the keysock module perimeter for IPsec
7147c478bd9Sstevel@tonic-gate * plumbing to be completed. If it fails, keysock_close()
7157c478bd9Sstevel@tonic-gate * undoes everything we just did.
7167c478bd9Sstevel@tonic-gate */
717f4b3ec61Sdh155122 if (!ipsec_loader_wait(q,
718f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_ipsec)) {
7197c478bd9Sstevel@tonic-gate (void) keysock_close(q);
7207c478bd9Sstevel@tonic-gate return (EPFNOSUPPORT);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate return (0);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate * Copy relevant state bits.
7317c478bd9Sstevel@tonic-gate */
7327c478bd9Sstevel@tonic-gate static void
keysock_copy_info(struct T_info_ack * tap,keysock_t * ks)7337c478bd9Sstevel@tonic-gate keysock_copy_info(struct T_info_ack *tap, keysock_t *ks)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate *tap = keysock_g_t_info_ack;
7367c478bd9Sstevel@tonic-gate tap->CURRENT_state = ks->keysock_state;
7377c478bd9Sstevel@tonic-gate tap->OPT_size = keysock_max_optsize;
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by
7427c478bd9Sstevel@tonic-gate * keysock_wput. Much of the T_CAPABILITY_ACK information is copied from
7437c478bd9Sstevel@tonic-gate * keysock_g_t_info_ack. The current state of the stream is copied from
7447c478bd9Sstevel@tonic-gate * keysock_state.
7457c478bd9Sstevel@tonic-gate */
7467c478bd9Sstevel@tonic-gate static void
keysock_capability_req(queue_t * q,mblk_t * mp)7477c478bd9Sstevel@tonic-gate keysock_capability_req(queue_t *q, mblk_t *mp)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr;
7507c478bd9Sstevel@tonic-gate t_uscalar_t cap_bits1;
7517c478bd9Sstevel@tonic-gate struct T_capability_ack *tcap;
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
7567c478bd9Sstevel@tonic-gate mp->b_datap->db_type, T_CAPABILITY_ACK);
7577c478bd9Sstevel@tonic-gate if (mp == NULL)
7587c478bd9Sstevel@tonic-gate return;
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr;
7617c478bd9Sstevel@tonic-gate tcap->CAP_bits1 = 0;
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) {
7647c478bd9Sstevel@tonic-gate keysock_copy_info(&tcap->INFO_ack, ks);
7657c478bd9Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO;
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate qreply(q, mp);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by
7737c478bd9Sstevel@tonic-gate * keysock_wput_other.
7747c478bd9Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack.
7757c478bd9Sstevel@tonic-gate * The current state of the stream is copied from keysock_state.
7767c478bd9Sstevel@tonic-gate */
7777c478bd9Sstevel@tonic-gate static void
keysock_info_req(q,mp)7787c478bd9Sstevel@tonic-gate keysock_info_req(q, mp)
7797c478bd9Sstevel@tonic-gate queue_t *q;
7807c478bd9Sstevel@tonic-gate mblk_t *mp;
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
7837c478bd9Sstevel@tonic-gate T_INFO_ACK);
7847c478bd9Sstevel@tonic-gate if (mp == NULL)
7857c478bd9Sstevel@tonic-gate return;
7867c478bd9Sstevel@tonic-gate keysock_copy_info((struct T_info_ack *)mp->b_rptr,
7877c478bd9Sstevel@tonic-gate (keysock_t *)q->q_ptr);
7887c478bd9Sstevel@tonic-gate qreply(q, mp);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate * keysock_err_ack. This routine creates a
7937c478bd9Sstevel@tonic-gate * T_ERROR_ACK message and passes it
7947c478bd9Sstevel@tonic-gate * upstream.
7957c478bd9Sstevel@tonic-gate */
7967c478bd9Sstevel@tonic-gate static void
keysock_err_ack(q,mp,t_error,sys_error)7977c478bd9Sstevel@tonic-gate keysock_err_ack(q, mp, t_error, sys_error)
7987c478bd9Sstevel@tonic-gate queue_t *q;
7997c478bd9Sstevel@tonic-gate mblk_t *mp;
8007c478bd9Sstevel@tonic-gate int t_error;
8017c478bd9Sstevel@tonic-gate int sys_error;
8027c478bd9Sstevel@tonic-gate {
8037c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
8047c478bd9Sstevel@tonic-gate qreply(q, mp);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate * This routine retrieves the current status of socket options.
8097c478bd9Sstevel@tonic-gate * It returns the size of the option retrieved.
8107c478bd9Sstevel@tonic-gate */
8117c478bd9Sstevel@tonic-gate /* ARGSUSED */
8127c478bd9Sstevel@tonic-gate int
keysock_opt_get(queue_t * q,int level,int name,uchar_t * ptr)8137c478bd9Sstevel@tonic-gate keysock_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate int *i1 = (int *)ptr;
8167c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate switch (level) {
8197c478bd9Sstevel@tonic-gate case SOL_SOCKET:
8207c478bd9Sstevel@tonic-gate mutex_enter(&ks->keysock_lock);
8217c478bd9Sstevel@tonic-gate switch (name) {
8227c478bd9Sstevel@tonic-gate case SO_TYPE:
8237c478bd9Sstevel@tonic-gate *i1 = SOCK_RAW;
8247c478bd9Sstevel@tonic-gate break;
8257c478bd9Sstevel@tonic-gate case SO_USELOOPBACK:
8267c478bd9Sstevel@tonic-gate *i1 = (int)(!((ks->keysock_flags & KEYSOCK_NOLOOP) ==
8277c478bd9Sstevel@tonic-gate KEYSOCK_NOLOOP));
8287c478bd9Sstevel@tonic-gate break;
8297c478bd9Sstevel@tonic-gate /*
8307c478bd9Sstevel@tonic-gate * The following two items can be manipulated,
8317c478bd9Sstevel@tonic-gate * but changing them should do nothing.
8327c478bd9Sstevel@tonic-gate */
8337c478bd9Sstevel@tonic-gate case SO_SNDBUF:
8347c478bd9Sstevel@tonic-gate *i1 = (int)q->q_hiwat;
8357c478bd9Sstevel@tonic-gate break;
8367c478bd9Sstevel@tonic-gate case SO_RCVBUF:
8377c478bd9Sstevel@tonic-gate *i1 = (int)(RD(q)->q_hiwat);
8387c478bd9Sstevel@tonic-gate break;
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate mutex_exit(&ks->keysock_lock);
8417c478bd9Sstevel@tonic-gate break;
8427c478bd9Sstevel@tonic-gate default:
8437c478bd9Sstevel@tonic-gate return (0);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate return (sizeof (int));
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate /*
8497c478bd9Sstevel@tonic-gate * This routine sets socket options.
8507c478bd9Sstevel@tonic-gate */
8517c478bd9Sstevel@tonic-gate /* ARGSUSED */
8527c478bd9Sstevel@tonic-gate int
keysock_opt_set(queue_t * q,uint_t mgmt_flags,int level,int name,uint_t inlen,uchar_t * invalp,uint_t * outlenp,uchar_t * outvalp,void * thisdg_attrs,cred_t * cr)8537c478bd9Sstevel@tonic-gate keysock_opt_set(queue_t *q, uint_t mgmt_flags, int level,
8547c478bd9Sstevel@tonic-gate int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
855bd670b35SErik Nordmark uchar_t *outvalp, void *thisdg_attrs, cred_t *cr)
8567c478bd9Sstevel@tonic-gate {
857b9c2bf66SDan McDonald int *i1 = (int *)invalp, errno = 0;
8587c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr;
859f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate switch (level) {
8627c478bd9Sstevel@tonic-gate case SOL_SOCKET:
8637c478bd9Sstevel@tonic-gate mutex_enter(&ks->keysock_lock);
8647c478bd9Sstevel@tonic-gate switch (name) {
8657c478bd9Sstevel@tonic-gate case SO_USELOOPBACK:
8667c478bd9Sstevel@tonic-gate if (!(*i1))
8677c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_NOLOOP;
8687c478bd9Sstevel@tonic-gate else ks->keysock_flags &= ~KEYSOCK_NOLOOP;
8697c478bd9Sstevel@tonic-gate break;
8707c478bd9Sstevel@tonic-gate case SO_SNDBUF:
871f4b3ec61Sdh155122 if (*i1 > keystack->keystack_max_buf)
872b9c2bf66SDan McDonald errno = ENOBUFS;
873b9c2bf66SDan McDonald else q->q_hiwat = *i1;
8747c478bd9Sstevel@tonic-gate break;
8757c478bd9Sstevel@tonic-gate case SO_RCVBUF:
876b9c2bf66SDan McDonald if (*i1 > keystack->keystack_max_buf) {
877b9c2bf66SDan McDonald errno = ENOBUFS;
878b9c2bf66SDan McDonald } else {
8797c478bd9Sstevel@tonic-gate RD(q)->q_hiwat = *i1;
8800f1702c5SYu Xiangning (void) proto_set_rx_hiwat(RD(q), NULL, *i1);
881b9c2bf66SDan McDonald }
8827c478bd9Sstevel@tonic-gate break;
883b9c2bf66SDan McDonald default:
884b9c2bf66SDan McDonald errno = EINVAL;
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate mutex_exit(&ks->keysock_lock);
8877c478bd9Sstevel@tonic-gate break;
888b9c2bf66SDan McDonald default:
889b9c2bf66SDan McDonald errno = EINVAL;
8907c478bd9Sstevel@tonic-gate }
891b9c2bf66SDan McDonald return (errno);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate * Handle STREAMS messages.
8967c478bd9Sstevel@tonic-gate */
8977c478bd9Sstevel@tonic-gate static void
keysock_wput_other(queue_t * q,mblk_t * mp)8987c478bd9Sstevel@tonic-gate keysock_wput_other(queue_t *q, mblk_t *mp)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate struct iocblk *iocp;
9017c478bd9Sstevel@tonic-gate int error;
902f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr;
903f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
904f4b3ec61Sdh155122 cred_t *cr;
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
9077c478bd9Sstevel@tonic-gate case M_PROTO:
9087c478bd9Sstevel@tonic-gate case M_PCPROTO:
9097c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) {
910f4b3ec61Sdh155122 ks3dbg(keystack, (
9117c478bd9Sstevel@tonic-gate "keysock_wput_other: Not big enough M_PROTO\n"));
9127c478bd9Sstevel@tonic-gate freemsg(mp);
9137c478bd9Sstevel@tonic-gate return;
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) {
9167c478bd9Sstevel@tonic-gate case T_CAPABILITY_REQ:
9177c478bd9Sstevel@tonic-gate keysock_capability_req(q, mp);
918f4b3ec61Sdh155122 break;
9197c478bd9Sstevel@tonic-gate case T_INFO_REQ:
9207c478bd9Sstevel@tonic-gate keysock_info_req(q, mp);
921f4b3ec61Sdh155122 break;
9227c478bd9Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ:
9237c478bd9Sstevel@tonic-gate case T_OPTMGMT_REQ:
924de8c4a14SErik Nordmark /*
925de8c4a14SErik Nordmark * All Solaris components should pass a db_credp
926de8c4a14SErik Nordmark * for this TPI message, hence we ASSERT.
927de8c4a14SErik Nordmark * But in case there is some other M_PROTO that looks
928de8c4a14SErik Nordmark * like a TPI message sent by some other kernel
929de8c4a14SErik Nordmark * component, we check and return an error.
930de8c4a14SErik Nordmark */
931de8c4a14SErik Nordmark cr = msg_getcred(mp, NULL);
932de8c4a14SErik Nordmark ASSERT(cr != NULL);
933de8c4a14SErik Nordmark if (cr == NULL) {
934de8c4a14SErik Nordmark keysock_err_ack(q, mp, TSYSERR, EINVAL);
935de8c4a14SErik Nordmark return;
936de8c4a14SErik Nordmark }
937de8c4a14SErik Nordmark if (((union T_primitives *)mp->b_rptr)->type ==
938de8c4a14SErik Nordmark T_SVR4_OPTMGMT_REQ) {
939bd670b35SErik Nordmark svr4_optcom_req(q, mp, cr, &keysock_opt_obj);
940de8c4a14SErik Nordmark } else {
941bd670b35SErik Nordmark tpi_optcom_req(q, mp, cr, &keysock_opt_obj);
942de8c4a14SErik Nordmark }
943f4b3ec61Sdh155122 break;
9447c478bd9Sstevel@tonic-gate case T_DATA_REQ:
9457c478bd9Sstevel@tonic-gate case T_EXDATA_REQ:
9467c478bd9Sstevel@tonic-gate case T_ORDREL_REQ:
9477c478bd9Sstevel@tonic-gate /* Illegal for keysock. */
9487c478bd9Sstevel@tonic-gate freemsg(mp);
9497c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO);
950f4b3ec61Sdh155122 break;
9517c478bd9Sstevel@tonic-gate default:
9527c478bd9Sstevel@tonic-gate /* Not supported by keysock. */
9537c478bd9Sstevel@tonic-gate keysock_err_ack(q, mp, TNOTSUPPORT, 0);
954f4b3ec61Sdh155122 break;
9557c478bd9Sstevel@tonic-gate }
956f4b3ec61Sdh155122 return;
9577c478bd9Sstevel@tonic-gate case M_IOCTL:
9587c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
9597c478bd9Sstevel@tonic-gate error = EINVAL;
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
9627c478bd9Sstevel@tonic-gate case ND_SET:
9637c478bd9Sstevel@tonic-gate case ND_GET:
964f4b3ec61Sdh155122 if (nd_getset(q, keystack->keystack_g_nd, mp)) {
9657c478bd9Sstevel@tonic-gate qreply(q, mp);
9667c478bd9Sstevel@tonic-gate return;
9677c478bd9Sstevel@tonic-gate } else
9687c478bd9Sstevel@tonic-gate error = ENOENT;
9697c478bd9Sstevel@tonic-gate /* FALLTHRU */
9707c478bd9Sstevel@tonic-gate default:
9717c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error);
9727c478bd9Sstevel@tonic-gate return;
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate case M_FLUSH:
9757c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
9767c478bd9Sstevel@tonic-gate flushq(q, FLUSHALL);
9777c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
9807c478bd9Sstevel@tonic-gate qreply(q, mp);
9817c478bd9Sstevel@tonic-gate return;
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate /* Else FALLTHRU */
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate /* If fell through, just black-hole the message. */
9877c478bd9Sstevel@tonic-gate freemsg(mp);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate * Transmit a PF_KEY error message to the instance either pointed to
9927c478bd9Sstevel@tonic-gate * by ks, the instance with serial number serial, or more, depending.
9937c478bd9Sstevel@tonic-gate *
9947c478bd9Sstevel@tonic-gate * The faulty message (or a reasonable facsimile thereof) is in mp.
9957c478bd9Sstevel@tonic-gate * This function will free mp or recycle it for delivery, thereby causing
9967c478bd9Sstevel@tonic-gate * the stream head to free it.
9977c478bd9Sstevel@tonic-gate */
9987c478bd9Sstevel@tonic-gate static void
keysock_error(keysock_t * ks,mblk_t * mp,int error,int diagnostic)9997c478bd9Sstevel@tonic-gate keysock_error(keysock_t *ks, mblk_t *mp, int error, int diagnostic)
10007c478bd9Sstevel@tonic-gate {
10017c478bd9Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr;
1002f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA);
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type < SADB_GETSPI ||
10077c478bd9Sstevel@tonic-gate samsg->sadb_msg_type > SADB_MAX)
10087c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_RESERVED;
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate * Strip out extension headers.
10127c478bd9Sstevel@tonic-gate */
10137c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + sizeof (*samsg) <= mp->b_datap->db_lim);
10147c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*samsg);
10157c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (sadb_msg_t));
10167c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error;
10177c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic;
10187c478bd9Sstevel@tonic-gate
1019f4b3ec61Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, keystack);
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate /*
10237c478bd9Sstevel@tonic-gate * Pass down a message to a consumer. Wrap it in KEYSOCK_IN, and copy
10247c478bd9Sstevel@tonic-gate * in the extv if passed in.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate static void
keysock_passdown(keysock_t * ks,mblk_t * mp,uint8_t satype,sadb_ext_t * extv[],boolean_t flushmsg)10277c478bd9Sstevel@tonic-gate keysock_passdown(keysock_t *ks, mblk_t *mp, uint8_t satype, sadb_ext_t *extv[],
10287c478bd9Sstevel@tonic-gate boolean_t flushmsg)
10297c478bd9Sstevel@tonic-gate {
10307c478bd9Sstevel@tonic-gate keysock_consumer_t *kc;
10317c478bd9Sstevel@tonic-gate mblk_t *wrapper;
10327c478bd9Sstevel@tonic-gate keysock_in_t *ksi;
10337c478bd9Sstevel@tonic-gate int i;
1034f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate wrapper = allocb(sizeof (ipsec_info_t), BPRI_HI);
10377c478bd9Sstevel@tonic-gate if (wrapper == NULL) {
1038f4b3ec61Sdh155122 ks3dbg(keystack, ("keysock_passdown: allocb failed.\n"));
10397c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_KEY_ENCRYPT] != NULL)
10407c478bd9Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_ENCRYPT],
10417c478bd9Sstevel@tonic-gate SADB_64TO8(
10427c478bd9Sstevel@tonic-gate extv[SADB_EXT_KEY_ENCRYPT]->sadb_ext_len));
10437c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_KEY_AUTH] != NULL)
10447c478bd9Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_AUTH],
10457c478bd9Sstevel@tonic-gate SADB_64TO8(
10467c478bd9Sstevel@tonic-gate extv[SADB_EXT_KEY_AUTH]->sadb_ext_len));
10477c478bd9Sstevel@tonic-gate if (flushmsg) {
10487c478bd9Sstevel@tonic-gate ks0dbg((
10497c478bd9Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n"));
10507c478bd9Sstevel@tonic-gate /* If this is true, I hold the perimeter. */
1051f4b3ec61Sdh155122 keystack->keystack_flushdump--;
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate freemsg(mp);
10547c478bd9Sstevel@tonic-gate return;
10557c478bd9Sstevel@tonic-gate }
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate wrapper->b_datap->db_type = M_CTL;
10587c478bd9Sstevel@tonic-gate ksi = (keysock_in_t *)wrapper->b_rptr;
10597c478bd9Sstevel@tonic-gate ksi->ks_in_type = KEYSOCK_IN;
10607c478bd9Sstevel@tonic-gate ksi->ks_in_len = sizeof (keysock_in_t);
10617c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] != NULL)
10627c478bd9Sstevel@tonic-gate ksi->ks_in_srctype = KS_IN_ADDR_UNKNOWN;
10637c478bd9Sstevel@tonic-gate else ksi->ks_in_srctype = KS_IN_ADDR_NOTTHERE;
10647c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] != NULL)
10657c478bd9Sstevel@tonic-gate ksi->ks_in_dsttype = KS_IN_ADDR_UNKNOWN;
10667c478bd9Sstevel@tonic-gate else ksi->ks_in_dsttype = KS_IN_ADDR_NOTTHERE;
10677c478bd9Sstevel@tonic-gate for (i = 0; i <= SADB_EXT_MAX; i++)
10687c478bd9Sstevel@tonic-gate ksi->ks_in_extv[i] = extv[i];
10697c478bd9Sstevel@tonic-gate ksi->ks_in_serial = ks->keysock_serial;
10707c478bd9Sstevel@tonic-gate wrapper->b_wptr += sizeof (ipsec_info_t);
10717c478bd9Sstevel@tonic-gate wrapper->b_cont = mp;
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate * Find the appropriate consumer where the message is passed down.
10757c478bd9Sstevel@tonic-gate */
1076f4b3ec61Sdh155122 kc = keystack->keystack_consumers[satype];
10777c478bd9Sstevel@tonic-gate if (kc == NULL) {
10787c478bd9Sstevel@tonic-gate freeb(wrapper);
10797c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE);
10807c478bd9Sstevel@tonic-gate if (flushmsg) {
10817c478bd9Sstevel@tonic-gate ks0dbg((
10827c478bd9Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n"));
10837c478bd9Sstevel@tonic-gate /* If this is true, I hold the perimeter. */
1084f4b3ec61Sdh155122 keystack->keystack_flushdump--;
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate return;
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate * NOTE: There used to be code in here to spin while a flush or
10917c478bd9Sstevel@tonic-gate * dump finished. Keysock now assumes that consumers have enough
10927c478bd9Sstevel@tonic-gate * MT-savviness to deal with that.
10937c478bd9Sstevel@tonic-gate */
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate /*
10967c478bd9Sstevel@tonic-gate * Current consumers (AH and ESP) are guaranteed to return a
10977c478bd9Sstevel@tonic-gate * FLUSH or DUMP message back, so when we reach here, we don't
10987c478bd9Sstevel@tonic-gate * have to worry about keysock_flushdumps.
10997c478bd9Sstevel@tonic-gate */
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, wrapper);
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate /*
11057c478bd9Sstevel@tonic-gate * High-level reality checking of extensions.
11067c478bd9Sstevel@tonic-gate */
11077c478bd9Sstevel@tonic-gate static boolean_t
ext_check(sadb_ext_t * ext,keysock_stack_t * keystack)1108f4b3ec61Sdh155122 ext_check(sadb_ext_t *ext, keysock_stack_t *keystack)
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate int i;
11117c478bd9Sstevel@tonic-gate uint64_t *lp;
11127c478bd9Sstevel@tonic-gate sadb_ident_t *id;
11137c478bd9Sstevel@tonic-gate char *idstr;
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate switch (ext->sadb_ext_type) {
11167c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC:
11177c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST:
11188810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC:
11198810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST:
11207c478bd9Sstevel@tonic-gate /* Check for at least enough addtl length for a sockaddr. */
11217c478bd9Sstevel@tonic-gate if (ext->sadb_ext_len <= SADB_8TO64(sizeof (sadb_address_t)))
11227c478bd9Sstevel@tonic-gate return (B_FALSE);
11237c478bd9Sstevel@tonic-gate break;
11247c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_HARD:
11257c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_SOFT:
11267c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_CURRENT:
11277c478bd9Sstevel@tonic-gate if (ext->sadb_ext_len != SADB_8TO64(sizeof (sadb_lifetime_t)))
11287c478bd9Sstevel@tonic-gate return (B_FALSE);
11297c478bd9Sstevel@tonic-gate break;
11307c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE:
11317c478bd9Sstevel@tonic-gate /* See if the SPI range is legit. */
11327c478bd9Sstevel@tonic-gate if (htonl(((sadb_spirange_t *)ext)->sadb_spirange_min) >
11337c478bd9Sstevel@tonic-gate htonl(((sadb_spirange_t *)ext)->sadb_spirange_max))
11347c478bd9Sstevel@tonic-gate return (B_FALSE);
11357c478bd9Sstevel@tonic-gate break;
11367c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH:
11377c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT:
11387c478bd9Sstevel@tonic-gate /* Key length check. */
11397c478bd9Sstevel@tonic-gate if (((sadb_key_t *)ext)->sadb_key_bits == 0)
11407c478bd9Sstevel@tonic-gate return (B_FALSE);
11417c478bd9Sstevel@tonic-gate /*
11427c478bd9Sstevel@tonic-gate * Check to see if the key length (in bits) is less than the
11437c478bd9Sstevel@tonic-gate * extension length (in 8-bits words).
11447c478bd9Sstevel@tonic-gate */
11457c478bd9Sstevel@tonic-gate if ((roundup(SADB_1TO8(((sadb_key_t *)ext)->sadb_key_bits), 8) +
11467c478bd9Sstevel@tonic-gate sizeof (sadb_key_t)) != SADB_64TO8(ext->sadb_ext_len)) {
1147f4b3ec61Sdh155122 ks1dbg(keystack, (
11487c478bd9Sstevel@tonic-gate "ext_check: Key bits/length inconsistent.\n"));
1149f4b3ec61Sdh155122 ks1dbg(keystack, ("%d bits, len is %d bytes.\n",
11507c478bd9Sstevel@tonic-gate ((sadb_key_t *)ext)->sadb_key_bits,
11517c478bd9Sstevel@tonic-gate SADB_64TO8(ext->sadb_ext_len)));
11527c478bd9Sstevel@tonic-gate return (B_FALSE);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate
11557c478bd9Sstevel@tonic-gate /* All-zeroes key check. */
11567c478bd9Sstevel@tonic-gate lp = (uint64_t *)(((char *)ext) + sizeof (sadb_key_t));
11577c478bd9Sstevel@tonic-gate for (i = 0;
11587c478bd9Sstevel@tonic-gate i < (ext->sadb_ext_len - SADB_8TO64(sizeof (sadb_key_t)));
11597c478bd9Sstevel@tonic-gate i++)
11607c478bd9Sstevel@tonic-gate if (lp[i] != 0)
11617c478bd9Sstevel@tonic-gate break; /* Out of for loop. */
11627c478bd9Sstevel@tonic-gate /* If finished the loop naturally, it's an all zero key. */
11637c478bd9Sstevel@tonic-gate if (lp[i] == 0)
11647c478bd9Sstevel@tonic-gate return (B_FALSE);
11657c478bd9Sstevel@tonic-gate break;
11667c478bd9Sstevel@tonic-gate case SADB_EXT_IDENTITY_SRC:
11677c478bd9Sstevel@tonic-gate case SADB_EXT_IDENTITY_DST:
11687c478bd9Sstevel@tonic-gate /*
11697c478bd9Sstevel@tonic-gate * Make sure the strings in these identities are
11707c478bd9Sstevel@tonic-gate * null-terminated. RFC 2367 underspecified how to handle
11717c478bd9Sstevel@tonic-gate * such a case. I "proactively" null-terminate the string
11727c478bd9Sstevel@tonic-gate * at the last byte if it's not terminated sooner.
11737c478bd9Sstevel@tonic-gate */
11747c478bd9Sstevel@tonic-gate id = (sadb_ident_t *)ext;
11757c478bd9Sstevel@tonic-gate i = SADB_64TO8(id->sadb_ident_len);
11767c478bd9Sstevel@tonic-gate i -= sizeof (sadb_ident_t);
11777c478bd9Sstevel@tonic-gate idstr = (char *)(id + 1);
11787c478bd9Sstevel@tonic-gate while (*idstr != '\0' && i > 0) {
11797c478bd9Sstevel@tonic-gate i--;
11807c478bd9Sstevel@tonic-gate idstr++;
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate if (i == 0) {
11837c478bd9Sstevel@tonic-gate /*
11847c478bd9Sstevel@tonic-gate * I.e., if the bozo user didn't NULL-terminate the
11857c478bd9Sstevel@tonic-gate * string...
11867c478bd9Sstevel@tonic-gate */
11877c478bd9Sstevel@tonic-gate idstr--;
11887c478bd9Sstevel@tonic-gate *idstr = '\0';
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate break;
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate return (B_TRUE); /* For now... */
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate /* Return values for keysock_get_ext(). */
11967c478bd9Sstevel@tonic-gate #define KGE_OK 0
11977c478bd9Sstevel@tonic-gate #define KGE_DUP 1
11987c478bd9Sstevel@tonic-gate #define KGE_UNK 2
11997c478bd9Sstevel@tonic-gate #define KGE_LEN 3
12007c478bd9Sstevel@tonic-gate #define KGE_CHK 4
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate * Parse basic extension headers and return in the passed-in pointer vector.
12047c478bd9Sstevel@tonic-gate * Return values include:
12057c478bd9Sstevel@tonic-gate *
12067c478bd9Sstevel@tonic-gate * KGE_OK Everything's nice and parsed out.
12077c478bd9Sstevel@tonic-gate * If there are no extensions, place NULL in extv[0].
12087c478bd9Sstevel@tonic-gate * KGE_DUP There is a duplicate extension.
12097c478bd9Sstevel@tonic-gate * First instance in appropriate bin. First duplicate in
12107c478bd9Sstevel@tonic-gate * extv[0].
12117c478bd9Sstevel@tonic-gate * KGE_UNK Unknown extension type encountered. extv[0] contains
12127c478bd9Sstevel@tonic-gate * unknown header.
12137c478bd9Sstevel@tonic-gate * KGE_LEN Extension length error.
12147c478bd9Sstevel@tonic-gate * KGE_CHK High-level reality check failed on specific extension.
12157c478bd9Sstevel@tonic-gate *
12167c478bd9Sstevel@tonic-gate * My apologies for some of the pointer arithmetic in here. I'm thinking
12177c478bd9Sstevel@tonic-gate * like an assembly programmer, yet trying to make the compiler happy.
12187c478bd9Sstevel@tonic-gate */
12197c478bd9Sstevel@tonic-gate static int
keysock_get_ext(sadb_ext_t * extv[],sadb_msg_t * basehdr,uint_t msgsize,keysock_stack_t * keystack)1220f4b3ec61Sdh155122 keysock_get_ext(sadb_ext_t *extv[], sadb_msg_t *basehdr, uint_t msgsize,
1221f4b3ec61Sdh155122 keysock_stack_t *keystack)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate bzero(extv, sizeof (sadb_ext_t *) * (SADB_EXT_MAX + 1));
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /* Use extv[0] as the "current working pointer". */
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate extv[0] = (sadb_ext_t *)(basehdr + 1);
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate while (extv[0] < (sadb_ext_t *)(((uint8_t *)basehdr) + msgsize)) {
12307c478bd9Sstevel@tonic-gate /* Check for unknown headers. */
12317c478bd9Sstevel@tonic-gate if (extv[0]->sadb_ext_type == 0 ||
12327c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type > SADB_EXT_MAX)
12337c478bd9Sstevel@tonic-gate return (KGE_UNK);
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate /*
12367c478bd9Sstevel@tonic-gate * Check length. Use uint64_t because extlen is in units
12377c478bd9Sstevel@tonic-gate * of 64-bit words. If length goes beyond the msgsize,
12387c478bd9Sstevel@tonic-gate * return an error. (Zero length also qualifies here.)
12397c478bd9Sstevel@tonic-gate */
12407c478bd9Sstevel@tonic-gate if (extv[0]->sadb_ext_len == 0 ||
12417c478bd9Sstevel@tonic-gate (void *)((uint64_t *)extv[0] + extv[0]->sadb_ext_len) >
12427c478bd9Sstevel@tonic-gate (void *)((uint8_t *)basehdr + msgsize))
12437c478bd9Sstevel@tonic-gate return (KGE_LEN);
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate /* Check for redundant headers. */
12467c478bd9Sstevel@tonic-gate if (extv[extv[0]->sadb_ext_type] != NULL)
12477c478bd9Sstevel@tonic-gate return (KGE_DUP);
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate /*
12507c478bd9Sstevel@tonic-gate * Reality check the extension if possible at the keysock
12517c478bd9Sstevel@tonic-gate * level.
12527c478bd9Sstevel@tonic-gate */
1253f4b3ec61Sdh155122 if (!ext_check(extv[0], keystack))
12547c478bd9Sstevel@tonic-gate return (KGE_CHK);
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate /* If I make it here, assign the appropriate bin. */
12577c478bd9Sstevel@tonic-gate extv[extv[0]->sadb_ext_type] = extv[0];
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate /* Advance pointer (See above for uint64_t ptr reasoning.) */
12607c478bd9Sstevel@tonic-gate extv[0] = (sadb_ext_t *)
12617c478bd9Sstevel@tonic-gate ((uint64_t *)extv[0] + extv[0]->sadb_ext_len);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate /* Everything's cool. */
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate /*
12677c478bd9Sstevel@tonic-gate * If extv[0] == NULL, then there are no extension headers in this
12687c478bd9Sstevel@tonic-gate * message. Ensure that this is the case.
12697c478bd9Sstevel@tonic-gate */
12707c478bd9Sstevel@tonic-gate if (extv[0] == (sadb_ext_t *)(basehdr + 1))
12717c478bd9Sstevel@tonic-gate extv[0] = NULL;
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate return (KGE_OK);
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate /*
12777c478bd9Sstevel@tonic-gate * qwriter() callback to handle flushes and dumps. This routine will hold
12787c478bd9Sstevel@tonic-gate * the inner perimeter.
12797c478bd9Sstevel@tonic-gate */
12807c478bd9Sstevel@tonic-gate void
keysock_do_flushdump(queue_t * q,mblk_t * mp)12817c478bd9Sstevel@tonic-gate keysock_do_flushdump(queue_t *q, mblk_t *mp)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate int i, start, finish;
12847c478bd9Sstevel@tonic-gate mblk_t *mp1 = NULL;
12857c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr;
12867c478bd9Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1];
12877c478bd9Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr;
1288f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate /*
12917c478bd9Sstevel@tonic-gate * I am guaranteed this will work. I did the work in keysock_parse()
12927c478bd9Sstevel@tonic-gate * already.
12937c478bd9Sstevel@tonic-gate */
1294f4b3ec61Sdh155122 (void) keysock_get_ext(extv, samsg, SADB_64TO8(samsg->sadb_msg_len),
1295f4b3ec61Sdh155122 keystack);
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate * I hold the perimeter, therefore I don't need to use atomic ops.
12997c478bd9Sstevel@tonic-gate */
1300f4b3ec61Sdh155122 if (keystack->keystack_flushdump != 0) {
13017c478bd9Sstevel@tonic-gate /* XXX Should I instead use EBUSY? */
13027c478bd9Sstevel@tonic-gate /* XXX Or is there a way to queue these up? */
13037c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, SADB_X_DIAGNOSTIC_NONE);
13047c478bd9Sstevel@tonic-gate return;
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
13087c478bd9Sstevel@tonic-gate start = 0;
13097c478bd9Sstevel@tonic-gate finish = KEYSOCK_MAX_CONSUMERS - 1;
13107c478bd9Sstevel@tonic-gate } else {
13117c478bd9Sstevel@tonic-gate start = samsg->sadb_msg_satype;
13127c478bd9Sstevel@tonic-gate finish = samsg->sadb_msg_satype;
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate
13157c478bd9Sstevel@tonic-gate /*
13167c478bd9Sstevel@tonic-gate * Fill up keysock_flushdump with the number of outstanding dumps
13177c478bd9Sstevel@tonic-gate * and/or flushes.
13187c478bd9Sstevel@tonic-gate */
13197c478bd9Sstevel@tonic-gate
1320f4b3ec61Sdh155122 keystack->keystack_flushdump_errno = 0;
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate * Okay, I hold the perimeter. Eventually keysock_flushdump will
13247c478bd9Sstevel@tonic-gate * contain the number of consumers with outstanding flush operations.
13257c478bd9Sstevel@tonic-gate *
13267c478bd9Sstevel@tonic-gate * SO, here's the plan:
13277c478bd9Sstevel@tonic-gate * * For each relevant consumer (Might be one, might be all)
13287c478bd9Sstevel@tonic-gate * * Twiddle on the FLUSHING flag.
13297c478bd9Sstevel@tonic-gate * * Pass down the FLUSH/DUMP message.
13307c478bd9Sstevel@tonic-gate *
13317c478bd9Sstevel@tonic-gate * When I see upbound FLUSH/DUMP messages, I will decrement the
13327c478bd9Sstevel@tonic-gate * keysock_flushdump. When I decrement it to 0, I will pass the
13337c478bd9Sstevel@tonic-gate * FLUSH/DUMP message back up to the PF_KEY sockets. Because I will
13347c478bd9Sstevel@tonic-gate * pass down the right SA type to the consumer (either its own, or
13357c478bd9Sstevel@tonic-gate * that of UNSPEC), the right one will be reflected from each consumer,
13367c478bd9Sstevel@tonic-gate * and accordingly back to the socket.
13377c478bd9Sstevel@tonic-gate */
13387c478bd9Sstevel@tonic-gate
1339f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock);
13407c478bd9Sstevel@tonic-gate for (i = start; i <= finish; i++) {
1341f4b3ec61Sdh155122 if (keystack->keystack_consumers[i] != NULL) {
13427c478bd9Sstevel@tonic-gate mp1 = copymsg(mp);
13437c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
13447c478bd9Sstevel@tonic-gate ks0dbg(("SADB_FLUSH copymsg() failed.\n"));
13457c478bd9Sstevel@tonic-gate /*
13467c478bd9Sstevel@tonic-gate * Error? And what about outstanding
13477c478bd9Sstevel@tonic-gate * flushes? Oh, yeah, they get sucked up and
13487c478bd9Sstevel@tonic-gate * the counter is decremented. Consumers
13497c478bd9Sstevel@tonic-gate * (see keysock_passdown()) are guaranteed
13507c478bd9Sstevel@tonic-gate * to deliver back a flush request, even if
13517c478bd9Sstevel@tonic-gate * it's an error.
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM,
13547c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE);
13557c478bd9Sstevel@tonic-gate return;
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate * Because my entry conditions are met above, the
13597c478bd9Sstevel@tonic-gate * following assertion should hold true.
13607c478bd9Sstevel@tonic-gate */
1361f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers[i]->kc_lock);
1362f4b3ec61Sdh155122 ASSERT((keystack->keystack_consumers[i]->kc_flags &
1363f4b3ec61Sdh155122 KC_FLUSHING) == 0);
1364f4b3ec61Sdh155122 keystack->keystack_consumers[i]->kc_flags |=
1365f4b3ec61Sdh155122 KC_FLUSHING;
1366f4b3ec61Sdh155122 mutex_exit(&(keystack->keystack_consumers[i]->kc_lock));
13677c478bd9Sstevel@tonic-gate /* Always increment the number of flushes... */
1368f4b3ec61Sdh155122 keystack->keystack_flushdump++;
13697c478bd9Sstevel@tonic-gate /* Guaranteed to return a message. */
13707c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp1, i, extv, B_TRUE);
13717c478bd9Sstevel@tonic-gate } else if (start == finish) {
13727c478bd9Sstevel@tonic-gate /*
13737c478bd9Sstevel@tonic-gate * In case where start == finish, and there's no
13747c478bd9Sstevel@tonic-gate * consumer, should we force an error? Yes.
13757c478bd9Sstevel@tonic-gate */
1376f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock);
13777c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL,
13787c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE);
13797c478bd9Sstevel@tonic-gate return;
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate }
1382f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock);
13837c478bd9Sstevel@tonic-gate
1384f4b3ec61Sdh155122 if (keystack->keystack_flushdump == 0) {
13857c478bd9Sstevel@tonic-gate /*
13867c478bd9Sstevel@tonic-gate * There were no consumers at all for this message.
13877c478bd9Sstevel@tonic-gate * XXX For now return ESRCH.
13887c478bd9Sstevel@tonic-gate */
13897c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ESRCH, SADB_X_DIAGNOSTIC_NO_SADBS);
13907c478bd9Sstevel@tonic-gate } else {
13917c478bd9Sstevel@tonic-gate /* Otherwise, free the original message. */
13927c478bd9Sstevel@tonic-gate freemsg(mp);
13937c478bd9Sstevel@tonic-gate }
13947c478bd9Sstevel@tonic-gate }
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate /*
13977c478bd9Sstevel@tonic-gate * Get the right diagnostic for a duplicate. Should probably use a static
13987c478bd9Sstevel@tonic-gate * table lookup.
13997c478bd9Sstevel@tonic-gate */
14007c478bd9Sstevel@tonic-gate int
keysock_duplicate(int ext_type)14017c478bd9Sstevel@tonic-gate keysock_duplicate(int ext_type)
14027c478bd9Sstevel@tonic-gate {
14037c478bd9Sstevel@tonic-gate int rc = 0;
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate switch (ext_type) {
14067c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC:
14077c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SRC;
14087c478bd9Sstevel@tonic-gate break;
14097c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST:
14107c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_DST;
14117c478bd9Sstevel@tonic-gate break;
14128810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC:
14138810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC;
14148810c16bSdanmcd break;
14158810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST:
14168810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST;
14178810c16bSdanmcd break;
14187c478bd9Sstevel@tonic-gate case SADB_EXT_SA:
14197c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SA;
14207c478bd9Sstevel@tonic-gate break;
14217c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE:
14227c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_RANGE;
14237c478bd9Sstevel@tonic-gate break;
14247c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH:
14257c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_AKEY;
14267c478bd9Sstevel@tonic-gate break;
14277c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT:
14287c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_EKEY;
14297c478bd9Sstevel@tonic-gate break;
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate return (rc);
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate /*
14357c478bd9Sstevel@tonic-gate * Get the right diagnostic for a reality check failure. Should probably use
14367c478bd9Sstevel@tonic-gate * a static table lookup.
14377c478bd9Sstevel@tonic-gate */
14387c478bd9Sstevel@tonic-gate int
keysock_malformed(int ext_type)14397c478bd9Sstevel@tonic-gate keysock_malformed(int ext_type)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate int rc = 0;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate switch (ext_type) {
14447c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC:
14457c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SRC;
14467c478bd9Sstevel@tonic-gate break;
14477c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST:
14487c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_DST;
14497c478bd9Sstevel@tonic-gate break;
14508810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC:
14518810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC;
14528810c16bSdanmcd break;
14538810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST:
14548810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST;
14558810c16bSdanmcd break;
14567c478bd9Sstevel@tonic-gate case SADB_EXT_SA:
14577c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SA;
14587c478bd9Sstevel@tonic-gate break;
14597c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE:
14607c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_RANGE;
14617c478bd9Sstevel@tonic-gate break;
14627c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH:
14637c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_AKEY;
14647c478bd9Sstevel@tonic-gate break;
14657c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT:
14667c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_EKEY;
14677c478bd9Sstevel@tonic-gate break;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate return (rc);
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate /*
14737c478bd9Sstevel@tonic-gate * Keysock massaging of an inverse ACQUIRE. Consult policy,
14747c478bd9Sstevel@tonic-gate * and construct an appropriate response.
14757c478bd9Sstevel@tonic-gate */
14767c478bd9Sstevel@tonic-gate static void
keysock_inverse_acquire(mblk_t * mp,sadb_msg_t * samsg,sadb_ext_t * extv[],keysock_t * ks)14777c478bd9Sstevel@tonic-gate keysock_inverse_acquire(mblk_t *mp, sadb_msg_t *samsg, sadb_ext_t *extv[],
14787c478bd9Sstevel@tonic-gate keysock_t *ks)
14797c478bd9Sstevel@tonic-gate {
14807c478bd9Sstevel@tonic-gate mblk_t *reply_mp;
1481f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
14827c478bd9Sstevel@tonic-gate
14837c478bd9Sstevel@tonic-gate /*
14847c478bd9Sstevel@tonic-gate * Reality check things...
14857c478bd9Sstevel@tonic-gate */
14867c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] == NULL) {
14877c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_SRC);
14887c478bd9Sstevel@tonic-gate return;
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] == NULL) {
14917c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_DST);
14928810c16bSdanmcd return;
14938810c16bSdanmcd }
14948810c16bSdanmcd
14958810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL &&
14968810c16bSdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] == NULL) {
14978810c16bSdanmcd keysock_error(ks, mp, EINVAL,
14988810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_DST);
14998810c16bSdanmcd return;
15008810c16bSdanmcd }
15018810c16bSdanmcd
15028810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] == NULL &&
15038810c16bSdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] != NULL) {
15048810c16bSdanmcd keysock_error(ks, mp, EINVAL,
15058810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_SRC);
15068810c16bSdanmcd return;
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate
1509f4b3ec61Sdh155122 reply_mp = ipsec_construct_inverse_acquire(samsg, extv,
1510f4b3ec61Sdh155122 keystack->keystack_netstack);
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate if (reply_mp != NULL) {
15137c478bd9Sstevel@tonic-gate freemsg(mp);
15147c478bd9Sstevel@tonic-gate keysock_passup(reply_mp, (sadb_msg_t *)reply_mp->b_rptr,
1515f4b3ec61Sdh155122 ks->keysock_serial, NULL, B_FALSE, keystack);
15167c478bd9Sstevel@tonic-gate } else {
15177c478bd9Sstevel@tonic-gate keysock_error(ks, mp, samsg->sadb_msg_errno,
15187c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate * Spew an extended REGISTER down to the relevant consumers.
15247c478bd9Sstevel@tonic-gate */
15257c478bd9Sstevel@tonic-gate static void
keysock_extended_register(keysock_t * ks,mblk_t * mp,sadb_ext_t * extv[])15267c478bd9Sstevel@tonic-gate keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
15277c478bd9Sstevel@tonic-gate {
15287c478bd9Sstevel@tonic-gate sadb_x_ereg_t *ereg = (sadb_x_ereg_t *)extv[SADB_X_EXT_EREG];
15297c478bd9Sstevel@tonic-gate uint8_t *satypes, *fencepost;
15307c478bd9Sstevel@tonic-gate mblk_t *downmp;
15317c478bd9Sstevel@tonic-gate sadb_ext_t *downextv[SADB_EXT_MAX + 1];
1532f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate if (ks->keysock_registered[0] != 0 || ks->keysock_registered[1] != 0 ||
15357c478bd9Sstevel@tonic-gate ks->keysock_registered[2] != 0 || ks->keysock_registered[3] != 0) {
15367c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0);
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_EXTENDED;
15407c478bd9Sstevel@tonic-gate if (ereg == NULL) {
15417c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
15427c478bd9Sstevel@tonic-gate } else {
15437c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + msgdsize(mp) == mp->b_wptr);
15447c478bd9Sstevel@tonic-gate fencepost = (uint8_t *)mp->b_wptr;
15457c478bd9Sstevel@tonic-gate satypes = ereg->sadb_x_ereg_satypes;
15467c478bd9Sstevel@tonic-gate while (*satypes != SADB_SATYPE_UNSPEC && satypes != fencepost) {
15477c478bd9Sstevel@tonic-gate downmp = copymsg(mp);
15487c478bd9Sstevel@tonic-gate if (downmp == NULL) {
15497c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 0);
15507c478bd9Sstevel@tonic-gate return;
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate /*
15537c478bd9Sstevel@tonic-gate * Since we've made it here, keysock_get_ext will work!
15547c478bd9Sstevel@tonic-gate */
15557c478bd9Sstevel@tonic-gate (void) keysock_get_ext(downextv,
1556f4b3ec61Sdh155122 (sadb_msg_t *)downmp->b_rptr, msgdsize(downmp),
1557f4b3ec61Sdh155122 keystack);
15587c478bd9Sstevel@tonic-gate keysock_passdown(ks, downmp, *satypes, downextv,
15597c478bd9Sstevel@tonic-gate B_FALSE);
15607c478bd9Sstevel@tonic-gate ++satypes;
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate freemsg(mp);
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate /*
15667c478bd9Sstevel@tonic-gate * Set global to indicate we prefer an extended ACQUIRE.
15677c478bd9Sstevel@tonic-gate */
1568*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&keystack->keystack_num_extended);
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate
15719c2c14abSThejaswini Singarajipura static void
keysock_delpair_all(keysock_t * ks,mblk_t * mp,sadb_ext_t * extv[])15729c2c14abSThejaswini Singarajipura keysock_delpair_all(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
15739c2c14abSThejaswini Singarajipura {
15749c2c14abSThejaswini Singarajipura int i, start, finish;
15759c2c14abSThejaswini Singarajipura mblk_t *mp1 = NULL;
15769c2c14abSThejaswini Singarajipura keysock_stack_t *keystack = ks->keysock_keystack;
15779c2c14abSThejaswini Singarajipura
15789c2c14abSThejaswini Singarajipura start = 0;
15799c2c14abSThejaswini Singarajipura finish = KEYSOCK_MAX_CONSUMERS - 1;
15809c2c14abSThejaswini Singarajipura
15819c2c14abSThejaswini Singarajipura for (i = start; i <= finish; i++) {
15829c2c14abSThejaswini Singarajipura if (keystack->keystack_consumers[i] != NULL) {
15839c2c14abSThejaswini Singarajipura mp1 = copymsg(mp);
15849c2c14abSThejaswini Singarajipura if (mp1 == NULL) {
15859c2c14abSThejaswini Singarajipura keysock_error(ks, mp, ENOMEM,
15869c2c14abSThejaswini Singarajipura SADB_X_DIAGNOSTIC_NONE);
15879c2c14abSThejaswini Singarajipura return;
15889c2c14abSThejaswini Singarajipura }
15899c2c14abSThejaswini Singarajipura keysock_passdown(ks, mp1, i, extv, B_FALSE);
15909c2c14abSThejaswini Singarajipura }
15919c2c14abSThejaswini Singarajipura }
15929c2c14abSThejaswini Singarajipura }
15939c2c14abSThejaswini Singarajipura
15947c478bd9Sstevel@tonic-gate /*
15957c478bd9Sstevel@tonic-gate * Handle PF_KEY messages.
15967c478bd9Sstevel@tonic-gate */
15977c478bd9Sstevel@tonic-gate static void
keysock_parse(queue_t * q,mblk_t * mp)15987c478bd9Sstevel@tonic-gate keysock_parse(queue_t *q, mblk_t *mp)
15997c478bd9Sstevel@tonic-gate {
16007c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
16017c478bd9Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1];
16027c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr;
16037c478bd9Sstevel@tonic-gate uint_t msgsize;
16047c478bd9Sstevel@tonic-gate uint8_t satype;
1605f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack;
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate /* Make sure I'm a PF_KEY socket. (i.e. nothing's below me) */
16087c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL);
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr;
1611f4b3ec61Sdh155122 ks2dbg(keystack, ("Received possible PF_KEY message, type %d.\n",
16127c478bd9Sstevel@tonic-gate samsg->sadb_msg_type));
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate msgsize = SADB_64TO8(samsg->sadb_msg_len);
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate if (msgdsize(mp) != msgsize) {
16177c478bd9Sstevel@tonic-gate /*
16187c478bd9Sstevel@tonic-gate * Message len incorrect w.r.t. actual size. Send an error
16197c478bd9Sstevel@tonic-gate * (EMSGSIZE). It may be necessary to massage things a
16207c478bd9Sstevel@tonic-gate * bit. For example, if the sadb_msg_type is hosed,
16217c478bd9Sstevel@tonic-gate * I need to set it to SADB_RESERVED to get delivery to
16227c478bd9Sstevel@tonic-gate * do the right thing. Then again, maybe just letting
16237c478bd9Sstevel@tonic-gate * the error delivery do the right thing.
16247c478bd9Sstevel@tonic-gate */
1625f4b3ec61Sdh155122 ks2dbg(keystack,
1626f4b3ec61Sdh155122 ("mblk (%lu) and base (%d) message sizes don't jibe.\n",
16277c478bd9Sstevel@tonic-gate msgdsize(mp), msgsize));
16287c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EMSGSIZE, SADB_X_DIAGNOSTIC_NONE);
16297c478bd9Sstevel@tonic-gate return;
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) {
16337c478bd9Sstevel@tonic-gate /* Get all message into one mblk. */
16347c478bd9Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) {
16357c478bd9Sstevel@tonic-gate /*
16367c478bd9Sstevel@tonic-gate * Something screwy happened.
16377c478bd9Sstevel@tonic-gate */
1638f4b3ec61Sdh155122 ks3dbg(keystack,
1639f4b3ec61Sdh155122 ("keysock_parse: pullupmsg() failed.\n"));
16407c478bd9Sstevel@tonic-gate return;
16417c478bd9Sstevel@tonic-gate } else {
16427c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr;
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate
1646f4b3ec61Sdh155122 switch (keysock_get_ext(extv, samsg, msgsize, keystack)) {
16477c478bd9Sstevel@tonic-gate case KGE_DUP:
16487c478bd9Sstevel@tonic-gate /* Handle duplicate extension. */
1649f4b3ec61Sdh155122 ks1dbg(keystack, ("Got duplicate extension of type %d.\n",
16507c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type));
16517c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL,
16527c478bd9Sstevel@tonic-gate keysock_duplicate(extv[0]->sadb_ext_type));
16537c478bd9Sstevel@tonic-gate return;
16547c478bd9Sstevel@tonic-gate case KGE_UNK:
16557c478bd9Sstevel@tonic-gate /* Handle unknown extension. */
1656f4b3ec61Sdh155122 ks1dbg(keystack, ("Got unknown extension of type %d.\n",
16577c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type));
16587c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_EXT);
16597c478bd9Sstevel@tonic-gate return;
16607c478bd9Sstevel@tonic-gate case KGE_LEN:
16617c478bd9Sstevel@tonic-gate /* Length error. */
1662f4b3ec61Sdh155122 ks1dbg(keystack,
1663f4b3ec61Sdh155122 ("Length %d on extension type %d overrun or 0.\n",
16647c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_len, extv[0]->sadb_ext_type));
16657c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_BAD_EXTLEN);
16667c478bd9Sstevel@tonic-gate return;
16677c478bd9Sstevel@tonic-gate case KGE_CHK:
16687c478bd9Sstevel@tonic-gate /* Reality check failed. */
1669f4b3ec61Sdh155122 ks1dbg(keystack,
1670f4b3ec61Sdh155122 ("Reality check failed on extension type %d.\n",
16717c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type));
16727c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL,
16737c478bd9Sstevel@tonic-gate keysock_malformed(extv[0]->sadb_ext_type));
16747c478bd9Sstevel@tonic-gate return;
16757c478bd9Sstevel@tonic-gate default:
16767c478bd9Sstevel@tonic-gate /* Default case is no errors. */
16777c478bd9Sstevel@tonic-gate break;
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) {
16817c478bd9Sstevel@tonic-gate case SADB_REGISTER:
16827c478bd9Sstevel@tonic-gate /*
16837c478bd9Sstevel@tonic-gate * There's a semantic weirdness in that a message OTHER than
16847c478bd9Sstevel@tonic-gate * the return REGISTER message may be passed up if I set the
16857c478bd9Sstevel@tonic-gate * registered bit BEFORE I pass it down.
16867c478bd9Sstevel@tonic-gate *
16877c478bd9Sstevel@tonic-gate * SOOOO, I'll not twiddle any registered bits until I see
16887c478bd9Sstevel@tonic-gate * the upbound REGISTER (with a serial number in it).
16897c478bd9Sstevel@tonic-gate */
16907c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
16917c478bd9Sstevel@tonic-gate /* Handle extended register here. */
16927c478bd9Sstevel@tonic-gate keysock_extended_register(ks, mp, extv);
16937c478bd9Sstevel@tonic-gate return;
16947c478bd9Sstevel@tonic-gate } else if (ks->keysock_flags & KEYSOCK_EXTENDED) {
16957c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0);
16967c478bd9Sstevel@tonic-gate return;
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate /* FALLTHRU */
16997c478bd9Sstevel@tonic-gate case SADB_GETSPI:
17007c478bd9Sstevel@tonic-gate case SADB_ADD:
17017c478bd9Sstevel@tonic-gate case SADB_UPDATE:
170238d95a78Smarkfen case SADB_X_UPDATEPAIR:
17037c478bd9Sstevel@tonic-gate case SADB_DELETE:
170438d95a78Smarkfen case SADB_X_DELPAIR:
17057c478bd9Sstevel@tonic-gate case SADB_GET:
17067c478bd9Sstevel@tonic-gate /*
17077c478bd9Sstevel@tonic-gate * Pass down to appropriate consumer.
17087c478bd9Sstevel@tonic-gate */
17097c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC)
17107c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv,
17117c478bd9Sstevel@tonic-gate B_FALSE);
17127c478bd9Sstevel@tonic-gate else keysock_error(ks, mp, EINVAL,
17137c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
17147c478bd9Sstevel@tonic-gate return;
17159c2c14abSThejaswini Singarajipura case SADB_X_DELPAIR_STATE:
17169c2c14abSThejaswini Singarajipura if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
17179c2c14abSThejaswini Singarajipura keysock_delpair_all(ks, mp, extv);
17189c2c14abSThejaswini Singarajipura } else {
17199c2c14abSThejaswini Singarajipura keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv,
17209c2c14abSThejaswini Singarajipura B_FALSE);
17219c2c14abSThejaswini Singarajipura }
17229c2c14abSThejaswini Singarajipura return;
17237c478bd9Sstevel@tonic-gate case SADB_ACQUIRE:
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate * If I _receive_ an acquire, this means I should spread it
17267c478bd9Sstevel@tonic-gate * out to registered sockets. Unless there's an errno...
17277c478bd9Sstevel@tonic-gate *
17287c478bd9Sstevel@tonic-gate * Need ADDRESS, may have ID, SENS, and PROP, unless errno,
17297c478bd9Sstevel@tonic-gate * in which case there should be NO extensions.
17307c478bd9Sstevel@tonic-gate *
17317c478bd9Sstevel@tonic-gate * Return to registered.
17327c478bd9Sstevel@tonic-gate */
17337c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) {
17347c478bd9Sstevel@tonic-gate satype = samsg->sadb_msg_satype;
17357c478bd9Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) {
17367c478bd9Sstevel@tonic-gate if (!(ks->keysock_flags & KEYSOCK_EXTENDED)) {
17377c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL,
17387c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
17397c478bd9Sstevel@tonic-gate return;
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate /*
17427c478bd9Sstevel@tonic-gate * Reassign satype based on the first
17437c478bd9Sstevel@tonic-gate * flags that KEYSOCK_SETREG says.
17447c478bd9Sstevel@tonic-gate */
17457c478bd9Sstevel@tonic-gate while (satype <= SADB_SATYPE_MAX) {
17467c478bd9Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype))
17477c478bd9Sstevel@tonic-gate break;
17487c478bd9Sstevel@tonic-gate satype++;
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate if (satype > SADB_SATYPE_MAX) {
17517c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0);
17527c478bd9Sstevel@tonic-gate return;
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp, satype, extv, B_FALSE);
17567c478bd9Sstevel@tonic-gate } else {
1757f4b3ec61Sdh155122 if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
17587c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL,
17597c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
1760f4b3ec61Sdh155122 } else {
1761f4b3ec61Sdh155122 keysock_passup(mp, samsg, 0, NULL, B_FALSE,
1762f4b3ec61Sdh155122 keystack);
1763f4b3ec61Sdh155122 }
17647c478bd9Sstevel@tonic-gate }
17657c478bd9Sstevel@tonic-gate return;
17667c478bd9Sstevel@tonic-gate case SADB_EXPIRE:
17677c478bd9Sstevel@tonic-gate /*
17687c478bd9Sstevel@tonic-gate * If someone sends this in, then send out to all senders.
17697c478bd9Sstevel@tonic-gate * (Save maybe ESP or AH, I have to be careful here.)
17707c478bd9Sstevel@tonic-gate *
17717c478bd9Sstevel@tonic-gate * Need ADDRESS, may have ID and SENS.
17727c478bd9Sstevel@tonic-gate *
17737c478bd9Sstevel@tonic-gate * XXX for now this is unsupported.
17747c478bd9Sstevel@tonic-gate */
17757c478bd9Sstevel@tonic-gate break;
17767c478bd9Sstevel@tonic-gate case SADB_FLUSH:
17777c478bd9Sstevel@tonic-gate /*
17789c2c14abSThejaswini Singarajipura * Nuke all SAs.
17797c478bd9Sstevel@tonic-gate *
17807c478bd9Sstevel@tonic-gate * No extensions at all. Return to all listeners.
17817c478bd9Sstevel@tonic-gate *
17827c478bd9Sstevel@tonic-gate * Question: Should I hold a lock here to prevent
17837c478bd9Sstevel@tonic-gate * additions/deletions while flushing?
17847c478bd9Sstevel@tonic-gate * Answer: No. (See keysock_passdown() for details.)
17857c478bd9Sstevel@tonic-gate */
17867c478bd9Sstevel@tonic-gate if (extv[0] != NULL) {
17877c478bd9Sstevel@tonic-gate /*
17889c2c14abSThejaswini Singarajipura * FLUSH messages shouldn't have extensions.
17897c478bd9Sstevel@tonic-gate * Return EINVAL.
17907c478bd9Sstevel@tonic-gate */
1791f4b3ec61Sdh155122 ks2dbg(keystack, ("FLUSH message with extension.\n"));
17927c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_NO_EXT);
17937c478bd9Sstevel@tonic-gate return;
17947c478bd9Sstevel@tonic-gate }
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate /* Passing down of DUMP/FLUSH messages are special. */
17977c478bd9Sstevel@tonic-gate qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
17987c478bd9Sstevel@tonic-gate return;
17999c2c14abSThejaswini Singarajipura case SADB_DUMP: /* not used by normal applications */
18009c2c14abSThejaswini Singarajipura if ((extv[0] != NULL) &&
18019c2c14abSThejaswini Singarajipura ((msgsize >
18029c2c14abSThejaswini Singarajipura (sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) ||
18039c2c14abSThejaswini Singarajipura (extv[SADB_X_EXT_EDUMP] == NULL))) {
18049c2c14abSThejaswini Singarajipura keysock_error(ks, mp, EINVAL,
18059c2c14abSThejaswini Singarajipura SADB_X_DIAGNOSTIC_NO_EXT);
18069c2c14abSThejaswini Singarajipura return;
18079c2c14abSThejaswini Singarajipura }
18089c2c14abSThejaswini Singarajipura qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
18099c2c14abSThejaswini Singarajipura return;
18107c478bd9Sstevel@tonic-gate case SADB_X_PROMISC:
18117c478bd9Sstevel@tonic-gate /*
18127c478bd9Sstevel@tonic-gate * Promiscuous processing message.
18137c478bd9Sstevel@tonic-gate */
18147c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == 0)
18157c478bd9Sstevel@tonic-gate ks->keysock_flags &= ~KEYSOCK_PROMISC;
18167c478bd9Sstevel@tonic-gate else
18177c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_PROMISC;
1818f4b3ec61Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE,
1819f4b3ec61Sdh155122 keystack);
18207c478bd9Sstevel@tonic-gate return;
18217c478bd9Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE:
18227c478bd9Sstevel@tonic-gate keysock_inverse_acquire(mp, samsg, extv, ks);
18237c478bd9Sstevel@tonic-gate return;
18247c478bd9Sstevel@tonic-gate default:
1825f4b3ec61Sdh155122 ks2dbg(keystack, ("Got unknown message type %d.\n",
18267c478bd9Sstevel@tonic-gate samsg->sadb_msg_type));
18277c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_MSG);
18287c478bd9Sstevel@tonic-gate return;
18297c478bd9Sstevel@tonic-gate }
18307c478bd9Sstevel@tonic-gate
18317c478bd9Sstevel@tonic-gate /* As a placeholder... */
18327c478bd9Sstevel@tonic-gate ks0dbg(("keysock_parse(): Hit EOPNOTSUPP\n"));
18337c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EOPNOTSUPP, SADB_X_DIAGNOSTIC_NONE);
18347c478bd9Sstevel@tonic-gate }
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate /*
18377c478bd9Sstevel@tonic-gate * wput routing for PF_KEY/keysock/whatever. Unlike the routing socket,
18387c478bd9Sstevel@tonic-gate * I don't convert to ioctl()'s for IP. I am the end-all driver as far
18397c478bd9Sstevel@tonic-gate * as PF_KEY sockets are concerned. I do some conversion, but not as much
18407c478bd9Sstevel@tonic-gate * as IP/rts does.
18417c478bd9Sstevel@tonic-gate */
18427c478bd9Sstevel@tonic-gate static void
keysock_wput(queue_t * q,mblk_t * mp)18437c478bd9Sstevel@tonic-gate keysock_wput(queue_t *q, mblk_t *mp)
18447c478bd9Sstevel@tonic-gate {
18457c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr;
18467c478bd9Sstevel@tonic-gate mblk_t *mp1;
1847f4b3ec61Sdh155122 keysock_t *ks;
1848f4b3ec61Sdh155122 keysock_stack_t *keystack;
18497c478bd9Sstevel@tonic-gate
18507c478bd9Sstevel@tonic-gate if (WR(q)->q_next) {
18517c478bd9Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr;
1852f4b3ec61Sdh155122 keystack = kc->kc_keystack;
1853f4b3ec61Sdh155122
1854f4b3ec61Sdh155122 ks3dbg(keystack, ("In keysock_wput\n"));
18557c478bd9Sstevel@tonic-gate
18567c478bd9Sstevel@tonic-gate /*
18577c478bd9Sstevel@tonic-gate * We shouldn't get writes on a consumer instance.
18587c478bd9Sstevel@tonic-gate * But for now, just passthru.
18597c478bd9Sstevel@tonic-gate */
1860f4b3ec61Sdh155122 ks1dbg(keystack, ("Huh? wput for an consumer instance (%d)?\n",
18617c478bd9Sstevel@tonic-gate kc->kc_sa_type));
18627c478bd9Sstevel@tonic-gate putnext(q, mp);
18637c478bd9Sstevel@tonic-gate return;
18647c478bd9Sstevel@tonic-gate }
1865f4b3ec61Sdh155122 ks = (keysock_t *)q->q_ptr;
1866f4b3ec61Sdh155122 keystack = ks->keysock_keystack;
1867f4b3ec61Sdh155122
1868f4b3ec61Sdh155122 ks3dbg(keystack, ("In keysock_wput\n"));
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
18717c478bd9Sstevel@tonic-gate case M_DATA:
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate * Silently discard.
18747c478bd9Sstevel@tonic-gate */
1875f4b3ec61Sdh155122 ks2dbg(keystack, ("raw M_DATA in keysock.\n"));
18767c478bd9Sstevel@tonic-gate freemsg(mp);
18777c478bd9Sstevel@tonic-gate return;
18787c478bd9Sstevel@tonic-gate case M_PROTO:
18797c478bd9Sstevel@tonic-gate case M_PCPROTO:
18807c478bd9Sstevel@tonic-gate if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) {
18817c478bd9Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) {
18827c478bd9Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) {
18837c478bd9Sstevel@tonic-gate /* No data after T_DATA_REQ. */
1884f4b3ec61Sdh155122 ks2dbg(keystack,
1885f4b3ec61Sdh155122 ("No data after DATA_REQ.\n"));
18867c478bd9Sstevel@tonic-gate freemsg(mp);
18877c478bd9Sstevel@tonic-gate return;
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate freeb(mp);
18907c478bd9Sstevel@tonic-gate mp = mp1;
1891f4b3ec61Sdh155122 ks2dbg(keystack, ("T_DATA_REQ\n"));
18927c478bd9Sstevel@tonic-gate break; /* Out of switch. */
18937c478bd9Sstevel@tonic-gate }
18947c478bd9Sstevel@tonic-gate }
18957c478bd9Sstevel@tonic-gate /* FALLTHRU */
18967c478bd9Sstevel@tonic-gate default:
1897f4b3ec61Sdh155122 ks3dbg(keystack, ("In default wput case (%d %d).\n",
18987c478bd9Sstevel@tonic-gate mp->b_datap->db_type, ((union T_primitives *)rptr)->type));
18997c478bd9Sstevel@tonic-gate keysock_wput_other(q, mp);
19007c478bd9Sstevel@tonic-gate return;
19017c478bd9Sstevel@tonic-gate }
19027c478bd9Sstevel@tonic-gate
19037c478bd9Sstevel@tonic-gate /* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */
19047c478bd9Sstevel@tonic-gate keysock_parse(q, mp);
19057c478bd9Sstevel@tonic-gate }
19067c478bd9Sstevel@tonic-gate
19077c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */
19087c478bd9Sstevel@tonic-gate
19097c478bd9Sstevel@tonic-gate /*
19107c478bd9Sstevel@tonic-gate * Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate
19117c478bd9Sstevel@tonic-gate * state vectors.
19127c478bd9Sstevel@tonic-gate */
19137c478bd9Sstevel@tonic-gate static void
keysock_link_consumer(uint8_t satype,keysock_consumer_t * kc)19147c478bd9Sstevel@tonic-gate keysock_link_consumer(uint8_t satype, keysock_consumer_t *kc)
19157c478bd9Sstevel@tonic-gate {
19167c478bd9Sstevel@tonic-gate keysock_t *ks;
1917f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack;
19187c478bd9Sstevel@tonic-gate
1919f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock);
19207c478bd9Sstevel@tonic-gate mutex_enter(&kc->kc_lock);
1921f4b3ec61Sdh155122 if (keystack->keystack_consumers[satype] != NULL) {
19227c478bd9Sstevel@tonic-gate ks0dbg((
19237c478bd9Sstevel@tonic-gate "Hmmmm, someone closed %d before the HELLO_ACK happened.\n",
19247c478bd9Sstevel@tonic-gate satype));
19257c478bd9Sstevel@tonic-gate /*
19267c478bd9Sstevel@tonic-gate * Perhaps updating the new below-me consumer with what I have
19277c478bd9Sstevel@tonic-gate * so far would work too?
19287c478bd9Sstevel@tonic-gate */
19297c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock);
1930f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock);
19317c478bd9Sstevel@tonic-gate } else {
19327c478bd9Sstevel@tonic-gate /* Add new below-me consumer. */
1933f4b3ec61Sdh155122 keystack->keystack_consumers[satype] = kc;
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate kc->kc_flags = 0;
19367c478bd9Sstevel@tonic-gate kc->kc_sa_type = satype;
19377c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock);
1938f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock);
19397c478bd9Sstevel@tonic-gate
19407c478bd9Sstevel@tonic-gate /* Scan the keysock list. */
1941f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock);
1942f4b3ec61Sdh155122 for (ks = keystack->keystack_list; ks != NULL;
1943f4b3ec61Sdh155122 ks = ks->keysock_next) {
19447c478bd9Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) {
19457c478bd9Sstevel@tonic-gate /*
19467c478bd9Sstevel@tonic-gate * XXX Perhaps send an SADB_REGISTER down on
19477c478bd9Sstevel@tonic-gate * the socket's behalf.
19487c478bd9Sstevel@tonic-gate */
1949f4b3ec61Sdh155122 ks1dbg(keystack,
1950f4b3ec61Sdh155122 ("Socket %u registered already for "
19517c478bd9Sstevel@tonic-gate "new consumer.\n", ks->keysock_serial));
19527c478bd9Sstevel@tonic-gate }
19537c478bd9Sstevel@tonic-gate }
1954f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock);
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate * Generate a KEYSOCK_OUT_ERR message for my consumer.
19607c478bd9Sstevel@tonic-gate */
19617c478bd9Sstevel@tonic-gate static void
keysock_out_err(keysock_consumer_t * kc,int ks_errno,mblk_t * mp)19627c478bd9Sstevel@tonic-gate keysock_out_err(keysock_consumer_t *kc, int ks_errno, mblk_t *mp)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate keysock_out_err_t *kse;
19657c478bd9Sstevel@tonic-gate mblk_t *imp;
1966f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack;
19677c478bd9Sstevel@tonic-gate
19687c478bd9Sstevel@tonic-gate imp = allocb(sizeof (ipsec_info_t), BPRI_HI);
19697c478bd9Sstevel@tonic-gate if (imp == NULL) {
1970f4b3ec61Sdh155122 ks1dbg(keystack, ("keysock_out_err: Can't alloc message.\n"));
19717c478bd9Sstevel@tonic-gate return;
19727c478bd9Sstevel@tonic-gate }
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate imp->b_datap->db_type = M_CTL;
19757c478bd9Sstevel@tonic-gate imp->b_wptr += sizeof (ipsec_info_t);
19767c478bd9Sstevel@tonic-gate
19777c478bd9Sstevel@tonic-gate kse = (keysock_out_err_t *)imp->b_rptr;
19787c478bd9Sstevel@tonic-gate imp->b_cont = mp;
19797c478bd9Sstevel@tonic-gate kse->ks_err_type = KEYSOCK_OUT_ERR;
19807c478bd9Sstevel@tonic-gate kse->ks_err_len = sizeof (*kse);
19817c478bd9Sstevel@tonic-gate /* Is serial necessary? */
19827c478bd9Sstevel@tonic-gate kse->ks_err_serial = 0;
19837c478bd9Sstevel@tonic-gate kse->ks_err_errno = ks_errno;
19847c478bd9Sstevel@tonic-gate
19857c478bd9Sstevel@tonic-gate /*
19867c478bd9Sstevel@tonic-gate * XXX What else do I need to do here w.r.t. information
19877c478bd9Sstevel@tonic-gate * to tell the consumer what caused this error?
19887c478bd9Sstevel@tonic-gate *
19897c478bd9Sstevel@tonic-gate * I believe the answer is the PF_KEY ACQUIRE (or other) message
19907c478bd9Sstevel@tonic-gate * attached in mp, which is appended at the end. I believe the
19917c478bd9Sstevel@tonic-gate * db_ref won't matter here, because the PF_KEY message is only read
19927c478bd9Sstevel@tonic-gate * for KEYSOCK_OUT_ERR.
19937c478bd9Sstevel@tonic-gate */
19947c478bd9Sstevel@tonic-gate
19957c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, imp);
19967c478bd9Sstevel@tonic-gate }
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate /* XXX this is a hack errno. */
19997c478bd9Sstevel@tonic-gate #define EIPSECNOSA 255
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate /*
20027c478bd9Sstevel@tonic-gate * Route message (pointed by mp, header in samsg) toward appropriate
20037c478bd9Sstevel@tonic-gate * sockets. Assume the message's creator did its job correctly.
20047c478bd9Sstevel@tonic-gate *
20057c478bd9Sstevel@tonic-gate * This should be a function that is followed by a return in its caller.
20067c478bd9Sstevel@tonic-gate * The compiler _should_ be able to use tail-call optimizations to make the
20077c478bd9Sstevel@tonic-gate * large ## of parameters not a huge deal.
20087c478bd9Sstevel@tonic-gate */
20097c478bd9Sstevel@tonic-gate static void
keysock_passup(mblk_t * mp,sadb_msg_t * samsg,minor_t serial,keysock_consumer_t * kc,boolean_t persistent,keysock_stack_t * keystack)20107c478bd9Sstevel@tonic-gate keysock_passup(mblk_t *mp, sadb_msg_t *samsg, minor_t serial,
2011f4b3ec61Sdh155122 keysock_consumer_t *kc, boolean_t persistent, keysock_stack_t *keystack)
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate keysock_t *ks;
20147c478bd9Sstevel@tonic-gate uint8_t satype = samsg->sadb_msg_satype;
20157c478bd9Sstevel@tonic-gate boolean_t toall = B_FALSE, allreg = B_FALSE, allereg = B_FALSE,
20167c478bd9Sstevel@tonic-gate setalg = B_FALSE;
20177c478bd9Sstevel@tonic-gate mblk_t *mp1;
20187c478bd9Sstevel@tonic-gate int err = EIPSECNOSA;
20197c478bd9Sstevel@tonic-gate
20207c478bd9Sstevel@tonic-gate /* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */
20217c478bd9Sstevel@tonic-gate mp1 = allocb(sizeof (struct T_data_req), BPRI_HI);
20227c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
20237c478bd9Sstevel@tonic-gate err = ENOMEM;
20247c478bd9Sstevel@tonic-gate goto error;
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate mp1->b_wptr += sizeof (struct T_data_req);
20277c478bd9Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->PRIM_type = T_DATA_IND;
20287c478bd9Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->MORE_flag = 0;
20297c478bd9Sstevel@tonic-gate mp1->b_datap->db_type = M_PROTO;
20307c478bd9Sstevel@tonic-gate mp1->b_cont = mp;
20317c478bd9Sstevel@tonic-gate mp = mp1;
20327c478bd9Sstevel@tonic-gate
20337c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) {
20347c478bd9Sstevel@tonic-gate case SADB_FLUSH:
20357c478bd9Sstevel@tonic-gate case SADB_GETSPI:
20367c478bd9Sstevel@tonic-gate case SADB_UPDATE:
203738d95a78Smarkfen case SADB_X_UPDATEPAIR:
20387c478bd9Sstevel@tonic-gate case SADB_ADD:
20397c478bd9Sstevel@tonic-gate case SADB_DELETE:
204038d95a78Smarkfen case SADB_X_DELPAIR:
20417c478bd9Sstevel@tonic-gate case SADB_EXPIRE:
20427c478bd9Sstevel@tonic-gate /*
20437c478bd9Sstevel@tonic-gate * These are most likely replies. Don't worry about
20447c478bd9Sstevel@tonic-gate * KEYSOCK_OUT_ERR handling. Deliver to all sockets.
20457c478bd9Sstevel@tonic-gate */
2046f4b3ec61Sdh155122 ks3dbg(keystack,
2047f4b3ec61Sdh155122 ("Delivering normal message (%d) to all sockets.\n",
20487c478bd9Sstevel@tonic-gate samsg->sadb_msg_type));
20497c478bd9Sstevel@tonic-gate toall = B_TRUE;
20507c478bd9Sstevel@tonic-gate break;
20517c478bd9Sstevel@tonic-gate case SADB_REGISTER:
20527c478bd9Sstevel@tonic-gate /*
20537c478bd9Sstevel@tonic-gate * REGISTERs come up for one of three reasons:
20547c478bd9Sstevel@tonic-gate *
20557c478bd9Sstevel@tonic-gate * 1.) In response to a normal SADB_REGISTER
20567c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
20577c478bd9Sstevel@tonic-gate * serial != 0)
20587c478bd9Sstevel@tonic-gate * Deliver to normal SADB_REGISTERed sockets.
20597c478bd9Sstevel@tonic-gate * 2.) In response to an extended REGISTER
20607c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC)
20617c478bd9Sstevel@tonic-gate * Deliver to extended REGISTERed socket.
20627c478bd9Sstevel@tonic-gate * 3.) Spontaneous algorithm changes
20637c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
20647c478bd9Sstevel@tonic-gate * serial == 0)
20657c478bd9Sstevel@tonic-gate * Deliver to REGISTERed sockets of all sorts.
20667c478bd9Sstevel@tonic-gate */
20677c478bd9Sstevel@tonic-gate if (kc == NULL) {
20687c478bd9Sstevel@tonic-gate /* Here because of keysock_error() call. */
20697c478bd9Sstevel@tonic-gate ASSERT(samsg->sadb_msg_errno != 0);
20707c478bd9Sstevel@tonic-gate break; /* Out of switch. */
20717c478bd9Sstevel@tonic-gate }
2072f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering REGISTER.\n"));
20737c478bd9Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) {
20747c478bd9Sstevel@tonic-gate /* REGISTER Reason #2 */
20757c478bd9Sstevel@tonic-gate allereg = B_TRUE;
20767c478bd9Sstevel@tonic-gate /*
20777c478bd9Sstevel@tonic-gate * Rewhack SA type so PF_KEY socket holder knows what
20787c478bd9Sstevel@tonic-gate * consumer generated this algorithm list.
20797c478bd9Sstevel@tonic-gate */
20807c478bd9Sstevel@tonic-gate satype = kc->kc_sa_type;
20817c478bd9Sstevel@tonic-gate samsg->sadb_msg_satype = satype;
20827c478bd9Sstevel@tonic-gate setalg = B_TRUE;
20837c478bd9Sstevel@tonic-gate } else if (serial == 0) {
20847c478bd9Sstevel@tonic-gate /* REGISTER Reason #3 */
20857c478bd9Sstevel@tonic-gate allreg = B_TRUE;
20867c478bd9Sstevel@tonic-gate allereg = B_TRUE;
20877c478bd9Sstevel@tonic-gate } else {
20887c478bd9Sstevel@tonic-gate /* REGISTER Reason #1 */
20897c478bd9Sstevel@tonic-gate allreg = B_TRUE;
20907c478bd9Sstevel@tonic-gate setalg = B_TRUE;
20917c478bd9Sstevel@tonic-gate }
20927c478bd9Sstevel@tonic-gate break;
20937c478bd9Sstevel@tonic-gate case SADB_ACQUIRE:
20947c478bd9Sstevel@tonic-gate /*
20957c478bd9Sstevel@tonic-gate * ACQUIREs are either extended (sadb_msg_satype == 0) or
20967c478bd9Sstevel@tonic-gate * regular (sadb_msg_satype != 0). And we're guaranteed
20977c478bd9Sstevel@tonic-gate * that serial == 0 for an ACQUIRE.
20987c478bd9Sstevel@tonic-gate */
2099f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering ACQUIRE.\n"));
21007c478bd9Sstevel@tonic-gate allereg = (satype == SADB_SATYPE_UNSPEC);
21017c478bd9Sstevel@tonic-gate allreg = !allereg;
21027c478bd9Sstevel@tonic-gate /*
21037c478bd9Sstevel@tonic-gate * Corner case - if we send a regular ACQUIRE and there's
21047c478bd9Sstevel@tonic-gate * extended ones registered, don't send an error down to
21057c478bd9Sstevel@tonic-gate * consumers if nobody's listening and prematurely destroy
21067c478bd9Sstevel@tonic-gate * their ACQUIRE record. This might be too hackish of a
21077c478bd9Sstevel@tonic-gate * solution.
21087c478bd9Sstevel@tonic-gate */
2109f4b3ec61Sdh155122 if (allreg && keystack->keystack_num_extended > 0)
21107c478bd9Sstevel@tonic-gate err = 0;
21117c478bd9Sstevel@tonic-gate break;
21127c478bd9Sstevel@tonic-gate case SADB_X_PROMISC:
21137c478bd9Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE:
21147c478bd9Sstevel@tonic-gate case SADB_DUMP:
21157c478bd9Sstevel@tonic-gate case SADB_GET:
21167c478bd9Sstevel@tonic-gate default:
21177c478bd9Sstevel@tonic-gate /*
21187c478bd9Sstevel@tonic-gate * Deliver to the sender and promiscuous only.
21197c478bd9Sstevel@tonic-gate */
2120f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering sender/promisc only (%d).\n",
21217c478bd9Sstevel@tonic-gate samsg->sadb_msg_type));
21227c478bd9Sstevel@tonic-gate break;
21237c478bd9Sstevel@tonic-gate }
21247c478bd9Sstevel@tonic-gate
2125f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock);
2126f4b3ec61Sdh155122 for (ks = keystack->keystack_list; ks != NULL; ks = ks->keysock_next) {
21277c478bd9Sstevel@tonic-gate /* Delivery loop. */
21287c478bd9Sstevel@tonic-gate
21297c478bd9Sstevel@tonic-gate /*
21307c478bd9Sstevel@tonic-gate * Check special keysock-setting cases (REGISTER replies)
21317c478bd9Sstevel@tonic-gate * here.
21327c478bd9Sstevel@tonic-gate */
21337c478bd9Sstevel@tonic-gate if (setalg && serial == ks->keysock_serial) {
21347c478bd9Sstevel@tonic-gate ASSERT(kc != NULL);
21357c478bd9Sstevel@tonic-gate ASSERT(kc->kc_sa_type == satype);
21367c478bd9Sstevel@tonic-gate KEYSOCK_SETREG(ks, satype);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate /*
21407c478bd9Sstevel@tonic-gate * NOLOOP takes precedence over PROMISC. So if you've set
21417c478bd9Sstevel@tonic-gate * !SO_USELOOPBACK, don't expect to see any data...
21427c478bd9Sstevel@tonic-gate */
21437c478bd9Sstevel@tonic-gate if (ks->keysock_flags & KEYSOCK_NOLOOP)
21447c478bd9Sstevel@tonic-gate continue;
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate /*
21477c478bd9Sstevel@tonic-gate * Messages to all, or promiscuous sockets just GET the
21487c478bd9Sstevel@tonic-gate * message. Perform rules-type checking iff it's not for all
21497c478bd9Sstevel@tonic-gate * listeners or the socket is in promiscuous mode.
21507c478bd9Sstevel@tonic-gate *
21517c478bd9Sstevel@tonic-gate * NOTE:Because of the (kc != NULL && ISREG()), make sure
21527c478bd9Sstevel@tonic-gate * extended ACQUIREs arrive off a consumer that is
21537c478bd9Sstevel@tonic-gate * part of the extended REGISTER set of consumers.
21547c478bd9Sstevel@tonic-gate */
21557c478bd9Sstevel@tonic-gate if (serial != ks->keysock_serial &&
21567c478bd9Sstevel@tonic-gate !toall &&
21577c478bd9Sstevel@tonic-gate !(ks->keysock_flags & KEYSOCK_PROMISC) &&
21587c478bd9Sstevel@tonic-gate !((ks->keysock_flags & KEYSOCK_EXTENDED) ?
21597c478bd9Sstevel@tonic-gate allereg : allreg && kc != NULL &&
21607c478bd9Sstevel@tonic-gate KEYSOCK_ISREG(ks, kc->kc_sa_type)))
21617c478bd9Sstevel@tonic-gate continue;
21627c478bd9Sstevel@tonic-gate
21637c478bd9Sstevel@tonic-gate mp1 = dupmsg(mp);
21647c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
2165f4b3ec61Sdh155122 ks2dbg(keystack, (
21667c478bd9Sstevel@tonic-gate "keysock_passup(): dupmsg() failed.\n"));
21677c478bd9Sstevel@tonic-gate mp1 = mp;
21687c478bd9Sstevel@tonic-gate mp = NULL;
21697c478bd9Sstevel@tonic-gate err = ENOMEM;
21707c478bd9Sstevel@tonic-gate }
21717c478bd9Sstevel@tonic-gate
21727c478bd9Sstevel@tonic-gate /*
21737c478bd9Sstevel@tonic-gate * At this point, we can deliver or attempt to deliver
21747c478bd9Sstevel@tonic-gate * this message. We're free of obligation to report
21757c478bd9Sstevel@tonic-gate * no listening PF_KEY sockets. So set err to 0.
21767c478bd9Sstevel@tonic-gate */
21777c478bd9Sstevel@tonic-gate err = 0;
21787c478bd9Sstevel@tonic-gate
21797c478bd9Sstevel@tonic-gate /*
21807c478bd9Sstevel@tonic-gate * See if we canputnext(), as well as see if the message
21817c478bd9Sstevel@tonic-gate * needs to be queued if we can't.
21827c478bd9Sstevel@tonic-gate */
21837c478bd9Sstevel@tonic-gate if (!canputnext(ks->keysock_rq)) {
21847c478bd9Sstevel@tonic-gate if (persistent) {
21857c478bd9Sstevel@tonic-gate if (putq(ks->keysock_rq, mp1) == 0) {
2186f4b3ec61Sdh155122 ks1dbg(keystack, (
21877c478bd9Sstevel@tonic-gate "keysock_passup: putq failed.\n"));
21887c478bd9Sstevel@tonic-gate } else {
21897c478bd9Sstevel@tonic-gate continue;
21907c478bd9Sstevel@tonic-gate }
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate freemsg(mp1);
21937c478bd9Sstevel@tonic-gate continue;
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate
2196f4b3ec61Sdh155122 ks3dbg(keystack,
2197f4b3ec61Sdh155122 ("Putting to serial %d.\n", ks->keysock_serial));
21987c478bd9Sstevel@tonic-gate /*
21997c478bd9Sstevel@tonic-gate * Unlike the specific keysock instance case, this
22007c478bd9Sstevel@tonic-gate * will only hit for listeners, so we will only
22017c478bd9Sstevel@tonic-gate * putnext() if we can.
22027c478bd9Sstevel@tonic-gate */
22037c478bd9Sstevel@tonic-gate putnext(ks->keysock_rq, mp1);
22047c478bd9Sstevel@tonic-gate if (mp == NULL)
22057c478bd9Sstevel@tonic-gate break; /* out of for loop. */
22067c478bd9Sstevel@tonic-gate }
2207f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock);
22087c478bd9Sstevel@tonic-gate
22097c478bd9Sstevel@tonic-gate error:
22107c478bd9Sstevel@tonic-gate if ((err != 0) && (kc != NULL)) {
22117c478bd9Sstevel@tonic-gate /*
22127c478bd9Sstevel@tonic-gate * Generate KEYSOCK_OUT_ERR for consumer.
22137c478bd9Sstevel@tonic-gate * Basically, I send this back if I have not been able to
22147c478bd9Sstevel@tonic-gate * transmit (for whatever reason)
22157c478bd9Sstevel@tonic-gate */
2216f4b3ec61Sdh155122 ks1dbg(keystack,
2217f4b3ec61Sdh155122 ("keysock_passup(): No registered of type %d.\n",
22187c478bd9Sstevel@tonic-gate satype));
22197c478bd9Sstevel@tonic-gate if (mp != NULL) {
22207c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_PROTO) {
22217c478bd9Sstevel@tonic-gate mp1 = mp;
22227c478bd9Sstevel@tonic-gate mp = mp->b_cont;
22237c478bd9Sstevel@tonic-gate freeb(mp1);
22247c478bd9Sstevel@tonic-gate }
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate * Do a copymsg() because people who get
22277c478bd9Sstevel@tonic-gate * KEYSOCK_OUT_ERR may alter the message contents.
22287c478bd9Sstevel@tonic-gate */
22297c478bd9Sstevel@tonic-gate mp1 = copymsg(mp);
22307c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
2231f4b3ec61Sdh155122 ks2dbg(keystack,
2232f4b3ec61Sdh155122 ("keysock_passup: copymsg() failed.\n"));
22337c478bd9Sstevel@tonic-gate mp1 = mp;
22347c478bd9Sstevel@tonic-gate mp = NULL;
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate keysock_out_err(kc, err, mp1);
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate }
22397c478bd9Sstevel@tonic-gate
22407c478bd9Sstevel@tonic-gate /*
22417c478bd9Sstevel@tonic-gate * XXX Blank the message somehow. This is difficult because we don't
22427c478bd9Sstevel@tonic-gate * know at this point if the message has db_ref > 1, etc.
22437c478bd9Sstevel@tonic-gate *
22447c478bd9Sstevel@tonic-gate * Optimally, keysock messages containing actual keying material would
22457c478bd9Sstevel@tonic-gate * be allocated with esballoc(), with a zeroing free function.
22467c478bd9Sstevel@tonic-gate */
22477c478bd9Sstevel@tonic-gate if (mp != NULL)
22487c478bd9Sstevel@tonic-gate freemsg(mp);
22497c478bd9Sstevel@tonic-gate }
22507c478bd9Sstevel@tonic-gate
22517c478bd9Sstevel@tonic-gate /*
22527c478bd9Sstevel@tonic-gate * Keysock's read service procedure is there only for PF_KEY reply
22537c478bd9Sstevel@tonic-gate * messages that really need to reach the top.
22547c478bd9Sstevel@tonic-gate */
22557c478bd9Sstevel@tonic-gate static void
keysock_rsrv(queue_t * q)22567c478bd9Sstevel@tonic-gate keysock_rsrv(queue_t *q)
22577c478bd9Sstevel@tonic-gate {
22587c478bd9Sstevel@tonic-gate mblk_t *mp;
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
22617c478bd9Sstevel@tonic-gate if (canputnext(q)) {
22627c478bd9Sstevel@tonic-gate putnext(q, mp);
22637c478bd9Sstevel@tonic-gate } else {
22647c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
22657c478bd9Sstevel@tonic-gate return;
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate /*
22717c478bd9Sstevel@tonic-gate * The read procedure should only be invoked by a keysock consumer, like
22727c478bd9Sstevel@tonic-gate * ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK
22737c478bd9Sstevel@tonic-gate * messages on my read queues.
22747c478bd9Sstevel@tonic-gate */
22757c478bd9Sstevel@tonic-gate static void
keysock_rput(queue_t * q,mblk_t * mp)22767c478bd9Sstevel@tonic-gate keysock_rput(queue_t *q, mblk_t *mp)
22777c478bd9Sstevel@tonic-gate {
22787c478bd9Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr;
22797c478bd9Sstevel@tonic-gate ipsec_info_t *ii;
22807c478bd9Sstevel@tonic-gate keysock_hello_ack_t *ksa;
22817c478bd9Sstevel@tonic-gate minor_t serial;
22827c478bd9Sstevel@tonic-gate mblk_t *mp1;
22837c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
2284f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack;
22857c478bd9Sstevel@tonic-gate
22867c478bd9Sstevel@tonic-gate /* Make sure I'm a consumer instance. (i.e. something's below me) */
22877c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL);
22887c478bd9Sstevel@tonic-gate
22897c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type != M_CTL) {
22907c478bd9Sstevel@tonic-gate /*
22917c478bd9Sstevel@tonic-gate * Keysock should only see keysock consumer interface
22927c478bd9Sstevel@tonic-gate * messages (see ipsec_info.h) on its read procedure.
22937c478bd9Sstevel@tonic-gate * To be robust, however, putnext() up so the STREAM head can
22947c478bd9Sstevel@tonic-gate * deal with it appropriately.
22957c478bd9Sstevel@tonic-gate */
2296f4b3ec61Sdh155122 ks1dbg(keystack,
2297f4b3ec61Sdh155122 ("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n",
22987c478bd9Sstevel@tonic-gate mp->b_datap->db_type, mp->b_datap->db_type));
22997c478bd9Sstevel@tonic-gate putnext(q, mp);
23007c478bd9Sstevel@tonic-gate return;
23017c478bd9Sstevel@tonic-gate }
23027c478bd9Sstevel@tonic-gate
23037c478bd9Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr;
23047c478bd9Sstevel@tonic-gate
23057c478bd9Sstevel@tonic-gate switch (ii->ipsec_info_type) {
23067c478bd9Sstevel@tonic-gate case KEYSOCK_OUT:
23077c478bd9Sstevel@tonic-gate /*
23087c478bd9Sstevel@tonic-gate * A consumer needs to pass a response message or an ACQUIRE
23097c478bd9Sstevel@tonic-gate * UP. I assume that the consumer has done the right
23107c478bd9Sstevel@tonic-gate * thing w.r.t. message creation, etc.
23117c478bd9Sstevel@tonic-gate */
23127c478bd9Sstevel@tonic-gate serial = ((keysock_out_t *)mp->b_rptr)->ks_out_serial;
23137c478bd9Sstevel@tonic-gate mp1 = mp->b_cont; /* Get M_DATA portion. */
23147c478bd9Sstevel@tonic-gate freeb(mp);
23157c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp1->b_rptr;
23167c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_FLUSH ||
23177c478bd9Sstevel@tonic-gate (samsg->sadb_msg_type == SADB_DUMP &&
23187c478bd9Sstevel@tonic-gate samsg->sadb_msg_len == SADB_8TO64(sizeof (*samsg)))) {
23197c478bd9Sstevel@tonic-gate /*
23207c478bd9Sstevel@tonic-gate * If I'm an end-of-FLUSH or an end-of-DUMP marker...
23217c478bd9Sstevel@tonic-gate */
2322f4b3ec61Sdh155122 ASSERT(keystack->keystack_flushdump != 0);
2323f4b3ec61Sdh155122 /* Am I flushing? */
23247c478bd9Sstevel@tonic-gate
23257c478bd9Sstevel@tonic-gate mutex_enter(&kc->kc_lock);
23267c478bd9Sstevel@tonic-gate kc->kc_flags &= ~KC_FLUSHING;
23277c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock);
23287c478bd9Sstevel@tonic-gate
23297c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0)
2330f4b3ec61Sdh155122 keystack->keystack_flushdump_errno =
2331f4b3ec61Sdh155122 samsg->sadb_msg_errno;
23327c478bd9Sstevel@tonic-gate
23337c478bd9Sstevel@tonic-gate /*
23347c478bd9Sstevel@tonic-gate * Lower the atomic "flushing" count. If it's
23357c478bd9Sstevel@tonic-gate * the last one, send up the end-of-{FLUSH,DUMP} to
23367c478bd9Sstevel@tonic-gate * the appropriate PF_KEY socket.
23377c478bd9Sstevel@tonic-gate */
2338*1a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&keystack->keystack_flushdump) !=
2339*1a5e258fSJosef 'Jeff' Sipek 0) {
2340f4b3ec61Sdh155122 ks1dbg(keystack,
2341f4b3ec61Sdh155122 ("One flush/dump message back from %d,"
23427c478bd9Sstevel@tonic-gate " more to go.\n", samsg->sadb_msg_satype));
23437c478bd9Sstevel@tonic-gate freemsg(mp1);
23447c478bd9Sstevel@tonic-gate return;
23457c478bd9Sstevel@tonic-gate }
23467c478bd9Sstevel@tonic-gate
23477c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno =
2348f4b3ec61Sdh155122 (uint8_t)keystack->keystack_flushdump_errno;
23497c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_DUMP) {
23507c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = 0;
23517c478bd9Sstevel@tonic-gate }
23527c478bd9Sstevel@tonic-gate }
23537c478bd9Sstevel@tonic-gate keysock_passup(mp1, samsg, serial, kc,
2354f4b3ec61Sdh155122 (samsg->sadb_msg_type == SADB_DUMP), keystack);
23557c478bd9Sstevel@tonic-gate return;
23567c478bd9Sstevel@tonic-gate case KEYSOCK_HELLO_ACK:
23577c478bd9Sstevel@tonic-gate /* Aha, now we can link in the consumer! */
23587c478bd9Sstevel@tonic-gate ksa = (keysock_hello_ack_t *)ii;
23597c478bd9Sstevel@tonic-gate keysock_link_consumer(ksa->ks_hello_satype, kc);
23607c478bd9Sstevel@tonic-gate freemsg(mp);
23617c478bd9Sstevel@tonic-gate return;
23627c478bd9Sstevel@tonic-gate default:
2363f4b3ec61Sdh155122 ks1dbg(keystack, ("Hmmm, an IPsec info I'm not used to, 0x%x\n",
23647c478bd9Sstevel@tonic-gate ii->ipsec_info_type));
23657c478bd9Sstevel@tonic-gate putnext(q, mp);
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate }
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate /*
23707c478bd9Sstevel@tonic-gate * So we can avoid external linking problems....
23717c478bd9Sstevel@tonic-gate */
23727c478bd9Sstevel@tonic-gate boolean_t
keysock_extended_reg(netstack_t * ns)2373f4b3ec61Sdh155122 keysock_extended_reg(netstack_t *ns)
23747c478bd9Sstevel@tonic-gate {
2375f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock;
2376f4b3ec61Sdh155122
2377f4b3ec61Sdh155122 return (keystack->keystack_num_extended != 0);
23787c478bd9Sstevel@tonic-gate }
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate uint32_t
keysock_next_seq(netstack_t * ns)2381f4b3ec61Sdh155122 keysock_next_seq(netstack_t *ns)
23827c478bd9Sstevel@tonic-gate {
2383f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock;
2384f4b3ec61Sdh155122
2385*1a5e258fSJosef 'Jeff' Sipek return (atomic_dec_32_nv(&keystack->keystack_acquire_seq));
23867c478bd9Sstevel@tonic-gate }
2387