10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52470Sgt29601 * Common Development and Distribution License (the "License").
62470Sgt29601 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11539SChunli.Zhang@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate * Kernel RPC filtering module
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stream.h>
370Sstevel@tonic-gate #include <sys/stropts.h>
388778SErik.Nordmark@Sun.COM #include <sys/strsubr.h>
390Sstevel@tonic-gate #include <sys/tihdr.h>
400Sstevel@tonic-gate #include <sys/timod.h>
410Sstevel@tonic-gate #include <sys/tiuser.h>
420Sstevel@tonic-gate #include <sys/debug.h>
430Sstevel@tonic-gate #include <sys/signal.h>
440Sstevel@tonic-gate #include <sys/pcb.h>
450Sstevel@tonic-gate #include <sys/user.h>
460Sstevel@tonic-gate #include <sys/errno.h>
470Sstevel@tonic-gate #include <sys/cred.h>
480Sstevel@tonic-gate #include <sys/policy.h>
490Sstevel@tonic-gate #include <sys/inline.h>
500Sstevel@tonic-gate #include <sys/cmn_err.h>
510Sstevel@tonic-gate #include <sys/kmem.h>
520Sstevel@tonic-gate #include <sys/file.h>
530Sstevel@tonic-gate #include <sys/sysmacros.h>
540Sstevel@tonic-gate #include <sys/systm.h>
550Sstevel@tonic-gate #include <sys/t_lock.h>
560Sstevel@tonic-gate #include <sys/ddi.h>
570Sstevel@tonic-gate #include <sys/vtrace.h>
580Sstevel@tonic-gate #include <sys/callb.h>
595444Smeem #include <sys/strsun.h>
600Sstevel@tonic-gate
610Sstevel@tonic-gate #include <sys/strlog.h>
620Sstevel@tonic-gate #include <rpc/rpc_com.h>
630Sstevel@tonic-gate #include <inet/common.h>
640Sstevel@tonic-gate #include <rpc/types.h>
650Sstevel@tonic-gate #include <sys/time.h>
660Sstevel@tonic-gate #include <rpc/xdr.h>
670Sstevel@tonic-gate #include <rpc/auth.h>
680Sstevel@tonic-gate #include <rpc/clnt.h>
690Sstevel@tonic-gate #include <rpc/rpc_msg.h>
700Sstevel@tonic-gate #include <rpc/clnt.h>
710Sstevel@tonic-gate #include <rpc/svc.h>
720Sstevel@tonic-gate #include <rpc/rpcsys.h>
730Sstevel@tonic-gate #include <rpc/rpc_rdma.h>
740Sstevel@tonic-gate
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * This is the loadable module wrapper.
770Sstevel@tonic-gate */
780Sstevel@tonic-gate #include <sys/conf.h>
790Sstevel@tonic-gate #include <sys/modctl.h>
800Sstevel@tonic-gate #include <sys/syscall.h>
810Sstevel@tonic-gate
820Sstevel@tonic-gate extern struct streamtab rpcinfo;
830Sstevel@tonic-gate
840Sstevel@tonic-gate static struct fmodsw fsw = {
850Sstevel@tonic-gate "rpcmod",
860Sstevel@tonic-gate &rpcinfo,
870Sstevel@tonic-gate D_NEW|D_MP,
880Sstevel@tonic-gate };
890Sstevel@tonic-gate
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate * Module linkage information for the kernel.
920Sstevel@tonic-gate */
930Sstevel@tonic-gate
940Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
950Sstevel@tonic-gate &mod_strmodops, "rpc interface str mod", &fsw
960Sstevel@tonic-gate };
970Sstevel@tonic-gate
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate * For the RPC system call.
1000Sstevel@tonic-gate */
1010Sstevel@tonic-gate static struct sysent rpcsysent = {
1020Sstevel@tonic-gate 2,
1030Sstevel@tonic-gate SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
1040Sstevel@tonic-gate rpcsys
1050Sstevel@tonic-gate };
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate static struct modlsys modlsys = {
1080Sstevel@tonic-gate &mod_syscallops,
1090Sstevel@tonic-gate "RPC syscall",
1100Sstevel@tonic-gate &rpcsysent
1110Sstevel@tonic-gate };
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1140Sstevel@tonic-gate static struct modlsys modlsys32 = {
1150Sstevel@tonic-gate &mod_syscallops32,
1160Sstevel@tonic-gate "32-bit RPC syscall",
1170Sstevel@tonic-gate &rpcsysent
1180Sstevel@tonic-gate };
1190Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static struct modlinkage modlinkage = {
1220Sstevel@tonic-gate MODREV_1,
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate &modlsys,
1250Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1260Sstevel@tonic-gate &modlsys32,
1270Sstevel@tonic-gate #endif
1280Sstevel@tonic-gate &modlstrmod,
1290Sstevel@tonic-gate NULL
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate };
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate int
_init(void)1340Sstevel@tonic-gate _init(void)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate int error = 0;
1370Sstevel@tonic-gate callb_id_t cid;
1380Sstevel@tonic-gate int status;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate svc_init();
1410Sstevel@tonic-gate clnt_init();
1420Sstevel@tonic-gate cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc");
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate if (error = mod_install(&modlinkage)) {
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate * Could not install module, cleanup previous
1470Sstevel@tonic-gate * initialization work.
1480Sstevel@tonic-gate */
1490Sstevel@tonic-gate clnt_fini();
1500Sstevel@tonic-gate if (cid != NULL)
1510Sstevel@tonic-gate (void) callb_delete(cid);
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate return (error);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate * Load up the RDMA plugins and initialize the stats. Even if the
1580Sstevel@tonic-gate * plugins loadup fails, but rpcmod was successfully installed the
1590Sstevel@tonic-gate * counters still get initialized.
1600Sstevel@tonic-gate */
1610Sstevel@tonic-gate rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL);
1620Sstevel@tonic-gate mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL);
1638695SRajkumar.Sivaprakasam@Sun.COM
1648695SRajkumar.Sivaprakasam@Sun.COM cv_init(&rdma_wait.svc_cv, NULL, CV_DEFAULT, NULL);
1658695SRajkumar.Sivaprakasam@Sun.COM mutex_init(&rdma_wait.svc_lock, NULL, MUTEX_DEFAULT, NULL);
1668695SRajkumar.Sivaprakasam@Sun.COM
1670Sstevel@tonic-gate mt_kstat_init();
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * Get our identification into ldi. This is used for loading
1710Sstevel@tonic-gate * other modules, e.g. rpcib.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate status = ldi_ident_from_mod(&modlinkage, &rpcmod_li);
1740Sstevel@tonic-gate if (status != 0) {
1750Sstevel@tonic-gate cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status);
1760Sstevel@tonic-gate rpcmod_li = NULL;
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate return (error);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate * The unload entry point fails, because we advertise entry points into
1840Sstevel@tonic-gate * rpcmod from the rest of kRPC: rpcmod_release().
1850Sstevel@tonic-gate */
1860Sstevel@tonic-gate int
_fini(void)1870Sstevel@tonic-gate _fini(void)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate return (EBUSY);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1930Sstevel@tonic-gate _info(struct modinfo *modinfop)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate extern int nulldev();
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate #define RPCMOD_ID 2049
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate int rmm_open(), rmm_close();
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value
2060Sstevel@tonic-gate * from these functions, they are defined as void here. Kind of icky, but...
2070Sstevel@tonic-gate */
2080Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *);
2090Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *);
2100Sstevel@tonic-gate void rmm_rsrv(queue_t *);
2110Sstevel@tonic-gate void rmm_wsrv(queue_t *);
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate int rpcmodopen(), rpcmodclose();
2140Sstevel@tonic-gate void rpcmodrput(), rpcmodwput();
2150Sstevel@tonic-gate void rpcmodrsrv(), rpcmodwsrv();
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate static void rpcmodwput_other(queue_t *, mblk_t *);
2180Sstevel@tonic-gate static int mir_close(queue_t *q);
2190Sstevel@tonic-gate static int mir_open(queue_t *q, dev_t *devp, int flag, int sflag,
2200Sstevel@tonic-gate cred_t *credp);
2210Sstevel@tonic-gate static void mir_rput(queue_t *q, mblk_t *mp);
2220Sstevel@tonic-gate static void mir_rsrv(queue_t *q);
2230Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp);
2240Sstevel@tonic-gate static void mir_wsrv(queue_t *q);
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate static struct module_info rpcmod_info =
2270Sstevel@tonic-gate {RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024};
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate * Read side has no service procedure.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate static struct qinit rpcmodrinit = {
2330Sstevel@tonic-gate (int (*)())rmm_rput,
2340Sstevel@tonic-gate (int (*)())rmm_rsrv,
2350Sstevel@tonic-gate rmm_open,
2360Sstevel@tonic-gate rmm_close,
2370Sstevel@tonic-gate nulldev,
2380Sstevel@tonic-gate &rpcmod_info,
2390Sstevel@tonic-gate NULL
2400Sstevel@tonic-gate };
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /*
2430Sstevel@tonic-gate * The write put procedure is simply putnext to conserve stack space.
2440Sstevel@tonic-gate * The write service procedure is not used to queue data, but instead to
2450Sstevel@tonic-gate * synchronize with flow control.
2460Sstevel@tonic-gate */
2470Sstevel@tonic-gate static struct qinit rpcmodwinit = {
2480Sstevel@tonic-gate (int (*)())rmm_wput,
2490Sstevel@tonic-gate (int (*)())rmm_wsrv,
2500Sstevel@tonic-gate rmm_open,
2510Sstevel@tonic-gate rmm_close,
2520Sstevel@tonic-gate nulldev,
2530Sstevel@tonic-gate &rpcmod_info,
2540Sstevel@tonic-gate NULL
2550Sstevel@tonic-gate };
2560Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL };
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate struct xprt_style_ops {
2590Sstevel@tonic-gate int (*xo_open)();
2600Sstevel@tonic-gate int (*xo_close)();
2610Sstevel@tonic-gate void (*xo_wput)();
2620Sstevel@tonic-gate void (*xo_wsrv)();
2630Sstevel@tonic-gate void (*xo_rput)();
2640Sstevel@tonic-gate void (*xo_rsrv)();
2650Sstevel@tonic-gate };
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = {
2680Sstevel@tonic-gate rpcmodopen,
2690Sstevel@tonic-gate rpcmodclose,
2700Sstevel@tonic-gate rpcmodwput,
2710Sstevel@tonic-gate rpcmodwsrv,
2720Sstevel@tonic-gate rpcmodrput,
2730Sstevel@tonic-gate NULL
2740Sstevel@tonic-gate };
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = {
2770Sstevel@tonic-gate mir_open,
2780Sstevel@tonic-gate mir_close,
2790Sstevel@tonic-gate mir_wput,
2800Sstevel@tonic-gate mir_wsrv,
2810Sstevel@tonic-gate mir_rput,
2820Sstevel@tonic-gate mir_rsrv
2830Sstevel@tonic-gate };
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Per rpcmod "slot" data structure. q->q_ptr points to one of these.
2870Sstevel@tonic-gate */
2880Sstevel@tonic-gate struct rpcm {
2890Sstevel@tonic-gate void *rm_krpc_cell; /* Reserved for use by KRPC */
2900Sstevel@tonic-gate struct xprt_style_ops *rm_ops;
2910Sstevel@tonic-gate int rm_type; /* Client or server side stream */
2920Sstevel@tonic-gate #define RM_CLOSING 0x1 /* somebody is trying to close slot */
2930Sstevel@tonic-gate uint_t rm_state; /* state of the slot. see above */
2940Sstevel@tonic-gate uint_t rm_ref; /* cnt of external references to slot */
2950Sstevel@tonic-gate kmutex_t rm_lock; /* mutex protecting above fields */
2960Sstevel@tonic-gate kcondvar_t rm_cwait; /* condition for closing */
2970Sstevel@tonic-gate zoneid_t rm_zoneid; /* zone which pushed rpcmod */
2980Sstevel@tonic-gate };
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate struct temp_slot {
3010Sstevel@tonic-gate void *cell;
3020Sstevel@tonic-gate struct xprt_style_ops *ops;
3030Sstevel@tonic-gate int type;
3040Sstevel@tonic-gate mblk_t *info_ack;
3050Sstevel@tonic-gate kmutex_t lock;
3060Sstevel@tonic-gate kcondvar_t wait;
3070Sstevel@tonic-gate };
3080Sstevel@tonic-gate
3094386Sgeorges typedef struct mir_s {
3104386Sgeorges void *mir_krpc_cell; /* Reserved for KRPC use. This field */
3114386Sgeorges /* must be first in the structure. */
3124386Sgeorges struct xprt_style_ops *rm_ops;
3134386Sgeorges int mir_type; /* Client or server side stream */
3144386Sgeorges
3154386Sgeorges mblk_t *mir_head_mp; /* RPC msg in progress */
3164386Sgeorges /*
3174386Sgeorges * mir_head_mp points the first mblk being collected in
3184386Sgeorges * the current RPC message. Record headers are removed
3194386Sgeorges * before data is linked into mir_head_mp.
3204386Sgeorges */
3214386Sgeorges mblk_t *mir_tail_mp; /* Last mblk in mir_head_mp */
3224386Sgeorges /*
3234386Sgeorges * mir_tail_mp points to the last mblk in the message
3244386Sgeorges * chain starting at mir_head_mp. It is only valid
3254386Sgeorges * if mir_head_mp is non-NULL and is used to add new
3264386Sgeorges * data blocks to the end of chain quickly.
3274386Sgeorges */
3284386Sgeorges
3294386Sgeorges int32_t mir_frag_len; /* Bytes seen in the current frag */
3304386Sgeorges /*
3314386Sgeorges * mir_frag_len starts at -4 for beginning of each fragment.
3324386Sgeorges * When this length is negative, it indicates the number of
3334386Sgeorges * bytes that rpcmod needs to complete the record marker
3344386Sgeorges * header. When it is positive or zero, it holds the number
3354386Sgeorges * of bytes that have arrived for the current fragment and
3364386Sgeorges * are held in mir_header_mp.
3374386Sgeorges */
3384386Sgeorges
3394386Sgeorges int32_t mir_frag_header;
3404386Sgeorges /*
3414386Sgeorges * Fragment header as collected for the current fragment.
3424386Sgeorges * It holds the last-fragment indicator and the number
3434386Sgeorges * of bytes in the fragment.
3444386Sgeorges */
3454386Sgeorges
3464386Sgeorges unsigned int
3474386Sgeorges mir_ordrel_pending : 1, /* Sent T_ORDREL_REQ */
3484386Sgeorges mir_hold_inbound : 1, /* Hold inbound messages on server */
3494386Sgeorges /* side until outbound flow control */
3504386Sgeorges /* is relieved. */
3514386Sgeorges mir_closing : 1, /* The stream is being closed */
3524386Sgeorges mir_inrservice : 1, /* data queued or rd srv proc running */
3534386Sgeorges mir_inwservice : 1, /* data queued or wr srv proc running */
3544386Sgeorges mir_inwflushdata : 1, /* flush M_DATAs when srv runs */
3554386Sgeorges /*
3564386Sgeorges * On client streams, mir_clntreq is 0 or 1; it is set
3574386Sgeorges * to 1 whenever a new request is sent out (mir_wput)
3584386Sgeorges * and cleared when the timer fires (mir_timer). If
3594386Sgeorges * the timer fires with this value equal to 0, then the
3604386Sgeorges * stream is considered idle and KRPC is notified.
3614386Sgeorges */
3624386Sgeorges mir_clntreq : 1,
3634386Sgeorges /*
3644386Sgeorges * On server streams, stop accepting messages
3654386Sgeorges */
3664386Sgeorges mir_svc_no_more_msgs : 1,
3674386Sgeorges mir_listen_stream : 1, /* listen end point */
3684386Sgeorges mir_unused : 1, /* no longer used */
3694386Sgeorges mir_timer_call : 1,
3704386Sgeorges mir_junk_fill_thru_bit_31 : 21;
3714386Sgeorges
3724386Sgeorges int mir_setup_complete; /* server has initialized everything */
3734386Sgeorges timeout_id_t mir_timer_id; /* Timer for idle checks */
3744386Sgeorges clock_t mir_idle_timeout; /* Allowed idle time before shutdown */
3754386Sgeorges /*
3764386Sgeorges * This value is copied from clnt_idle_timeout or
3774386Sgeorges * svc_idle_timeout during the appropriate ioctl.
3784386Sgeorges * Kept in milliseconds
3794386Sgeorges */
3804386Sgeorges clock_t mir_use_timestamp; /* updated on client with each use */
3814386Sgeorges /*
3824386Sgeorges * This value is set to lbolt
3834386Sgeorges * every time a client stream sends or receives data.
3844386Sgeorges * Even if the timer message arrives, we don't shutdown
3854386Sgeorges * client unless:
3864386Sgeorges * lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp.
3874386Sgeorges * This value is kept in HZ.
3884386Sgeorges */
3894386Sgeorges
3904386Sgeorges uint_t *mir_max_msg_sizep; /* Reference to sanity check size */
3914386Sgeorges /*
3924386Sgeorges * This pointer is set to &clnt_max_msg_size or
3934386Sgeorges * &svc_max_msg_size during the appropriate ioctl.
3944386Sgeorges */
3954386Sgeorges zoneid_t mir_zoneid; /* zone which pushed rpcmod */
3964386Sgeorges /* Server-side fields. */
3974386Sgeorges int mir_ref_cnt; /* Reference count: server side only */
3984386Sgeorges /* counts the number of references */
3994386Sgeorges /* that a kernel RPC server thread */
4004386Sgeorges /* (see svc_run()) has on this rpcmod */
4014386Sgeorges /* slot. Effectively, it is the */
4024386Sgeorges /* number * of unprocessed messages */
4034386Sgeorges /* that have been passed up to the */
4044386Sgeorges /* KRPC layer */
4054386Sgeorges
4064386Sgeorges mblk_t *mir_svc_pend_mp; /* Pending T_ORDREL_IND or */
4074386Sgeorges /* T_DISCON_IND */
4084386Sgeorges
4094386Sgeorges /*
4104386Sgeorges * these fields are for both client and server, but for debugging,
4114386Sgeorges * it is easier to have these last in the structure.
4124386Sgeorges */
4134386Sgeorges kmutex_t mir_mutex; /* Mutex and condvar for close */
4144386Sgeorges kcondvar_t mir_condvar; /* synchronization. */
4154386Sgeorges kcondvar_t mir_timer_cv; /* Timer routine sync. */
4164386Sgeorges } mir_t;
4174386Sgeorges
4180Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp);
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate struct xprt_style_ops tmpops = {
4210Sstevel@tonic-gate NULL,
4220Sstevel@tonic-gate NULL,
4230Sstevel@tonic-gate putnext,
4240Sstevel@tonic-gate NULL,
4250Sstevel@tonic-gate tmp_rput,
4260Sstevel@tonic-gate NULL
4270Sstevel@tonic-gate };
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate void
tmp_rput(queue_t * q,mblk_t * mp)4300Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate struct temp_slot *t = (struct temp_slot *)(q->q_ptr);
4330Sstevel@tonic-gate struct T_info_ack *pptr;
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate switch (mp->b_datap->db_type) {
4360Sstevel@tonic-gate case M_PCPROTO:
4370Sstevel@tonic-gate pptr = (struct T_info_ack *)mp->b_rptr;
4380Sstevel@tonic-gate switch (pptr->PRIM_type) {
4390Sstevel@tonic-gate case T_INFO_ACK:
4400Sstevel@tonic-gate mutex_enter(&t->lock);
4410Sstevel@tonic-gate t->info_ack = mp;
4420Sstevel@tonic-gate cv_signal(&t->wait);
4430Sstevel@tonic-gate mutex_exit(&t->lock);
4440Sstevel@tonic-gate return;
4450Sstevel@tonic-gate default:
4460Sstevel@tonic-gate break;
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate default:
4490Sstevel@tonic-gate break;
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate /*
4530Sstevel@tonic-gate * Not an info-ack, so free it. This is ok because we should
4540Sstevel@tonic-gate * not be receiving data until the open finishes: rpcmod
4550Sstevel@tonic-gate * is pushed well before the end-point is bound to an address.
4560Sstevel@tonic-gate */
4570Sstevel@tonic-gate freemsg(mp);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate int
rmm_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)4610Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate mblk_t *bp;
4640Sstevel@tonic-gate struct temp_slot ts, *t;
4650Sstevel@tonic-gate struct T_info_ack *pptr;
4660Sstevel@tonic-gate int error = 0;
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate ASSERT(q != NULL);
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * Check for re-opens.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate if (q->q_ptr) {
4730Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END,
4740Sstevel@tonic-gate "rpcmodopen_end:(%s)", "q->qptr");
4750Sstevel@tonic-gate return (0);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate t = &ts;
4790Sstevel@tonic-gate bzero(t, sizeof (*t));
4800Sstevel@tonic-gate q->q_ptr = (void *)t;
4814386Sgeorges WR(q)->q_ptr = (void *)t;
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate /*
4840Sstevel@tonic-gate * Allocate the required messages upfront.
4850Sstevel@tonic-gate */
4868778SErik.Nordmark@Sun.COM if ((bp = allocb_cred(sizeof (struct T_info_req) +
4878778SErik.Nordmark@Sun.COM sizeof (struct T_info_ack), crp, curproc->p_pid)) == NULL) {
4880Sstevel@tonic-gate return (ENOBUFS);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL);
4920Sstevel@tonic-gate cv_init(&t->wait, NULL, CV_DEFAULT, NULL);
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate t->ops = &tmpops;
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate qprocson(q);
4970Sstevel@tonic-gate bp->b_datap->db_type = M_PCPROTO;
4980Sstevel@tonic-gate *(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ;
4990Sstevel@tonic-gate bp->b_wptr += sizeof (struct T_info_req);
5000Sstevel@tonic-gate putnext(WR(q), bp);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate mutex_enter(&t->lock);
5034386Sgeorges while (t->info_ack == NULL) {
5040Sstevel@tonic-gate if (cv_wait_sig(&t->wait, &t->lock) == 0) {
5050Sstevel@tonic-gate error = EINTR;
5060Sstevel@tonic-gate break;
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate mutex_exit(&t->lock);
5104386Sgeorges
5110Sstevel@tonic-gate if (error)
5120Sstevel@tonic-gate goto out;
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate pptr = (struct T_info_ack *)t->info_ack->b_rptr;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate if (pptr->SERV_type == T_CLTS) {
5174386Sgeorges if ((error = rpcmodopen(q, devp, flag, sflag, crp)) == 0)
5184386Sgeorges ((struct rpcm *)q->q_ptr)->rm_ops = &xprt_clts_ops;
5190Sstevel@tonic-gate } else {
5204386Sgeorges if ((error = mir_open(q, devp, flag, sflag, crp)) == 0)
5214386Sgeorges ((mir_t *)q->q_ptr)->rm_ops = &xprt_cots_ops;
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate out:
5254386Sgeorges if (error)
5260Sstevel@tonic-gate qprocsoff(q);
5270Sstevel@tonic-gate
5284386Sgeorges freemsg(t->info_ack);
5294386Sgeorges mutex_destroy(&t->lock);
5304386Sgeorges cv_destroy(&t->wait);
5314386Sgeorges
5320Sstevel@tonic-gate return (error);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate void
rmm_rput(queue_t * q,mblk_t * mp)5360Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t *mp)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate void
rmm_rsrv(queue_t * q)5420Sstevel@tonic-gate rmm_rsrv(queue_t *q)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q);
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate void
rmm_wput(queue_t * q,mblk_t * mp)5480Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate void
rmm_wsrv(queue_t * q)5540Sstevel@tonic-gate rmm_wsrv(queue_t *q)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate int
rmm_close(queue_t * q,int flag,cred_t * crp)5600Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp));
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate
5659694SScott.Rotondo@Sun.COM static void rpcmod_release(queue_t *, mblk_t *);
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * rpcmodopen - open routine gets called when the module gets pushed
5680Sstevel@tonic-gate * onto the stream.
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate /*ARGSUSED*/
5710Sstevel@tonic-gate int
rpcmodopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)5720Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
5730Sstevel@tonic-gate {
5740Sstevel@tonic-gate struct rpcm *rmp;
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate extern void (*rpc_rele)(queue_t *, mblk_t *);
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:");
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate * Initialize entry points to release a rpcmod slot (and an input
5820Sstevel@tonic-gate * message if supplied) and to send an output message to the module
5830Sstevel@tonic-gate * below rpcmod.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate if (rpc_rele == NULL)
5860Sstevel@tonic-gate rpc_rele = rpcmod_release;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate /*
5890Sstevel@tonic-gate * Only sufficiently privileged users can use this module, and it
5900Sstevel@tonic-gate * is assumed that they will use this module properly, and NOT send
5910Sstevel@tonic-gate * bulk data from downstream.
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate if (secpolicy_rpcmod_open(crp) != 0)
5940Sstevel@tonic-gate return (EPERM);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /*
5970Sstevel@tonic-gate * Allocate slot data structure.
5980Sstevel@tonic-gate */
5990Sstevel@tonic-gate rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP);
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL);
6020Sstevel@tonic-gate cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL);
603766Scarlsonj rmp->rm_zoneid = rpc_zoneid();
6040Sstevel@tonic-gate /*
6050Sstevel@tonic-gate * slot type will be set by kRPC client and server ioctl's
6060Sstevel@tonic-gate */
6070Sstevel@tonic-gate rmp->rm_type = 0;
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate q->q_ptr = (void *)rmp;
6100Sstevel@tonic-gate WR(q)->q_ptr = (void *)rmp;
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end");
6130Sstevel@tonic-gate return (0);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate * rpcmodclose - This routine gets called when the module gets popped
6180Sstevel@tonic-gate * off of the stream.
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate /*ARGSUSED*/
6210Sstevel@tonic-gate int
rpcmodclose(queue_t * q,int flag,cred_t * crp)6220Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate struct rpcm *rmp;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate ASSERT(q != NULL);
6270Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * Mark our state as closing.
6310Sstevel@tonic-gate */
6320Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
6330Sstevel@tonic-gate rmp->rm_state |= RM_CLOSING;
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate /*
6360Sstevel@tonic-gate * Check and see if there are any messages on the queue. If so, send
6370Sstevel@tonic-gate * the messages, regardless whether the downstream module is ready to
6380Sstevel@tonic-gate * accept data.
6390Sstevel@tonic-gate */
6400Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER) {
6410Sstevel@tonic-gate flushq(q, FLUSHDATA);
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate qenable(WR(q));
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate if (rmp->rm_ref) {
6460Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6470Sstevel@tonic-gate /*
6480Sstevel@tonic-gate * call into SVC to clean the queue
6490Sstevel@tonic-gate */
6500Sstevel@tonic-gate svc_queueclean(q);
6510Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate /*
6540Sstevel@tonic-gate * Block while there are kRPC threads with a reference
6550Sstevel@tonic-gate * to this message.
6560Sstevel@tonic-gate */
6570Sstevel@tonic-gate while (rmp->rm_ref)
6580Sstevel@tonic-gate cv_wait(&rmp->rm_cwait, &rmp->rm_lock);
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * It is now safe to remove this queue from the stream. No kRPC
6650Sstevel@tonic-gate * threads have a reference to the stream, and none ever will,
6660Sstevel@tonic-gate * because RM_CLOSING is set.
6670Sstevel@tonic-gate */
6680Sstevel@tonic-gate qprocsoff(q);
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate /* Notify kRPC that this stream is going away. */
6710Sstevel@tonic-gate svc_queueclose(q);
6720Sstevel@tonic-gate } else {
6730Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6740Sstevel@tonic-gate qprocsoff(q);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate q->q_ptr = NULL;
6780Sstevel@tonic-gate WR(q)->q_ptr = NULL;
6790Sstevel@tonic-gate mutex_destroy(&rmp->rm_lock);
6800Sstevel@tonic-gate cv_destroy(&rmp->rm_cwait);
6810Sstevel@tonic-gate kmem_free(rmp, sizeof (*rmp));
6820Sstevel@tonic-gate return (0);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate #ifdef DEBUG
6860Sstevel@tonic-gate int rpcmod_send_msg_up = 0;
6870Sstevel@tonic-gate int rpcmod_send_uderr = 0;
6880Sstevel@tonic-gate int rpcmod_send_dup = 0;
6890Sstevel@tonic-gate int rpcmod_send_dup_cnt = 0;
6900Sstevel@tonic-gate #endif
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate /*
6930Sstevel@tonic-gate * rpcmodrput - Module read put procedure. This is called from
6940Sstevel@tonic-gate * the module, driver, or stream head downstream.
6950Sstevel@tonic-gate */
6960Sstevel@tonic-gate void
rpcmodrput(queue_t * q,mblk_t * mp)6970Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate struct rpcm *rmp;
7000Sstevel@tonic-gate union T_primitives *pptr;
7010Sstevel@tonic-gate int hdrsz;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:");
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate ASSERT(q != NULL);
7060Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate if (rmp->rm_type == 0) {
7090Sstevel@tonic-gate freemsg(mp);
7100Sstevel@tonic-gate return;
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate #ifdef DEBUG
7140Sstevel@tonic-gate if (rpcmod_send_msg_up > 0) {
7150Sstevel@tonic-gate mblk_t *nmp = copymsg(mp);
7160Sstevel@tonic-gate if (nmp) {
7170Sstevel@tonic-gate putnext(q, nmp);
7180Sstevel@tonic-gate rpcmod_send_msg_up--;
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate if ((rpcmod_send_uderr > 0) && mp->b_datap->db_type == M_PROTO) {
7220Sstevel@tonic-gate mblk_t *nmp;
7230Sstevel@tonic-gate struct T_unitdata_ind *data;
7240Sstevel@tonic-gate struct T_uderror_ind *ud;
7250Sstevel@tonic-gate int d;
7260Sstevel@tonic-gate data = (struct T_unitdata_ind *)mp->b_rptr;
7270Sstevel@tonic-gate if (data->PRIM_type == T_UNITDATA_IND) {
7280Sstevel@tonic-gate d = sizeof (*ud) - sizeof (*data);
7290Sstevel@tonic-gate nmp = allocb(mp->b_wptr - mp->b_rptr + d, BPRI_HI);
7300Sstevel@tonic-gate if (nmp) {
7310Sstevel@tonic-gate ud = (struct T_uderror_ind *)nmp->b_rptr;
7320Sstevel@tonic-gate ud->PRIM_type = T_UDERROR_IND;
7330Sstevel@tonic-gate ud->DEST_length = data->SRC_length;
7340Sstevel@tonic-gate ud->DEST_offset = data->SRC_offset + d;
7350Sstevel@tonic-gate ud->OPT_length = data->OPT_length;
7360Sstevel@tonic-gate ud->OPT_offset = data->OPT_offset + d;
7370Sstevel@tonic-gate ud->ERROR_type = ENETDOWN;
7380Sstevel@tonic-gate if (data->SRC_length) {
7390Sstevel@tonic-gate bcopy(mp->b_rptr +
7400Sstevel@tonic-gate data->SRC_offset,
7410Sstevel@tonic-gate nmp->b_rptr +
7420Sstevel@tonic-gate ud->DEST_offset,
7430Sstevel@tonic-gate data->SRC_length);
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate if (data->OPT_length) {
7460Sstevel@tonic-gate bcopy(mp->b_rptr +
7470Sstevel@tonic-gate data->OPT_offset,
7480Sstevel@tonic-gate nmp->b_rptr +
7490Sstevel@tonic-gate ud->OPT_offset,
7500Sstevel@tonic-gate data->OPT_length);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate nmp->b_wptr += d;
7530Sstevel@tonic-gate nmp->b_wptr += (mp->b_wptr - mp->b_rptr);
7540Sstevel@tonic-gate nmp->b_datap->db_type = M_PROTO;
7550Sstevel@tonic-gate putnext(q, nmp);
7560Sstevel@tonic-gate rpcmod_send_uderr--;
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate #endif
7610Sstevel@tonic-gate switch (mp->b_datap->db_type) {
7620Sstevel@tonic-gate default:
7630Sstevel@tonic-gate putnext(q, mp);
7640Sstevel@tonic-gate break;
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate case M_PROTO:
7670Sstevel@tonic-gate case M_PCPROTO:
7680Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t));
7690Sstevel@tonic-gate pptr = (union T_primitives *)mp->b_rptr;
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate * Forward this message to krpc if it is data.
7730Sstevel@tonic-gate */
7740Sstevel@tonic-gate if (pptr->type == T_UNITDATA_IND) {
7754741Sgt29601 mblk_t *nmp;
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate /*
7780Sstevel@tonic-gate * Check if the module is being popped.
7790Sstevel@tonic-gate */
7804741Sgt29601 mutex_enter(&rmp->rm_lock);
7814741Sgt29601 if (rmp->rm_state & RM_CLOSING) {
7824741Sgt29601 mutex_exit(&rmp->rm_lock);
7834741Sgt29601 putnext(q, mp);
7844741Sgt29601 break;
7854741Sgt29601 }
7864741Sgt29601
7874741Sgt29601 switch (rmp->rm_type) {
7884741Sgt29601 case RPC_CLIENT:
7894741Sgt29601 mutex_exit(&rmp->rm_lock);
7904741Sgt29601 hdrsz = mp->b_wptr - mp->b_rptr;
7914741Sgt29601
7924741Sgt29601 /*
7934741Sgt29601 * Make sure the header is sane.
7944741Sgt29601 */
7954741Sgt29601 if (hdrsz < TUNITDATAINDSZ ||
7964741Sgt29601 hdrsz < (pptr->unitdata_ind.OPT_length +
7974741Sgt29601 pptr->unitdata_ind.OPT_offset) ||
7984741Sgt29601 hdrsz < (pptr->unitdata_ind.SRC_length +
7994741Sgt29601 pptr->unitdata_ind.SRC_offset)) {
8004741Sgt29601 freemsg(mp);
8014741Sgt29601 return;
8024741Sgt29601 }
8034741Sgt29601
8044741Sgt29601 /*
8054741Sgt29601 * Call clnt_clts_dispatch_notify, so that it
8064741Sgt29601 * can pass the message to the proper caller.
8074741Sgt29601 * Don't discard the header just yet since the
8084741Sgt29601 * client may need the sender's address.
8094741Sgt29601 */
8104741Sgt29601 clnt_clts_dispatch_notify(mp, hdrsz,
8114741Sgt29601 rmp->rm_zoneid);
8124741Sgt29601 return;
8134741Sgt29601 case RPC_SERVER:
8144741Sgt29601 /*
8154741Sgt29601 * rm_krpc_cell is exclusively used by the kRPC
8164741Sgt29601 * CLTS server
8174741Sgt29601 */
8184741Sgt29601 if (rmp->rm_krpc_cell) {
8194741Sgt29601 #ifdef DEBUG
8204741Sgt29601 /*
8214741Sgt29601 * Test duplicate request cache and
8224741Sgt29601 * rm_ref count handling by sending a
8234741Sgt29601 * duplicate every so often, if
8244741Sgt29601 * desired.
8254741Sgt29601 */
8264741Sgt29601 if (rpcmod_send_dup &&
8274741Sgt29601 rpcmod_send_dup_cnt++ %
8284741Sgt29601 rpcmod_send_dup)
8294741Sgt29601 nmp = copymsg(mp);
8304741Sgt29601 else
8314741Sgt29601 nmp = NULL;
8324741Sgt29601 #endif
8334741Sgt29601 /*
8344741Sgt29601 * Raise the reference count on this
8354741Sgt29601 * module to prevent it from being
8364741Sgt29601 * popped before krpc generates the
8374741Sgt29601 * reply.
8384741Sgt29601 */
8394741Sgt29601 rmp->rm_ref++;
8404741Sgt29601 mutex_exit(&rmp->rm_lock);
8414741Sgt29601
8424741Sgt29601 /*
8434741Sgt29601 * Submit the message to krpc.
8444741Sgt29601 */
8454741Sgt29601 svc_queuereq(q, mp);
8464741Sgt29601 #ifdef DEBUG
8474741Sgt29601 /*
8484741Sgt29601 * Send duplicate if we created one.
8494741Sgt29601 */
8504741Sgt29601 if (nmp) {
8514741Sgt29601 mutex_enter(&rmp->rm_lock);
8524741Sgt29601 rmp->rm_ref++;
8534741Sgt29601 mutex_exit(&rmp->rm_lock);
8544741Sgt29601 svc_queuereq(q, nmp);
8554741Sgt29601 }
8564741Sgt29601 #endif
8574741Sgt29601 } else {
8584741Sgt29601 mutex_exit(&rmp->rm_lock);
8594741Sgt29601 freemsg(mp);
8604741Sgt29601 }
8614741Sgt29601 return;
8624741Sgt29601 default:
8634741Sgt29601 mutex_exit(&rmp->rm_lock);
8644741Sgt29601 freemsg(mp);
8654741Sgt29601 return;
8664741Sgt29601 } /* end switch(rmp->rm_type) */
8674741Sgt29601 } else if (pptr->type == T_UDERROR_IND) {
8684741Sgt29601 mutex_enter(&rmp->rm_lock);
8690Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr;
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate /*
8724741Sgt29601 * Make sure the header is sane
8730Sstevel@tonic-gate */
8744741Sgt29601 if (hdrsz < TUDERRORINDSZ ||
8754741Sgt29601 hdrsz < (pptr->uderror_ind.OPT_length +
8764741Sgt29601 pptr->uderror_ind.OPT_offset) ||
8774741Sgt29601 hdrsz < (pptr->uderror_ind.DEST_length +
8784741Sgt29601 pptr->uderror_ind.DEST_offset)) {
8794741Sgt29601 mutex_exit(&rmp->rm_lock);
8804741Sgt29601 freemsg(mp);
8814741Sgt29601 return;
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate /*
8854741Sgt29601 * In the case where a unit data error has been
8864741Sgt29601 * received, all we need to do is clear the message from
8874741Sgt29601 * the queue.
8880Sstevel@tonic-gate */
8890Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
8900Sstevel@tonic-gate freemsg(mp);
8914741Sgt29601 RPCLOG(32, "rpcmodrput: unitdata error received at "
8924741Sgt29601 "%ld\n", gethrestime_sec());
8930Sstevel@tonic-gate return;
8940Sstevel@tonic-gate } /* end else if (pptr->type == T_UDERROR_IND) */
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate putnext(q, mp);
8970Sstevel@tonic-gate break;
8980Sstevel@tonic-gate } /* end switch (mp->b_datap->db_type) */
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END,
9014741Sgt29601 "rpcmodrput_end:");
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate * Return codes are not looked at by the STREAMS framework.
9040Sstevel@tonic-gate */
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate * write put procedure
9090Sstevel@tonic-gate */
9100Sstevel@tonic-gate void
rpcmodwput(queue_t * q,mblk_t * mp)9110Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate struct rpcm *rmp;
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate ASSERT(q != NULL);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate switch (mp->b_datap->db_type) {
9184741Sgt29601 case M_PROTO:
9194741Sgt29601 case M_PCPROTO:
9204741Sgt29601 break;
9214741Sgt29601 default:
9224741Sgt29601 rpcmodwput_other(q, mp);
9234741Sgt29601 return;
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate /*
9270Sstevel@tonic-gate * Check to see if we can send the message downstream.
9280Sstevel@tonic-gate */
9290Sstevel@tonic-gate if (canputnext(q)) {
9300Sstevel@tonic-gate putnext(q, mp);
9310Sstevel@tonic-gate return;
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
9350Sstevel@tonic-gate ASSERT(rmp != NULL);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /*
9380Sstevel@tonic-gate * The first canputnext failed. Try again except this time with the
9390Sstevel@tonic-gate * lock held, so that we can check the state of the stream to see if
9400Sstevel@tonic-gate * it is closing. If either of these conditions evaluate to true
9410Sstevel@tonic-gate * then send the meesage.
9420Sstevel@tonic-gate */
9430Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
9440Sstevel@tonic-gate if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) {
9450Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
9460Sstevel@tonic-gate putnext(q, mp);
9470Sstevel@tonic-gate } else {
9480Sstevel@tonic-gate /*
9490Sstevel@tonic-gate * canputnext failed again and the stream is not closing.
9500Sstevel@tonic-gate * Place the message on the queue and let the service
9510Sstevel@tonic-gate * procedure handle the message.
9520Sstevel@tonic-gate */
9530Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
9540Sstevel@tonic-gate (void) putq(q, mp);
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate static void
rpcmodwput_other(queue_t * q,mblk_t * mp)9590Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate struct rpcm *rmp;
9620Sstevel@tonic-gate struct iocblk *iocp;
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
9650Sstevel@tonic-gate ASSERT(rmp != NULL);
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate switch (mp->b_datap->db_type) {
9680Sstevel@tonic-gate case M_IOCTL:
9690Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
9700Sstevel@tonic-gate ASSERT(iocp != NULL);
9710Sstevel@tonic-gate switch (iocp->ioc_cmd) {
9724741Sgt29601 case RPC_CLIENT:
9734741Sgt29601 case RPC_SERVER:
9744741Sgt29601 mutex_enter(&rmp->rm_lock);
9754741Sgt29601 rmp->rm_type = iocp->ioc_cmd;
9764741Sgt29601 mutex_exit(&rmp->rm_lock);
9774741Sgt29601 mp->b_datap->db_type = M_IOCACK;
9784741Sgt29601 qreply(q, mp);
9794741Sgt29601 return;
9804741Sgt29601 default:
9810Sstevel@tonic-gate /*
9820Sstevel@tonic-gate * pass the ioctl downstream and hope someone
9830Sstevel@tonic-gate * down there knows how to handle it.
9840Sstevel@tonic-gate */
9854741Sgt29601 putnext(q, mp);
9864741Sgt29601 return;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate default:
9890Sstevel@tonic-gate break;
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate * This is something we definitely do not know how to handle, just
9930Sstevel@tonic-gate * pass the message downstream
9940Sstevel@tonic-gate */
9950Sstevel@tonic-gate putnext(q, mp);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate * Module write service procedure. This is called by downstream modules
10000Sstevel@tonic-gate * for back enabling during flow control.
10010Sstevel@tonic-gate */
10020Sstevel@tonic-gate void
rpcmodwsrv(queue_t * q)10030Sstevel@tonic-gate rpcmodwsrv(queue_t *q)
10040Sstevel@tonic-gate {
10050Sstevel@tonic-gate struct rpcm *rmp;
10060Sstevel@tonic-gate mblk_t *mp = NULL;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
10090Sstevel@tonic-gate ASSERT(rmp != NULL);
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate /*
10120Sstevel@tonic-gate * Get messages that may be queued and send them down stream
10130Sstevel@tonic-gate */
10140Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate * Optimize the service procedure for the server-side, by
10170Sstevel@tonic-gate * avoiding a call to canputnext().
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER || canputnext(q)) {
10200Sstevel@tonic-gate putnext(q, mp);
10210Sstevel@tonic-gate continue;
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate (void) putbq(q, mp);
10240Sstevel@tonic-gate return;
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate static void
rpcmod_release(queue_t * q,mblk_t * bp)10290Sstevel@tonic-gate rpcmod_release(queue_t *q, mblk_t *bp)
10300Sstevel@tonic-gate {
10310Sstevel@tonic-gate struct rpcm *rmp;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate /*
10340Sstevel@tonic-gate * For now, just free the message.
10350Sstevel@tonic-gate */
10360Sstevel@tonic-gate if (bp)
10370Sstevel@tonic-gate freemsg(bp);
10380Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
10410Sstevel@tonic-gate rmp->rm_ref--;
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) {
10440Sstevel@tonic-gate cv_broadcast(&rmp->rm_cwait);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate /*
10510Sstevel@tonic-gate * This part of rpcmod is pushed on a connection-oriented transport for use
10520Sstevel@tonic-gate * by RPC. It serves to bypass the Stream head, implements
10530Sstevel@tonic-gate * the record marking protocol, and dispatches incoming RPC messages.
10540Sstevel@tonic-gate */
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /* Default idle timer values */
10570Sstevel@tonic-gate #define MIR_CLNT_IDLE_TIMEOUT (5 * (60 * 1000L)) /* 5 minutes */
10580Sstevel@tonic-gate #define MIR_SVC_IDLE_TIMEOUT (6 * (60 * 1000L)) /* 6 minutes */
10590Sstevel@tonic-gate #define MIR_SVC_ORDREL_TIMEOUT (10 * (60 * 1000L)) /* 10 minutes */
10600Sstevel@tonic-gate #define MIR_LASTFRAG 0x80000000 /* Record marker */
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate #define MIR_SVC_QUIESCED(mir) \
10630Sstevel@tonic-gate (mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0)
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate #define MIR_CLEAR_INRSRV(mir_ptr) { \
10660Sstevel@tonic-gate (mir_ptr)->mir_inrservice = 0; \
10670Sstevel@tonic-gate if ((mir_ptr)->mir_type == RPC_SERVER && \
10680Sstevel@tonic-gate (mir_ptr)->mir_closing) \
10690Sstevel@tonic-gate cv_signal(&(mir_ptr)->mir_condvar); \
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate /*
10730Sstevel@tonic-gate * Don't block service procedure (and mir_close) if
10740Sstevel@tonic-gate * we are in the process of closing.
10750Sstevel@tonic-gate */
10760Sstevel@tonic-gate #define MIR_WCANPUTNEXT(mir_ptr, write_q) \
10770Sstevel@tonic-gate (canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1))
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate static int mir_clnt_dup_request(queue_t *q, mblk_t *mp);
10800Sstevel@tonic-gate static void mir_rput_proto(queue_t *q, mblk_t *mp);
10810Sstevel@tonic-gate static int mir_svc_policy_notify(queue_t *q, int event);
10820Sstevel@tonic-gate static void mir_svc_release(queue_t *wq, mblk_t *mp);
10830Sstevel@tonic-gate static void mir_svc_start(queue_t *wq);
10840Sstevel@tonic-gate static void mir_svc_idle_start(queue_t *, mir_t *);
10850Sstevel@tonic-gate static void mir_svc_idle_stop(queue_t *, mir_t *);
10860Sstevel@tonic-gate static void mir_svc_start_close(queue_t *, mir_t *);
10870Sstevel@tonic-gate static void mir_clnt_idle_do_stop(queue_t *);
10880Sstevel@tonic-gate static void mir_clnt_idle_stop(queue_t *, mir_t *);
10890Sstevel@tonic-gate static void mir_clnt_idle_start(queue_t *, mir_t *);
10900Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp);
10910Sstevel@tonic-gate static void mir_wput_other(queue_t *q, mblk_t *mp);
10920Sstevel@tonic-gate static void mir_wsrv(queue_t *q);
10930Sstevel@tonic-gate static void mir_disconnect(queue_t *, mir_t *ir);
10940Sstevel@tonic-gate static int mir_check_len(queue_t *, int32_t, mblk_t *);
10950Sstevel@tonic-gate static void mir_timer(void *);
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate extern void (*mir_rele)(queue_t *, mblk_t *);
10980Sstevel@tonic-gate extern void (*mir_start)(queue_t *);
10990Sstevel@tonic-gate extern void (*clnt_stop_idle)(queue_t *);
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate clock_t clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT;
11020Sstevel@tonic-gate clock_t svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT;
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate * Timeout for subsequent notifications of idle connection. This is
11060Sstevel@tonic-gate * typically used to clean up after a wedged orderly release.
11070Sstevel@tonic-gate */
11080Sstevel@tonic-gate clock_t svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate extern uint_t *clnt_max_msg_sizep;
11110Sstevel@tonic-gate extern uint_t *svc_max_msg_sizep;
11120Sstevel@tonic-gate uint_t clnt_max_msg_size = RPC_MAXDATASIZE;
11130Sstevel@tonic-gate uint_t svc_max_msg_size = RPC_MAXDATASIZE;
11140Sstevel@tonic-gate uint_t mir_krpc_cell_null;
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate static void
mir_timer_stop(mir_t * mir)11170Sstevel@tonic-gate mir_timer_stop(mir_t *mir)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate timeout_id_t tid;
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate /*
11240Sstevel@tonic-gate * Since the mir_mutex lock needs to be released to call
11250Sstevel@tonic-gate * untimeout(), we need to make sure that no other thread
11260Sstevel@tonic-gate * can start/stop the timer (changing mir_timer_id) during
11270Sstevel@tonic-gate * that time. The mir_timer_call bit and the mir_timer_cv
11280Sstevel@tonic-gate * condition variable are used to synchronize this. Setting
11290Sstevel@tonic-gate * mir_timer_call also tells mir_timer() (refer to the comments
11300Sstevel@tonic-gate * in mir_timer()) that it does not need to do anything.
11310Sstevel@tonic-gate */
11320Sstevel@tonic-gate while (mir->mir_timer_call)
11330Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
11340Sstevel@tonic-gate mir->mir_timer_call = B_TRUE;
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) {
11370Sstevel@tonic-gate mir->mir_timer_id = 0;
11380Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
11390Sstevel@tonic-gate (void) untimeout(tid);
11400Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate mir->mir_timer_call = B_FALSE;
11430Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv);
11440Sstevel@tonic-gate }
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate static void
mir_timer_start(queue_t * q,mir_t * mir,clock_t intrvl)11470Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl)
11480Sstevel@tonic-gate {
11490Sstevel@tonic-gate timeout_id_t tid;
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate while (mir->mir_timer_call)
11540Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
11550Sstevel@tonic-gate mir->mir_timer_call = B_TRUE;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) {
11580Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
11590Sstevel@tonic-gate (void) untimeout(tid);
11600Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate /* Only start the timer when it is not closing. */
11630Sstevel@tonic-gate if (!mir->mir_closing) {
11640Sstevel@tonic-gate mir->mir_timer_id = timeout(mir_timer, q,
11650Sstevel@tonic-gate MSEC_TO_TICK(intrvl));
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate mir->mir_timer_call = B_FALSE;
11680Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate static int
mir_clnt_dup_request(queue_t * q,mblk_t * mp)11720Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp)
11730Sstevel@tonic-gate {
11740Sstevel@tonic-gate mblk_t *mp1;
11750Sstevel@tonic-gate uint32_t new_xid;
11760Sstevel@tonic-gate uint32_t old_xid;
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex));
11790Sstevel@tonic-gate new_xid = BE32_TO_U32(&mp->b_rptr[4]);
11800Sstevel@tonic-gate /*
11810Sstevel@tonic-gate * This loop is a bit tacky -- it walks the STREAMS list of
11820Sstevel@tonic-gate * flow-controlled messages.
11830Sstevel@tonic-gate */
11840Sstevel@tonic-gate if ((mp1 = q->q_first) != NULL) {
11850Sstevel@tonic-gate do {
11860Sstevel@tonic-gate old_xid = BE32_TO_U32(&mp1->b_rptr[4]);
11870Sstevel@tonic-gate if (new_xid == old_xid)
11880Sstevel@tonic-gate return (1);
11890Sstevel@tonic-gate } while ((mp1 = mp1->b_next) != NULL);
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate return (0);
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate static int
mir_close(queue_t * q)11950Sstevel@tonic-gate mir_close(queue_t *q)
11960Sstevel@tonic-gate {
11975604Smeem mir_t *mir = q->q_ptr;
11980Sstevel@tonic-gate mblk_t *mp;
11990Sstevel@tonic-gate bool_t queue_cleaned = FALSE;
12000Sstevel@tonic-gate
12010Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q);
12020Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
12030Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
12040Sstevel@tonic-gate if ((mp = mir->mir_head_mp) != NULL) {
12055604Smeem mir->mir_head_mp = NULL;
12065604Smeem mir->mir_tail_mp = NULL;
12070Sstevel@tonic-gate freemsg(mp);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate /*
12100Sstevel@tonic-gate * Set mir_closing so we get notified when MIR_SVC_QUIESCED()
12110Sstevel@tonic-gate * is TRUE. And mir_timer_start() won't start the timer again.
12120Sstevel@tonic-gate */
12130Sstevel@tonic-gate mir->mir_closing = B_TRUE;
12140Sstevel@tonic-gate mir_timer_stop(mir);
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER) {
12170Sstevel@tonic-gate flushq(q, FLUSHDATA); /* Ditch anything waiting on read q */
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate * This will prevent more requests from arriving and
12210Sstevel@tonic-gate * will force rpcmod to ignore flow control.
12220Sstevel@tonic-gate */
12230Sstevel@tonic-gate mir_svc_start_close(WR(q), mir);
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) {
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate if (mir->mir_ref_cnt && !mir->mir_inrservice &&
12284741Sgt29601 (queue_cleaned == FALSE)) {
12290Sstevel@tonic-gate /*
12300Sstevel@tonic-gate * call into SVC to clean the queue
12310Sstevel@tonic-gate */
12320Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
12330Sstevel@tonic-gate svc_queueclean(q);
12340Sstevel@tonic-gate queue_cleaned = TRUE;
12350Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
12360Sstevel@tonic-gate continue;
12370Sstevel@tonic-gate }
12380Sstevel@tonic-gate
12390Sstevel@tonic-gate /*
12400Sstevel@tonic-gate * Bugid 1253810 - Force the write service
12410Sstevel@tonic-gate * procedure to send its messages, regardless
12420Sstevel@tonic-gate * whether the downstream module is ready
12430Sstevel@tonic-gate * to accept data.
12440Sstevel@tonic-gate */
12450Sstevel@tonic-gate if (mir->mir_inwservice == 1)
12460Sstevel@tonic-gate qenable(WR(q));
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate cv_wait(&mir->mir_condvar, &mir->mir_mutex);
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
12520Sstevel@tonic-gate qprocsoff(q);
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /* Notify KRPC that this stream is going away. */
12550Sstevel@tonic-gate svc_queueclose(q);
12560Sstevel@tonic-gate } else {
12570Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
12580Sstevel@tonic-gate qprocsoff(q);
12590Sstevel@tonic-gate }
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate mutex_destroy(&mir->mir_mutex);
12620Sstevel@tonic-gate cv_destroy(&mir->mir_condvar);
12630Sstevel@tonic-gate cv_destroy(&mir->mir_timer_cv);
12640Sstevel@tonic-gate kmem_free(mir, sizeof (mir_t));
12650Sstevel@tonic-gate return (0);
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /*
12690Sstevel@tonic-gate * This is server side only (RPC_SERVER).
12700Sstevel@tonic-gate *
12710Sstevel@tonic-gate * Exit idle mode.
12720Sstevel@tonic-gate */
12730Sstevel@tonic-gate static void
mir_svc_idle_stop(queue_t * q,mir_t * mir)12740Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir)
12750Sstevel@tonic-gate {
12760Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
12770Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
12780Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
12790Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q);
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate mir_timer_stop(mir);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate * This is server side only (RPC_SERVER).
12860Sstevel@tonic-gate *
12870Sstevel@tonic-gate * Start idle processing, which will include setting idle timer if the
12880Sstevel@tonic-gate * stream is not being closed.
12890Sstevel@tonic-gate */
12900Sstevel@tonic-gate static void
mir_svc_idle_start(queue_t * q,mir_t * mir)12910Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
12940Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
12950Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
12960Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q);
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate /*
12990Sstevel@tonic-gate * Don't re-start idle timer if we are closing queues.
13000Sstevel@tonic-gate */
13010Sstevel@tonic-gate if (mir->mir_closing) {
13020Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n",
13034741Sgt29601 (void *)q);
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED()
13070Sstevel@tonic-gate * is true. When it is true, and we are in the process of
13080Sstevel@tonic-gate * closing the stream, signal any thread waiting in
13090Sstevel@tonic-gate * mir_close().
13100Sstevel@tonic-gate */
13110Sstevel@tonic-gate if (mir->mir_inwservice == 0)
13120Sstevel@tonic-gate cv_signal(&mir->mir_condvar);
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate } else {
13150Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - reset %s timer\n",
13164741Sgt29601 mir->mir_ordrel_pending ? "ordrel" : "normal");
13170Sstevel@tonic-gate /*
13180Sstevel@tonic-gate * Normal condition, start the idle timer. If an orderly
13190Sstevel@tonic-gate * release has been sent, set the timeout to wait for the
13200Sstevel@tonic-gate * client to close its side of the connection. Otherwise,
13210Sstevel@tonic-gate * use the normal idle timeout.
13220Sstevel@tonic-gate */
13230Sstevel@tonic-gate mir_timer_start(q, mir, mir->mir_ordrel_pending ?
13240Sstevel@tonic-gate svc_ordrel_timeout : mir->mir_idle_timeout);
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate /* ARGSUSED */
13290Sstevel@tonic-gate static int
mir_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)13300Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate mir_t *mir;
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q);
13350Sstevel@tonic-gate /* Set variables used directly by KRPC. */
13360Sstevel@tonic-gate if (!mir_rele)
13370Sstevel@tonic-gate mir_rele = mir_svc_release;
13380Sstevel@tonic-gate if (!mir_start)
13390Sstevel@tonic-gate mir_start = mir_svc_start;
13400Sstevel@tonic-gate if (!clnt_stop_idle)
13410Sstevel@tonic-gate clnt_stop_idle = mir_clnt_idle_do_stop;
13420Sstevel@tonic-gate if (!clnt_max_msg_sizep)
13430Sstevel@tonic-gate clnt_max_msg_sizep = &clnt_max_msg_size;
13440Sstevel@tonic-gate if (!svc_max_msg_sizep)
13450Sstevel@tonic-gate svc_max_msg_sizep = &svc_max_msg_size;
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate /* Allocate a zero'ed out mir structure for this stream. */
13480Sstevel@tonic-gate mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP);
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate * We set hold inbound here so that incoming messages will
13520Sstevel@tonic-gate * be held on the read-side queue until the stream is completely
13530Sstevel@tonic-gate * initialized with a RPC_CLIENT or RPC_SERVER ioctl. During
13540Sstevel@tonic-gate * the ioctl processing, the flag is cleared and any messages that
13550Sstevel@tonic-gate * arrived between the open and the ioctl are delivered to KRPC.
13560Sstevel@tonic-gate *
13570Sstevel@tonic-gate * Early data should never arrive on a client stream since
13580Sstevel@tonic-gate * servers only respond to our requests and we do not send any.
13590Sstevel@tonic-gate * until after the stream is initialized. Early data is
13600Sstevel@tonic-gate * very common on a server stream where the client will start
13610Sstevel@tonic-gate * sending data as soon as the connection is made (and this
13620Sstevel@tonic-gate * is especially true with TCP where the protocol accepts the
13630Sstevel@tonic-gate * connection before nfsd or KRPC is notified about it).
13640Sstevel@tonic-gate */
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate mir->mir_hold_inbound = 1;
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate /*
13690Sstevel@tonic-gate * Start the record marker looking for a 4-byte header. When
13700Sstevel@tonic-gate * this length is negative, it indicates that rpcmod is looking
13710Sstevel@tonic-gate * for bytes to consume for the record marker header. When it
13720Sstevel@tonic-gate * is positive, it holds the number of bytes that have arrived
13730Sstevel@tonic-gate * for the current fragment and are being held in mir_header_mp.
13740Sstevel@tonic-gate */
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
13770Sstevel@tonic-gate
1378766Scarlsonj mir->mir_zoneid = rpc_zoneid();
13790Sstevel@tonic-gate mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL);
13800Sstevel@tonic-gate cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL);
13810Sstevel@tonic-gate cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL);
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate q->q_ptr = (char *)mir;
13840Sstevel@tonic-gate WR(q)->q_ptr = (char *)mir;
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate /*
13870Sstevel@tonic-gate * We noenable the read-side queue because we don't want it
13880Sstevel@tonic-gate * automatically enabled by putq. We enable it explicitly
13890Sstevel@tonic-gate * in mir_wsrv when appropriate. (See additional comments on
13900Sstevel@tonic-gate * flow control at the beginning of mir_rsrv.)
13910Sstevel@tonic-gate */
13920Sstevel@tonic-gate noenable(q);
13930Sstevel@tonic-gate
13940Sstevel@tonic-gate qprocson(q);
13950Sstevel@tonic-gate return (0);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate * Read-side put routine for both the client and server side. Does the
14000Sstevel@tonic-gate * record marking for incoming RPC messages, and when complete, dispatches
14010Sstevel@tonic-gate * the message to either the client or server.
14020Sstevel@tonic-gate */
14030Sstevel@tonic-gate static void
mir_rput(queue_t * q,mblk_t * mp)14045444Smeem mir_rput(queue_t *q, mblk_t *mp)
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate int excess;
14075444Smeem int32_t frag_len, frag_header;
14085444Smeem mblk_t *cont_mp, *head_mp, *tail_mp, *mp1;
14095444Smeem mir_t *mir = q->q_ptr;
14105444Smeem boolean_t stop_timer = B_FALSE;
14115444Smeem
14120Sstevel@tonic-gate ASSERT(mir != NULL);
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER
14160Sstevel@tonic-gate * with the corresponding ioctl, then don't accept
14170Sstevel@tonic-gate * any inbound data. This should never happen for streams
14180Sstevel@tonic-gate * created by nfsd or client-side KRPC because they are careful
14190Sstevel@tonic-gate * to set the mode of the stream before doing anything else.
14200Sstevel@tonic-gate */
14210Sstevel@tonic-gate if (mir->mir_type == 0) {
14220Sstevel@tonic-gate freemsg(mp);
14230Sstevel@tonic-gate return;
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate switch (mp->b_datap->db_type) {
14290Sstevel@tonic-gate case M_DATA:
14300Sstevel@tonic-gate break;
14310Sstevel@tonic-gate case M_PROTO:
14320Sstevel@tonic-gate case M_PCPROTO:
14335444Smeem if (MBLKL(mp) < sizeof (t_scalar_t)) {
14340Sstevel@tonic-gate RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n",
14355444Smeem (int)MBLKL(mp));
14360Sstevel@tonic-gate freemsg(mp);
14370Sstevel@tonic-gate return;
14380Sstevel@tonic-gate }
14395444Smeem if (((union T_primitives *)mp->b_rptr)->type != T_DATA_IND) {
14400Sstevel@tonic-gate mir_rput_proto(q, mp);
14410Sstevel@tonic-gate return;
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate /* Throw away the T_DATA_IND block and continue with data. */
14450Sstevel@tonic-gate mp1 = mp;
14460Sstevel@tonic-gate mp = mp->b_cont;
14470Sstevel@tonic-gate freeb(mp1);
14480Sstevel@tonic-gate break;
14490Sstevel@tonic-gate case M_SETOPTS:
14500Sstevel@tonic-gate /*
14510Sstevel@tonic-gate * If a module on the stream is trying set the Stream head's
14520Sstevel@tonic-gate * high water mark, then set our hiwater to the requested
14530Sstevel@tonic-gate * value. We are the "stream head" for all inbound
14540Sstevel@tonic-gate * data messages since messages are passed directly to KRPC.
14550Sstevel@tonic-gate */
14565444Smeem if (MBLKL(mp) >= sizeof (struct stroptions)) {
14570Sstevel@tonic-gate struct stroptions *stropts;
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate stropts = (struct stroptions *)mp->b_rptr;
14600Sstevel@tonic-gate if ((stropts->so_flags & SO_HIWAT) &&
14614741Sgt29601 !(stropts->so_flags & SO_BAND)) {
14620Sstevel@tonic-gate (void) strqset(q, QHIWAT, 0, stropts->so_hiwat);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate putnext(q, mp);
14660Sstevel@tonic-gate return;
14670Sstevel@tonic-gate case M_FLUSH:
14685444Smeem RPCLOG(32, "mir_rput: ignoring M_FLUSH %x ", *mp->b_rptr);
14695444Smeem RPCLOG(32, "on q 0x%p\n", (void *)q);
14700Sstevel@tonic-gate putnext(q, mp);
14710Sstevel@tonic-gate return;
14720Sstevel@tonic-gate default:
14730Sstevel@tonic-gate putnext(q, mp);
14740Sstevel@tonic-gate return;
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * If this connection is closing, don't accept any new messages.
14810Sstevel@tonic-gate */
14820Sstevel@tonic-gate if (mir->mir_svc_no_more_msgs) {
14830Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
14840Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
14850Sstevel@tonic-gate freemsg(mp);
14860Sstevel@tonic-gate return;
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate /* Get local copies for quicker access. */
14900Sstevel@tonic-gate frag_len = mir->mir_frag_len;
14910Sstevel@tonic-gate frag_header = mir->mir_frag_header;
14920Sstevel@tonic-gate head_mp = mir->mir_head_mp;
14930Sstevel@tonic-gate tail_mp = mir->mir_tail_mp;
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate /* Loop, processing each message block in the mp chain separately. */
14960Sstevel@tonic-gate do {
14970Sstevel@tonic-gate cont_mp = mp->b_cont;
14985444Smeem mp->b_cont = NULL;
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate /*
15016009Smeem * Drop zero-length mblks to prevent unbounded kernel memory
15026009Smeem * consumption.
15036009Smeem */
15046009Smeem if (MBLKL(mp) == 0) {
15056009Smeem freeb(mp);
15066009Smeem continue;
15076009Smeem }
15086009Smeem
15096009Smeem /*
15105444Smeem * If frag_len is negative, we're still in the process of
15115444Smeem * building frag_header -- try to complete it with this mblk.
15120Sstevel@tonic-gate */
15135444Smeem while (frag_len < 0 && mp->b_rptr < mp->b_wptr) {
15145444Smeem frag_len++;
15155444Smeem frag_header <<= 8;
15165444Smeem frag_header += *mp->b_rptr++;
15175444Smeem }
15185444Smeem
15196009Smeem if (MBLKL(mp) == 0 && frag_len < 0) {
15200Sstevel@tonic-gate /*
15216009Smeem * We consumed this mblk while trying to complete the
15226009Smeem * fragment header. Free it and move on.
15230Sstevel@tonic-gate */
15245444Smeem freeb(mp);
15255444Smeem continue;
15265444Smeem }
15275444Smeem
15285444Smeem ASSERT(frag_len >= 0);
15295444Smeem
15305444Smeem /*
15315444Smeem * Now frag_header has the number of bytes in this fragment
15325444Smeem * and we're just waiting to collect them all. Chain our
15335444Smeem * latest mblk onto the list and see if we now have enough
15345444Smeem * bytes to complete the fragment.
15355444Smeem */
15365444Smeem if (head_mp == NULL) {
15375444Smeem ASSERT(tail_mp == NULL);
15385444Smeem head_mp = tail_mp = mp;
15395444Smeem } else {
15405444Smeem tail_mp->b_cont = mp;
15415444Smeem tail_mp = mp;
15425444Smeem }
15435444Smeem
15445444Smeem frag_len += MBLKL(mp);
15455444Smeem excess = frag_len - (frag_header & ~MIR_LASTFRAG);
15465444Smeem if (excess < 0) {
15475444Smeem /*
15485444Smeem * We still haven't received enough data to complete
15495444Smeem * the fragment, so continue on to the next mblk.
15505444Smeem */
15510Sstevel@tonic-gate continue;
15520Sstevel@tonic-gate }
15530Sstevel@tonic-gate
15540Sstevel@tonic-gate /*
15555444Smeem * We've got a complete fragment. If there are excess bytes,
15565444Smeem * then they're part of the next fragment's header (of either
15575444Smeem * this RPC message or the next RPC message). Split that part
15585444Smeem * into its own mblk so that we can safely freeb() it when
15595444Smeem * building frag_header above.
15600Sstevel@tonic-gate */
15610Sstevel@tonic-gate if (excess > 0) {
15625444Smeem if ((mp1 = dupb(mp)) == NULL &&
15635444Smeem (mp1 = copyb(mp)) == NULL) {
15640Sstevel@tonic-gate freemsg(head_mp);
15655444Smeem freemsg(cont_mp);
15665444Smeem RPCLOG0(1, "mir_rput: dupb/copyb failed\n");
15670Sstevel@tonic-gate mir->mir_frag_header = 0;
15685444Smeem mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
15690Sstevel@tonic-gate mir->mir_head_mp = NULL;
15700Sstevel@tonic-gate mir->mir_tail_mp = NULL;
15715444Smeem mir_disconnect(q, mir); /* drops mir_mutex */
15720Sstevel@tonic-gate return;
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate /*
15765444Smeem * Relink the message chain so that the next mblk is
15775444Smeem * the next fragment header, followed by the rest of
15785444Smeem * the message chain.
15790Sstevel@tonic-gate */
15800Sstevel@tonic-gate mp1->b_cont = cont_mp;
15810Sstevel@tonic-gate cont_mp = mp1;
15825444Smeem
15830Sstevel@tonic-gate /*
15845444Smeem * Data in the new mblk begins at the next fragment,
15855444Smeem * and data in the old mblk ends at the next fragment.
15860Sstevel@tonic-gate */
15875444Smeem mp1->b_rptr = mp1->b_wptr - excess;
15885444Smeem mp->b_wptr -= excess;
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate
15915444Smeem /*
15925444Smeem * Reset frag_len and frag_header for the next fragment.
15935444Smeem */
15945444Smeem frag_len = -(int32_t)sizeof (uint32_t);
15955444Smeem if (!(frag_header & MIR_LASTFRAG)) {
15965444Smeem /*
15975444Smeem * The current fragment is complete, but more
15985444Smeem * fragments need to be processed before we can
15995444Smeem * pass along the RPC message headed at head_mp.
16005444Smeem */
16015444Smeem frag_header = 0;
16025444Smeem continue;
16035444Smeem }
16045444Smeem frag_header = 0;
16055444Smeem
16065444Smeem /*
16075444Smeem * We've got a complete RPC message; pass it to the
16085444Smeem * appropriate consumer.
16095444Smeem */
16100Sstevel@tonic-gate switch (mir->mir_type) {
16110Sstevel@tonic-gate case RPC_CLIENT:
16120Sstevel@tonic-gate if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) {
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate * Mark this stream as active. This marker
16150Sstevel@tonic-gate * is used in mir_timer().
16160Sstevel@tonic-gate */
16170Sstevel@tonic-gate mir->mir_clntreq = 1;
161811066Srafael.vanoni@sun.com mir->mir_use_timestamp = ddi_get_lbolt();
16195444Smeem } else {
16200Sstevel@tonic-gate freemsg(head_mp);
16215444Smeem }
16220Sstevel@tonic-gate break;
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate case RPC_SERVER:
16250Sstevel@tonic-gate /*
16260Sstevel@tonic-gate * Check for flow control before passing the
16270Sstevel@tonic-gate * message to KRPC.
16280Sstevel@tonic-gate */
16290Sstevel@tonic-gate if (!mir->mir_hold_inbound) {
16304741Sgt29601 if (mir->mir_krpc_cell) {
16314741Sgt29601 /*
16324741Sgt29601 * If the reference count is 0
16334741Sgt29601 * (not including this request),
16344741Sgt29601 * then the stream is transitioning
16354741Sgt29601 * from idle to non-idle. In this case,
16364741Sgt29601 * we cancel the idle timer.
16374741Sgt29601 */
16384741Sgt29601 if (mir->mir_ref_cnt++ == 0)
16394741Sgt29601 stop_timer = B_TRUE;
16404741Sgt29601 if (mir_check_len(q,
16414741Sgt29601 (int32_t)msgdsize(mp), mp))
16420Sstevel@tonic-gate return;
16434741Sgt29601 svc_queuereq(q, head_mp); /* to KRPC */
16444741Sgt29601 } else {
16454741Sgt29601 /*
16464741Sgt29601 * Count # of times this happens. Should
16474741Sgt29601 * be never, but experience shows
16484741Sgt29601 * otherwise.
16494741Sgt29601 */
16504741Sgt29601 mir_krpc_cell_null++;
16514741Sgt29601 freemsg(head_mp);
16524741Sgt29601 }
16530Sstevel@tonic-gate } else {
16540Sstevel@tonic-gate /*
16550Sstevel@tonic-gate * If the outbound side of the stream is
16560Sstevel@tonic-gate * flow controlled, then hold this message
16570Sstevel@tonic-gate * until client catches up. mir_hold_inbound
16580Sstevel@tonic-gate * is set in mir_wput and cleared in mir_wsrv.
16590Sstevel@tonic-gate */
16605444Smeem (void) putq(q, head_mp);
16610Sstevel@tonic-gate mir->mir_inrservice = B_TRUE;
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate break;
16640Sstevel@tonic-gate default:
16650Sstevel@tonic-gate RPCLOG(1, "mir_rput: unknown mir_type %d\n",
16664741Sgt29601 mir->mir_type);
16670Sstevel@tonic-gate freemsg(head_mp);
16680Sstevel@tonic-gate break;
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate /*
16725444Smeem * Reset the chain since we're starting on a new RPC message.
16730Sstevel@tonic-gate */
16745444Smeem head_mp = tail_mp = NULL;
16750Sstevel@tonic-gate } while ((mp = cont_mp) != NULL);
16760Sstevel@tonic-gate
16770Sstevel@tonic-gate /*
16785444Smeem * Sanity check the message length; if it's too large mir_check_len()
16795444Smeem * will shutdown the connection, drop mir_mutex, and return non-zero.
16800Sstevel@tonic-gate */
16810Sstevel@tonic-gate if (head_mp != NULL && mir->mir_setup_complete &&
16824741Sgt29601 mir_check_len(q, frag_len, head_mp))
16830Sstevel@tonic-gate return;
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate /* Save our local copies back in the mir structure. */
16860Sstevel@tonic-gate mir->mir_frag_header = frag_header;
16870Sstevel@tonic-gate mir->mir_frag_len = frag_len;
16880Sstevel@tonic-gate mir->mir_head_mp = head_mp;
16890Sstevel@tonic-gate mir->mir_tail_mp = tail_mp;
16900Sstevel@tonic-gate
16910Sstevel@tonic-gate /*
16920Sstevel@tonic-gate * The timer is stopped after the whole message chain is processed.
16930Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex
16940Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced
16950Sstevel@tonic-gate * while we are still processing the message chain. This is not
16960Sstevel@tonic-gate * good. So we stop the timer here instead.
16970Sstevel@tonic-gate *
16980Sstevel@tonic-gate * Note that if the timer fires before we stop it, it will not
16990Sstevel@tonic-gate * do any harm as MIR_SVC_QUIESCED() is false and mir_timer()
17005444Smeem * will just return.
17010Sstevel@tonic-gate */
17020Sstevel@tonic-gate if (stop_timer) {
17035444Smeem RPCLOG(16, "mir_rput: stopping idle timer on 0x%p because "
17045444Smeem "ref cnt going to non zero\n", (void *)WR(q));
17050Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
17060Sstevel@tonic-gate }
17070Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate
17100Sstevel@tonic-gate static void
mir_rput_proto(queue_t * q,mblk_t * mp)17110Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp)
17120Sstevel@tonic-gate {
17130Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
17140Sstevel@tonic-gate uint32_t type;
17150Sstevel@tonic-gate uint32_t reason = 0;
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate type = ((union T_primitives *)mp->b_rptr)->type;
17200Sstevel@tonic-gate switch (mir->mir_type) {
17210Sstevel@tonic-gate case RPC_CLIENT:
17220Sstevel@tonic-gate switch (type) {
17230Sstevel@tonic-gate case T_DISCON_IND:
17244741Sgt29601 reason = ((struct T_discon_ind *)
17254741Sgt29601 (mp->b_rptr))->DISCON_reason;
17265444Smeem /*FALLTHROUGH*/
17270Sstevel@tonic-gate case T_ORDREL_IND:
17280Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
17290Sstevel@tonic-gate if (mir->mir_head_mp) {
17300Sstevel@tonic-gate freemsg(mir->mir_head_mp);
17310Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0;
17320Sstevel@tonic-gate mir->mir_tail_mp = (mblk_t *)0;
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate /*
17350Sstevel@tonic-gate * We are disconnecting, but not necessarily
17360Sstevel@tonic-gate * closing. By not closing, we will fail to
17370Sstevel@tonic-gate * pick up a possibly changed global timeout value,
17380Sstevel@tonic-gate * unless we store it now.
17390Sstevel@tonic-gate */
17400Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
17410Sstevel@tonic-gate mir_clnt_idle_stop(WR(q), mir);
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate /*
17440Sstevel@tonic-gate * Even though we are unconnected, we still
17450Sstevel@tonic-gate * leave the idle timer going on the client. The
17460Sstevel@tonic-gate * reason for is that if we've disconnected due
17470Sstevel@tonic-gate * to a server-side disconnect, reset, or connection
17480Sstevel@tonic-gate * timeout, there is a possibility the client may
17490Sstevel@tonic-gate * retry the RPC request. This retry needs to done on
17500Sstevel@tonic-gate * the same bound address for the server to interpret
17510Sstevel@tonic-gate * it as such. However, we don't want
17520Sstevel@tonic-gate * to wait forever for that possibility. If the
17530Sstevel@tonic-gate * end-point stays unconnected for mir_idle_timeout
17540Sstevel@tonic-gate * units of time, then that is a signal to the
17550Sstevel@tonic-gate * connection manager to give up waiting for the
17560Sstevel@tonic-gate * application (eg. NFS) to send a retry.
17570Sstevel@tonic-gate */
17580Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir);
17590Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
17600Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
17610Sstevel@tonic-gate freemsg(mp);
17620Sstevel@tonic-gate return;
17630Sstevel@tonic-gate case T_ERROR_ACK:
17640Sstevel@tonic-gate {
17650Sstevel@tonic-gate struct T_error_ack *terror;
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate terror = (struct T_error_ack *)mp->b_rptr;
17680Sstevel@tonic-gate RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p",
17694741Sgt29601 (void *)q);
17700Sstevel@tonic-gate RPCLOG(1, " ERROR_prim: %s,",
17714741Sgt29601 rpc_tpiprim2name(terror->ERROR_prim));
17720Sstevel@tonic-gate RPCLOG(1, " TLI_error: %s,",
17734741Sgt29601 rpc_tpierr2name(terror->TLI_error));
17740Sstevel@tonic-gate RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error);
17750Sstevel@tonic-gate if (terror->ERROR_prim == T_DISCON_REQ) {
17760Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
17770Sstevel@tonic-gate freemsg(mp);
17780Sstevel@tonic-gate return;
17790Sstevel@tonic-gate } else {
17800Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
17810Sstevel@tonic-gate return;
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate break;
17840Sstevel@tonic-gate }
17850Sstevel@tonic-gate case T_OK_ACK:
17860Sstevel@tonic-gate {
17870Sstevel@tonic-gate struct T_ok_ack *tok = (struct T_ok_ack *)mp->b_rptr;
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate if (tok->CORRECT_prim == T_DISCON_REQ) {
17900Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
17910Sstevel@tonic-gate freemsg(mp);
17920Sstevel@tonic-gate return;
17930Sstevel@tonic-gate } else {
17940Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
17950Sstevel@tonic-gate return;
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate break;
17980Sstevel@tonic-gate }
17990Sstevel@tonic-gate case T_CONN_CON:
18000Sstevel@tonic-gate case T_INFO_ACK:
18010Sstevel@tonic-gate case T_OPTMGMT_ACK:
18020Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
18030Sstevel@tonic-gate return;
18040Sstevel@tonic-gate break;
18050Sstevel@tonic-gate case T_BIND_ACK:
18060Sstevel@tonic-gate break;
18070Sstevel@tonic-gate default:
18080Sstevel@tonic-gate RPCLOG(1, "mir_rput: unexpected message %d "
18090Sstevel@tonic-gate "for KRPC client\n",
18100Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type);
18110Sstevel@tonic-gate break;
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate break;
18140Sstevel@tonic-gate
18150Sstevel@tonic-gate case RPC_SERVER:
18160Sstevel@tonic-gate switch (type) {
18170Sstevel@tonic-gate case T_BIND_ACK:
18180Sstevel@tonic-gate {
18190Sstevel@tonic-gate struct T_bind_ack *tbind;
18200Sstevel@tonic-gate
18210Sstevel@tonic-gate /*
18220Sstevel@tonic-gate * If this is a listening stream, then shut
18230Sstevel@tonic-gate * off the idle timer.
18240Sstevel@tonic-gate */
18250Sstevel@tonic-gate tbind = (struct T_bind_ack *)mp->b_rptr;
18260Sstevel@tonic-gate if (tbind->CONIND_number > 0) {
18270Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
18280Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate /*
18310Sstevel@tonic-gate * mark this as a listen endpoint
18320Sstevel@tonic-gate * for special handling.
18330Sstevel@tonic-gate */
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate mir->mir_listen_stream = 1;
18360Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate break;
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate case T_DISCON_IND:
18410Sstevel@tonic-gate case T_ORDREL_IND:
18420Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: got %s indication\n",
18434741Sgt29601 type == T_DISCON_IND ? "disconnect"
18444741Sgt29601 : "orderly release");
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate /*
18470Sstevel@tonic-gate * For listen endpoint just pass
18480Sstevel@tonic-gate * on the message.
18490Sstevel@tonic-gate */
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate if (mir->mir_listen_stream)
18520Sstevel@tonic-gate break;
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate /*
18570Sstevel@tonic-gate * If client wants to break off connection, record
18580Sstevel@tonic-gate * that fact.
18590Sstevel@tonic-gate */
18600Sstevel@tonic-gate mir_svc_start_close(WR(q), mir);
18610Sstevel@tonic-gate
18620Sstevel@tonic-gate /*
18630Sstevel@tonic-gate * If we are idle, then send the orderly release
18640Sstevel@tonic-gate * or disconnect indication to nfsd.
18650Sstevel@tonic-gate */
18660Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) {
18670Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
18680Sstevel@tonic-gate break;
18690Sstevel@tonic-gate }
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: not idle, so "
18724741Sgt29601 "disconnect/ord rel indication not passed "
18734741Sgt29601 "upstream on 0x%p\n", (void *)q);
18740Sstevel@tonic-gate
18750Sstevel@tonic-gate /*
18760Sstevel@tonic-gate * Hold the indication until we get idle
18770Sstevel@tonic-gate * If there already is an indication stored,
18780Sstevel@tonic-gate * replace it if the new one is a disconnect. The
18790Sstevel@tonic-gate * reasoning is that disconnection takes less time
18800Sstevel@tonic-gate * to process, and once a client decides to
18810Sstevel@tonic-gate * disconnect, we should do that.
18820Sstevel@tonic-gate */
18830Sstevel@tonic-gate if (mir->mir_svc_pend_mp) {
18840Sstevel@tonic-gate if (type == T_DISCON_IND) {
18850Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: replacing"
18860Sstevel@tonic-gate " held disconnect/ord rel"
18870Sstevel@tonic-gate " indication with disconnect on"
18880Sstevel@tonic-gate " 0x%p\n", (void *)q);
18890Sstevel@tonic-gate
18900Sstevel@tonic-gate freemsg(mir->mir_svc_pend_mp);
18910Sstevel@tonic-gate mir->mir_svc_pend_mp = mp;
18920Sstevel@tonic-gate } else {
18930Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: already "
18940Sstevel@tonic-gate "held a disconnect/ord rel "
18950Sstevel@tonic-gate "indication. freeing ord rel "
18960Sstevel@tonic-gate "ind on 0x%p\n", (void *)q);
18970Sstevel@tonic-gate freemsg(mp);
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate } else
19000Sstevel@tonic-gate mir->mir_svc_pend_mp = mp;
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
19030Sstevel@tonic-gate return;
19040Sstevel@tonic-gate
19050Sstevel@tonic-gate default:
19060Sstevel@tonic-gate /* nfsd handles server-side non-data messages. */
19070Sstevel@tonic-gate break;
19080Sstevel@tonic-gate }
19090Sstevel@tonic-gate break;
19100Sstevel@tonic-gate
19110Sstevel@tonic-gate default:
19120Sstevel@tonic-gate break;
19130Sstevel@tonic-gate }
19140Sstevel@tonic-gate
19150Sstevel@tonic-gate putnext(q, mp);
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate
19180Sstevel@tonic-gate /*
19190Sstevel@tonic-gate * The server-side read queues are used to hold inbound messages while
19200Sstevel@tonic-gate * outbound flow control is exerted. When outbound flow control is
19210Sstevel@tonic-gate * relieved, mir_wsrv qenables the read-side queue. Read-side queues
19220Sstevel@tonic-gate * are not enabled by STREAMS and are explicitly noenable'ed in mir_open.
19230Sstevel@tonic-gate *
19240Sstevel@tonic-gate * For the server side, we have two types of messages queued. The first type
19250Sstevel@tonic-gate * are messages that are ready to be XDR decoded and and then sent to the
19260Sstevel@tonic-gate * RPC program's dispatch routine. The second type are "raw" messages that
19270Sstevel@tonic-gate * haven't been processed, i.e. assembled from rpc record fragements into
19280Sstevel@tonic-gate * full requests. The only time we will see the second type of message
19290Sstevel@tonic-gate * queued is if we have a memory allocation failure while processing a
19300Sstevel@tonic-gate * a raw message. The field mir_first_non_processed_mblk will mark the
19310Sstevel@tonic-gate * first such raw message. So the flow for server side is:
19320Sstevel@tonic-gate *
19330Sstevel@tonic-gate * - send processed queued messages to kRPC until we run out or find
19340Sstevel@tonic-gate * one that needs additional processing because we were short on memory
19350Sstevel@tonic-gate * earlier
19360Sstevel@tonic-gate * - process a message that was deferred because of lack of
19370Sstevel@tonic-gate * memory
19380Sstevel@tonic-gate * - continue processing messages until the queue empties or we
19390Sstevel@tonic-gate * have to stop because of lack of memory
19400Sstevel@tonic-gate * - during each of the above phase, if the queue is empty and
19410Sstevel@tonic-gate * there are no pending messages that were passed to the RPC
19420Sstevel@tonic-gate * layer, send upstream the pending disconnect/ordrel indication if
19430Sstevel@tonic-gate * there is one
19440Sstevel@tonic-gate *
19450Sstevel@tonic-gate * The read-side queue is also enabled by a bufcall callback if dupmsg
19460Sstevel@tonic-gate * fails in mir_rput.
19470Sstevel@tonic-gate */
19480Sstevel@tonic-gate static void
mir_rsrv(queue_t * q)19490Sstevel@tonic-gate mir_rsrv(queue_t *q)
19500Sstevel@tonic-gate {
19510Sstevel@tonic-gate mir_t *mir;
19520Sstevel@tonic-gate mblk_t *mp;
19530Sstevel@tonic-gate mblk_t *cmp = NULL;
19540Sstevel@tonic-gate boolean_t stop_timer = B_FALSE;
19550Sstevel@tonic-gate
19560Sstevel@tonic-gate mir = (mir_t *)q->q_ptr;
19570Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate mp = NULL;
19600Sstevel@tonic-gate switch (mir->mir_type) {
19610Sstevel@tonic-gate case RPC_SERVER:
19620Sstevel@tonic-gate if (mir->mir_ref_cnt == 0)
19630Sstevel@tonic-gate mir->mir_hold_inbound = 0;
19640Sstevel@tonic-gate if (mir->mir_hold_inbound) {
19650Sstevel@tonic-gate
19660Sstevel@tonic-gate ASSERT(cmp == NULL);
19670Sstevel@tonic-gate if (q->q_first == NULL) {
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir);
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) {
19720Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp;
19730Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL;
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate
19770Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
19780Sstevel@tonic-gate
19790Sstevel@tonic-gate if (cmp != NULL) {
19800Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held "
19810Sstevel@tonic-gate "disconnect/ord rel indication upstream\n",
19820Sstevel@tonic-gate __LINE__);
19830Sstevel@tonic-gate putnext(q, cmp);
19840Sstevel@tonic-gate }
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate return;
19870Sstevel@tonic-gate }
19880Sstevel@tonic-gate while (mp = getq(q)) {
19894741Sgt29601 if (mir->mir_krpc_cell &&
19904741Sgt29601 (mir->mir_svc_no_more_msgs == 0)) {
19910Sstevel@tonic-gate /*
19920Sstevel@tonic-gate * If we were idle, turn off idle timer since
19930Sstevel@tonic-gate * we aren't idle any more.
19940Sstevel@tonic-gate */
19950Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0)
19960Sstevel@tonic-gate stop_timer = B_TRUE;
19970Sstevel@tonic-gate if (mir_check_len(q,
19984741Sgt29601 (int32_t)msgdsize(mp), mp))
19994741Sgt29601 return;
20000Sstevel@tonic-gate svc_queuereq(q, mp);
20010Sstevel@tonic-gate } else {
20020Sstevel@tonic-gate /*
20030Sstevel@tonic-gate * Count # of times this happens. Should be
20040Sstevel@tonic-gate * never, but experience shows otherwise.
20050Sstevel@tonic-gate */
20064741Sgt29601 if (mir->mir_krpc_cell == NULL)
20074741Sgt29601 mir_krpc_cell_null++;
20080Sstevel@tonic-gate freemsg(mp);
20090Sstevel@tonic-gate }
20100Sstevel@tonic-gate }
20110Sstevel@tonic-gate break;
20120Sstevel@tonic-gate case RPC_CLIENT:
20130Sstevel@tonic-gate break;
20140Sstevel@tonic-gate default:
20150Sstevel@tonic-gate RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type);
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate if (q->q_first == NULL)
20180Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir);
20190Sstevel@tonic-gate
20200Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
20210Sstevel@tonic-gate
20220Sstevel@tonic-gate return;
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate
20250Sstevel@tonic-gate /*
20260Sstevel@tonic-gate * The timer is stopped after all the messages are processed.
20270Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex
20280Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced
20290Sstevel@tonic-gate * while we are still processing the message queue. This is not
20300Sstevel@tonic-gate * good. So we stop the timer here instead.
20310Sstevel@tonic-gate */
20320Sstevel@tonic-gate if (stop_timer) {
20330Sstevel@tonic-gate RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref "
20340Sstevel@tonic-gate "cnt going to non zero\n", (void *)WR(q));
20350Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
20360Sstevel@tonic-gate }
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate if (q->q_first == NULL) {
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir);
20410Sstevel@tonic-gate
20420Sstevel@tonic-gate ASSERT(cmp == NULL);
20430Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) {
20440Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp;
20450Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL;
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
20490Sstevel@tonic-gate
20500Sstevel@tonic-gate if (cmp != NULL) {
20510Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held "
20524741Sgt29601 "disconnect/ord rel indication upstream\n",
20534741Sgt29601 __LINE__);
20540Sstevel@tonic-gate putnext(q, cmp);
20550Sstevel@tonic-gate }
20560Sstevel@tonic-gate
20570Sstevel@tonic-gate return;
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate
20620Sstevel@tonic-gate static int mir_svc_policy_fails;
20630Sstevel@tonic-gate
20640Sstevel@tonic-gate /*
20650Sstevel@tonic-gate * Called to send an event code to nfsd/lockd so that it initiates
20660Sstevel@tonic-gate * connection close.
20670Sstevel@tonic-gate */
20680Sstevel@tonic-gate static int
mir_svc_policy_notify(queue_t * q,int event)20690Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event)
20700Sstevel@tonic-gate {
20710Sstevel@tonic-gate mblk_t *mp;
20720Sstevel@tonic-gate #ifdef DEBUG
20730Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
20740Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
20750Sstevel@tonic-gate #endif
20760Sstevel@tonic-gate ASSERT(q->q_flag & QREADR);
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate /*
20790Sstevel@tonic-gate * Create an M_DATA message with the event code and pass it to the
20800Sstevel@tonic-gate * Stream head (nfsd or whoever created the stream will consume it).
20810Sstevel@tonic-gate */
20820Sstevel@tonic-gate mp = allocb(sizeof (int), BPRI_HI);
20830Sstevel@tonic-gate
20840Sstevel@tonic-gate if (!mp) {
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate mir_svc_policy_fails++;
20870Sstevel@tonic-gate RPCLOG(16, "mir_svc_policy_notify: could not allocate event "
20884741Sgt29601 "%d\n", event);
20890Sstevel@tonic-gate return (ENOMEM);
20900Sstevel@tonic-gate }
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate U32_TO_BE32(event, mp->b_rptr);
20930Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (int);
20940Sstevel@tonic-gate putnext(q, mp);
20950Sstevel@tonic-gate return (0);
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate /*
20990Sstevel@tonic-gate * Server side: start the close phase. We want to get this rpcmod slot in an
21000Sstevel@tonic-gate * idle state before mir_close() is called.
21010Sstevel@tonic-gate */
21020Sstevel@tonic-gate static void
mir_svc_start_close(queue_t * wq,mir_t * mir)21030Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir)
21040Sstevel@tonic-gate {
21050Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
21060Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
21070Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
21080Sstevel@tonic-gate
21090Sstevel@tonic-gate
21100Sstevel@tonic-gate /*
21110Sstevel@tonic-gate * Do not accept any more messages.
21120Sstevel@tonic-gate */
21130Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1;
21140Sstevel@tonic-gate
21150Sstevel@tonic-gate /*
21160Sstevel@tonic-gate * Next two statements will make the read service procedure invoke
21170Sstevel@tonic-gate * svc_queuereq() on everything stuck in the streams read queue.
21180Sstevel@tonic-gate * It's not necessary because enabling the write queue will
21190Sstevel@tonic-gate * have the same effect, but why not speed the process along?
21200Sstevel@tonic-gate */
21210Sstevel@tonic-gate mir->mir_hold_inbound = 0;
21220Sstevel@tonic-gate qenable(RD(wq));
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate /*
21250Sstevel@tonic-gate * Meanwhile force the write service procedure to send the
21260Sstevel@tonic-gate * responses downstream, regardless of flow control.
21270Sstevel@tonic-gate */
21280Sstevel@tonic-gate qenable(wq);
21290Sstevel@tonic-gate }
21300Sstevel@tonic-gate
21310Sstevel@tonic-gate /*
21320Sstevel@tonic-gate * This routine is called directly by KRPC after a request is completed,
21330Sstevel@tonic-gate * whether a reply was sent or the request was dropped.
21340Sstevel@tonic-gate */
21350Sstevel@tonic-gate static void
mir_svc_release(queue_t * wq,mblk_t * mp)21360Sstevel@tonic-gate mir_svc_release(queue_t *wq, mblk_t *mp)
21370Sstevel@tonic-gate {
21380Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
21390Sstevel@tonic-gate mblk_t *cmp = NULL;
21400Sstevel@tonic-gate
21410Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
21420Sstevel@tonic-gate if (mp)
21430Sstevel@tonic-gate freemsg(mp);
21440Sstevel@tonic-gate
21450Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate /*
21480Sstevel@tonic-gate * Start idle processing if this is the last reference.
21490Sstevel@tonic-gate */
21502610Smaheshvs if ((mir->mir_ref_cnt == 1) && (mir->mir_inrservice == 0)) {
21518022SMarcel.Telka@Sun.COM cmp = mir->mir_svc_pend_mp;
21528022SMarcel.Telka@Sun.COM mir->mir_svc_pend_mp = NULL;
21538022SMarcel.Telka@Sun.COM }
21548022SMarcel.Telka@Sun.COM
21558022SMarcel.Telka@Sun.COM if (cmp) {
21568022SMarcel.Telka@Sun.COM RPCLOG(16, "mir_svc_release: sending a held "
21578022SMarcel.Telka@Sun.COM "disconnect/ord rel indication upstream on queue 0x%p\n",
21588022SMarcel.Telka@Sun.COM (void *)RD(wq));
21598022SMarcel.Telka@Sun.COM
21608022SMarcel.Telka@Sun.COM mutex_exit(&mir->mir_mutex);
21618022SMarcel.Telka@Sun.COM
21628022SMarcel.Telka@Sun.COM putnext(RD(wq), cmp);
21638022SMarcel.Telka@Sun.COM
21648022SMarcel.Telka@Sun.COM mutex_enter(&mir->mir_mutex);
21658022SMarcel.Telka@Sun.COM }
21668022SMarcel.Telka@Sun.COM
21678022SMarcel.Telka@Sun.COM /*
21688022SMarcel.Telka@Sun.COM * Start idle processing if this is the last reference.
21698022SMarcel.Telka@Sun.COM */
21708022SMarcel.Telka@Sun.COM if (mir->mir_ref_cnt == 1 && mir->mir_inrservice == 0) {
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate RPCLOG(16, "mir_svc_release starting idle timer on 0x%p "
21730Sstevel@tonic-gate "because ref cnt is zero\n", (void *) wq);
21740Sstevel@tonic-gate
21750Sstevel@tonic-gate mir_svc_idle_start(wq, mir);
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate
21782610Smaheshvs mir->mir_ref_cnt--;
21792610Smaheshvs ASSERT(mir->mir_ref_cnt >= 0);
21802610Smaheshvs
21812610Smaheshvs /*
21822610Smaheshvs * Wake up the thread waiting to close.
21832610Smaheshvs */
21842610Smaheshvs
21852610Smaheshvs if ((mir->mir_ref_cnt == 0) && mir->mir_closing)
21862610Smaheshvs cv_signal(&mir->mir_condvar);
21872610Smaheshvs
21880Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate
21910Sstevel@tonic-gate /*
21920Sstevel@tonic-gate * This routine is called by server-side KRPC when it is ready to
21930Sstevel@tonic-gate * handle inbound messages on the stream.
21940Sstevel@tonic-gate */
21950Sstevel@tonic-gate static void
mir_svc_start(queue_t * wq)21960Sstevel@tonic-gate mir_svc_start(queue_t *wq)
21970Sstevel@tonic-gate {
21980Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
21990Sstevel@tonic-gate
22002470Sgt29601 /*
22012470Sgt29601 * no longer need to take the mir_mutex because the
22022470Sgt29601 * mir_setup_complete field has been moved out of
22032470Sgt29601 * the binary field protected by the mir_mutex.
22042470Sgt29601 */
22052470Sgt29601
22060Sstevel@tonic-gate mir->mir_setup_complete = 1;
22070Sstevel@tonic-gate qenable(RD(wq));
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate
22100Sstevel@tonic-gate /*
22110Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout.
22120Sstevel@tonic-gate */
22130Sstevel@tonic-gate static void
mir_clnt_idle_stop(queue_t * wq,mir_t * mir)22140Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir)
22150Sstevel@tonic-gate {
22160Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
22170Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
22180Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT);
22190Sstevel@tonic-gate
22200Sstevel@tonic-gate mir_timer_stop(mir);
22210Sstevel@tonic-gate }
22220Sstevel@tonic-gate
22230Sstevel@tonic-gate /*
22240Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout.
22250Sstevel@tonic-gate */
22260Sstevel@tonic-gate static void
mir_clnt_idle_start(queue_t * wq,mir_t * mir)22270Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir)
22280Sstevel@tonic-gate {
22290Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
22300Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
22310Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT);
22320Sstevel@tonic-gate
22330Sstevel@tonic-gate mir_timer_start(wq, mir, mir->mir_idle_timeout);
22340Sstevel@tonic-gate }
22350Sstevel@tonic-gate
22360Sstevel@tonic-gate /*
22370Sstevel@tonic-gate * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on
22380Sstevel@tonic-gate * end-points that aren't connected.
22390Sstevel@tonic-gate */
22400Sstevel@tonic-gate static void
mir_clnt_idle_do_stop(queue_t * wq)22410Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq)
22420Sstevel@tonic-gate {
22430Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
22440Sstevel@tonic-gate
22450Sstevel@tonic-gate RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq);
22460Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
22470Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
22480Sstevel@tonic-gate mir_clnt_idle_stop(wq, mir);
22490Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22500Sstevel@tonic-gate }
22510Sstevel@tonic-gate
22520Sstevel@tonic-gate /*
22530Sstevel@tonic-gate * Timer handler. It handles idle timeout and memory shortage problem.
22540Sstevel@tonic-gate */
22550Sstevel@tonic-gate static void
mir_timer(void * arg)22560Sstevel@tonic-gate mir_timer(void *arg)
22570Sstevel@tonic-gate {
22580Sstevel@tonic-gate queue_t *wq = (queue_t *)arg;
22590Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
22600Sstevel@tonic-gate boolean_t notify;
226111066Srafael.vanoni@sun.com clock_t now;
22620Sstevel@tonic-gate
22630Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
22640Sstevel@tonic-gate
22650Sstevel@tonic-gate /*
22660Sstevel@tonic-gate * mir_timer_call is set only when either mir_timer_[start|stop]
22670Sstevel@tonic-gate * is progressing. And mir_timer() can only be run while they
22680Sstevel@tonic-gate * are progressing if the timer is being stopped. So just
22690Sstevel@tonic-gate * return.
22700Sstevel@tonic-gate */
22710Sstevel@tonic-gate if (mir->mir_timer_call) {
22720Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22730Sstevel@tonic-gate return;
22740Sstevel@tonic-gate }
22750Sstevel@tonic-gate mir->mir_timer_id = 0;
22760Sstevel@tonic-gate
22770Sstevel@tonic-gate switch (mir->mir_type) {
22780Sstevel@tonic-gate case RPC_CLIENT:
22790Sstevel@tonic-gate
22800Sstevel@tonic-gate /*
22810Sstevel@tonic-gate * For clients, the timer fires at clnt_idle_timeout
22820Sstevel@tonic-gate * intervals. If the activity marker (mir_clntreq) is
22830Sstevel@tonic-gate * zero, then the stream has been idle since the last
22840Sstevel@tonic-gate * timer event and we notify KRPC. If mir_clntreq is
22850Sstevel@tonic-gate * non-zero, then the stream is active and we just
22860Sstevel@tonic-gate * restart the timer for another interval. mir_clntreq
22870Sstevel@tonic-gate * is set to 1 in mir_wput for every request passed
22880Sstevel@tonic-gate * downstream.
22890Sstevel@tonic-gate *
22900Sstevel@tonic-gate * If this was a memory shortage timer reset the idle
22910Sstevel@tonic-gate * timeout regardless; the mir_clntreq will not be a
22920Sstevel@tonic-gate * valid indicator.
22930Sstevel@tonic-gate *
22940Sstevel@tonic-gate * The timer is initially started in mir_wput during
22950Sstevel@tonic-gate * RPC_CLIENT ioctl processing.
22960Sstevel@tonic-gate *
22970Sstevel@tonic-gate * The timer interval can be changed for individual
22980Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout".
22990Sstevel@tonic-gate */
230011066Srafael.vanoni@sun.com now = ddi_get_lbolt();
23010Sstevel@tonic-gate if (mir->mir_clntreq > 0 && mir->mir_use_timestamp +
230211066Srafael.vanoni@sun.com MSEC_TO_TICK(mir->mir_idle_timeout) - now >= 0) {
23030Sstevel@tonic-gate clock_t tout;
23040Sstevel@tonic-gate
23050Sstevel@tonic-gate tout = mir->mir_idle_timeout -
230611066Srafael.vanoni@sun.com TICK_TO_MSEC(now - mir->mir_use_timestamp);
23070Sstevel@tonic-gate if (tout < 0)
23080Sstevel@tonic-gate tout = 1000;
23090Sstevel@tonic-gate #if 0
23104741Sgt29601 printf("mir_timer[%d < %d + %d]: reset client timer "
231111066Srafael.vanoni@sun.com "to %d (ms)\n", TICK_TO_MSEC(now),
23124741Sgt29601 TICK_TO_MSEC(mir->mir_use_timestamp),
23134741Sgt29601 mir->mir_idle_timeout, tout);
23140Sstevel@tonic-gate #endif
23150Sstevel@tonic-gate mir->mir_clntreq = 0;
23160Sstevel@tonic-gate mir_timer_start(wq, mir, tout);
23170Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23180Sstevel@tonic-gate return;
23190Sstevel@tonic-gate }
23200Sstevel@tonic-gate #if 0
232111066Srafael.vanoni@sun.com printf("mir_timer[%d]: doing client timeout\n", now / hz);
23220Sstevel@tonic-gate #endif
23230Sstevel@tonic-gate /*
23240Sstevel@tonic-gate * We are disconnecting, but not necessarily
23250Sstevel@tonic-gate * closing. By not closing, we will fail to
23260Sstevel@tonic-gate * pick up a possibly changed global timeout value,
23270Sstevel@tonic-gate * unless we store it now.
23280Sstevel@tonic-gate */
23290Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
23300Sstevel@tonic-gate mir_clnt_idle_start(wq, mir);
23310Sstevel@tonic-gate
23320Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23330Sstevel@tonic-gate /*
23340Sstevel@tonic-gate * We pass T_ORDREL_REQ as an integer value
23350Sstevel@tonic-gate * to KRPC as the indication that the stream
23360Sstevel@tonic-gate * is idle. This is not a T_ORDREL_REQ message,
23370Sstevel@tonic-gate * it is just a convenient value since we call
23380Sstevel@tonic-gate * the same KRPC routine for T_ORDREL_INDs and
23390Sstevel@tonic-gate * T_DISCON_INDs.
23400Sstevel@tonic-gate */
23410Sstevel@tonic-gate clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0);
23420Sstevel@tonic-gate return;
23430Sstevel@tonic-gate
23440Sstevel@tonic-gate case RPC_SERVER:
23450Sstevel@tonic-gate
23460Sstevel@tonic-gate /*
23470Sstevel@tonic-gate * For servers, the timer is only running when the stream
23480Sstevel@tonic-gate * is really idle or memory is short. The timer is started
23490Sstevel@tonic-gate * by mir_wput when mir_type is set to RPC_SERVER and
23500Sstevel@tonic-gate * by mir_svc_idle_start whenever the stream goes idle
23510Sstevel@tonic-gate * (mir_ref_cnt == 0). The timer is cancelled in
23520Sstevel@tonic-gate * mir_rput whenever a new inbound request is passed to KRPC
23530Sstevel@tonic-gate * and the stream was previously idle.
23540Sstevel@tonic-gate *
23550Sstevel@tonic-gate * The timer interval can be changed for individual
23560Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout".
23570Sstevel@tonic-gate *
23580Sstevel@tonic-gate * If the stream is not idle do nothing.
23590Sstevel@tonic-gate */
23600Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir)) {
23610Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23620Sstevel@tonic-gate return;
23630Sstevel@tonic-gate }
23640Sstevel@tonic-gate
23650Sstevel@tonic-gate notify = !mir->mir_inrservice;
23660Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23670Sstevel@tonic-gate
23680Sstevel@tonic-gate /*
23690Sstevel@tonic-gate * If there is no packet queued up in read queue, the stream
23700Sstevel@tonic-gate * is really idle so notify nfsd to close it.
23710Sstevel@tonic-gate */
23720Sstevel@tonic-gate if (notify) {
23730Sstevel@tonic-gate RPCLOG(16, "mir_timer: telling stream head listener "
23740Sstevel@tonic-gate "to close stream (0x%p)\n", (void *) RD(wq));
23750Sstevel@tonic-gate (void) mir_svc_policy_notify(RD(wq), 1);
23760Sstevel@tonic-gate }
23770Sstevel@tonic-gate return;
23780Sstevel@tonic-gate default:
23790Sstevel@tonic-gate RPCLOG(1, "mir_timer: unexpected mir_type %d\n",
23804741Sgt29601 mir->mir_type);
23810Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23820Sstevel@tonic-gate return;
23830Sstevel@tonic-gate }
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate
23860Sstevel@tonic-gate /*
23870Sstevel@tonic-gate * Called by the RPC package to send either a call or a return, or a
23880Sstevel@tonic-gate * transport connection request. Adds the record marking header.
23890Sstevel@tonic-gate */
23900Sstevel@tonic-gate static void
mir_wput(queue_t * q,mblk_t * mp)23910Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp)
23920Sstevel@tonic-gate {
23930Sstevel@tonic-gate uint_t frag_header;
23940Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
23950Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr;
23960Sstevel@tonic-gate
23970Sstevel@tonic-gate if (!mir) {
23980Sstevel@tonic-gate freemsg(mp);
23990Sstevel@tonic-gate return;
24000Sstevel@tonic-gate }
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) {
24030Sstevel@tonic-gate mir_wput_other(q, mp);
24040Sstevel@tonic-gate return;
24050Sstevel@tonic-gate }
24060Sstevel@tonic-gate
24070Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) {
24080Sstevel@tonic-gate freemsg(mp);
24090Sstevel@tonic-gate RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n",
24104741Sgt29601 (void *)q);
24110Sstevel@tonic-gate return;
24120Sstevel@tonic-gate }
24130Sstevel@tonic-gate
24140Sstevel@tonic-gate frag_header = (uint_t)DLEN(mp);
24150Sstevel@tonic-gate frag_header |= MIR_LASTFRAG;
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate /* Stick in the 4 byte record marking header. */
24180Sstevel@tonic-gate if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) ||
24190Sstevel@tonic-gate !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
24200Sstevel@tonic-gate /*
24210Sstevel@tonic-gate * Since we know that M_DATA messages are created exclusively
24220Sstevel@tonic-gate * by KRPC, we expect that KRPC will leave room for our header
24230Sstevel@tonic-gate * and 4 byte align which is normal for XDR.
24240Sstevel@tonic-gate * If KRPC (or someone else) does not cooperate, then we
24250Sstevel@tonic-gate * just throw away the message.
24260Sstevel@tonic-gate */
24270Sstevel@tonic-gate RPCLOG(1, "mir_wput: KRPC did not leave space for record "
24280Sstevel@tonic-gate "fragment header (%d bytes left)\n",
24290Sstevel@tonic-gate (int)(rptr - mp->b_datap->db_base));
24300Sstevel@tonic-gate freemsg(mp);
24310Sstevel@tonic-gate return;
24320Sstevel@tonic-gate }
24330Sstevel@tonic-gate rptr -= sizeof (uint32_t);
24340Sstevel@tonic-gate *(uint32_t *)rptr = htonl(frag_header);
24350Sstevel@tonic-gate mp->b_rptr = rptr;
24360Sstevel@tonic-gate
24370Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
24380Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) {
24390Sstevel@tonic-gate /*
24400Sstevel@tonic-gate * For the client, set mir_clntreq to indicate that the
24410Sstevel@tonic-gate * connection is active.
24420Sstevel@tonic-gate */
24430Sstevel@tonic-gate mir->mir_clntreq = 1;
244411066Srafael.vanoni@sun.com mir->mir_use_timestamp = ddi_get_lbolt();
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate /*
24480Sstevel@tonic-gate * If we haven't already queued some data and the downstream module
24490Sstevel@tonic-gate * can accept more data, send it on, otherwise we queue the message
24500Sstevel@tonic-gate * and take other actions depending on mir_type.
24510Sstevel@tonic-gate */
24520Sstevel@tonic-gate if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) {
24530Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24540Sstevel@tonic-gate
24550Sstevel@tonic-gate /*
24560Sstevel@tonic-gate * Now we pass the RPC message downstream.
24570Sstevel@tonic-gate */
24580Sstevel@tonic-gate putnext(q, mp);
24590Sstevel@tonic-gate return;
24600Sstevel@tonic-gate }
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate switch (mir->mir_type) {
24630Sstevel@tonic-gate case RPC_CLIENT:
24640Sstevel@tonic-gate /*
24650Sstevel@tonic-gate * Check for a previous duplicate request on the
24660Sstevel@tonic-gate * queue. If there is one, then we throw away
24670Sstevel@tonic-gate * the current message and let the previous one
24680Sstevel@tonic-gate * go through. If we can't find a duplicate, then
24690Sstevel@tonic-gate * send this one. This tap dance is an effort
24700Sstevel@tonic-gate * to reduce traffic and processing requirements
24710Sstevel@tonic-gate * under load conditions.
24720Sstevel@tonic-gate */
24730Sstevel@tonic-gate if (mir_clnt_dup_request(q, mp)) {
24740Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24750Sstevel@tonic-gate freemsg(mp);
24760Sstevel@tonic-gate return;
24770Sstevel@tonic-gate }
24780Sstevel@tonic-gate break;
24790Sstevel@tonic-gate case RPC_SERVER:
24800Sstevel@tonic-gate /*
24810Sstevel@tonic-gate * Set mir_hold_inbound so that new inbound RPC
24820Sstevel@tonic-gate * messages will be held until the client catches
24830Sstevel@tonic-gate * up on the earlier replies. This flag is cleared
24840Sstevel@tonic-gate * in mir_wsrv after flow control is relieved;
24850Sstevel@tonic-gate * the read-side queue is also enabled at that time.
24860Sstevel@tonic-gate */
24870Sstevel@tonic-gate mir->mir_hold_inbound = 1;
24880Sstevel@tonic-gate break;
24890Sstevel@tonic-gate default:
24900Sstevel@tonic-gate RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type);
24910Sstevel@tonic-gate break;
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate mir->mir_inwservice = 1;
24940Sstevel@tonic-gate (void) putq(q, mp);
24950Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24960Sstevel@tonic-gate }
24970Sstevel@tonic-gate
24980Sstevel@tonic-gate static void
mir_wput_other(queue_t * q,mblk_t * mp)24990Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp)
25000Sstevel@tonic-gate {
25010Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
25020Sstevel@tonic-gate struct iocblk *iocp;
25030Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr;
25040Sstevel@tonic-gate bool_t flush_in_svc = FALSE;
25050Sstevel@tonic-gate
25060Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
25070Sstevel@tonic-gate switch (mp->b_datap->db_type) {
25080Sstevel@tonic-gate case M_IOCTL:
25090Sstevel@tonic-gate iocp = (struct iocblk *)rptr;
25100Sstevel@tonic-gate switch (iocp->ioc_cmd) {
25110Sstevel@tonic-gate case RPC_CLIENT:
25120Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
25130Sstevel@tonic-gate if (mir->mir_type != 0 &&
25140Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) {
25150Sstevel@tonic-gate ioc_eperm:
25160Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25170Sstevel@tonic-gate iocp->ioc_error = EPERM;
25180Sstevel@tonic-gate iocp->ioc_count = 0;
25190Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
25200Sstevel@tonic-gate qreply(q, mp);
25210Sstevel@tonic-gate return;
25220Sstevel@tonic-gate }
25230Sstevel@tonic-gate
25240Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd;
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate /*
25270Sstevel@tonic-gate * Clear mir_hold_inbound which was set to 1 by
25280Sstevel@tonic-gate * mir_open. This flag is not used on client
25290Sstevel@tonic-gate * streams.
25300Sstevel@tonic-gate */
25310Sstevel@tonic-gate mir->mir_hold_inbound = 0;
25320Sstevel@tonic-gate mir->mir_max_msg_sizep = &clnt_max_msg_size;
25330Sstevel@tonic-gate
25340Sstevel@tonic-gate /*
25350Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more
25360Sstevel@tonic-gate * information on how client timers work.
25370Sstevel@tonic-gate */
25380Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
25390Sstevel@tonic-gate mir_clnt_idle_start(q, mir);
25400Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25410Sstevel@tonic-gate
25420Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
25430Sstevel@tonic-gate qreply(q, mp);
25440Sstevel@tonic-gate return;
25450Sstevel@tonic-gate case RPC_SERVER:
25460Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
25470Sstevel@tonic-gate if (mir->mir_type != 0 &&
25480Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd)
25490Sstevel@tonic-gate goto ioc_eperm;
25500Sstevel@tonic-gate
25510Sstevel@tonic-gate /*
25520Sstevel@tonic-gate * We don't clear mir_hold_inbound here because
25530Sstevel@tonic-gate * mir_hold_inbound is used in the flow control
25540Sstevel@tonic-gate * model. If we cleared it here, then we'd commit
25550Sstevel@tonic-gate * a small violation to the model where the transport
25560Sstevel@tonic-gate * might immediately block downstream flow.
25570Sstevel@tonic-gate */
25580Sstevel@tonic-gate
25590Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd;
25600Sstevel@tonic-gate mir->mir_max_msg_sizep = &svc_max_msg_size;
25610Sstevel@tonic-gate
25620Sstevel@tonic-gate /*
25630Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more
25640Sstevel@tonic-gate * information on how server timers work.
25650Sstevel@tonic-gate *
25660Sstevel@tonic-gate * Note that it is important to start the idle timer
25670Sstevel@tonic-gate * here so that connections time out even if we
25680Sstevel@tonic-gate * never receive any data on them.
25690Sstevel@tonic-gate */
25700Sstevel@tonic-gate mir->mir_idle_timeout = svc_idle_timeout;
25710Sstevel@tonic-gate RPCLOG(16, "mir_wput_other starting idle timer on 0x%p "
25720Sstevel@tonic-gate "because we got RPC_SERVER ioctl\n", (void *)q);
25730Sstevel@tonic-gate mir_svc_idle_start(q, mir);
25740Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25750Sstevel@tonic-gate
25760Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
25770Sstevel@tonic-gate qreply(q, mp);
25780Sstevel@tonic-gate return;
25790Sstevel@tonic-gate default:
25800Sstevel@tonic-gate break;
25810Sstevel@tonic-gate }
25820Sstevel@tonic-gate break;
25830Sstevel@tonic-gate
25840Sstevel@tonic-gate case M_PROTO:
25850Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) {
25860Sstevel@tonic-gate /*
25870Sstevel@tonic-gate * We are likely being called from the context of a
25880Sstevel@tonic-gate * service procedure. So we need to enqueue. However
25890Sstevel@tonic-gate * enqueing may put our message behind data messages.
25900Sstevel@tonic-gate * So flush the data first.
25910Sstevel@tonic-gate */
25920Sstevel@tonic-gate flush_in_svc = TRUE;
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (uint32_t) ||
25954741Sgt29601 !IS_P2ALIGNED(rptr, sizeof (uint32_t)))
25960Sstevel@tonic-gate break;
25970Sstevel@tonic-gate
25980Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) {
25990Sstevel@tonic-gate case T_DATA_REQ:
26000Sstevel@tonic-gate /* Don't pass T_DATA_REQ messages downstream. */
26010Sstevel@tonic-gate freemsg(mp);
26020Sstevel@tonic-gate return;
26030Sstevel@tonic-gate case T_ORDREL_REQ:
26040Sstevel@tonic-gate RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n",
26050Sstevel@tonic-gate (void *)q);
26060Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
26070Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) {
26080Sstevel@tonic-gate /*
26090Sstevel@tonic-gate * We are likely being called from
26100Sstevel@tonic-gate * clnt_dispatch_notifyall(). Sending
26110Sstevel@tonic-gate * a T_ORDREL_REQ will result in
26120Sstevel@tonic-gate * a some kind of _IND message being sent,
26130Sstevel@tonic-gate * will be another call to
26140Sstevel@tonic-gate * clnt_dispatch_notifyall(). To keep the stack
26150Sstevel@tonic-gate * lean, queue this message.
26160Sstevel@tonic-gate */
26170Sstevel@tonic-gate mir->mir_inwservice = 1;
26180Sstevel@tonic-gate (void) putq(q, mp);
26190Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26200Sstevel@tonic-gate return;
26210Sstevel@tonic-gate }
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate /*
26240Sstevel@tonic-gate * Mark the structure such that we don't accept any
26250Sstevel@tonic-gate * more requests from client. We could defer this
26260Sstevel@tonic-gate * until we actually send the orderly release
26270Sstevel@tonic-gate * request downstream, but all that does is delay
26280Sstevel@tonic-gate * the closing of this stream.
26290Sstevel@tonic-gate */
26300Sstevel@tonic-gate RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ "
26310Sstevel@tonic-gate " so calling mir_svc_start_close\n", (void *)q);
26320Sstevel@tonic-gate
26330Sstevel@tonic-gate mir_svc_start_close(q, mir);
26340Sstevel@tonic-gate
26350Sstevel@tonic-gate /*
26360Sstevel@tonic-gate * If we have sent down a T_ORDREL_REQ, don't send
26370Sstevel@tonic-gate * any more.
26380Sstevel@tonic-gate */
26390Sstevel@tonic-gate if (mir->mir_ordrel_pending) {
26400Sstevel@tonic-gate freemsg(mp);
26410Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26420Sstevel@tonic-gate return;
26430Sstevel@tonic-gate }
26440Sstevel@tonic-gate
26450Sstevel@tonic-gate /*
26460Sstevel@tonic-gate * If the stream is not idle, then we hold the
26470Sstevel@tonic-gate * orderly release until it becomes idle. This
26480Sstevel@tonic-gate * ensures that KRPC will be able to reply to
26490Sstevel@tonic-gate * all requests that we have passed to it.
26500Sstevel@tonic-gate *
26510Sstevel@tonic-gate * We also queue the request if there is data already
26520Sstevel@tonic-gate * queued, because we cannot allow the T_ORDREL_REQ
26530Sstevel@tonic-gate * to go before data. When we had a separate reply
26540Sstevel@tonic-gate * count, this was not a problem, because the
26550Sstevel@tonic-gate * reply count was reconciled when mir_wsrv()
26560Sstevel@tonic-gate * completed.
26570Sstevel@tonic-gate */
26580Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir) ||
26590Sstevel@tonic-gate mir->mir_inwservice == 1) {
26600Sstevel@tonic-gate mir->mir_inwservice = 1;
26610Sstevel@tonic-gate (void) putq(q, mp);
26620Sstevel@tonic-gate
26630Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: queuing "
26640Sstevel@tonic-gate "T_ORDREL_REQ on 0x%p\n", (void *)q);
26650Sstevel@tonic-gate
26660Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26670Sstevel@tonic-gate return;
26680Sstevel@tonic-gate }
26690Sstevel@tonic-gate
26700Sstevel@tonic-gate /*
26710Sstevel@tonic-gate * Mark the structure so that we know we sent
26720Sstevel@tonic-gate * an orderly release request, and reset the idle timer.
26730Sstevel@tonic-gate */
26740Sstevel@tonic-gate mir->mir_ordrel_pending = 1;
26750Sstevel@tonic-gate
26760Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start"
26770Sstevel@tonic-gate " on 0x%p because we got T_ORDREL_REQ\n",
26780Sstevel@tonic-gate (void *)q);
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate mir_svc_idle_start(q, mir);
26810Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26820Sstevel@tonic-gate
26830Sstevel@tonic-gate /*
26840Sstevel@tonic-gate * When we break, we will putnext the T_ORDREL_REQ.
26850Sstevel@tonic-gate */
26860Sstevel@tonic-gate break;
26870Sstevel@tonic-gate
26880Sstevel@tonic-gate case T_CONN_REQ:
26890Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
26900Sstevel@tonic-gate if (mir->mir_head_mp != NULL) {
26910Sstevel@tonic-gate freemsg(mir->mir_head_mp);
26920Sstevel@tonic-gate mir->mir_head_mp = NULL;
26930Sstevel@tonic-gate mir->mir_tail_mp = NULL;
26940Sstevel@tonic-gate }
26950Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
26960Sstevel@tonic-gate /*
26970Sstevel@tonic-gate * Restart timer in case mir_clnt_idle_do_stop() was
26980Sstevel@tonic-gate * called.
26990Sstevel@tonic-gate */
27000Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
27010Sstevel@tonic-gate mir_clnt_idle_stop(q, mir);
27020Sstevel@tonic-gate mir_clnt_idle_start(q, mir);
27030Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27040Sstevel@tonic-gate break;
27050Sstevel@tonic-gate
27060Sstevel@tonic-gate default:
27070Sstevel@tonic-gate /*
27080Sstevel@tonic-gate * T_DISCON_REQ is one of the interesting default
27090Sstevel@tonic-gate * cases here. Ideally, an M_FLUSH is done before
27100Sstevel@tonic-gate * T_DISCON_REQ is done. However, that is somewhat
27110Sstevel@tonic-gate * cumbersome for clnt_cots.c to do. So we queue
27120Sstevel@tonic-gate * T_DISCON_REQ, and let the service procedure
27130Sstevel@tonic-gate * flush all M_DATA.
27140Sstevel@tonic-gate */
27150Sstevel@tonic-gate break;
27160Sstevel@tonic-gate }
27170Sstevel@tonic-gate /* fallthru */;
27180Sstevel@tonic-gate default:
27190Sstevel@tonic-gate if (mp->b_datap->db_type >= QPCTL) {
27200Sstevel@tonic-gate if (mp->b_datap->db_type == M_FLUSH) {
27210Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT &&
27220Sstevel@tonic-gate *mp->b_rptr & FLUSHW) {
27230Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: flushing "
27240Sstevel@tonic-gate "wq 0x%p\n", (void *)q);
27250Sstevel@tonic-gate if (*mp->b_rptr & FLUSHBAND) {
27260Sstevel@tonic-gate flushband(q, *(mp->b_rptr + 1),
27274741Sgt29601 FLUSHDATA);
27280Sstevel@tonic-gate } else {
27290Sstevel@tonic-gate flushq(q, FLUSHDATA);
27300Sstevel@tonic-gate }
27310Sstevel@tonic-gate } else {
27320Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: ignoring "
27330Sstevel@tonic-gate "M_FLUSH on wq 0x%p\n", (void *)q);
27340Sstevel@tonic-gate }
27350Sstevel@tonic-gate }
27360Sstevel@tonic-gate break;
27370Sstevel@tonic-gate }
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
27400Sstevel@tonic-gate if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) {
27410Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27420Sstevel@tonic-gate break;
27430Sstevel@tonic-gate }
27440Sstevel@tonic-gate mir->mir_inwservice = 1;
27450Sstevel@tonic-gate mir->mir_inwflushdata = flush_in_svc;
27460Sstevel@tonic-gate (void) putq(q, mp);
27470Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27480Sstevel@tonic-gate qenable(q);
27490Sstevel@tonic-gate
27500Sstevel@tonic-gate return;
27510Sstevel@tonic-gate }
27520Sstevel@tonic-gate putnext(q, mp);
27530Sstevel@tonic-gate }
27540Sstevel@tonic-gate
27550Sstevel@tonic-gate static void
mir_wsrv(queue_t * q)27560Sstevel@tonic-gate mir_wsrv(queue_t *q)
27570Sstevel@tonic-gate {
27580Sstevel@tonic-gate mblk_t *mp;
27590Sstevel@tonic-gate mir_t *mir;
27600Sstevel@tonic-gate bool_t flushdata;
27610Sstevel@tonic-gate
27620Sstevel@tonic-gate mir = (mir_t *)q->q_ptr;
27630Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
27640Sstevel@tonic-gate
27650Sstevel@tonic-gate flushdata = mir->mir_inwflushdata;
27660Sstevel@tonic-gate mir->mir_inwflushdata = 0;
27670Sstevel@tonic-gate
27680Sstevel@tonic-gate while (mp = getq(q)) {
27690Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) {
27700Sstevel@tonic-gate /*
27710Sstevel@tonic-gate * Do not send any more data if we have sent
27720Sstevel@tonic-gate * a T_ORDREL_REQ.
27730Sstevel@tonic-gate */
27740Sstevel@tonic-gate if (flushdata || mir->mir_ordrel_pending == 1) {
27750Sstevel@tonic-gate freemsg(mp);
27760Sstevel@tonic-gate continue;
27770Sstevel@tonic-gate }
27780Sstevel@tonic-gate
27790Sstevel@tonic-gate /*
27800Sstevel@tonic-gate * Make sure that the stream can really handle more
27810Sstevel@tonic-gate * data.
27820Sstevel@tonic-gate */
27830Sstevel@tonic-gate if (!MIR_WCANPUTNEXT(mir, q)) {
27840Sstevel@tonic-gate (void) putbq(q, mp);
27850Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27860Sstevel@tonic-gate return;
27870Sstevel@tonic-gate }
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate /*
27900Sstevel@tonic-gate * Now we pass the RPC message downstream.
27910Sstevel@tonic-gate */
27920Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27930Sstevel@tonic-gate putnext(q, mp);
27940Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
27950Sstevel@tonic-gate continue;
27960Sstevel@tonic-gate }
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate /*
27990Sstevel@tonic-gate * This is not an RPC message, pass it downstream
28000Sstevel@tonic-gate * (ignoring flow control) if the server side is not sending a
28010Sstevel@tonic-gate * T_ORDREL_REQ downstream.
28020Sstevel@tonic-gate */
28030Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER ||
28044741Sgt29601 ((union T_primitives *)mp->b_rptr)->type !=
28054741Sgt29601 T_ORDREL_REQ) {
28060Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28070Sstevel@tonic-gate putnext(q, mp);
28080Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
28090Sstevel@tonic-gate continue;
28100Sstevel@tonic-gate }
28110Sstevel@tonic-gate
28120Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) {
28130Sstevel@tonic-gate /*
28140Sstevel@tonic-gate * Don't send two T_ORDRELs
28150Sstevel@tonic-gate */
28160Sstevel@tonic-gate freemsg(mp);
28170Sstevel@tonic-gate continue;
28180Sstevel@tonic-gate }
28190Sstevel@tonic-gate
28200Sstevel@tonic-gate /*
28210Sstevel@tonic-gate * Mark the structure so that we know we sent an orderly
28220Sstevel@tonic-gate * release request. We will check to see slot is idle at the
28230Sstevel@tonic-gate * end of this routine, and if so, reset the idle timer to
28240Sstevel@tonic-gate * handle orderly release timeouts.
28250Sstevel@tonic-gate */
28260Sstevel@tonic-gate mir->mir_ordrel_pending = 1;
28270Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n",
28284741Sgt29601 (void *)q);
28290Sstevel@tonic-gate /*
28300Sstevel@tonic-gate * Send the orderly release downstream. If there are other
28310Sstevel@tonic-gate * pending replies we won't be able to send them. However,
28320Sstevel@tonic-gate * the only reason we should send the orderly release is if
28330Sstevel@tonic-gate * we were idle, or if an unusual event occurred.
28340Sstevel@tonic-gate */
28350Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28360Sstevel@tonic-gate putnext(q, mp);
28370Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
28380Sstevel@tonic-gate }
28390Sstevel@tonic-gate
28400Sstevel@tonic-gate if (q->q_first == NULL)
28410Sstevel@tonic-gate /*
28420Sstevel@tonic-gate * If we call mir_svc_idle_start() below, then
28430Sstevel@tonic-gate * clearing mir_inwservice here will also result in
28440Sstevel@tonic-gate * any thread waiting in mir_close() to be signaled.
28450Sstevel@tonic-gate */
28460Sstevel@tonic-gate mir->mir_inwservice = 0;
28470Sstevel@tonic-gate
28480Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) {
28490Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28500Sstevel@tonic-gate return;
28510Sstevel@tonic-gate }
28520Sstevel@tonic-gate
28530Sstevel@tonic-gate /*
28540Sstevel@tonic-gate * If idle we call mir_svc_idle_start to start the timer (or wakeup
28550Sstevel@tonic-gate * a close). Also make sure not to start the idle timer on the
28560Sstevel@tonic-gate * listener stream. This can cause nfsd to send an orderly release
28570Sstevel@tonic-gate * command on the listener stream.
28580Sstevel@tonic-gate */
28590Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) {
28600Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p "
28610Sstevel@tonic-gate "because mir slot is idle\n", (void *)q);
28620Sstevel@tonic-gate mir_svc_idle_start(q, mir);
28630Sstevel@tonic-gate }
28640Sstevel@tonic-gate
28650Sstevel@tonic-gate /*
28660Sstevel@tonic-gate * If outbound flow control has been relieved, then allow new
28670Sstevel@tonic-gate * inbound requests to be processed.
28680Sstevel@tonic-gate */
28690Sstevel@tonic-gate if (mir->mir_hold_inbound) {
28700Sstevel@tonic-gate mir->mir_hold_inbound = 0;
28710Sstevel@tonic-gate qenable(RD(q));
28720Sstevel@tonic-gate }
28730Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28740Sstevel@tonic-gate }
28750Sstevel@tonic-gate
28760Sstevel@tonic-gate static void
mir_disconnect(queue_t * q,mir_t * mir)28770Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir)
28780Sstevel@tonic-gate {
28790Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
28800Sstevel@tonic-gate
28810Sstevel@tonic-gate switch (mir->mir_type) {
28820Sstevel@tonic-gate case RPC_CLIENT:
28830Sstevel@tonic-gate /*
28840Sstevel@tonic-gate * We are disconnecting, but not necessarily
28850Sstevel@tonic-gate * closing. By not closing, we will fail to
28860Sstevel@tonic-gate * pick up a possibly changed global timeout value,
28870Sstevel@tonic-gate * unless we store it now.
28880Sstevel@tonic-gate */
28890Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
28900Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir);
28910Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28920Sstevel@tonic-gate
28930Sstevel@tonic-gate /*
28940Sstevel@tonic-gate * T_DISCON_REQ is passed to KRPC as an integer value
28950Sstevel@tonic-gate * (this is not a TPI message). It is used as a
28960Sstevel@tonic-gate * convenient value to indicate a sanity check
28970Sstevel@tonic-gate * failure -- the same KRPC routine is also called
28980Sstevel@tonic-gate * for T_DISCON_INDs and T_ORDREL_INDs.
28990Sstevel@tonic-gate */
29000Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0);
29010Sstevel@tonic-gate break;
29020Sstevel@tonic-gate
29030Sstevel@tonic-gate case RPC_SERVER:
29040Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1;
29050Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
29060Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
29070Sstevel@tonic-gate RPCLOG(16, "mir_disconnect: telling "
29084741Sgt29601 "stream head listener to disconnect stream "
29094741Sgt29601 "(0x%p)\n", (void *) q);
29100Sstevel@tonic-gate (void) mir_svc_policy_notify(q, 2);
29110Sstevel@tonic-gate break;
29120Sstevel@tonic-gate
29130Sstevel@tonic-gate default:
29140Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
29150Sstevel@tonic-gate break;
29160Sstevel@tonic-gate }
29170Sstevel@tonic-gate }
29180Sstevel@tonic-gate
29190Sstevel@tonic-gate /*
29205444Smeem * Sanity check the message length, and if it's too large, shutdown the
29215444Smeem * connection. Returns 1 if the connection is shutdown; 0 otherwise.
29220Sstevel@tonic-gate */
29230Sstevel@tonic-gate static int
mir_check_len(queue_t * q,int32_t frag_len,mblk_t * head_mp)29245444Smeem mir_check_len(queue_t *q, int32_t frag_len, mblk_t *head_mp)
29250Sstevel@tonic-gate {
29265444Smeem mir_t *mir = q->q_ptr;
29275444Smeem uint_t maxsize = 0;
29285444Smeem
29295444Smeem if (mir->mir_max_msg_sizep != NULL)
29305444Smeem maxsize = *mir->mir_max_msg_sizep;
29315444Smeem
29325444Smeem if (maxsize == 0 || frag_len <= (int)maxsize)
29330Sstevel@tonic-gate return (0);
29340Sstevel@tonic-gate
29350Sstevel@tonic-gate freemsg(head_mp);
29365444Smeem mir->mir_head_mp = NULL;
29375444Smeem mir->mir_tail_mp = NULL;
29385444Smeem mir->mir_frag_header = 0;
29395444Smeem mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
29400Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) {
29410Sstevel@tonic-gate cmn_err(CE_NOTE,
29424741Sgt29601 "KRPC: record fragment from %s of size(%d) exceeds "
29434741Sgt29601 "maximum (%u). Disconnecting",
29444741Sgt29601 (mir->mir_type == RPC_CLIENT) ? "server" :
29454741Sgt29601 (mir->mir_type == RPC_SERVER) ? "client" :
29465444Smeem "test tool", frag_len, maxsize);
29470Sstevel@tonic-gate }
29480Sstevel@tonic-gate
29490Sstevel@tonic-gate mir_disconnect(q, mir);
29500Sstevel@tonic-gate return (1);
29510Sstevel@tonic-gate }
2952