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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*766Scarlsonj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 290Sstevel@tonic-gate /* All Rights Reserved */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate 320Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * Kernel RPC filtering module 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include <sys/param.h> 390Sstevel@tonic-gate #include <sys/types.h> 400Sstevel@tonic-gate #include <sys/stream.h> 410Sstevel@tonic-gate #include <sys/stropts.h> 420Sstevel@tonic-gate #include <sys/tihdr.h> 430Sstevel@tonic-gate #include <sys/timod.h> 440Sstevel@tonic-gate #include <sys/tiuser.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate #include <sys/signal.h> 470Sstevel@tonic-gate #include <sys/pcb.h> 480Sstevel@tonic-gate #include <sys/user.h> 490Sstevel@tonic-gate #include <sys/errno.h> 500Sstevel@tonic-gate #include <sys/cred.h> 510Sstevel@tonic-gate #include <sys/policy.h> 520Sstevel@tonic-gate #include <sys/inline.h> 530Sstevel@tonic-gate #include <sys/cmn_err.h> 540Sstevel@tonic-gate #include <sys/kmem.h> 550Sstevel@tonic-gate #include <sys/file.h> 560Sstevel@tonic-gate #include <sys/sysmacros.h> 570Sstevel@tonic-gate #include <sys/systm.h> 580Sstevel@tonic-gate #include <sys/t_lock.h> 590Sstevel@tonic-gate #include <sys/ddi.h> 600Sstevel@tonic-gate #include <sys/vtrace.h> 610Sstevel@tonic-gate #include <sys/callb.h> 620Sstevel@tonic-gate 630Sstevel@tonic-gate #include <sys/strlog.h> 640Sstevel@tonic-gate #include <rpc/rpc_com.h> 650Sstevel@tonic-gate #include <inet/common.h> 660Sstevel@tonic-gate #include <rpc/types.h> 670Sstevel@tonic-gate #include <sys/time.h> 680Sstevel@tonic-gate #include <rpc/xdr.h> 690Sstevel@tonic-gate #include <rpc/auth.h> 700Sstevel@tonic-gate #include <rpc/clnt.h> 710Sstevel@tonic-gate #include <rpc/rpc_msg.h> 720Sstevel@tonic-gate #include <rpc/clnt.h> 730Sstevel@tonic-gate #include <rpc/svc.h> 740Sstevel@tonic-gate #include <rpc/rpcsys.h> 750Sstevel@tonic-gate #include <rpc/rpc_rdma.h> 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* 780Sstevel@tonic-gate * This is the loadable module wrapper. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate #include <sys/conf.h> 810Sstevel@tonic-gate #include <sys/modctl.h> 820Sstevel@tonic-gate #include <sys/syscall.h> 830Sstevel@tonic-gate 840Sstevel@tonic-gate extern struct streamtab rpcinfo; 850Sstevel@tonic-gate 860Sstevel@tonic-gate static struct fmodsw fsw = { 870Sstevel@tonic-gate "rpcmod", 880Sstevel@tonic-gate &rpcinfo, 890Sstevel@tonic-gate D_NEW|D_MP, 900Sstevel@tonic-gate }; 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Module linkage information for the kernel. 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate 960Sstevel@tonic-gate static struct modlstrmod modlstrmod = { 970Sstevel@tonic-gate &mod_strmodops, "rpc interface str mod", &fsw 980Sstevel@tonic-gate }; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * For the RPC system call. 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate static struct sysent rpcsysent = { 1040Sstevel@tonic-gate 2, 1050Sstevel@tonic-gate SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD, 1060Sstevel@tonic-gate rpcsys 1070Sstevel@tonic-gate }; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate static struct modlsys modlsys = { 1100Sstevel@tonic-gate &mod_syscallops, 1110Sstevel@tonic-gate "RPC syscall", 1120Sstevel@tonic-gate &rpcsysent 1130Sstevel@tonic-gate }; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1160Sstevel@tonic-gate static struct modlsys modlsys32 = { 1170Sstevel@tonic-gate &mod_syscallops32, 1180Sstevel@tonic-gate "32-bit RPC syscall", 1190Sstevel@tonic-gate &rpcsysent 1200Sstevel@tonic-gate }; 1210Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate static struct modlinkage modlinkage = { 1240Sstevel@tonic-gate MODREV_1, 1250Sstevel@tonic-gate { 1260Sstevel@tonic-gate &modlsys, 1270Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1280Sstevel@tonic-gate &modlsys32, 1290Sstevel@tonic-gate #endif 1300Sstevel@tonic-gate &modlstrmod, 1310Sstevel@tonic-gate NULL 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate }; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate int 1360Sstevel@tonic-gate _init(void) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate int error = 0; 1390Sstevel@tonic-gate callb_id_t cid; 1400Sstevel@tonic-gate int status; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate svc_init(); 1430Sstevel@tonic-gate clnt_init(); 1440Sstevel@tonic-gate cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc"); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if (error = mod_install(&modlinkage)) { 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * Could not install module, cleanup previous 1490Sstevel@tonic-gate * initialization work. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate clnt_fini(); 1520Sstevel@tonic-gate if (cid != NULL) 1530Sstevel@tonic-gate (void) callb_delete(cid); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate return (error); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * Load up the RDMA plugins and initialize the stats. Even if the 1600Sstevel@tonic-gate * plugins loadup fails, but rpcmod was successfully installed the 1610Sstevel@tonic-gate * counters still get initialized. 1620Sstevel@tonic-gate */ 1630Sstevel@tonic-gate rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL); 1640Sstevel@tonic-gate mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL); 1650Sstevel@tonic-gate mt_kstat_init(); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Get our identification into ldi. This is used for loading 1690Sstevel@tonic-gate * other modules, e.g. rpcib. 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate status = ldi_ident_from_mod(&modlinkage, &rpcmod_li); 1720Sstevel@tonic-gate if (status != 0) { 1730Sstevel@tonic-gate cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status); 1740Sstevel@tonic-gate rpcmod_li = NULL; 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate return (error); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * The unload entry point fails, because we advertise entry points into 1820Sstevel@tonic-gate * rpcmod from the rest of kRPC: rpcmod_release(). 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate int 1850Sstevel@tonic-gate _fini(void) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate return (EBUSY); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate int 1910Sstevel@tonic-gate _info(struct modinfo *modinfop) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate extern int nulldev(); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate #define RPCMOD_ID 2049 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate int rmm_open(), rmm_close(); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value 2040Sstevel@tonic-gate * from these functions, they are defined as void here. Kind of icky, but... 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *); 2070Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *); 2080Sstevel@tonic-gate void rmm_rsrv(queue_t *); 2090Sstevel@tonic-gate void rmm_wsrv(queue_t *); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate int rpcmodopen(), rpcmodclose(); 2120Sstevel@tonic-gate void rpcmodrput(), rpcmodwput(); 2130Sstevel@tonic-gate void rpcmodrsrv(), rpcmodwsrv(); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate static void rpcmodwput_other(queue_t *, mblk_t *); 2160Sstevel@tonic-gate static int mir_close(queue_t *q); 2170Sstevel@tonic-gate static int mir_open(queue_t *q, dev_t *devp, int flag, int sflag, 2180Sstevel@tonic-gate cred_t *credp); 2190Sstevel@tonic-gate static void mir_rput(queue_t *q, mblk_t *mp); 2200Sstevel@tonic-gate static void mir_rsrv(queue_t *q); 2210Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp); 2220Sstevel@tonic-gate static void mir_wsrv(queue_t *q); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate static struct module_info rpcmod_info = 2250Sstevel@tonic-gate {RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024}; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* 2280Sstevel@tonic-gate * Read side has no service procedure. 2290Sstevel@tonic-gate */ 2300Sstevel@tonic-gate static struct qinit rpcmodrinit = { 2310Sstevel@tonic-gate (int (*)())rmm_rput, 2320Sstevel@tonic-gate (int (*)())rmm_rsrv, 2330Sstevel@tonic-gate rmm_open, 2340Sstevel@tonic-gate rmm_close, 2350Sstevel@tonic-gate nulldev, 2360Sstevel@tonic-gate &rpcmod_info, 2370Sstevel@tonic-gate NULL 2380Sstevel@tonic-gate }; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* 2410Sstevel@tonic-gate * The write put procedure is simply putnext to conserve stack space. 2420Sstevel@tonic-gate * The write service procedure is not used to queue data, but instead to 2430Sstevel@tonic-gate * synchronize with flow control. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate static struct qinit rpcmodwinit = { 2460Sstevel@tonic-gate (int (*)())rmm_wput, 2470Sstevel@tonic-gate (int (*)())rmm_wsrv, 2480Sstevel@tonic-gate rmm_open, 2490Sstevel@tonic-gate rmm_close, 2500Sstevel@tonic-gate nulldev, 2510Sstevel@tonic-gate &rpcmod_info, 2520Sstevel@tonic-gate NULL 2530Sstevel@tonic-gate }; 2540Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL }; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate struct xprt_style_ops { 2570Sstevel@tonic-gate int (*xo_open)(); 2580Sstevel@tonic-gate int (*xo_close)(); 2590Sstevel@tonic-gate void (*xo_wput)(); 2600Sstevel@tonic-gate void (*xo_wsrv)(); 2610Sstevel@tonic-gate void (*xo_rput)(); 2620Sstevel@tonic-gate void (*xo_rsrv)(); 2630Sstevel@tonic-gate }; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = { 2660Sstevel@tonic-gate rpcmodopen, 2670Sstevel@tonic-gate rpcmodclose, 2680Sstevel@tonic-gate rpcmodwput, 2690Sstevel@tonic-gate rpcmodwsrv, 2700Sstevel@tonic-gate rpcmodrput, 2710Sstevel@tonic-gate NULL 2720Sstevel@tonic-gate }; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = { 2750Sstevel@tonic-gate mir_open, 2760Sstevel@tonic-gate mir_close, 2770Sstevel@tonic-gate mir_wput, 2780Sstevel@tonic-gate mir_wsrv, 2790Sstevel@tonic-gate mir_rput, 2800Sstevel@tonic-gate mir_rsrv 2810Sstevel@tonic-gate }; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate /* 2840Sstevel@tonic-gate * Per rpcmod "slot" data structure. q->q_ptr points to one of these. 2850Sstevel@tonic-gate */ 2860Sstevel@tonic-gate struct rpcm { 2870Sstevel@tonic-gate void *rm_krpc_cell; /* Reserved for use by KRPC */ 2880Sstevel@tonic-gate struct xprt_style_ops *rm_ops; 2890Sstevel@tonic-gate int rm_type; /* Client or server side stream */ 2900Sstevel@tonic-gate #define RM_CLOSING 0x1 /* somebody is trying to close slot */ 2910Sstevel@tonic-gate uint_t rm_state; /* state of the slot. see above */ 2920Sstevel@tonic-gate uint_t rm_ref; /* cnt of external references to slot */ 2930Sstevel@tonic-gate kmutex_t rm_lock; /* mutex protecting above fields */ 2940Sstevel@tonic-gate kcondvar_t rm_cwait; /* condition for closing */ 2950Sstevel@tonic-gate zoneid_t rm_zoneid; /* zone which pushed rpcmod */ 2960Sstevel@tonic-gate }; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate struct temp_slot { 2990Sstevel@tonic-gate void *cell; 3000Sstevel@tonic-gate struct xprt_style_ops *ops; 3010Sstevel@tonic-gate int type; 3020Sstevel@tonic-gate mblk_t *info_ack; 3030Sstevel@tonic-gate kmutex_t lock; 3040Sstevel@tonic-gate kcondvar_t wait; 3050Sstevel@tonic-gate }; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate struct xprt_style_ops tmpops = { 3100Sstevel@tonic-gate NULL, 3110Sstevel@tonic-gate NULL, 3120Sstevel@tonic-gate putnext, 3130Sstevel@tonic-gate NULL, 3140Sstevel@tonic-gate tmp_rput, 3150Sstevel@tonic-gate NULL 3160Sstevel@tonic-gate }; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate void 3190Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp) 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate struct temp_slot *t = (struct temp_slot *)(q->q_ptr); 3220Sstevel@tonic-gate struct T_info_ack *pptr; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3250Sstevel@tonic-gate case M_PCPROTO: 3260Sstevel@tonic-gate pptr = (struct T_info_ack *)mp->b_rptr; 3270Sstevel@tonic-gate switch (pptr->PRIM_type) { 3280Sstevel@tonic-gate case T_INFO_ACK: 3290Sstevel@tonic-gate mutex_enter(&t->lock); 3300Sstevel@tonic-gate t->info_ack = mp; 3310Sstevel@tonic-gate cv_signal(&t->wait); 3320Sstevel@tonic-gate mutex_exit(&t->lock); 3330Sstevel@tonic-gate return; 3340Sstevel@tonic-gate default: 3350Sstevel@tonic-gate break; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate default: 3380Sstevel@tonic-gate break; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Not an info-ack, so free it. This is ok because we should 3430Sstevel@tonic-gate * not be receiving data until the open finishes: rpcmod 3440Sstevel@tonic-gate * is pushed well before the end-point is bound to an address. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate freemsg(mp); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate int 3500Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 3510Sstevel@tonic-gate { 3520Sstevel@tonic-gate mblk_t *bp; 3530Sstevel@tonic-gate struct temp_slot ts, *t; 3540Sstevel@tonic-gate struct T_info_ack *pptr; 3550Sstevel@tonic-gate int error = 0; 3560Sstevel@tonic-gate int procson = 0; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate ASSERT(q != NULL); 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * Check for re-opens. 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate if (q->q_ptr) { 3630Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, 3640Sstevel@tonic-gate "rpcmodopen_end:(%s)", "q->qptr"); 3650Sstevel@tonic-gate return (0); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate t = &ts; 3690Sstevel@tonic-gate bzero(t, sizeof (*t)); 3700Sstevel@tonic-gate q->q_ptr = (void *)t; 3710Sstevel@tonic-gate /* WR(q)->q_ptr = (void *)t; */ 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * Allocate the required messages upfront. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate if ((bp = allocb(sizeof (struct T_info_req) + 3770Sstevel@tonic-gate sizeof (struct T_info_ack), BPRI_LO)) == (mblk_t *)NULL) { 3780Sstevel@tonic-gate return (ENOBUFS); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL); 3820Sstevel@tonic-gate cv_init(&t->wait, NULL, CV_DEFAULT, NULL); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate t->ops = &tmpops; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate qprocson(q); 3870Sstevel@tonic-gate procson = 1; 3880Sstevel@tonic-gate bp->b_datap->db_type = M_PCPROTO; 3890Sstevel@tonic-gate *(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ; 3900Sstevel@tonic-gate bp->b_wptr += sizeof (struct T_info_req); 3910Sstevel@tonic-gate putnext(WR(q), bp); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate mutex_enter(&t->lock); 3940Sstevel@tonic-gate while ((bp = t->info_ack) == NULL) { 3950Sstevel@tonic-gate if (cv_wait_sig(&t->wait, &t->lock) == 0) { 3960Sstevel@tonic-gate error = EINTR; 3970Sstevel@tonic-gate break; 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate mutex_exit(&t->lock); 4010Sstevel@tonic-gate mutex_destroy(&t->lock); 4020Sstevel@tonic-gate cv_destroy(&t->wait); 4030Sstevel@tonic-gate if (error) 4040Sstevel@tonic-gate goto out; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate pptr = (struct T_info_ack *)t->info_ack->b_rptr; 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if (pptr->SERV_type == T_CLTS) { 4090Sstevel@tonic-gate error = rpcmodopen(q, devp, flag, sflag, crp); 4100Sstevel@tonic-gate if (error == 0) { 4110Sstevel@tonic-gate t = (struct temp_slot *)q->q_ptr; 4120Sstevel@tonic-gate t->ops = &xprt_clts_ops; 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate } else { 4150Sstevel@tonic-gate error = mir_open(q, devp, flag, sflag, crp); 4160Sstevel@tonic-gate if (error == 0) { 4170Sstevel@tonic-gate t = (struct temp_slot *)q->q_ptr; 4180Sstevel@tonic-gate t->ops = &xprt_cots_ops; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate out: 4230Sstevel@tonic-gate freemsg(bp); 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (error && procson) 4260Sstevel@tonic-gate qprocsoff(q); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate return (error); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate void 4320Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t *mp) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate void 4380Sstevel@tonic-gate rmm_rsrv(queue_t *q) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate void 4440Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp) 4450Sstevel@tonic-gate { 4460Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate void 4500Sstevel@tonic-gate rmm_wsrv(queue_t *q) 4510Sstevel@tonic-gate { 4520Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate int 4560Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp) 4570Sstevel@tonic-gate { 4580Sstevel@tonic-gate return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp)); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * rpcmodopen - open routine gets called when the module gets pushed 4630Sstevel@tonic-gate * onto the stream. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate /*ARGSUSED*/ 4660Sstevel@tonic-gate int 4670Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 4680Sstevel@tonic-gate { 4690Sstevel@tonic-gate struct rpcm *rmp; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate extern void (*rpc_rele)(queue_t *, mblk_t *); 4720Sstevel@tonic-gate static void rpcmod_release(queue_t *, mblk_t *); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:"); 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * Initialize entry points to release a rpcmod slot (and an input 4780Sstevel@tonic-gate * message if supplied) and to send an output message to the module 4790Sstevel@tonic-gate * below rpcmod. 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate if (rpc_rele == NULL) 4820Sstevel@tonic-gate rpc_rele = rpcmod_release; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * Only sufficiently privileged users can use this module, and it 4860Sstevel@tonic-gate * is assumed that they will use this module properly, and NOT send 4870Sstevel@tonic-gate * bulk data from downstream. 4880Sstevel@tonic-gate */ 4890Sstevel@tonic-gate if (secpolicy_rpcmod_open(crp) != 0) 4900Sstevel@tonic-gate return (EPERM); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* 4930Sstevel@tonic-gate * Allocate slot data structure. 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP); 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL); 4980Sstevel@tonic-gate cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL); 499*766Scarlsonj rmp->rm_zoneid = rpc_zoneid(); 5000Sstevel@tonic-gate /* 5010Sstevel@tonic-gate * slot type will be set by kRPC client and server ioctl's 5020Sstevel@tonic-gate */ 5030Sstevel@tonic-gate rmp->rm_type = 0; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate q->q_ptr = (void *)rmp; 5060Sstevel@tonic-gate WR(q)->q_ptr = (void *)rmp; 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end"); 5090Sstevel@tonic-gate return (0); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * rpcmodclose - This routine gets called when the module gets popped 5140Sstevel@tonic-gate * off of the stream. 5150Sstevel@tonic-gate */ 5160Sstevel@tonic-gate /*ARGSUSED*/ 5170Sstevel@tonic-gate int 5180Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp) 5190Sstevel@tonic-gate { 5200Sstevel@tonic-gate struct rpcm *rmp; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate ASSERT(q != NULL); 5230Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate /* 5260Sstevel@tonic-gate * Mark our state as closing. 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 5290Sstevel@tonic-gate rmp->rm_state |= RM_CLOSING; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * Check and see if there are any messages on the queue. If so, send 5330Sstevel@tonic-gate * the messages, regardless whether the downstream module is ready to 5340Sstevel@tonic-gate * accept data. 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER) { 5370Sstevel@tonic-gate flushq(q, FLUSHDATA); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate qenable(WR(q)); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (rmp->rm_ref) { 5420Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * call into SVC to clean the queue 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate svc_queueclean(q); 5470Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* 5500Sstevel@tonic-gate * Block while there are kRPC threads with a reference 5510Sstevel@tonic-gate * to this message. 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate while (rmp->rm_ref) 5540Sstevel@tonic-gate cv_wait(&rmp->rm_cwait, &rmp->rm_lock); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* 5600Sstevel@tonic-gate * It is now safe to remove this queue from the stream. No kRPC 5610Sstevel@tonic-gate * threads have a reference to the stream, and none ever will, 5620Sstevel@tonic-gate * because RM_CLOSING is set. 5630Sstevel@tonic-gate */ 5640Sstevel@tonic-gate qprocsoff(q); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* Notify kRPC that this stream is going away. */ 5670Sstevel@tonic-gate svc_queueclose(q); 5680Sstevel@tonic-gate } else { 5690Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 5700Sstevel@tonic-gate qprocsoff(q); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate q->q_ptr = NULL; 5740Sstevel@tonic-gate WR(q)->q_ptr = NULL; 5750Sstevel@tonic-gate mutex_destroy(&rmp->rm_lock); 5760Sstevel@tonic-gate cv_destroy(&rmp->rm_cwait); 5770Sstevel@tonic-gate kmem_free(rmp, sizeof (*rmp)); 5780Sstevel@tonic-gate return (0); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate #ifdef DEBUG 5820Sstevel@tonic-gate int rpcmod_send_msg_up = 0; 5830Sstevel@tonic-gate int rpcmod_send_uderr = 0; 5840Sstevel@tonic-gate int rpcmod_send_dup = 0; 5850Sstevel@tonic-gate int rpcmod_send_dup_cnt = 0; 5860Sstevel@tonic-gate #endif 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * rpcmodrput - Module read put procedure. This is called from 5900Sstevel@tonic-gate * the module, driver, or stream head downstream. 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate void 5930Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp) 5940Sstevel@tonic-gate { 5950Sstevel@tonic-gate struct rpcm *rmp; 5960Sstevel@tonic-gate union T_primitives *pptr; 5970Sstevel@tonic-gate int hdrsz; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:"); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate ASSERT(q != NULL); 6020Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (rmp->rm_type == 0) { 6050Sstevel@tonic-gate freemsg(mp); 6060Sstevel@tonic-gate return; 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate #ifdef DEBUG 6100Sstevel@tonic-gate if (rpcmod_send_msg_up > 0) { 6110Sstevel@tonic-gate mblk_t *nmp = copymsg(mp); 6120Sstevel@tonic-gate if (nmp) { 6130Sstevel@tonic-gate putnext(q, nmp); 6140Sstevel@tonic-gate rpcmod_send_msg_up--; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate if ((rpcmod_send_uderr > 0) && mp->b_datap->db_type == M_PROTO) { 6180Sstevel@tonic-gate mblk_t *nmp; 6190Sstevel@tonic-gate struct T_unitdata_ind *data; 6200Sstevel@tonic-gate struct T_uderror_ind *ud; 6210Sstevel@tonic-gate int d; 6220Sstevel@tonic-gate data = (struct T_unitdata_ind *)mp->b_rptr; 6230Sstevel@tonic-gate if (data->PRIM_type == T_UNITDATA_IND) { 6240Sstevel@tonic-gate d = sizeof (*ud) - sizeof (*data); 6250Sstevel@tonic-gate nmp = allocb(mp->b_wptr - mp->b_rptr + d, BPRI_HI); 6260Sstevel@tonic-gate if (nmp) { 6270Sstevel@tonic-gate ud = (struct T_uderror_ind *)nmp->b_rptr; 6280Sstevel@tonic-gate ud->PRIM_type = T_UDERROR_IND; 6290Sstevel@tonic-gate ud->DEST_length = data->SRC_length; 6300Sstevel@tonic-gate ud->DEST_offset = data->SRC_offset + d; 6310Sstevel@tonic-gate ud->OPT_length = data->OPT_length; 6320Sstevel@tonic-gate ud->OPT_offset = data->OPT_offset + d; 6330Sstevel@tonic-gate ud->ERROR_type = ENETDOWN; 6340Sstevel@tonic-gate if (data->SRC_length) { 6350Sstevel@tonic-gate bcopy(mp->b_rptr + 6360Sstevel@tonic-gate data->SRC_offset, 6370Sstevel@tonic-gate nmp->b_rptr + 6380Sstevel@tonic-gate ud->DEST_offset, 6390Sstevel@tonic-gate data->SRC_length); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate if (data->OPT_length) { 6420Sstevel@tonic-gate bcopy(mp->b_rptr + 6430Sstevel@tonic-gate data->OPT_offset, 6440Sstevel@tonic-gate nmp->b_rptr + 6450Sstevel@tonic-gate ud->OPT_offset, 6460Sstevel@tonic-gate data->OPT_length); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate nmp->b_wptr += d; 6490Sstevel@tonic-gate nmp->b_wptr += (mp->b_wptr - mp->b_rptr); 6500Sstevel@tonic-gate nmp->b_datap->db_type = M_PROTO; 6510Sstevel@tonic-gate putnext(q, nmp); 6520Sstevel@tonic-gate rpcmod_send_uderr--; 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate #endif 6570Sstevel@tonic-gate switch (mp->b_datap->db_type) { 6580Sstevel@tonic-gate default: 6590Sstevel@tonic-gate putnext(q, mp); 6600Sstevel@tonic-gate break; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate case M_PROTO: 6630Sstevel@tonic-gate case M_PCPROTO: 6640Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t)); 6650Sstevel@tonic-gate pptr = (union T_primitives *)mp->b_rptr; 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate /* 6680Sstevel@tonic-gate * Forward this message to krpc if it is data. 6690Sstevel@tonic-gate */ 6700Sstevel@tonic-gate if (pptr->type == T_UNITDATA_IND) { 6710Sstevel@tonic-gate mblk_t *nmp; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * Check if the module is being popped. 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 6770Sstevel@tonic-gate if (rmp->rm_state & RM_CLOSING) { 6780Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 6790Sstevel@tonic-gate putnext(q, mp); 6800Sstevel@tonic-gate break; 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate switch (rmp->rm_type) { 6840Sstevel@tonic-gate case RPC_CLIENT: 6850Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 6860Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * Make sure the header is sane. 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate if (hdrsz < TUNITDATAINDSZ || 6920Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.OPT_length + 6930Sstevel@tonic-gate pptr->unitdata_ind.OPT_offset) || 6940Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.SRC_length + 6950Sstevel@tonic-gate pptr->unitdata_ind.SRC_offset)) { 6960Sstevel@tonic-gate freemsg(mp); 6970Sstevel@tonic-gate return; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Call clnt_clts_dispatch_notify, so that it can 7020Sstevel@tonic-gate * pass the message to the proper caller. Don't 7030Sstevel@tonic-gate * discard the header just yet since the client may 7040Sstevel@tonic-gate * need the sender's address. 7050Sstevel@tonic-gate */ 7060Sstevel@tonic-gate clnt_clts_dispatch_notify(mp, hdrsz, rmp->rm_zoneid); 7070Sstevel@tonic-gate return; 7080Sstevel@tonic-gate case RPC_SERVER: 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * rm_krpc_cell is exclusively used by the kRPC 7110Sstevel@tonic-gate * CLTS server 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate if (rmp->rm_krpc_cell) { 7140Sstevel@tonic-gate #ifdef DEBUG 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * Test duplicate request cache and 7170Sstevel@tonic-gate * rm_ref count handling by sending a 7180Sstevel@tonic-gate * duplicate every so often, if 7190Sstevel@tonic-gate * desired. 7200Sstevel@tonic-gate */ 7210Sstevel@tonic-gate if (rpcmod_send_dup && 7220Sstevel@tonic-gate rpcmod_send_dup_cnt++ % 7230Sstevel@tonic-gate rpcmod_send_dup) 7240Sstevel@tonic-gate nmp = copymsg(mp); 7250Sstevel@tonic-gate else 7260Sstevel@tonic-gate nmp = NULL; 7270Sstevel@tonic-gate #endif 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * Raise the reference count on this 7300Sstevel@tonic-gate * module to prevent it from being 7310Sstevel@tonic-gate * popped before krpc generates the 7320Sstevel@tonic-gate * reply. 7330Sstevel@tonic-gate */ 7340Sstevel@tonic-gate rmp->rm_ref++; 7350Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Submit the message to krpc. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate svc_queuereq(q, mp); 7410Sstevel@tonic-gate #ifdef DEBUG 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * Send duplicate if we created one. 7440Sstevel@tonic-gate */ 7450Sstevel@tonic-gate if (nmp) { 7460Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 7470Sstevel@tonic-gate rmp->rm_ref++; 7480Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7490Sstevel@tonic-gate svc_queuereq(q, nmp); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate #endif 7520Sstevel@tonic-gate } else { 7530Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7540Sstevel@tonic-gate freemsg(mp); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate return; 7570Sstevel@tonic-gate default: 7580Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7590Sstevel@tonic-gate freemsg(mp); 7600Sstevel@tonic-gate return; 7610Sstevel@tonic-gate } /* end switch(rmp->rm_type) */ 7620Sstevel@tonic-gate } else if (pptr->type == T_UDERROR_IND) { 7630Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 7640Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /* 7670Sstevel@tonic-gate * Make sure the header is sane 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate if (hdrsz < TUDERRORINDSZ || 7700Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.OPT_length + 7710Sstevel@tonic-gate pptr->uderror_ind.OPT_offset) || 7720Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.DEST_length + 7730Sstevel@tonic-gate pptr->uderror_ind.DEST_offset)) { 7740Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7750Sstevel@tonic-gate freemsg(mp); 7760Sstevel@tonic-gate return; 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7800Sstevel@tonic-gate * In the case where a unit data error has been 7810Sstevel@tonic-gate * received, all we need to do is clear the message from 7820Sstevel@tonic-gate * the queue. 7830Sstevel@tonic-gate */ 7840Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 7850Sstevel@tonic-gate freemsg(mp); 7860Sstevel@tonic-gate RPCLOG(32, "rpcmodrput: unitdata error received at " 7870Sstevel@tonic-gate "%ld\n", gethrestime_sec()); 7880Sstevel@tonic-gate return; 7890Sstevel@tonic-gate } /* end else if (pptr->type == T_UDERROR_IND) */ 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate putnext(q, mp); 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate } /* end switch (mp->b_datap->db_type) */ 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END, 7960Sstevel@tonic-gate "rpcmodrput_end:"); 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Return codes are not looked at by the STREAMS framework. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* 8030Sstevel@tonic-gate * write put procedure 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate void 8060Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp) 8070Sstevel@tonic-gate { 8080Sstevel@tonic-gate struct rpcm *rmp; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate ASSERT(q != NULL); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate switch (mp->b_datap->db_type) { 8130Sstevel@tonic-gate case M_PROTO: 8140Sstevel@tonic-gate case M_PCPROTO: 8150Sstevel@tonic-gate break; 8160Sstevel@tonic-gate default: 8170Sstevel@tonic-gate rpcmodwput_other(q, mp); 8180Sstevel@tonic-gate return; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* 8220Sstevel@tonic-gate * Check to see if we can send the message downstream. 8230Sstevel@tonic-gate */ 8240Sstevel@tonic-gate if (canputnext(q)) { 8250Sstevel@tonic-gate putnext(q, mp); 8260Sstevel@tonic-gate return; 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 8300Sstevel@tonic-gate ASSERT(rmp != NULL); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate /* 8330Sstevel@tonic-gate * The first canputnext failed. Try again except this time with the 8340Sstevel@tonic-gate * lock held, so that we can check the state of the stream to see if 8350Sstevel@tonic-gate * it is closing. If either of these conditions evaluate to true 8360Sstevel@tonic-gate * then send the meesage. 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 8390Sstevel@tonic-gate if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) { 8400Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 8410Sstevel@tonic-gate putnext(q, mp); 8420Sstevel@tonic-gate } else { 8430Sstevel@tonic-gate /* 8440Sstevel@tonic-gate * canputnext failed again and the stream is not closing. 8450Sstevel@tonic-gate * Place the message on the queue and let the service 8460Sstevel@tonic-gate * procedure handle the message. 8470Sstevel@tonic-gate */ 8480Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 8490Sstevel@tonic-gate (void) putq(q, mp); 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate static void 8540Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate struct rpcm *rmp; 8570Sstevel@tonic-gate struct iocblk *iocp; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 8600Sstevel@tonic-gate ASSERT(rmp != NULL); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate switch (mp->b_datap->db_type) { 8630Sstevel@tonic-gate case M_IOCTL: 8640Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 8650Sstevel@tonic-gate ASSERT(iocp != NULL); 8660Sstevel@tonic-gate switch (iocp->ioc_cmd) { 8670Sstevel@tonic-gate case RPC_CLIENT: 8680Sstevel@tonic-gate case RPC_SERVER: 8690Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 8700Sstevel@tonic-gate rmp->rm_type = iocp->ioc_cmd; 8710Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 8720Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 8730Sstevel@tonic-gate qreply(q, mp); 8740Sstevel@tonic-gate return; 8750Sstevel@tonic-gate default: 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * pass the ioctl downstream and hope someone 8780Sstevel@tonic-gate * down there knows how to handle it. 8790Sstevel@tonic-gate */ 8800Sstevel@tonic-gate putnext(q, mp); 8810Sstevel@tonic-gate return; 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate default: 8840Sstevel@tonic-gate break; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate /* 8870Sstevel@tonic-gate * This is something we definitely do not know how to handle, just 8880Sstevel@tonic-gate * pass the message downstream 8890Sstevel@tonic-gate */ 8900Sstevel@tonic-gate putnext(q, mp); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate /* 8940Sstevel@tonic-gate * Module write service procedure. This is called by downstream modules 8950Sstevel@tonic-gate * for back enabling during flow control. 8960Sstevel@tonic-gate */ 8970Sstevel@tonic-gate void 8980Sstevel@tonic-gate rpcmodwsrv(queue_t *q) 8990Sstevel@tonic-gate { 9000Sstevel@tonic-gate struct rpcm *rmp; 9010Sstevel@tonic-gate mblk_t *mp = NULL; 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 9040Sstevel@tonic-gate ASSERT(rmp != NULL); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * Get messages that may be queued and send them down stream 9080Sstevel@tonic-gate */ 9090Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * Optimize the service procedure for the server-side, by 9120Sstevel@tonic-gate * avoiding a call to canputnext(). 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER || canputnext(q)) { 9150Sstevel@tonic-gate putnext(q, mp); 9160Sstevel@tonic-gate continue; 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate (void) putbq(q, mp); 9190Sstevel@tonic-gate return; 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate static void 9240Sstevel@tonic-gate rpcmod_release(queue_t *q, mblk_t *bp) 9250Sstevel@tonic-gate { 9260Sstevel@tonic-gate struct rpcm *rmp; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate /* 9290Sstevel@tonic-gate * For now, just free the message. 9300Sstevel@tonic-gate */ 9310Sstevel@tonic-gate if (bp) 9320Sstevel@tonic-gate freemsg(bp); 9330Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 9360Sstevel@tonic-gate rmp->rm_ref--; 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) { 9390Sstevel@tonic-gate cv_broadcast(&rmp->rm_cwait); 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * This part of rpcmod is pushed on a connection-oriented transport for use 9470Sstevel@tonic-gate * by RPC. It serves to bypass the Stream head, implements 9480Sstevel@tonic-gate * the record marking protocol, and dispatches incoming RPC messages. 9490Sstevel@tonic-gate */ 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate /* Default idle timer values */ 9520Sstevel@tonic-gate #define MIR_CLNT_IDLE_TIMEOUT (5 * (60 * 1000L)) /* 5 minutes */ 9530Sstevel@tonic-gate #define MIR_SVC_IDLE_TIMEOUT (6 * (60 * 1000L)) /* 6 minutes */ 9540Sstevel@tonic-gate #define MIR_SVC_ORDREL_TIMEOUT (10 * (60 * 1000L)) /* 10 minutes */ 9550Sstevel@tonic-gate #define MIR_LASTFRAG 0x80000000 /* Record marker */ 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate #define DLEN(mp) (mp->b_cont ? msgdsize(mp) : (mp->b_wptr - mp->b_rptr)) 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate typedef struct mir_s { 9600Sstevel@tonic-gate void *mir_krpc_cell; /* Reserved for KRPC use. This field */ 9610Sstevel@tonic-gate /* must be first in the structure. */ 9620Sstevel@tonic-gate struct xprt_style_ops *rm_ops; 9630Sstevel@tonic-gate int mir_type; /* Client or server side stream */ 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate mblk_t *mir_head_mp; /* RPC msg in progress */ 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * mir_head_mp points the first mblk being collected in 9680Sstevel@tonic-gate * the current RPC message. Record headers are removed 9690Sstevel@tonic-gate * before data is linked into mir_head_mp. 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate mblk_t *mir_tail_mp; /* Last mblk in mir_head_mp */ 9720Sstevel@tonic-gate /* 9730Sstevel@tonic-gate * mir_tail_mp points to the last mblk in the message 9740Sstevel@tonic-gate * chain starting at mir_head_mp. It is only valid 9750Sstevel@tonic-gate * if mir_head_mp is non-NULL and is used to add new 9760Sstevel@tonic-gate * data blocks to the end of chain quickly. 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate int32_t mir_frag_len; /* Bytes seen in the current frag */ 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * mir_frag_len starts at -4 for beginning of each fragment. 9820Sstevel@tonic-gate * When this length is negative, it indicates the number of 9830Sstevel@tonic-gate * bytes that rpcmod needs to complete the record marker 9840Sstevel@tonic-gate * header. When it is positive or zero, it holds the number 9850Sstevel@tonic-gate * of bytes that have arrived for the current fragment and 9860Sstevel@tonic-gate * are held in mir_header_mp. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate int32_t mir_frag_header; 9900Sstevel@tonic-gate /* 9910Sstevel@tonic-gate * Fragment header as collected for the current fragment. 9920Sstevel@tonic-gate * It holds the last-fragment indicator and the number 9930Sstevel@tonic-gate * of bytes in the fragment. 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate unsigned int 9970Sstevel@tonic-gate mir_ordrel_pending : 1, /* Sent T_ORDREL_REQ */ 9980Sstevel@tonic-gate mir_hold_inbound : 1, /* Hold inbound messages on server */ 9990Sstevel@tonic-gate /* side until outbound flow control */ 10000Sstevel@tonic-gate /* is relieved. */ 10010Sstevel@tonic-gate mir_closing : 1, /* The stream is being closed */ 10020Sstevel@tonic-gate mir_inrservice : 1, /* data queued or rd srv proc running */ 10030Sstevel@tonic-gate mir_inwservice : 1, /* data queued or wr srv proc running */ 10040Sstevel@tonic-gate mir_inwflushdata : 1, /* flush M_DATAs when srv runs */ 10050Sstevel@tonic-gate /* 10060Sstevel@tonic-gate * On client streams, mir_clntreq is 0 or 1; it is set 10070Sstevel@tonic-gate * to 1 whenever a new request is sent out (mir_wput) 10080Sstevel@tonic-gate * and cleared when the timer fires (mir_timer). If 10090Sstevel@tonic-gate * the timer fires with this value equal to 0, then the 10100Sstevel@tonic-gate * stream is considered idle and KRPC is notified. 10110Sstevel@tonic-gate */ 10120Sstevel@tonic-gate mir_clntreq : 1, 10130Sstevel@tonic-gate /* 10140Sstevel@tonic-gate * On server streams, stop accepting messages 10150Sstevel@tonic-gate */ 10160Sstevel@tonic-gate mir_svc_no_more_msgs : 1, 10170Sstevel@tonic-gate mir_listen_stream : 1, /* listen end point */ 10180Sstevel@tonic-gate mir_setup_complete : 1, /* server has initialized everything */ 10190Sstevel@tonic-gate mir_timer_call : 1, 10200Sstevel@tonic-gate mir_junk_fill_thru_bit_31 : 21; 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate timeout_id_t mir_timer_id; /* Timer for idle checks */ 10230Sstevel@tonic-gate clock_t mir_idle_timeout; /* Allowed idle time before shutdown */ 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * This value is copied from clnt_idle_timeout or 10260Sstevel@tonic-gate * svc_idle_timeout during the appropriate ioctl. 10270Sstevel@tonic-gate * Kept in milliseconds 10280Sstevel@tonic-gate */ 10290Sstevel@tonic-gate clock_t mir_use_timestamp; /* updated on client with each use */ 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * This value is set to lbolt 10320Sstevel@tonic-gate * every time a client stream sends or receives data. 10330Sstevel@tonic-gate * Even if the timer message arrives, we don't shutdown 10340Sstevel@tonic-gate * client unless: 10350Sstevel@tonic-gate * lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp. 10360Sstevel@tonic-gate * This value is kept in HZ. 10370Sstevel@tonic-gate */ 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate uint_t *mir_max_msg_sizep; /* Reference to sanity check size */ 10400Sstevel@tonic-gate /* 10410Sstevel@tonic-gate * This pointer is set to &clnt_max_msg_size or 10420Sstevel@tonic-gate * &svc_max_msg_size during the appropriate ioctl. 10430Sstevel@tonic-gate */ 10440Sstevel@tonic-gate zoneid_t mir_zoneid; /* zone which pushed rpcmod */ 10450Sstevel@tonic-gate /* Server-side fields. */ 10460Sstevel@tonic-gate int mir_ref_cnt; /* Reference count: server side only */ 10470Sstevel@tonic-gate /* counts the number of references */ 10480Sstevel@tonic-gate /* that a kernel RPC server thread */ 10490Sstevel@tonic-gate /* (see svc_run()) has on this rpcmod */ 10500Sstevel@tonic-gate /* slot. Effectively, it is the */ 10510Sstevel@tonic-gate /* number * of unprocessed messages */ 10520Sstevel@tonic-gate /* that have been passed up to the */ 10530Sstevel@tonic-gate /* KRPC layer */ 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate mblk_t *mir_svc_pend_mp; /* Pending T_ORDREL_IND or */ 10560Sstevel@tonic-gate /* T_DISCON_IND */ 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 10590Sstevel@tonic-gate * these fields are for both client and server, but for debugging, 10600Sstevel@tonic-gate * it is easier to have these last in the structure. 10610Sstevel@tonic-gate */ 10620Sstevel@tonic-gate kmutex_t mir_mutex; /* Mutex and condvar for close */ 10630Sstevel@tonic-gate kcondvar_t mir_condvar; /* synchronization. */ 10640Sstevel@tonic-gate kcondvar_t mir_timer_cv; /* Timer routine sync. */ 10650Sstevel@tonic-gate } mir_t; 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate #define MIR_SVC_QUIESCED(mir) \ 10680Sstevel@tonic-gate (mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0) 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate #define MIR_CLEAR_INRSRV(mir_ptr) { \ 10710Sstevel@tonic-gate (mir_ptr)->mir_inrservice = 0; \ 10720Sstevel@tonic-gate if ((mir_ptr)->mir_type == RPC_SERVER && \ 10730Sstevel@tonic-gate (mir_ptr)->mir_closing) \ 10740Sstevel@tonic-gate cv_signal(&(mir_ptr)->mir_condvar); \ 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate /* 10780Sstevel@tonic-gate * Don't block service procedure (and mir_close) if 10790Sstevel@tonic-gate * we are in the process of closing. 10800Sstevel@tonic-gate */ 10810Sstevel@tonic-gate #define MIR_WCANPUTNEXT(mir_ptr, write_q) \ 10820Sstevel@tonic-gate (canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1)) 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate static int mir_clnt_dup_request(queue_t *q, mblk_t *mp); 10850Sstevel@tonic-gate static void mir_rput_proto(queue_t *q, mblk_t *mp); 10860Sstevel@tonic-gate static int mir_svc_policy_notify(queue_t *q, int event); 10870Sstevel@tonic-gate static void mir_svc_release(queue_t *wq, mblk_t *mp); 10880Sstevel@tonic-gate static void mir_svc_start(queue_t *wq); 10890Sstevel@tonic-gate static void mir_svc_idle_start(queue_t *, mir_t *); 10900Sstevel@tonic-gate static void mir_svc_idle_stop(queue_t *, mir_t *); 10910Sstevel@tonic-gate static void mir_svc_start_close(queue_t *, mir_t *); 10920Sstevel@tonic-gate static void mir_clnt_idle_do_stop(queue_t *); 10930Sstevel@tonic-gate static void mir_clnt_idle_stop(queue_t *, mir_t *); 10940Sstevel@tonic-gate static void mir_clnt_idle_start(queue_t *, mir_t *); 10950Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp); 10960Sstevel@tonic-gate static void mir_wput_other(queue_t *q, mblk_t *mp); 10970Sstevel@tonic-gate static void mir_wsrv(queue_t *q); 10980Sstevel@tonic-gate static void mir_disconnect(queue_t *, mir_t *ir); 10990Sstevel@tonic-gate static int mir_check_len(queue_t *, int32_t, mblk_t *); 11000Sstevel@tonic-gate static void mir_timer(void *); 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate extern void (*mir_rele)(queue_t *, mblk_t *); 11030Sstevel@tonic-gate extern void (*mir_start)(queue_t *); 11040Sstevel@tonic-gate extern void (*clnt_stop_idle)(queue_t *); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate clock_t clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT; 11070Sstevel@tonic-gate clock_t svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate /* 11100Sstevel@tonic-gate * Timeout for subsequent notifications of idle connection. This is 11110Sstevel@tonic-gate * typically used to clean up after a wedged orderly release. 11120Sstevel@tonic-gate */ 11130Sstevel@tonic-gate clock_t svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */ 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate extern uint_t *clnt_max_msg_sizep; 11160Sstevel@tonic-gate extern uint_t *svc_max_msg_sizep; 11170Sstevel@tonic-gate uint_t clnt_max_msg_size = RPC_MAXDATASIZE; 11180Sstevel@tonic-gate uint_t svc_max_msg_size = RPC_MAXDATASIZE; 11190Sstevel@tonic-gate uint_t mir_krpc_cell_null; 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate static void 11220Sstevel@tonic-gate mir_timer_stop(mir_t *mir) 11230Sstevel@tonic-gate { 11240Sstevel@tonic-gate timeout_id_t tid; 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate /* 11290Sstevel@tonic-gate * Since the mir_mutex lock needs to be released to call 11300Sstevel@tonic-gate * untimeout(), we need to make sure that no other thread 11310Sstevel@tonic-gate * can start/stop the timer (changing mir_timer_id) during 11320Sstevel@tonic-gate * that time. The mir_timer_call bit and the mir_timer_cv 11330Sstevel@tonic-gate * condition variable are used to synchronize this. Setting 11340Sstevel@tonic-gate * mir_timer_call also tells mir_timer() (refer to the comments 11350Sstevel@tonic-gate * in mir_timer()) that it does not need to do anything. 11360Sstevel@tonic-gate */ 11370Sstevel@tonic-gate while (mir->mir_timer_call) 11380Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex); 11390Sstevel@tonic-gate mir->mir_timer_call = B_TRUE; 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) { 11420Sstevel@tonic-gate mir->mir_timer_id = 0; 11430Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 11440Sstevel@tonic-gate (void) untimeout(tid); 11450Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate mir->mir_timer_call = B_FALSE; 11480Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv); 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate static void 11520Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl) 11530Sstevel@tonic-gate { 11540Sstevel@tonic-gate timeout_id_t tid; 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate while (mir->mir_timer_call) 11590Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex); 11600Sstevel@tonic-gate mir->mir_timer_call = B_TRUE; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) { 11630Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 11640Sstevel@tonic-gate (void) untimeout(tid); 11650Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate /* Only start the timer when it is not closing. */ 11680Sstevel@tonic-gate if (!mir->mir_closing) { 11690Sstevel@tonic-gate mir->mir_timer_id = timeout(mir_timer, q, 11700Sstevel@tonic-gate MSEC_TO_TICK(intrvl)); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate mir->mir_timer_call = B_FALSE; 11730Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv); 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate static int 11770Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp) 11780Sstevel@tonic-gate { 11790Sstevel@tonic-gate mblk_t *mp1; 11800Sstevel@tonic-gate uint32_t new_xid; 11810Sstevel@tonic-gate uint32_t old_xid; 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex)); 11840Sstevel@tonic-gate new_xid = BE32_TO_U32(&mp->b_rptr[4]); 11850Sstevel@tonic-gate /* 11860Sstevel@tonic-gate * This loop is a bit tacky -- it walks the STREAMS list of 11870Sstevel@tonic-gate * flow-controlled messages. 11880Sstevel@tonic-gate */ 11890Sstevel@tonic-gate if ((mp1 = q->q_first) != NULL) { 11900Sstevel@tonic-gate do { 11910Sstevel@tonic-gate old_xid = BE32_TO_U32(&mp1->b_rptr[4]); 11920Sstevel@tonic-gate if (new_xid == old_xid) 11930Sstevel@tonic-gate return (1); 11940Sstevel@tonic-gate } while ((mp1 = mp1->b_next) != NULL); 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate return (0); 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate static int 12000Sstevel@tonic-gate mir_close(queue_t *q) 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate mir_t *mir; 12030Sstevel@tonic-gate mblk_t *mp; 12040Sstevel@tonic-gate bool_t queue_cleaned = FALSE; 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q); 12070Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 12080Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 12090Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 12100Sstevel@tonic-gate if ((mp = mir->mir_head_mp) != NULL) { 12110Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 12120Sstevel@tonic-gate freemsg(mp); 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate /* 12150Sstevel@tonic-gate * Set mir_closing so we get notified when MIR_SVC_QUIESCED() 12160Sstevel@tonic-gate * is TRUE. And mir_timer_start() won't start the timer again. 12170Sstevel@tonic-gate */ 12180Sstevel@tonic-gate mir->mir_closing = B_TRUE; 12190Sstevel@tonic-gate mir_timer_stop(mir); 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER) { 12220Sstevel@tonic-gate flushq(q, FLUSHDATA); /* Ditch anything waiting on read q */ 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate /* 12250Sstevel@tonic-gate * This will prevent more requests from arriving and 12260Sstevel@tonic-gate * will force rpcmod to ignore flow control. 12270Sstevel@tonic-gate */ 12280Sstevel@tonic-gate mir_svc_start_close(WR(q), mir); 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) { 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate if (mir->mir_ref_cnt && !mir->mir_inrservice && 12330Sstevel@tonic-gate (queue_cleaned == FALSE)) { 12340Sstevel@tonic-gate /* 12350Sstevel@tonic-gate * call into SVC to clean the queue 12360Sstevel@tonic-gate */ 12370Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 12380Sstevel@tonic-gate svc_queueclean(q); 12390Sstevel@tonic-gate queue_cleaned = TRUE; 12400Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 12410Sstevel@tonic-gate continue; 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate /* 12450Sstevel@tonic-gate * Bugid 1253810 - Force the write service 12460Sstevel@tonic-gate * procedure to send its messages, regardless 12470Sstevel@tonic-gate * whether the downstream module is ready 12480Sstevel@tonic-gate * to accept data. 12490Sstevel@tonic-gate */ 12500Sstevel@tonic-gate if (mir->mir_inwservice == 1) 12510Sstevel@tonic-gate qenable(WR(q)); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate cv_wait(&mir->mir_condvar, &mir->mir_mutex); 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 12570Sstevel@tonic-gate qprocsoff(q); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate /* Notify KRPC that this stream is going away. */ 12600Sstevel@tonic-gate svc_queueclose(q); 12610Sstevel@tonic-gate } else { 12620Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 12630Sstevel@tonic-gate qprocsoff(q); 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate mutex_destroy(&mir->mir_mutex); 12670Sstevel@tonic-gate cv_destroy(&mir->mir_condvar); 12680Sstevel@tonic-gate cv_destroy(&mir->mir_timer_cv); 12690Sstevel@tonic-gate kmem_free(mir, sizeof (mir_t)); 12700Sstevel@tonic-gate return (0); 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate /* 12740Sstevel@tonic-gate * This is server side only (RPC_SERVER). 12750Sstevel@tonic-gate * 12760Sstevel@tonic-gate * Exit idle mode. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate static void 12790Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir) 12800Sstevel@tonic-gate { 12810Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 12820Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0); 12830Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 12840Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q); 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate mir_timer_stop(mir); 12870Sstevel@tonic-gate } 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate /* 12900Sstevel@tonic-gate * This is server side only (RPC_SERVER). 12910Sstevel@tonic-gate * 12920Sstevel@tonic-gate * Start idle processing, which will include setting idle timer if the 12930Sstevel@tonic-gate * stream is not being closed. 12940Sstevel@tonic-gate */ 12950Sstevel@tonic-gate static void 12960Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir) 12970Sstevel@tonic-gate { 12980Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 12990Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0); 13000Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 13010Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q); 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate /* 13040Sstevel@tonic-gate * Don't re-start idle timer if we are closing queues. 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate if (mir->mir_closing) { 13070Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n", 13080Sstevel@tonic-gate (void *)q); 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED() 13120Sstevel@tonic-gate * is true. When it is true, and we are in the process of 13130Sstevel@tonic-gate * closing the stream, signal any thread waiting in 13140Sstevel@tonic-gate * mir_close(). 13150Sstevel@tonic-gate */ 13160Sstevel@tonic-gate if (mir->mir_inwservice == 0) 13170Sstevel@tonic-gate cv_signal(&mir->mir_condvar); 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate } else { 13200Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - reset %s timer\n", 13210Sstevel@tonic-gate mir->mir_ordrel_pending ? "ordrel" : "normal"); 13220Sstevel@tonic-gate /* 13230Sstevel@tonic-gate * Normal condition, start the idle timer. If an orderly 13240Sstevel@tonic-gate * release has been sent, set the timeout to wait for the 13250Sstevel@tonic-gate * client to close its side of the connection. Otherwise, 13260Sstevel@tonic-gate * use the normal idle timeout. 13270Sstevel@tonic-gate */ 13280Sstevel@tonic-gate mir_timer_start(q, mir, mir->mir_ordrel_pending ? 13290Sstevel@tonic-gate svc_ordrel_timeout : mir->mir_idle_timeout); 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate /* ARGSUSED */ 13340Sstevel@tonic-gate static int 13350Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 13360Sstevel@tonic-gate { 13370Sstevel@tonic-gate mir_t *mir; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q); 13400Sstevel@tonic-gate /* Set variables used directly by KRPC. */ 13410Sstevel@tonic-gate if (!mir_rele) 13420Sstevel@tonic-gate mir_rele = mir_svc_release; 13430Sstevel@tonic-gate if (!mir_start) 13440Sstevel@tonic-gate mir_start = mir_svc_start; 13450Sstevel@tonic-gate if (!clnt_stop_idle) 13460Sstevel@tonic-gate clnt_stop_idle = mir_clnt_idle_do_stop; 13470Sstevel@tonic-gate if (!clnt_max_msg_sizep) 13480Sstevel@tonic-gate clnt_max_msg_sizep = &clnt_max_msg_size; 13490Sstevel@tonic-gate if (!svc_max_msg_sizep) 13500Sstevel@tonic-gate svc_max_msg_sizep = &svc_max_msg_size; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate /* Allocate a zero'ed out mir structure for this stream. */ 13530Sstevel@tonic-gate mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP); 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate /* 13560Sstevel@tonic-gate * We set hold inbound here so that incoming messages will 13570Sstevel@tonic-gate * be held on the read-side queue until the stream is completely 13580Sstevel@tonic-gate * initialized with a RPC_CLIENT or RPC_SERVER ioctl. During 13590Sstevel@tonic-gate * the ioctl processing, the flag is cleared and any messages that 13600Sstevel@tonic-gate * arrived between the open and the ioctl are delivered to KRPC. 13610Sstevel@tonic-gate * 13620Sstevel@tonic-gate * Early data should never arrive on a client stream since 13630Sstevel@tonic-gate * servers only respond to our requests and we do not send any. 13640Sstevel@tonic-gate * until after the stream is initialized. Early data is 13650Sstevel@tonic-gate * very common on a server stream where the client will start 13660Sstevel@tonic-gate * sending data as soon as the connection is made (and this 13670Sstevel@tonic-gate * is especially true with TCP where the protocol accepts the 13680Sstevel@tonic-gate * connection before nfsd or KRPC is notified about it). 13690Sstevel@tonic-gate */ 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate mir->mir_hold_inbound = 1; 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * Start the record marker looking for a 4-byte header. When 13750Sstevel@tonic-gate * this length is negative, it indicates that rpcmod is looking 13760Sstevel@tonic-gate * for bytes to consume for the record marker header. When it 13770Sstevel@tonic-gate * is positive, it holds the number of bytes that have arrived 13780Sstevel@tonic-gate * for the current fragment and are being held in mir_header_mp. 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t); 13820Sstevel@tonic-gate 1383*766Scarlsonj mir->mir_zoneid = rpc_zoneid(); 13840Sstevel@tonic-gate mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL); 13850Sstevel@tonic-gate cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL); 13860Sstevel@tonic-gate cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL); 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate q->q_ptr = (char *)mir; 13890Sstevel@tonic-gate WR(q)->q_ptr = (char *)mir; 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate /* 13920Sstevel@tonic-gate * We noenable the read-side queue because we don't want it 13930Sstevel@tonic-gate * automatically enabled by putq. We enable it explicitly 13940Sstevel@tonic-gate * in mir_wsrv when appropriate. (See additional comments on 13950Sstevel@tonic-gate * flow control at the beginning of mir_rsrv.) 13960Sstevel@tonic-gate */ 13970Sstevel@tonic-gate noenable(q); 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate qprocson(q); 14000Sstevel@tonic-gate return (0); 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate /* 14040Sstevel@tonic-gate * Read-side put routine for both the client and server side. Does the 14050Sstevel@tonic-gate * record marking for incoming RPC messages, and when complete, dispatches 14060Sstevel@tonic-gate * the message to either the client or server. 14070Sstevel@tonic-gate */ 14080Sstevel@tonic-gate static void 14090Sstevel@tonic-gate mir_do_rput(queue_t *q, mblk_t *mp, int srv) 14100Sstevel@tonic-gate { 14110Sstevel@tonic-gate mblk_t *cont_mp; 14120Sstevel@tonic-gate int excess; 14130Sstevel@tonic-gate int32_t frag_len; 14140Sstevel@tonic-gate int32_t frag_header; 14150Sstevel@tonic-gate mblk_t *head_mp; 14160Sstevel@tonic-gate int len; 14170Sstevel@tonic-gate mir_t *mir; 14180Sstevel@tonic-gate mblk_t *mp1; 14190Sstevel@tonic-gate unsigned char *rptr; 14200Sstevel@tonic-gate mblk_t *tail_mp; 14210Sstevel@tonic-gate unsigned char *wptr; 14220Sstevel@tonic-gate boolean_t stop_timer = B_FALSE; 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 14250Sstevel@tonic-gate ASSERT(mir != NULL); 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate /* 14280Sstevel@tonic-gate * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER 14290Sstevel@tonic-gate * with the corresponding ioctl, then don't accept 14300Sstevel@tonic-gate * any inbound data. This should never happen for streams 14310Sstevel@tonic-gate * created by nfsd or client-side KRPC because they are careful 14320Sstevel@tonic-gate * to set the mode of the stream before doing anything else. 14330Sstevel@tonic-gate */ 14340Sstevel@tonic-gate if (mir->mir_type == 0) { 14350Sstevel@tonic-gate freemsg(mp); 14360Sstevel@tonic-gate return; 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate switch (mp->b_datap->db_type) { 14420Sstevel@tonic-gate case M_DATA: 14430Sstevel@tonic-gate break; 14440Sstevel@tonic-gate case M_PROTO: 14450Sstevel@tonic-gate case M_PCPROTO: 14460Sstevel@tonic-gate rptr = mp->b_rptr; 14470Sstevel@tonic-gate if (mp->b_wptr - rptr < sizeof (uint32_t)) { 14480Sstevel@tonic-gate RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n", 14490Sstevel@tonic-gate (int)(mp->b_wptr - rptr)); 14500Sstevel@tonic-gate freemsg(mp); 14510Sstevel@tonic-gate return; 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate if (((union T_primitives *)rptr)->type != T_DATA_IND) { 14540Sstevel@tonic-gate mir_rput_proto(q, mp); 14550Sstevel@tonic-gate return; 14560Sstevel@tonic-gate } 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate /* Throw away the T_DATA_IND block and continue with data. */ 14590Sstevel@tonic-gate mp1 = mp; 14600Sstevel@tonic-gate mp = mp->b_cont; 14610Sstevel@tonic-gate freeb(mp1); 14620Sstevel@tonic-gate break; 14630Sstevel@tonic-gate case M_SETOPTS: 14640Sstevel@tonic-gate /* 14650Sstevel@tonic-gate * If a module on the stream is trying set the Stream head's 14660Sstevel@tonic-gate * high water mark, then set our hiwater to the requested 14670Sstevel@tonic-gate * value. We are the "stream head" for all inbound 14680Sstevel@tonic-gate * data messages since messages are passed directly to KRPC. 14690Sstevel@tonic-gate */ 14700Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) >= sizeof (struct stroptions)) { 14710Sstevel@tonic-gate struct stroptions *stropts; 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate stropts = (struct stroptions *)mp->b_rptr; 14740Sstevel@tonic-gate if ((stropts->so_flags & SO_HIWAT) && 14750Sstevel@tonic-gate !(stropts->so_flags & SO_BAND)) { 14760Sstevel@tonic-gate (void) strqset(q, QHIWAT, 0, stropts->so_hiwat); 14770Sstevel@tonic-gate } 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate putnext(q, mp); 14800Sstevel@tonic-gate return; 14810Sstevel@tonic-gate case M_FLUSH: 14820Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: ignoring M_FLUSH on q 0x%p. ", 14830Sstevel@tonic-gate (void *)q); 14840Sstevel@tonic-gate RPCLOG(32, "M_FLUSH is %x\n", (uint_t)*mp->b_rptr); 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate putnext(q, mp); 14870Sstevel@tonic-gate return; 14880Sstevel@tonic-gate default: 14890Sstevel@tonic-gate putnext(q, mp); 14900Sstevel@tonic-gate return; 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate /* 14960Sstevel@tonic-gate * If this connection is closing, don't accept any new messages. 14970Sstevel@tonic-gate */ 14980Sstevel@tonic-gate if (mir->mir_svc_no_more_msgs) { 14990Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 15000Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 15010Sstevel@tonic-gate freemsg(mp); 15020Sstevel@tonic-gate return; 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate /* Get local copies for quicker access. */ 15060Sstevel@tonic-gate frag_len = mir->mir_frag_len; 15070Sstevel@tonic-gate frag_header = mir->mir_frag_header; 15080Sstevel@tonic-gate head_mp = mir->mir_head_mp; 15090Sstevel@tonic-gate tail_mp = mir->mir_tail_mp; 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate /* Loop, processing each message block in the mp chain separately. */ 15120Sstevel@tonic-gate do { 15130Sstevel@tonic-gate /* 15140Sstevel@tonic-gate * cont_mp is used in the do/while condition below to 15150Sstevel@tonic-gate * walk to the next block in the STREAMS message. 15160Sstevel@tonic-gate * mp->b_cont may be nil'ed during processing so we 15170Sstevel@tonic-gate * can't rely on it to find the next block. 15180Sstevel@tonic-gate */ 15190Sstevel@tonic-gate cont_mp = mp->b_cont; 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate /* 15220Sstevel@tonic-gate * Get local copies of rptr and wptr for our processing. 15230Sstevel@tonic-gate * These always point into "mp" (the current block being 15240Sstevel@tonic-gate * processed), but rptr is updated as we consume any 15250Sstevel@tonic-gate * record header in this message, and wptr is updated to 15260Sstevel@tonic-gate * point to the end of the data for the current fragment, 15270Sstevel@tonic-gate * if it ends in this block. The main point is that 15280Sstevel@tonic-gate * they are not always the same as b_rptr and b_wptr. 15290Sstevel@tonic-gate * b_rptr and b_wptr will be updated when appropriate. 15300Sstevel@tonic-gate */ 15310Sstevel@tonic-gate rptr = mp->b_rptr; 15320Sstevel@tonic-gate wptr = mp->b_wptr; 15330Sstevel@tonic-gate same_mblk:; 15340Sstevel@tonic-gate len = (int)(wptr - rptr); 15350Sstevel@tonic-gate if (len <= 0) { 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * If we have processed all of the data in the message 15380Sstevel@tonic-gate * or the block is empty to begin with, then we're 15390Sstevel@tonic-gate * done with this block and can go on to cont_mp, 15400Sstevel@tonic-gate * if there is one. 15410Sstevel@tonic-gate * 15420Sstevel@tonic-gate * First, we check to see if the current block is 15430Sstevel@tonic-gate * now zero-length and, if so, we free it. 15440Sstevel@tonic-gate * This happens when either the block was empty 15450Sstevel@tonic-gate * to begin with or we consumed all of the data 15460Sstevel@tonic-gate * for the record marking header. 15470Sstevel@tonic-gate */ 15480Sstevel@tonic-gate if (rptr <= mp->b_rptr) { 15490Sstevel@tonic-gate /* 15500Sstevel@tonic-gate * If head_mp is non-NULL, add cont_mp to the 15510Sstevel@tonic-gate * mblk list. XXX But there is a possibility 15520Sstevel@tonic-gate * that tail_mp = mp or even head_mp = mp XXX 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate if (head_mp) { 15550Sstevel@tonic-gate if (head_mp == mp) 15560Sstevel@tonic-gate head_mp = NULL; 15570Sstevel@tonic-gate else if (tail_mp != mp) { 15580Sstevel@tonic-gate ASSERT((tail_mp->b_cont == NULL) || (tail_mp->b_cont == mp)); 15590Sstevel@tonic-gate tail_mp->b_cont = cont_mp; 15600Sstevel@tonic-gate /* 15610Sstevel@tonic-gate * It's possible that, because 15620Sstevel@tonic-gate * of a very short mblk (0-3 15630Sstevel@tonic-gate * bytes), we've ended up here 15640Sstevel@tonic-gate * and that cont_mp could be 15650Sstevel@tonic-gate * NULL (if we're at the end 15660Sstevel@tonic-gate * of an mblk chain). If so, 15670Sstevel@tonic-gate * don't set tail_mp to 15680Sstevel@tonic-gate * cont_mp, because the next 15690Sstevel@tonic-gate * time we access it, we'll 15700Sstevel@tonic-gate * dereference a NULL pointer 15710Sstevel@tonic-gate * and crash. Just leave 15720Sstevel@tonic-gate * tail_mp pointing at the 15730Sstevel@tonic-gate * current end of chain. 15740Sstevel@tonic-gate */ 15750Sstevel@tonic-gate if (cont_mp) 15760Sstevel@tonic-gate tail_mp = cont_mp; 15770Sstevel@tonic-gate } else { 15780Sstevel@tonic-gate mblk_t *smp = head_mp; 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate while ((smp->b_cont != NULL) && 15810Sstevel@tonic-gate (smp->b_cont != mp)) 15820Sstevel@tonic-gate smp = smp->b_cont; 15830Sstevel@tonic-gate smp->b_cont = cont_mp; 15840Sstevel@tonic-gate /* 15850Sstevel@tonic-gate * Don't set tail_mp to cont_mp 15860Sstevel@tonic-gate * if it's NULL. Instead, set 15870Sstevel@tonic-gate * tail_mp to smp, which is the 15880Sstevel@tonic-gate * end of the chain starting 15890Sstevel@tonic-gate * at head_mp. 15900Sstevel@tonic-gate */ 15910Sstevel@tonic-gate if (cont_mp) 15920Sstevel@tonic-gate tail_mp = cont_mp; 15930Sstevel@tonic-gate else 15940Sstevel@tonic-gate tail_mp = smp; 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate freeb(mp); 15980Sstevel@tonic-gate } 15990Sstevel@tonic-gate continue; 16000Sstevel@tonic-gate } 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate /* 16030Sstevel@tonic-gate * frag_len starts at -4 and is incremented past the record 16040Sstevel@tonic-gate * marking header to 0, and then becomes positive as real data 16050Sstevel@tonic-gate * bytes are received for the message. While frag_len is less 16060Sstevel@tonic-gate * than zero, we need more bytes for the record marking 16070Sstevel@tonic-gate * header. 16080Sstevel@tonic-gate */ 16090Sstevel@tonic-gate if (frag_len < 0) { 16100Sstevel@tonic-gate uchar_t *up = rptr; 16110Sstevel@tonic-gate /* 16120Sstevel@tonic-gate * Collect as many bytes as we need for the record 16130Sstevel@tonic-gate * marking header and that are available in this block. 16140Sstevel@tonic-gate */ 16150Sstevel@tonic-gate do { 16160Sstevel@tonic-gate --len; 16170Sstevel@tonic-gate frag_len++; 16180Sstevel@tonic-gate frag_header <<= 8; 16190Sstevel@tonic-gate frag_header += (*up++ & 0xFF); 16200Sstevel@tonic-gate } while (len > 0 && frag_len < 0); 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate if (rptr == mp->b_rptr) { 16230Sstevel@tonic-gate /* 16240Sstevel@tonic-gate * The record header is located at the 16250Sstevel@tonic-gate * beginning of the block, so just walk 16260Sstevel@tonic-gate * b_rptr past it. 16270Sstevel@tonic-gate */ 16280Sstevel@tonic-gate mp->b_rptr = rptr = up; 16290Sstevel@tonic-gate } else { 16300Sstevel@tonic-gate /* 16310Sstevel@tonic-gate * The record header is located in the middle 16320Sstevel@tonic-gate * of a block, so copy any remaining data up. 16330Sstevel@tonic-gate * This happens when an RPC message is 16340Sstevel@tonic-gate * fragmented into multiple pieces and 16350Sstevel@tonic-gate * a middle (or end) fragment immediately 16360Sstevel@tonic-gate * follows a previous fragment in the same 16370Sstevel@tonic-gate * message block. 16380Sstevel@tonic-gate */ 16390Sstevel@tonic-gate wptr = &rptr[len]; 16400Sstevel@tonic-gate mp->b_wptr = wptr; 16410Sstevel@tonic-gate if (len) { 16420Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: copying %d " 16430Sstevel@tonic-gate "bytes of data up", len); 16440Sstevel@tonic-gate RPCLOG(32, " db_ref %d\n", 16450Sstevel@tonic-gate (uint_t)mp->b_datap->db_ref); 16460Sstevel@tonic-gate bcopy(up, rptr, len); 16470Sstevel@tonic-gate } 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate /* 16510Sstevel@tonic-gate * If we haven't received the complete record header 16520Sstevel@tonic-gate * yet, then loop around to get the next block in the 16530Sstevel@tonic-gate * STREAMS message. The logic at same_mblk label will 16540Sstevel@tonic-gate * free the current block if it has become empty. 16550Sstevel@tonic-gate */ 16560Sstevel@tonic-gate if (frag_len < 0) { 16570Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: frag_len is still < 0 " 16580Sstevel@tonic-gate "(%d)", len); 16590Sstevel@tonic-gate goto same_mblk; 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate #ifdef RPCDEBUG 16630Sstevel@tonic-gate if ((frag_header & MIR_LASTFRAG) == 0) { 16640Sstevel@tonic-gate RPCLOG0(32, "mir_do_rput: multi-fragment " 16650Sstevel@tonic-gate "record\n"); 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate { 16680Sstevel@tonic-gate uint_t l = frag_header & ~MIR_LASTFRAG; 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate if (l != 0 && mir->mir_max_msg_sizep && 16710Sstevel@tonic-gate l >= *mir->mir_max_msg_sizep) { 16720Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: fragment size" 16730Sstevel@tonic-gate " (%d) > maximum", l); 16740Sstevel@tonic-gate RPCLOG(32, " (%u)\n", 16750Sstevel@tonic-gate *mir->mir_max_msg_sizep); 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate #endif 16790Sstevel@tonic-gate /* 16800Sstevel@tonic-gate * At this point we have retrieved the complete record 16810Sstevel@tonic-gate * header for this fragment. If the current block is 16820Sstevel@tonic-gate * empty, then we need to free it and walk to the next 16830Sstevel@tonic-gate * block. 16840Sstevel@tonic-gate */ 16850Sstevel@tonic-gate if (mp->b_rptr >= wptr) { 16860Sstevel@tonic-gate /* 16870Sstevel@tonic-gate * If this is not the last fragment or if we 16880Sstevel@tonic-gate * have not received all the data for this 16890Sstevel@tonic-gate * RPC message, then loop around to the next 16900Sstevel@tonic-gate * block. 16910Sstevel@tonic-gate */ 16920Sstevel@tonic-gate if (!(frag_header & MIR_LASTFRAG) || 16930Sstevel@tonic-gate (frag_len - 16940Sstevel@tonic-gate (frag_header & ~MIR_LASTFRAG)) || 16950Sstevel@tonic-gate !head_mp) 16960Sstevel@tonic-gate goto same_mblk; 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate /* 16990Sstevel@tonic-gate * Quick walk to next block in the 17000Sstevel@tonic-gate * STREAMS message. 17010Sstevel@tonic-gate */ 17020Sstevel@tonic-gate freeb(mp); 17030Sstevel@tonic-gate continue; 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate * We've collected the complete record header. The data 17090Sstevel@tonic-gate * in the current block is added to the end of the RPC 17100Sstevel@tonic-gate * message. Note that tail_mp is the same as mp after 17110Sstevel@tonic-gate * this linkage. 17120Sstevel@tonic-gate */ 17130Sstevel@tonic-gate if (!head_mp) 17140Sstevel@tonic-gate head_mp = mp; 17150Sstevel@tonic-gate else if (tail_mp != mp) { 17160Sstevel@tonic-gate ASSERT((tail_mp->b_cont == NULL) || 17170Sstevel@tonic-gate (tail_mp->b_cont == mp)); 17180Sstevel@tonic-gate tail_mp->b_cont = mp; 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate tail_mp = mp; 17210Sstevel@tonic-gate 17220Sstevel@tonic-gate /* 17230Sstevel@tonic-gate * Add the length of this block to the accumulated 17240Sstevel@tonic-gate * fragment length. 17250Sstevel@tonic-gate */ 17260Sstevel@tonic-gate frag_len += len; 17270Sstevel@tonic-gate excess = frag_len - (frag_header & ~MIR_LASTFRAG); 17280Sstevel@tonic-gate /* 17290Sstevel@tonic-gate * If we have not received all the data for this fragment, 17300Sstevel@tonic-gate * then walk to the next block. 17310Sstevel@tonic-gate */ 17320Sstevel@tonic-gate if (excess < 0) 17330Sstevel@tonic-gate continue; 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate /* 17360Sstevel@tonic-gate * We've received a complete fragment, so reset frag_len 17370Sstevel@tonic-gate * for the next one. 17380Sstevel@tonic-gate */ 17390Sstevel@tonic-gate frag_len = -(int32_t)sizeof (uint32_t); 17400Sstevel@tonic-gate 17410Sstevel@tonic-gate /* 17420Sstevel@tonic-gate * Update rptr to point to the beginning of the next 17430Sstevel@tonic-gate * fragment in this block. If there are no more bytes 17440Sstevel@tonic-gate * in the block (excess is 0), then rptr will be equal 17450Sstevel@tonic-gate * to wptr. 17460Sstevel@tonic-gate */ 17470Sstevel@tonic-gate rptr = wptr - excess; 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate /* 17500Sstevel@tonic-gate * Now we check to see if this fragment is the last one in 17510Sstevel@tonic-gate * the RPC message. 17520Sstevel@tonic-gate */ 17530Sstevel@tonic-gate if (!(frag_header & MIR_LASTFRAG)) { 17540Sstevel@tonic-gate /* 17550Sstevel@tonic-gate * This isn't the last one, so start processing the 17560Sstevel@tonic-gate * next fragment. 17570Sstevel@tonic-gate */ 17580Sstevel@tonic-gate frag_header = 0; 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate /* 17610Sstevel@tonic-gate * If excess is 0, the next fragment 17620Sstevel@tonic-gate * starts at the beginning of the next block -- 17630Sstevel@tonic-gate * we "continue" to the end of the while loop and 17640Sstevel@tonic-gate * walk to cont_mp. 17650Sstevel@tonic-gate */ 17660Sstevel@tonic-gate if (excess == 0) 17670Sstevel@tonic-gate continue; 17680Sstevel@tonic-gate RPCLOG0(32, "mir_do_rput: multi-fragment message with " 17690Sstevel@tonic-gate "two or more fragments in one mblk\n"); 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate /* 17720Sstevel@tonic-gate * If excess is non-0, then the next fragment starts 17730Sstevel@tonic-gate * in this block. rptr points to the beginning 17740Sstevel@tonic-gate * of the next fragment and we "goto same_mblk" 17750Sstevel@tonic-gate * to continue processing. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate goto same_mblk; 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate /* 17810Sstevel@tonic-gate * We've got a complete RPC message. Before passing it 17820Sstevel@tonic-gate * upstream, check to see if there is extra data in this 17830Sstevel@tonic-gate * message block. If so, then we separate the excess 17840Sstevel@tonic-gate * from the complete message. The excess data is processed 17850Sstevel@tonic-gate * after the current message goes upstream. 17860Sstevel@tonic-gate */ 17870Sstevel@tonic-gate if (excess > 0) { 17880Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: end of record, but excess " 17890Sstevel@tonic-gate "data (%d bytes) in this mblk. dupb/copyb " 17900Sstevel@tonic-gate "needed\n", excess); 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate /* Duplicate only the overlapping block. */ 17930Sstevel@tonic-gate mp1 = dupb(tail_mp); 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate /* 17960Sstevel@tonic-gate * dupb() might have failed due to ref count wrap around 17970Sstevel@tonic-gate * so try a copyb(). 17980Sstevel@tonic-gate */ 17990Sstevel@tonic-gate if (mp1 == NULL) 18000Sstevel@tonic-gate mp1 = copyb(tail_mp); 18010Sstevel@tonic-gate 18020Sstevel@tonic-gate /* 18030Sstevel@tonic-gate * Do not use bufcall() to schedule a "buffer 18040Sstevel@tonic-gate * availability event." The reason is that 18050Sstevel@tonic-gate * bufcall() has problems. For example, if memory 18060Sstevel@tonic-gate * runs out, bufcall() itself will fail since it 18070Sstevel@tonic-gate * needs to allocate memory. The most appropriate 18080Sstevel@tonic-gate * action right now is to disconnect this connection 18090Sstevel@tonic-gate * as the system is under stress. We should try to 18100Sstevel@tonic-gate * free up resources. 18110Sstevel@tonic-gate */ 18120Sstevel@tonic-gate if (mp1 == NULL) { 18130Sstevel@tonic-gate freemsg(head_mp); 18140Sstevel@tonic-gate RPCLOG0(1, "mir_do_rput: dupb/copyb failed\n"); 18150Sstevel@tonic-gate mir->mir_frag_header = 0; 18160Sstevel@tonic-gate mir->mir_frag_len = -(int)sizeof (uint32_t); 18170Sstevel@tonic-gate mir->mir_head_mp = NULL; 18180Sstevel@tonic-gate mir->mir_tail_mp = NULL; 18190Sstevel@tonic-gate 18200Sstevel@tonic-gate mir_disconnect(q, mir); 18210Sstevel@tonic-gate return; 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate /* 18250Sstevel@tonic-gate * The new message block is linked with the 18260Sstevel@tonic-gate * continuation block in cont_mp. We then point 18270Sstevel@tonic-gate * cont_mp to the new block so that we will 18280Sstevel@tonic-gate * process it next. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate mp1->b_cont = cont_mp; 18310Sstevel@tonic-gate cont_mp = mp1; 18320Sstevel@tonic-gate /* 18330Sstevel@tonic-gate * Data in the new block begins at the 18340Sstevel@tonic-gate * next fragment (rptr). 18350Sstevel@tonic-gate */ 18360Sstevel@tonic-gate cont_mp->b_rptr += (rptr - tail_mp->b_rptr); 18370Sstevel@tonic-gate ASSERT(cont_mp->b_rptr >= cont_mp->b_datap->db_base); 18380Sstevel@tonic-gate ASSERT(cont_mp->b_rptr <= cont_mp->b_wptr); 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate /* Data in the current fragment ends at rptr. */ 18410Sstevel@tonic-gate tail_mp->b_wptr = rptr; 18420Sstevel@tonic-gate ASSERT(tail_mp->b_wptr <= tail_mp->b_datap->db_lim); 18430Sstevel@tonic-gate ASSERT(tail_mp->b_wptr >= tail_mp->b_rptr); 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate } 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate /* tail_mp is the last block with data for this RPC message. */ 18480Sstevel@tonic-gate tail_mp->b_cont = NULL; 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate /* Pass the RPC message to the current consumer. */ 18510Sstevel@tonic-gate switch (mir->mir_type) { 18520Sstevel@tonic-gate case RPC_CLIENT: 18530Sstevel@tonic-gate if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) { 18540Sstevel@tonic-gate /* 18550Sstevel@tonic-gate * Mark this stream as active. This marker 18560Sstevel@tonic-gate * is used in mir_timer(). 18570Sstevel@tonic-gate */ 18580Sstevel@tonic-gate 18590Sstevel@tonic-gate mir->mir_clntreq = 1; 18600Sstevel@tonic-gate mir->mir_use_timestamp = lbolt; 18610Sstevel@tonic-gate } else 18620Sstevel@tonic-gate freemsg(head_mp); 18630Sstevel@tonic-gate break; 18640Sstevel@tonic-gate 18650Sstevel@tonic-gate case RPC_SERVER: 18660Sstevel@tonic-gate /* 18670Sstevel@tonic-gate * Check for flow control before passing the 18680Sstevel@tonic-gate * message to KRPC. 18690Sstevel@tonic-gate */ 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate if (!mir->mir_hold_inbound) { 18720Sstevel@tonic-gate if (mir->mir_krpc_cell) { 18730Sstevel@tonic-gate /* 18740Sstevel@tonic-gate * If the reference count is 0 18750Sstevel@tonic-gate * (not including this request), 18760Sstevel@tonic-gate * then the stream is transitioning 18770Sstevel@tonic-gate * from idle to non-idle. In this case, 18780Sstevel@tonic-gate * we cancel the idle timer. 18790Sstevel@tonic-gate */ 18800Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0) 18810Sstevel@tonic-gate stop_timer = B_TRUE; 18820Sstevel@tonic-gate if (mir_check_len(q, 18830Sstevel@tonic-gate (int32_t)msgdsize(mp), mp)) 18840Sstevel@tonic-gate return; 18850Sstevel@tonic-gate svc_queuereq(q, head_mp); /* to KRPC */ 18860Sstevel@tonic-gate } else { 18870Sstevel@tonic-gate /* 18880Sstevel@tonic-gate * Count # of times this happens. Should be 18890Sstevel@tonic-gate * never, but experience shows otherwise. 18900Sstevel@tonic-gate */ 18910Sstevel@tonic-gate mir_krpc_cell_null++; 18920Sstevel@tonic-gate freemsg(head_mp); 18930Sstevel@tonic-gate } 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate } else { 18960Sstevel@tonic-gate /* 18970Sstevel@tonic-gate * If the outbound side of the stream is 18980Sstevel@tonic-gate * flow controlled, then hold this message 18990Sstevel@tonic-gate * until client catches up. mir_hold_inbound 19000Sstevel@tonic-gate * is set in mir_wput and cleared in mir_wsrv. 19010Sstevel@tonic-gate */ 19020Sstevel@tonic-gate if (srv) 19030Sstevel@tonic-gate (void) putbq(q, head_mp); 19040Sstevel@tonic-gate else 19050Sstevel@tonic-gate (void) putq(q, head_mp); 19060Sstevel@tonic-gate mir->mir_inrservice = B_TRUE; 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate break; 19090Sstevel@tonic-gate default: 19100Sstevel@tonic-gate RPCLOG(1, "mir_rput: unknown mir_type %d\n", 19110Sstevel@tonic-gate mir->mir_type); 19120Sstevel@tonic-gate freemsg(head_mp); 19130Sstevel@tonic-gate break; 19140Sstevel@tonic-gate } 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate /* 19170Sstevel@tonic-gate * Reset head_mp and frag_header since we're starting on a 19180Sstevel@tonic-gate * new RPC fragment and message. 19190Sstevel@tonic-gate */ 19200Sstevel@tonic-gate head_mp = NULL; 19210Sstevel@tonic-gate tail_mp = NULL; 19220Sstevel@tonic-gate frag_header = 0; 19230Sstevel@tonic-gate } while ((mp = cont_mp) != NULL); 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate /* 19260Sstevel@tonic-gate * Do a sanity check on the message length. If this message is 19270Sstevel@tonic-gate * getting excessively large, shut down the connection. 19280Sstevel@tonic-gate */ 19290Sstevel@tonic-gate if (head_mp != NULL && mir->mir_setup_complete && 19300Sstevel@tonic-gate mir_check_len(q, frag_len, head_mp)) 19310Sstevel@tonic-gate return; 19320Sstevel@tonic-gate 19330Sstevel@tonic-gate /* Save our local copies back in the mir structure. */ 19340Sstevel@tonic-gate mir->mir_frag_header = frag_header; 19350Sstevel@tonic-gate mir->mir_frag_len = frag_len; 19360Sstevel@tonic-gate mir->mir_head_mp = head_mp; 19370Sstevel@tonic-gate mir->mir_tail_mp = tail_mp; 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate /* 19400Sstevel@tonic-gate * The timer is stopped after the whole message chain is processed. 19410Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex 19420Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced 19430Sstevel@tonic-gate * while we are still processing the message chain. This is not 19440Sstevel@tonic-gate * good. So we stop the timer here instead. 19450Sstevel@tonic-gate * 19460Sstevel@tonic-gate * Note that if the timer fires before we stop it, it will not 19470Sstevel@tonic-gate * do any harm as MIR_SVC_QUIESCED() is false and mir_timer() 19480Sstevel@tonic-gate * will just return; 19490Sstevel@tonic-gate */ 19500Sstevel@tonic-gate if (stop_timer) { 19510Sstevel@tonic-gate RPCLOG(16, "mir_do_rput stopping idle timer on 0x%p because " 19520Sstevel@tonic-gate "ref cnt going to non zero\n", (void *) WR(q)); 19530Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 19540Sstevel@tonic-gate } 19550Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 19560Sstevel@tonic-gate } 19570Sstevel@tonic-gate 19580Sstevel@tonic-gate static void 19590Sstevel@tonic-gate mir_rput(queue_t *q, mblk_t *mp) 19600Sstevel@tonic-gate { 19610Sstevel@tonic-gate mir_do_rput(q, mp, 0); 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate static void 19650Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp) 19660Sstevel@tonic-gate { 19670Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 19680Sstevel@tonic-gate uint32_t type; 19690Sstevel@tonic-gate uint32_t reason = 0; 19700Sstevel@tonic-gate 19710Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate type = ((union T_primitives *)mp->b_rptr)->type; 19740Sstevel@tonic-gate switch (mir->mir_type) { 19750Sstevel@tonic-gate case RPC_CLIENT: 19760Sstevel@tonic-gate switch (type) { 19770Sstevel@tonic-gate case T_DISCON_IND: 19780Sstevel@tonic-gate reason = 19790Sstevel@tonic-gate ((struct T_discon_ind *)(mp->b_rptr))->DISCON_reason; 19800Sstevel@tonic-gate /*FALLTHROUGH*/ 19810Sstevel@tonic-gate case T_ORDREL_IND: 19820Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 19830Sstevel@tonic-gate if (mir->mir_head_mp) { 19840Sstevel@tonic-gate freemsg(mir->mir_head_mp); 19850Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 19860Sstevel@tonic-gate mir->mir_tail_mp = (mblk_t *)0; 19870Sstevel@tonic-gate } 19880Sstevel@tonic-gate /* 19890Sstevel@tonic-gate * We are disconnecting, but not necessarily 19900Sstevel@tonic-gate * closing. By not closing, we will fail to 19910Sstevel@tonic-gate * pick up a possibly changed global timeout value, 19920Sstevel@tonic-gate * unless we store it now. 19930Sstevel@tonic-gate */ 19940Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 19950Sstevel@tonic-gate mir_clnt_idle_stop(WR(q), mir); 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate /* 19980Sstevel@tonic-gate * Even though we are unconnected, we still 19990Sstevel@tonic-gate * leave the idle timer going on the client. The 20000Sstevel@tonic-gate * reason for is that if we've disconnected due 20010Sstevel@tonic-gate * to a server-side disconnect, reset, or connection 20020Sstevel@tonic-gate * timeout, there is a possibility the client may 20030Sstevel@tonic-gate * retry the RPC request. This retry needs to done on 20040Sstevel@tonic-gate * the same bound address for the server to interpret 20050Sstevel@tonic-gate * it as such. However, we don't want 20060Sstevel@tonic-gate * to wait forever for that possibility. If the 20070Sstevel@tonic-gate * end-point stays unconnected for mir_idle_timeout 20080Sstevel@tonic-gate * units of time, then that is a signal to the 20090Sstevel@tonic-gate * connection manager to give up waiting for the 20100Sstevel@tonic-gate * application (eg. NFS) to send a retry. 20110Sstevel@tonic-gate */ 20120Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir); 20130Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 20140Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 20150Sstevel@tonic-gate freemsg(mp); 20160Sstevel@tonic-gate return; 20170Sstevel@tonic-gate case T_ERROR_ACK: 20180Sstevel@tonic-gate { 20190Sstevel@tonic-gate struct T_error_ack *terror; 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate terror = (struct T_error_ack *)mp->b_rptr; 20220Sstevel@tonic-gate RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p", 20230Sstevel@tonic-gate (void *)q); 20240Sstevel@tonic-gate RPCLOG(1, " ERROR_prim: %s,", 20250Sstevel@tonic-gate rpc_tpiprim2name(terror->ERROR_prim)); 20260Sstevel@tonic-gate RPCLOG(1, " TLI_error: %s,", 20270Sstevel@tonic-gate rpc_tpierr2name(terror->TLI_error)); 20280Sstevel@tonic-gate RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error); 20290Sstevel@tonic-gate if (terror->ERROR_prim == T_DISCON_REQ) { 20300Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 20310Sstevel@tonic-gate freemsg(mp); 20320Sstevel@tonic-gate return; 20330Sstevel@tonic-gate } else { 20340Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 20350Sstevel@tonic-gate return; 20360Sstevel@tonic-gate } 20370Sstevel@tonic-gate break; 20380Sstevel@tonic-gate } 20390Sstevel@tonic-gate case T_OK_ACK: 20400Sstevel@tonic-gate { 20410Sstevel@tonic-gate struct T_ok_ack *tok = (struct T_ok_ack *)mp->b_rptr; 20420Sstevel@tonic-gate 20430Sstevel@tonic-gate if (tok->CORRECT_prim == T_DISCON_REQ) { 20440Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 20450Sstevel@tonic-gate freemsg(mp); 20460Sstevel@tonic-gate return; 20470Sstevel@tonic-gate } else { 20480Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 20490Sstevel@tonic-gate return; 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate break; 20520Sstevel@tonic-gate } 20530Sstevel@tonic-gate case T_CONN_CON: 20540Sstevel@tonic-gate case T_INFO_ACK: 20550Sstevel@tonic-gate case T_OPTMGMT_ACK: 20560Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 20570Sstevel@tonic-gate return; 20580Sstevel@tonic-gate break; 20590Sstevel@tonic-gate case T_BIND_ACK: 20600Sstevel@tonic-gate break; 20610Sstevel@tonic-gate default: 20620Sstevel@tonic-gate RPCLOG(1, "mir_rput: unexpected message %d " 20630Sstevel@tonic-gate "for KRPC client\n", 20640Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type); 20650Sstevel@tonic-gate break; 20660Sstevel@tonic-gate } 20670Sstevel@tonic-gate break; 20680Sstevel@tonic-gate 20690Sstevel@tonic-gate case RPC_SERVER: 20700Sstevel@tonic-gate switch (type) { 20710Sstevel@tonic-gate case T_BIND_ACK: 20720Sstevel@tonic-gate { 20730Sstevel@tonic-gate struct T_bind_ack *tbind; 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate /* 20760Sstevel@tonic-gate * If this is a listening stream, then shut 20770Sstevel@tonic-gate * off the idle timer. 20780Sstevel@tonic-gate */ 20790Sstevel@tonic-gate tbind = (struct T_bind_ack *)mp->b_rptr; 20800Sstevel@tonic-gate if (tbind->CONIND_number > 0) { 20810Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 20820Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 20830Sstevel@tonic-gate 20840Sstevel@tonic-gate /* 20850Sstevel@tonic-gate * mark this as a listen endpoint 20860Sstevel@tonic-gate * for special handling. 20870Sstevel@tonic-gate */ 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate mir->mir_listen_stream = 1; 20900Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate break; 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate case T_DISCON_IND: 20950Sstevel@tonic-gate case T_ORDREL_IND: 20960Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: got %s indication\n", 20970Sstevel@tonic-gate type == T_DISCON_IND ? "disconnect" 20980Sstevel@tonic-gate : "orderly release"); 20990Sstevel@tonic-gate 21000Sstevel@tonic-gate /* 21010Sstevel@tonic-gate * For listen endpoint just pass 21020Sstevel@tonic-gate * on the message. 21030Sstevel@tonic-gate */ 21040Sstevel@tonic-gate 21050Sstevel@tonic-gate if (mir->mir_listen_stream) 21060Sstevel@tonic-gate break; 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 21090Sstevel@tonic-gate 21100Sstevel@tonic-gate /* 21110Sstevel@tonic-gate * If client wants to break off connection, record 21120Sstevel@tonic-gate * that fact. 21130Sstevel@tonic-gate */ 21140Sstevel@tonic-gate mir_svc_start_close(WR(q), mir); 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate /* 21170Sstevel@tonic-gate * If we are idle, then send the orderly release 21180Sstevel@tonic-gate * or disconnect indication to nfsd. 21190Sstevel@tonic-gate */ 21200Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 21210Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 21220Sstevel@tonic-gate break; 21230Sstevel@tonic-gate } 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: not idle, so " 21260Sstevel@tonic-gate "disconnect/ord rel indication not passed " 21270Sstevel@tonic-gate "upstream on 0x%p\n", (void *)q); 21280Sstevel@tonic-gate 21290Sstevel@tonic-gate /* 21300Sstevel@tonic-gate * Hold the indication until we get idle 21310Sstevel@tonic-gate * If there already is an indication stored, 21320Sstevel@tonic-gate * replace it if the new one is a disconnect. The 21330Sstevel@tonic-gate * reasoning is that disconnection takes less time 21340Sstevel@tonic-gate * to process, and once a client decides to 21350Sstevel@tonic-gate * disconnect, we should do that. 21360Sstevel@tonic-gate */ 21370Sstevel@tonic-gate if (mir->mir_svc_pend_mp) { 21380Sstevel@tonic-gate if (type == T_DISCON_IND) { 21390Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: replacing" 21400Sstevel@tonic-gate " held disconnect/ord rel" 21410Sstevel@tonic-gate " indication with disconnect on" 21420Sstevel@tonic-gate " 0x%p\n", (void *)q); 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate freemsg(mir->mir_svc_pend_mp); 21450Sstevel@tonic-gate mir->mir_svc_pend_mp = mp; 21460Sstevel@tonic-gate } else { 21470Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: already " 21480Sstevel@tonic-gate "held a disconnect/ord rel " 21490Sstevel@tonic-gate "indication. freeing ord rel " 21500Sstevel@tonic-gate "ind on 0x%p\n", (void *)q); 21510Sstevel@tonic-gate freemsg(mp); 21520Sstevel@tonic-gate } 21530Sstevel@tonic-gate } else 21540Sstevel@tonic-gate mir->mir_svc_pend_mp = mp; 21550Sstevel@tonic-gate 21560Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 21570Sstevel@tonic-gate return; 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate default: 21600Sstevel@tonic-gate /* nfsd handles server-side non-data messages. */ 21610Sstevel@tonic-gate break; 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate break; 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate default: 21660Sstevel@tonic-gate break; 21670Sstevel@tonic-gate } 21680Sstevel@tonic-gate 21690Sstevel@tonic-gate putnext(q, mp); 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate /* 21730Sstevel@tonic-gate * The server-side read queues are used to hold inbound messages while 21740Sstevel@tonic-gate * outbound flow control is exerted. When outbound flow control is 21750Sstevel@tonic-gate * relieved, mir_wsrv qenables the read-side queue. Read-side queues 21760Sstevel@tonic-gate * are not enabled by STREAMS and are explicitly noenable'ed in mir_open. 21770Sstevel@tonic-gate * 21780Sstevel@tonic-gate * For the server side, we have two types of messages queued. The first type 21790Sstevel@tonic-gate * are messages that are ready to be XDR decoded and and then sent to the 21800Sstevel@tonic-gate * RPC program's dispatch routine. The second type are "raw" messages that 21810Sstevel@tonic-gate * haven't been processed, i.e. assembled from rpc record fragements into 21820Sstevel@tonic-gate * full requests. The only time we will see the second type of message 21830Sstevel@tonic-gate * queued is if we have a memory allocation failure while processing a 21840Sstevel@tonic-gate * a raw message. The field mir_first_non_processed_mblk will mark the 21850Sstevel@tonic-gate * first such raw message. So the flow for server side is: 21860Sstevel@tonic-gate * 21870Sstevel@tonic-gate * - send processed queued messages to kRPC until we run out or find 21880Sstevel@tonic-gate * one that needs additional processing because we were short on memory 21890Sstevel@tonic-gate * earlier 21900Sstevel@tonic-gate * - process a message that was deferred because of lack of 21910Sstevel@tonic-gate * memory 21920Sstevel@tonic-gate * - continue processing messages until the queue empties or we 21930Sstevel@tonic-gate * have to stop because of lack of memory 21940Sstevel@tonic-gate * - during each of the above phase, if the queue is empty and 21950Sstevel@tonic-gate * there are no pending messages that were passed to the RPC 21960Sstevel@tonic-gate * layer, send upstream the pending disconnect/ordrel indication if 21970Sstevel@tonic-gate * there is one 21980Sstevel@tonic-gate * 21990Sstevel@tonic-gate * The read-side queue is also enabled by a bufcall callback if dupmsg 22000Sstevel@tonic-gate * fails in mir_rput. 22010Sstevel@tonic-gate */ 22020Sstevel@tonic-gate static void 22030Sstevel@tonic-gate mir_rsrv(queue_t *q) 22040Sstevel@tonic-gate { 22050Sstevel@tonic-gate mir_t *mir; 22060Sstevel@tonic-gate mblk_t *mp; 22070Sstevel@tonic-gate mblk_t *cmp = NULL; 22080Sstevel@tonic-gate boolean_t stop_timer = B_FALSE; 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 22110Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 22120Sstevel@tonic-gate 22130Sstevel@tonic-gate mp = NULL; 22140Sstevel@tonic-gate switch (mir->mir_type) { 22150Sstevel@tonic-gate case RPC_SERVER: 22160Sstevel@tonic-gate if (mir->mir_ref_cnt == 0) 22170Sstevel@tonic-gate mir->mir_hold_inbound = 0; 22180Sstevel@tonic-gate if (mir->mir_hold_inbound) { 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate ASSERT(cmp == NULL); 22210Sstevel@tonic-gate if (q->q_first == NULL) { 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 22240Sstevel@tonic-gate 22250Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 22260Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 22270Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 22280Sstevel@tonic-gate } 22290Sstevel@tonic-gate } 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 22320Sstevel@tonic-gate 22330Sstevel@tonic-gate if (cmp != NULL) { 22340Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held " 22350Sstevel@tonic-gate "disconnect/ord rel indication upstream\n", 22360Sstevel@tonic-gate __LINE__); 22370Sstevel@tonic-gate putnext(q, cmp); 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate return; 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate while (mp = getq(q)) { 22430Sstevel@tonic-gate if (mir->mir_krpc_cell) { 22440Sstevel@tonic-gate /* 22450Sstevel@tonic-gate * If we were idle, turn off idle timer since 22460Sstevel@tonic-gate * we aren't idle any more. 22470Sstevel@tonic-gate */ 22480Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0) 22490Sstevel@tonic-gate stop_timer = B_TRUE; 22500Sstevel@tonic-gate if (mir_check_len(q, 22510Sstevel@tonic-gate (int32_t)msgdsize(mp), mp)) 22520Sstevel@tonic-gate return; 22530Sstevel@tonic-gate svc_queuereq(q, mp); 22540Sstevel@tonic-gate } else { 22550Sstevel@tonic-gate /* 22560Sstevel@tonic-gate * Count # of times this happens. Should be 22570Sstevel@tonic-gate * never, but experience shows otherwise. 22580Sstevel@tonic-gate */ 22590Sstevel@tonic-gate mir_krpc_cell_null++; 22600Sstevel@tonic-gate freemsg(mp); 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate } 22630Sstevel@tonic-gate break; 22640Sstevel@tonic-gate case RPC_CLIENT: 22650Sstevel@tonic-gate break; 22660Sstevel@tonic-gate default: 22670Sstevel@tonic-gate RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type); 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate if (q->q_first == NULL) 22700Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 22730Sstevel@tonic-gate 22740Sstevel@tonic-gate return; 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate 22770Sstevel@tonic-gate /* 22780Sstevel@tonic-gate * The timer is stopped after all the messages are processed. 22790Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex 22800Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced 22810Sstevel@tonic-gate * while we are still processing the message queue. This is not 22820Sstevel@tonic-gate * good. So we stop the timer here instead. 22830Sstevel@tonic-gate */ 22840Sstevel@tonic-gate if (stop_timer) { 22850Sstevel@tonic-gate RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref " 22860Sstevel@tonic-gate "cnt going to non zero\n", (void *)WR(q)); 22870Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 22880Sstevel@tonic-gate } 22890Sstevel@tonic-gate 22900Sstevel@tonic-gate if (q->q_first == NULL) { 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate ASSERT(cmp == NULL); 22950Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) { 22960Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 22970Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 22980Sstevel@tonic-gate } 22990Sstevel@tonic-gate 23000Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 23010Sstevel@tonic-gate 23020Sstevel@tonic-gate if (cmp != NULL) { 23030Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held " 23040Sstevel@tonic-gate "disconnect/ord rel indication upstream\n", 23050Sstevel@tonic-gate __LINE__); 23060Sstevel@tonic-gate putnext(q, cmp); 23070Sstevel@tonic-gate } 23080Sstevel@tonic-gate 23090Sstevel@tonic-gate return; 23100Sstevel@tonic-gate } 23110Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 23120Sstevel@tonic-gate } 23130Sstevel@tonic-gate 23140Sstevel@tonic-gate static int mir_svc_policy_fails; 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate /* 23170Sstevel@tonic-gate * Called to send an event code to nfsd/lockd so that it initiates 23180Sstevel@tonic-gate * connection close. 23190Sstevel@tonic-gate */ 23200Sstevel@tonic-gate static int 23210Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event) 23220Sstevel@tonic-gate { 23230Sstevel@tonic-gate mblk_t *mp; 23240Sstevel@tonic-gate #ifdef DEBUG 23250Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 23260Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 23270Sstevel@tonic-gate #endif 23280Sstevel@tonic-gate ASSERT(q->q_flag & QREADR); 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate /* 23310Sstevel@tonic-gate * Create an M_DATA message with the event code and pass it to the 23320Sstevel@tonic-gate * Stream head (nfsd or whoever created the stream will consume it). 23330Sstevel@tonic-gate */ 23340Sstevel@tonic-gate mp = allocb(sizeof (int), BPRI_HI); 23350Sstevel@tonic-gate 23360Sstevel@tonic-gate if (!mp) { 23370Sstevel@tonic-gate 23380Sstevel@tonic-gate mir_svc_policy_fails++; 23390Sstevel@tonic-gate RPCLOG(16, "mir_svc_policy_notify: could not allocate event " 23400Sstevel@tonic-gate "%d\n", event); 23410Sstevel@tonic-gate return (ENOMEM); 23420Sstevel@tonic-gate } 23430Sstevel@tonic-gate 23440Sstevel@tonic-gate U32_TO_BE32(event, mp->b_rptr); 23450Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (int); 23460Sstevel@tonic-gate putnext(q, mp); 23470Sstevel@tonic-gate return (0); 23480Sstevel@tonic-gate } 23490Sstevel@tonic-gate 23500Sstevel@tonic-gate /* 23510Sstevel@tonic-gate * Server side: start the close phase. We want to get this rpcmod slot in an 23520Sstevel@tonic-gate * idle state before mir_close() is called. 23530Sstevel@tonic-gate */ 23540Sstevel@tonic-gate static void 23550Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir) 23560Sstevel@tonic-gate { 23570Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 23580Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 23590Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate 23620Sstevel@tonic-gate /* 23630Sstevel@tonic-gate * Do not accept any more messages. 23640Sstevel@tonic-gate */ 23650Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1; 23660Sstevel@tonic-gate 23670Sstevel@tonic-gate /* 23680Sstevel@tonic-gate * Next two statements will make the read service procedure invoke 23690Sstevel@tonic-gate * svc_queuereq() on everything stuck in the streams read queue. 23700Sstevel@tonic-gate * It's not necessary because enabling the write queue will 23710Sstevel@tonic-gate * have the same effect, but why not speed the process along? 23720Sstevel@tonic-gate */ 23730Sstevel@tonic-gate mir->mir_hold_inbound = 0; 23740Sstevel@tonic-gate qenable(RD(wq)); 23750Sstevel@tonic-gate 23760Sstevel@tonic-gate /* 23770Sstevel@tonic-gate * Meanwhile force the write service procedure to send the 23780Sstevel@tonic-gate * responses downstream, regardless of flow control. 23790Sstevel@tonic-gate */ 23800Sstevel@tonic-gate qenable(wq); 23810Sstevel@tonic-gate } 23820Sstevel@tonic-gate 23830Sstevel@tonic-gate /* 23840Sstevel@tonic-gate * This routine is called directly by KRPC after a request is completed, 23850Sstevel@tonic-gate * whether a reply was sent or the request was dropped. 23860Sstevel@tonic-gate */ 23870Sstevel@tonic-gate static void 23880Sstevel@tonic-gate mir_svc_release(queue_t *wq, mblk_t *mp) 23890Sstevel@tonic-gate { 23900Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 23910Sstevel@tonic-gate mblk_t *cmp = NULL; 23920Sstevel@tonic-gate 23930Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 23940Sstevel@tonic-gate if (mp) 23950Sstevel@tonic-gate freemsg(mp); 23960Sstevel@tonic-gate 23970Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 23980Sstevel@tonic-gate mir->mir_ref_cnt--; 23990Sstevel@tonic-gate ASSERT(mir->mir_ref_cnt >= 0); 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate /* 24020Sstevel@tonic-gate * Start idle processing if this is the last reference. 24030Sstevel@tonic-gate */ 24040Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate RPCLOG(16, "mir_svc_release starting idle timer on 0x%p " 24070Sstevel@tonic-gate "because ref cnt is zero\n", (void *) wq); 24080Sstevel@tonic-gate 24090Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 24100Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 24110Sstevel@tonic-gate mir_svc_idle_start(wq, mir); 24120Sstevel@tonic-gate } 24130Sstevel@tonic-gate 24140Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate if (cmp) { 24170Sstevel@tonic-gate RPCLOG(16, "mir_svc_release: sending a held " 24180Sstevel@tonic-gate "disconnect/ord rel indication upstream on queue 0x%p\n", 24190Sstevel@tonic-gate (void *)RD(wq)); 24200Sstevel@tonic-gate 24210Sstevel@tonic-gate putnext(RD(wq), cmp); 24220Sstevel@tonic-gate } 24230Sstevel@tonic-gate } 24240Sstevel@tonic-gate 24250Sstevel@tonic-gate /* 24260Sstevel@tonic-gate * This routine is called by server-side KRPC when it is ready to 24270Sstevel@tonic-gate * handle inbound messages on the stream. 24280Sstevel@tonic-gate */ 24290Sstevel@tonic-gate static void 24300Sstevel@tonic-gate mir_svc_start(queue_t *wq) 24310Sstevel@tonic-gate { 24320Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 24330Sstevel@tonic-gate 24340Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 24350Sstevel@tonic-gate mir->mir_setup_complete = 1; 24360Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 24370Sstevel@tonic-gate qenable(RD(wq)); 24380Sstevel@tonic-gate } 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate /* 24410Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout. 24420Sstevel@tonic-gate */ 24430Sstevel@tonic-gate static void 24440Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir) 24450Sstevel@tonic-gate { 24460Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 24470Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 24480Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT); 24490Sstevel@tonic-gate 24500Sstevel@tonic-gate mir_timer_stop(mir); 24510Sstevel@tonic-gate } 24520Sstevel@tonic-gate 24530Sstevel@tonic-gate /* 24540Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout. 24550Sstevel@tonic-gate */ 24560Sstevel@tonic-gate static void 24570Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir) 24580Sstevel@tonic-gate { 24590Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 24600Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 24610Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT); 24620Sstevel@tonic-gate 24630Sstevel@tonic-gate mir_timer_start(wq, mir, mir->mir_idle_timeout); 24640Sstevel@tonic-gate } 24650Sstevel@tonic-gate 24660Sstevel@tonic-gate /* 24670Sstevel@tonic-gate * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on 24680Sstevel@tonic-gate * end-points that aren't connected. 24690Sstevel@tonic-gate */ 24700Sstevel@tonic-gate static void 24710Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq) 24720Sstevel@tonic-gate { 24730Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 24740Sstevel@tonic-gate 24750Sstevel@tonic-gate RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq); 24760Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 24770Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 24780Sstevel@tonic-gate mir_clnt_idle_stop(wq, mir); 24790Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 24800Sstevel@tonic-gate } 24810Sstevel@tonic-gate 24820Sstevel@tonic-gate /* 24830Sstevel@tonic-gate * Timer handler. It handles idle timeout and memory shortage problem. 24840Sstevel@tonic-gate */ 24850Sstevel@tonic-gate static void 24860Sstevel@tonic-gate mir_timer(void *arg) 24870Sstevel@tonic-gate { 24880Sstevel@tonic-gate queue_t *wq = (queue_t *)arg; 24890Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 24900Sstevel@tonic-gate boolean_t notify; 24910Sstevel@tonic-gate 24920Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 24930Sstevel@tonic-gate 24940Sstevel@tonic-gate /* 24950Sstevel@tonic-gate * mir_timer_call is set only when either mir_timer_[start|stop] 24960Sstevel@tonic-gate * is progressing. And mir_timer() can only be run while they 24970Sstevel@tonic-gate * are progressing if the timer is being stopped. So just 24980Sstevel@tonic-gate * return. 24990Sstevel@tonic-gate */ 25000Sstevel@tonic-gate if (mir->mir_timer_call) { 25010Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 25020Sstevel@tonic-gate return; 25030Sstevel@tonic-gate } 25040Sstevel@tonic-gate mir->mir_timer_id = 0; 25050Sstevel@tonic-gate 25060Sstevel@tonic-gate switch (mir->mir_type) { 25070Sstevel@tonic-gate case RPC_CLIENT: 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate /* 25100Sstevel@tonic-gate * For clients, the timer fires at clnt_idle_timeout 25110Sstevel@tonic-gate * intervals. If the activity marker (mir_clntreq) is 25120Sstevel@tonic-gate * zero, then the stream has been idle since the last 25130Sstevel@tonic-gate * timer event and we notify KRPC. If mir_clntreq is 25140Sstevel@tonic-gate * non-zero, then the stream is active and we just 25150Sstevel@tonic-gate * restart the timer for another interval. mir_clntreq 25160Sstevel@tonic-gate * is set to 1 in mir_wput for every request passed 25170Sstevel@tonic-gate * downstream. 25180Sstevel@tonic-gate * 25190Sstevel@tonic-gate * If this was a memory shortage timer reset the idle 25200Sstevel@tonic-gate * timeout regardless; the mir_clntreq will not be a 25210Sstevel@tonic-gate * valid indicator. 25220Sstevel@tonic-gate * 25230Sstevel@tonic-gate * The timer is initially started in mir_wput during 25240Sstevel@tonic-gate * RPC_CLIENT ioctl processing. 25250Sstevel@tonic-gate * 25260Sstevel@tonic-gate * The timer interval can be changed for individual 25270Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout". 25280Sstevel@tonic-gate */ 25290Sstevel@tonic-gate if (mir->mir_clntreq > 0 && mir->mir_use_timestamp + 25300Sstevel@tonic-gate MSEC_TO_TICK(mir->mir_idle_timeout) - lbolt >= 0) { 25310Sstevel@tonic-gate clock_t tout; 25320Sstevel@tonic-gate 25330Sstevel@tonic-gate tout = mir->mir_idle_timeout - 25340Sstevel@tonic-gate TICK_TO_MSEC(lbolt - mir->mir_use_timestamp); 25350Sstevel@tonic-gate if (tout < 0) 25360Sstevel@tonic-gate tout = 1000; 25370Sstevel@tonic-gate #if 0 25380Sstevel@tonic-gate printf("mir_timer[%d < %d + %d]: reset client timer to %d (ms)\n", 25390Sstevel@tonic-gate TICK_TO_MSEC(lbolt), TICK_TO_MSEC(mir->mir_use_timestamp), 25400Sstevel@tonic-gate mir->mir_idle_timeout, tout); 25410Sstevel@tonic-gate #endif 25420Sstevel@tonic-gate mir->mir_clntreq = 0; 25430Sstevel@tonic-gate mir_timer_start(wq, mir, tout); 25440Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 25450Sstevel@tonic-gate return; 25460Sstevel@tonic-gate } 25470Sstevel@tonic-gate #if 0 25480Sstevel@tonic-gate printf("mir_timer[%d]: doing client timeout\n", lbolt / hz); 25490Sstevel@tonic-gate #endif 25500Sstevel@tonic-gate /* 25510Sstevel@tonic-gate * We are disconnecting, but not necessarily 25520Sstevel@tonic-gate * closing. By not closing, we will fail to 25530Sstevel@tonic-gate * pick up a possibly changed global timeout value, 25540Sstevel@tonic-gate * unless we store it now. 25550Sstevel@tonic-gate */ 25560Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 25570Sstevel@tonic-gate mir_clnt_idle_start(wq, mir); 25580Sstevel@tonic-gate 25590Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 25600Sstevel@tonic-gate /* 25610Sstevel@tonic-gate * We pass T_ORDREL_REQ as an integer value 25620Sstevel@tonic-gate * to KRPC as the indication that the stream 25630Sstevel@tonic-gate * is idle. This is not a T_ORDREL_REQ message, 25640Sstevel@tonic-gate * it is just a convenient value since we call 25650Sstevel@tonic-gate * the same KRPC routine for T_ORDREL_INDs and 25660Sstevel@tonic-gate * T_DISCON_INDs. 25670Sstevel@tonic-gate */ 25680Sstevel@tonic-gate clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0); 25690Sstevel@tonic-gate return; 25700Sstevel@tonic-gate 25710Sstevel@tonic-gate case RPC_SERVER: 25720Sstevel@tonic-gate 25730Sstevel@tonic-gate /* 25740Sstevel@tonic-gate * For servers, the timer is only running when the stream 25750Sstevel@tonic-gate * is really idle or memory is short. The timer is started 25760Sstevel@tonic-gate * by mir_wput when mir_type is set to RPC_SERVER and 25770Sstevel@tonic-gate * by mir_svc_idle_start whenever the stream goes idle 25780Sstevel@tonic-gate * (mir_ref_cnt == 0). The timer is cancelled in 25790Sstevel@tonic-gate * mir_rput whenever a new inbound request is passed to KRPC 25800Sstevel@tonic-gate * and the stream was previously idle. 25810Sstevel@tonic-gate * 25820Sstevel@tonic-gate * The timer interval can be changed for individual 25830Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout". 25840Sstevel@tonic-gate * 25850Sstevel@tonic-gate * If the stream is not idle do nothing. 25860Sstevel@tonic-gate */ 25870Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir)) { 25880Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 25890Sstevel@tonic-gate return; 25900Sstevel@tonic-gate } 25910Sstevel@tonic-gate 25920Sstevel@tonic-gate notify = !mir->mir_inrservice; 25930Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 25940Sstevel@tonic-gate 25950Sstevel@tonic-gate /* 25960Sstevel@tonic-gate * If there is no packet queued up in read queue, the stream 25970Sstevel@tonic-gate * is really idle so notify nfsd to close it. 25980Sstevel@tonic-gate */ 25990Sstevel@tonic-gate if (notify) { 26000Sstevel@tonic-gate RPCLOG(16, "mir_timer: telling stream head listener " 26010Sstevel@tonic-gate "to close stream (0x%p)\n", (void *) RD(wq)); 26020Sstevel@tonic-gate (void) mir_svc_policy_notify(RD(wq), 1); 26030Sstevel@tonic-gate } 26040Sstevel@tonic-gate return; 26050Sstevel@tonic-gate default: 26060Sstevel@tonic-gate RPCLOG(1, "mir_timer: unexpected mir_type %d\n", 26070Sstevel@tonic-gate mir->mir_type); 26080Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 26090Sstevel@tonic-gate return; 26100Sstevel@tonic-gate } 26110Sstevel@tonic-gate } 26120Sstevel@tonic-gate 26130Sstevel@tonic-gate /* 26140Sstevel@tonic-gate * Called by the RPC package to send either a call or a return, or a 26150Sstevel@tonic-gate * transport connection request. Adds the record marking header. 26160Sstevel@tonic-gate */ 26170Sstevel@tonic-gate static void 26180Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp) 26190Sstevel@tonic-gate { 26200Sstevel@tonic-gate uint_t frag_header; 26210Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 26220Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 26230Sstevel@tonic-gate 26240Sstevel@tonic-gate if (!mir) { 26250Sstevel@tonic-gate freemsg(mp); 26260Sstevel@tonic-gate return; 26270Sstevel@tonic-gate } 26280Sstevel@tonic-gate 26290Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 26300Sstevel@tonic-gate mir_wput_other(q, mp); 26310Sstevel@tonic-gate return; 26320Sstevel@tonic-gate } 26330Sstevel@tonic-gate 26340Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) { 26350Sstevel@tonic-gate freemsg(mp); 26360Sstevel@tonic-gate RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n", 26370Sstevel@tonic-gate (void *)q); 26380Sstevel@tonic-gate return; 26390Sstevel@tonic-gate } 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate frag_header = (uint_t)DLEN(mp); 26420Sstevel@tonic-gate frag_header |= MIR_LASTFRAG; 26430Sstevel@tonic-gate 26440Sstevel@tonic-gate /* Stick in the 4 byte record marking header. */ 26450Sstevel@tonic-gate if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) || 26460Sstevel@tonic-gate !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) { 26470Sstevel@tonic-gate /* 26480Sstevel@tonic-gate * Since we know that M_DATA messages are created exclusively 26490Sstevel@tonic-gate * by KRPC, we expect that KRPC will leave room for our header 26500Sstevel@tonic-gate * and 4 byte align which is normal for XDR. 26510Sstevel@tonic-gate * If KRPC (or someone else) does not cooperate, then we 26520Sstevel@tonic-gate * just throw away the message. 26530Sstevel@tonic-gate */ 26540Sstevel@tonic-gate RPCLOG(1, "mir_wput: KRPC did not leave space for record " 26550Sstevel@tonic-gate "fragment header (%d bytes left)\n", 26560Sstevel@tonic-gate (int)(rptr - mp->b_datap->db_base)); 26570Sstevel@tonic-gate freemsg(mp); 26580Sstevel@tonic-gate return; 26590Sstevel@tonic-gate } 26600Sstevel@tonic-gate rptr -= sizeof (uint32_t); 26610Sstevel@tonic-gate *(uint32_t *)rptr = htonl(frag_header); 26620Sstevel@tonic-gate mp->b_rptr = rptr; 26630Sstevel@tonic-gate 26640Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 26650Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) { 26660Sstevel@tonic-gate /* 26670Sstevel@tonic-gate * For the client, set mir_clntreq to indicate that the 26680Sstevel@tonic-gate * connection is active. 26690Sstevel@tonic-gate */ 26700Sstevel@tonic-gate mir->mir_clntreq = 1; 26710Sstevel@tonic-gate mir->mir_use_timestamp = lbolt; 26720Sstevel@tonic-gate } 26730Sstevel@tonic-gate 26740Sstevel@tonic-gate /* 26750Sstevel@tonic-gate * If we haven't already queued some data and the downstream module 26760Sstevel@tonic-gate * can accept more data, send it on, otherwise we queue the message 26770Sstevel@tonic-gate * and take other actions depending on mir_type. 26780Sstevel@tonic-gate */ 26790Sstevel@tonic-gate if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) { 26800Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 26810Sstevel@tonic-gate 26820Sstevel@tonic-gate /* 26830Sstevel@tonic-gate * Now we pass the RPC message downstream. 26840Sstevel@tonic-gate */ 26850Sstevel@tonic-gate putnext(q, mp); 26860Sstevel@tonic-gate return; 26870Sstevel@tonic-gate } 26880Sstevel@tonic-gate 26890Sstevel@tonic-gate switch (mir->mir_type) { 26900Sstevel@tonic-gate case RPC_CLIENT: 26910Sstevel@tonic-gate /* 26920Sstevel@tonic-gate * Check for a previous duplicate request on the 26930Sstevel@tonic-gate * queue. If there is one, then we throw away 26940Sstevel@tonic-gate * the current message and let the previous one 26950Sstevel@tonic-gate * go through. If we can't find a duplicate, then 26960Sstevel@tonic-gate * send this one. This tap dance is an effort 26970Sstevel@tonic-gate * to reduce traffic and processing requirements 26980Sstevel@tonic-gate * under load conditions. 26990Sstevel@tonic-gate */ 27000Sstevel@tonic-gate if (mir_clnt_dup_request(q, mp)) { 27010Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 27020Sstevel@tonic-gate freemsg(mp); 27030Sstevel@tonic-gate return; 27040Sstevel@tonic-gate } 27050Sstevel@tonic-gate break; 27060Sstevel@tonic-gate case RPC_SERVER: 27070Sstevel@tonic-gate /* 27080Sstevel@tonic-gate * Set mir_hold_inbound so that new inbound RPC 27090Sstevel@tonic-gate * messages will be held until the client catches 27100Sstevel@tonic-gate * up on the earlier replies. This flag is cleared 27110Sstevel@tonic-gate * in mir_wsrv after flow control is relieved; 27120Sstevel@tonic-gate * the read-side queue is also enabled at that time. 27130Sstevel@tonic-gate */ 27140Sstevel@tonic-gate mir->mir_hold_inbound = 1; 27150Sstevel@tonic-gate break; 27160Sstevel@tonic-gate default: 27170Sstevel@tonic-gate RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type); 27180Sstevel@tonic-gate break; 27190Sstevel@tonic-gate } 27200Sstevel@tonic-gate mir->mir_inwservice = 1; 27210Sstevel@tonic-gate (void) putq(q, mp); 27220Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 27230Sstevel@tonic-gate } 27240Sstevel@tonic-gate 27250Sstevel@tonic-gate static void 27260Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp) 27270Sstevel@tonic-gate { 27280Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 27290Sstevel@tonic-gate struct iocblk *iocp; 27300Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 27310Sstevel@tonic-gate bool_t flush_in_svc = FALSE; 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 27340Sstevel@tonic-gate switch (mp->b_datap->db_type) { 27350Sstevel@tonic-gate case M_IOCTL: 27360Sstevel@tonic-gate iocp = (struct iocblk *)rptr; 27370Sstevel@tonic-gate switch (iocp->ioc_cmd) { 27380Sstevel@tonic-gate case RPC_CLIENT: 27390Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 27400Sstevel@tonic-gate if (mir->mir_type != 0 && 27410Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) { 27420Sstevel@tonic-gate ioc_eperm: 27430Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 27440Sstevel@tonic-gate iocp->ioc_error = EPERM; 27450Sstevel@tonic-gate iocp->ioc_count = 0; 27460Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 27470Sstevel@tonic-gate qreply(q, mp); 27480Sstevel@tonic-gate return; 27490Sstevel@tonic-gate } 27500Sstevel@tonic-gate 27510Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd; 27520Sstevel@tonic-gate 27530Sstevel@tonic-gate /* 27540Sstevel@tonic-gate * Clear mir_hold_inbound which was set to 1 by 27550Sstevel@tonic-gate * mir_open. This flag is not used on client 27560Sstevel@tonic-gate * streams. 27570Sstevel@tonic-gate */ 27580Sstevel@tonic-gate mir->mir_hold_inbound = 0; 27590Sstevel@tonic-gate mir->mir_max_msg_sizep = &clnt_max_msg_size; 27600Sstevel@tonic-gate 27610Sstevel@tonic-gate /* 27620Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more 27630Sstevel@tonic-gate * information on how client timers work. 27640Sstevel@tonic-gate */ 27650Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 27660Sstevel@tonic-gate mir_clnt_idle_start(q, mir); 27670Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 27680Sstevel@tonic-gate 27690Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 27700Sstevel@tonic-gate qreply(q, mp); 27710Sstevel@tonic-gate return; 27720Sstevel@tonic-gate case RPC_SERVER: 27730Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 27740Sstevel@tonic-gate if (mir->mir_type != 0 && 27750Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) 27760Sstevel@tonic-gate goto ioc_eperm; 27770Sstevel@tonic-gate 27780Sstevel@tonic-gate /* 27790Sstevel@tonic-gate * We don't clear mir_hold_inbound here because 27800Sstevel@tonic-gate * mir_hold_inbound is used in the flow control 27810Sstevel@tonic-gate * model. If we cleared it here, then we'd commit 27820Sstevel@tonic-gate * a small violation to the model where the transport 27830Sstevel@tonic-gate * might immediately block downstream flow. 27840Sstevel@tonic-gate */ 27850Sstevel@tonic-gate 27860Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd; 27870Sstevel@tonic-gate mir->mir_max_msg_sizep = &svc_max_msg_size; 27880Sstevel@tonic-gate 27890Sstevel@tonic-gate /* 27900Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more 27910Sstevel@tonic-gate * information on how server timers work. 27920Sstevel@tonic-gate * 27930Sstevel@tonic-gate * Note that it is important to start the idle timer 27940Sstevel@tonic-gate * here so that connections time out even if we 27950Sstevel@tonic-gate * never receive any data on them. 27960Sstevel@tonic-gate */ 27970Sstevel@tonic-gate mir->mir_idle_timeout = svc_idle_timeout; 27980Sstevel@tonic-gate RPCLOG(16, "mir_wput_other starting idle timer on 0x%p " 27990Sstevel@tonic-gate "because we got RPC_SERVER ioctl\n", (void *)q); 28000Sstevel@tonic-gate mir_svc_idle_start(q, mir); 28010Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 28020Sstevel@tonic-gate 28030Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 28040Sstevel@tonic-gate qreply(q, mp); 28050Sstevel@tonic-gate return; 28060Sstevel@tonic-gate default: 28070Sstevel@tonic-gate break; 28080Sstevel@tonic-gate } 28090Sstevel@tonic-gate break; 28100Sstevel@tonic-gate 28110Sstevel@tonic-gate case M_PROTO: 28120Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) { 28130Sstevel@tonic-gate /* 28140Sstevel@tonic-gate * We are likely being called from the context of a 28150Sstevel@tonic-gate * service procedure. So we need to enqueue. However 28160Sstevel@tonic-gate * enqueing may put our message behind data messages. 28170Sstevel@tonic-gate * So flush the data first. 28180Sstevel@tonic-gate */ 28190Sstevel@tonic-gate flush_in_svc = TRUE; 28200Sstevel@tonic-gate } 28210Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (uint32_t) || 28220Sstevel@tonic-gate !IS_P2ALIGNED(rptr, sizeof (uint32_t))) 28230Sstevel@tonic-gate break; 28240Sstevel@tonic-gate 28250Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 28260Sstevel@tonic-gate case T_DATA_REQ: 28270Sstevel@tonic-gate /* Don't pass T_DATA_REQ messages downstream. */ 28280Sstevel@tonic-gate freemsg(mp); 28290Sstevel@tonic-gate return; 28300Sstevel@tonic-gate case T_ORDREL_REQ: 28310Sstevel@tonic-gate RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n", 28320Sstevel@tonic-gate (void *)q); 28330Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 28340Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) { 28350Sstevel@tonic-gate /* 28360Sstevel@tonic-gate * We are likely being called from 28370Sstevel@tonic-gate * clnt_dispatch_notifyall(). Sending 28380Sstevel@tonic-gate * a T_ORDREL_REQ will result in 28390Sstevel@tonic-gate * a some kind of _IND message being sent, 28400Sstevel@tonic-gate * will be another call to 28410Sstevel@tonic-gate * clnt_dispatch_notifyall(). To keep the stack 28420Sstevel@tonic-gate * lean, queue this message. 28430Sstevel@tonic-gate */ 28440Sstevel@tonic-gate mir->mir_inwservice = 1; 28450Sstevel@tonic-gate (void) putq(q, mp); 28460Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 28470Sstevel@tonic-gate return; 28480Sstevel@tonic-gate } 28490Sstevel@tonic-gate 28500Sstevel@tonic-gate /* 28510Sstevel@tonic-gate * Mark the structure such that we don't accept any 28520Sstevel@tonic-gate * more requests from client. We could defer this 28530Sstevel@tonic-gate * until we actually send the orderly release 28540Sstevel@tonic-gate * request downstream, but all that does is delay 28550Sstevel@tonic-gate * the closing of this stream. 28560Sstevel@tonic-gate */ 28570Sstevel@tonic-gate RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ " 28580Sstevel@tonic-gate " so calling mir_svc_start_close\n", (void *)q); 28590Sstevel@tonic-gate 28600Sstevel@tonic-gate mir_svc_start_close(q, mir); 28610Sstevel@tonic-gate 28620Sstevel@tonic-gate /* 28630Sstevel@tonic-gate * If we have sent down a T_ORDREL_REQ, don't send 28640Sstevel@tonic-gate * any more. 28650Sstevel@tonic-gate */ 28660Sstevel@tonic-gate if (mir->mir_ordrel_pending) { 28670Sstevel@tonic-gate freemsg(mp); 28680Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 28690Sstevel@tonic-gate return; 28700Sstevel@tonic-gate } 28710Sstevel@tonic-gate 28720Sstevel@tonic-gate /* 28730Sstevel@tonic-gate * If the stream is not idle, then we hold the 28740Sstevel@tonic-gate * orderly release until it becomes idle. This 28750Sstevel@tonic-gate * ensures that KRPC will be able to reply to 28760Sstevel@tonic-gate * all requests that we have passed to it. 28770Sstevel@tonic-gate * 28780Sstevel@tonic-gate * We also queue the request if there is data already 28790Sstevel@tonic-gate * queued, because we cannot allow the T_ORDREL_REQ 28800Sstevel@tonic-gate * to go before data. When we had a separate reply 28810Sstevel@tonic-gate * count, this was not a problem, because the 28820Sstevel@tonic-gate * reply count was reconciled when mir_wsrv() 28830Sstevel@tonic-gate * completed. 28840Sstevel@tonic-gate */ 28850Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir) || 28860Sstevel@tonic-gate mir->mir_inwservice == 1) { 28870Sstevel@tonic-gate mir->mir_inwservice = 1; 28880Sstevel@tonic-gate (void) putq(q, mp); 28890Sstevel@tonic-gate 28900Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: queuing " 28910Sstevel@tonic-gate "T_ORDREL_REQ on 0x%p\n", (void *)q); 28920Sstevel@tonic-gate 28930Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 28940Sstevel@tonic-gate return; 28950Sstevel@tonic-gate } 28960Sstevel@tonic-gate 28970Sstevel@tonic-gate /* 28980Sstevel@tonic-gate * Mark the structure so that we know we sent 28990Sstevel@tonic-gate * an orderly release request, and reset the idle timer. 29000Sstevel@tonic-gate */ 29010Sstevel@tonic-gate mir->mir_ordrel_pending = 1; 29020Sstevel@tonic-gate 29030Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start" 29040Sstevel@tonic-gate " on 0x%p because we got T_ORDREL_REQ\n", 29050Sstevel@tonic-gate (void *)q); 29060Sstevel@tonic-gate 29070Sstevel@tonic-gate mir_svc_idle_start(q, mir); 29080Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 29090Sstevel@tonic-gate 29100Sstevel@tonic-gate /* 29110Sstevel@tonic-gate * When we break, we will putnext the T_ORDREL_REQ. 29120Sstevel@tonic-gate */ 29130Sstevel@tonic-gate break; 29140Sstevel@tonic-gate 29150Sstevel@tonic-gate case T_CONN_REQ: 29160Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 29170Sstevel@tonic-gate if (mir->mir_head_mp != NULL) { 29180Sstevel@tonic-gate freemsg(mir->mir_head_mp); 29190Sstevel@tonic-gate mir->mir_head_mp = NULL; 29200Sstevel@tonic-gate mir->mir_tail_mp = NULL; 29210Sstevel@tonic-gate } 29220Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t); 29230Sstevel@tonic-gate /* 29240Sstevel@tonic-gate * Restart timer in case mir_clnt_idle_do_stop() was 29250Sstevel@tonic-gate * called. 29260Sstevel@tonic-gate */ 29270Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 29280Sstevel@tonic-gate mir_clnt_idle_stop(q, mir); 29290Sstevel@tonic-gate mir_clnt_idle_start(q, mir); 29300Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 29310Sstevel@tonic-gate break; 29320Sstevel@tonic-gate 29330Sstevel@tonic-gate default: 29340Sstevel@tonic-gate /* 29350Sstevel@tonic-gate * T_DISCON_REQ is one of the interesting default 29360Sstevel@tonic-gate * cases here. Ideally, an M_FLUSH is done before 29370Sstevel@tonic-gate * T_DISCON_REQ is done. However, that is somewhat 29380Sstevel@tonic-gate * cumbersome for clnt_cots.c to do. So we queue 29390Sstevel@tonic-gate * T_DISCON_REQ, and let the service procedure 29400Sstevel@tonic-gate * flush all M_DATA. 29410Sstevel@tonic-gate */ 29420Sstevel@tonic-gate break; 29430Sstevel@tonic-gate } 29440Sstevel@tonic-gate /* fallthru */; 29450Sstevel@tonic-gate default: 29460Sstevel@tonic-gate if (mp->b_datap->db_type >= QPCTL) { 29470Sstevel@tonic-gate if (mp->b_datap->db_type == M_FLUSH) { 29480Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT && 29490Sstevel@tonic-gate *mp->b_rptr & FLUSHW) { 29500Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: flushing " 29510Sstevel@tonic-gate "wq 0x%p\n", (void *)q); 29520Sstevel@tonic-gate if (*mp->b_rptr & FLUSHBAND) { 29530Sstevel@tonic-gate flushband(q, *(mp->b_rptr + 1), 29540Sstevel@tonic-gate FLUSHDATA); 29550Sstevel@tonic-gate } else { 29560Sstevel@tonic-gate flushq(q, FLUSHDATA); 29570Sstevel@tonic-gate } 29580Sstevel@tonic-gate } else { 29590Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: ignoring " 29600Sstevel@tonic-gate "M_FLUSH on wq 0x%p\n", (void *)q); 29610Sstevel@tonic-gate } 29620Sstevel@tonic-gate } 29630Sstevel@tonic-gate break; 29640Sstevel@tonic-gate } 29650Sstevel@tonic-gate 29660Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 29670Sstevel@tonic-gate if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) { 29680Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 29690Sstevel@tonic-gate break; 29700Sstevel@tonic-gate } 29710Sstevel@tonic-gate mir->mir_inwservice = 1; 29720Sstevel@tonic-gate mir->mir_inwflushdata = flush_in_svc; 29730Sstevel@tonic-gate (void) putq(q, mp); 29740Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 29750Sstevel@tonic-gate qenable(q); 29760Sstevel@tonic-gate 29770Sstevel@tonic-gate return; 29780Sstevel@tonic-gate } 29790Sstevel@tonic-gate putnext(q, mp); 29800Sstevel@tonic-gate } 29810Sstevel@tonic-gate 29820Sstevel@tonic-gate static void 29830Sstevel@tonic-gate mir_wsrv(queue_t *q) 29840Sstevel@tonic-gate { 29850Sstevel@tonic-gate mblk_t *mp; 29860Sstevel@tonic-gate mir_t *mir; 29870Sstevel@tonic-gate bool_t flushdata; 29880Sstevel@tonic-gate 29890Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 29900Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate flushdata = mir->mir_inwflushdata; 29930Sstevel@tonic-gate mir->mir_inwflushdata = 0; 29940Sstevel@tonic-gate 29950Sstevel@tonic-gate while (mp = getq(q)) { 29960Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 29970Sstevel@tonic-gate /* 29980Sstevel@tonic-gate * Do not send any more data if we have sent 29990Sstevel@tonic-gate * a T_ORDREL_REQ. 30000Sstevel@tonic-gate */ 30010Sstevel@tonic-gate if (flushdata || mir->mir_ordrel_pending == 1) { 30020Sstevel@tonic-gate freemsg(mp); 30030Sstevel@tonic-gate continue; 30040Sstevel@tonic-gate } 30050Sstevel@tonic-gate 30060Sstevel@tonic-gate /* 30070Sstevel@tonic-gate * Make sure that the stream can really handle more 30080Sstevel@tonic-gate * data. 30090Sstevel@tonic-gate */ 30100Sstevel@tonic-gate if (!MIR_WCANPUTNEXT(mir, q)) { 30110Sstevel@tonic-gate (void) putbq(q, mp); 30120Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 30130Sstevel@tonic-gate return; 30140Sstevel@tonic-gate } 30150Sstevel@tonic-gate 30160Sstevel@tonic-gate /* 30170Sstevel@tonic-gate * Now we pass the RPC message downstream. 30180Sstevel@tonic-gate */ 30190Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 30200Sstevel@tonic-gate putnext(q, mp); 30210Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 30220Sstevel@tonic-gate continue; 30230Sstevel@tonic-gate } 30240Sstevel@tonic-gate 30250Sstevel@tonic-gate /* 30260Sstevel@tonic-gate * This is not an RPC message, pass it downstream 30270Sstevel@tonic-gate * (ignoring flow control) if the server side is not sending a 30280Sstevel@tonic-gate * T_ORDREL_REQ downstream. 30290Sstevel@tonic-gate */ 30300Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || 30310Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type != 30320Sstevel@tonic-gate T_ORDREL_REQ) { 30330Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 30340Sstevel@tonic-gate putnext(q, mp); 30350Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 30360Sstevel@tonic-gate continue; 30370Sstevel@tonic-gate } 30380Sstevel@tonic-gate 30390Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) { 30400Sstevel@tonic-gate /* 30410Sstevel@tonic-gate * Don't send two T_ORDRELs 30420Sstevel@tonic-gate */ 30430Sstevel@tonic-gate freemsg(mp); 30440Sstevel@tonic-gate continue; 30450Sstevel@tonic-gate } 30460Sstevel@tonic-gate 30470Sstevel@tonic-gate /* 30480Sstevel@tonic-gate * Mark the structure so that we know we sent an orderly 30490Sstevel@tonic-gate * release request. We will check to see slot is idle at the 30500Sstevel@tonic-gate * end of this routine, and if so, reset the idle timer to 30510Sstevel@tonic-gate * handle orderly release timeouts. 30520Sstevel@tonic-gate */ 30530Sstevel@tonic-gate mir->mir_ordrel_pending = 1; 30540Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n", 30550Sstevel@tonic-gate (void *)q); 30560Sstevel@tonic-gate /* 30570Sstevel@tonic-gate * Send the orderly release downstream. If there are other 30580Sstevel@tonic-gate * pending replies we won't be able to send them. However, 30590Sstevel@tonic-gate * the only reason we should send the orderly release is if 30600Sstevel@tonic-gate * we were idle, or if an unusual event occurred. 30610Sstevel@tonic-gate */ 30620Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 30630Sstevel@tonic-gate putnext(q, mp); 30640Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 30650Sstevel@tonic-gate } 30660Sstevel@tonic-gate 30670Sstevel@tonic-gate if (q->q_first == NULL) 30680Sstevel@tonic-gate /* 30690Sstevel@tonic-gate * If we call mir_svc_idle_start() below, then 30700Sstevel@tonic-gate * clearing mir_inwservice here will also result in 30710Sstevel@tonic-gate * any thread waiting in mir_close() to be signaled. 30720Sstevel@tonic-gate */ 30730Sstevel@tonic-gate mir->mir_inwservice = 0; 30740Sstevel@tonic-gate 30750Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) { 30760Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 30770Sstevel@tonic-gate return; 30780Sstevel@tonic-gate } 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate /* 30810Sstevel@tonic-gate * If idle we call mir_svc_idle_start to start the timer (or wakeup 30820Sstevel@tonic-gate * a close). Also make sure not to start the idle timer on the 30830Sstevel@tonic-gate * listener stream. This can cause nfsd to send an orderly release 30840Sstevel@tonic-gate * command on the listener stream. 30850Sstevel@tonic-gate */ 30860Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) { 30870Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p " 30880Sstevel@tonic-gate "because mir slot is idle\n", (void *)q); 30890Sstevel@tonic-gate mir_svc_idle_start(q, mir); 30900Sstevel@tonic-gate } 30910Sstevel@tonic-gate 30920Sstevel@tonic-gate /* 30930Sstevel@tonic-gate * If outbound flow control has been relieved, then allow new 30940Sstevel@tonic-gate * inbound requests to be processed. 30950Sstevel@tonic-gate */ 30960Sstevel@tonic-gate if (mir->mir_hold_inbound) { 30970Sstevel@tonic-gate mir->mir_hold_inbound = 0; 30980Sstevel@tonic-gate qenable(RD(q)); 30990Sstevel@tonic-gate } 31000Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 31010Sstevel@tonic-gate } 31020Sstevel@tonic-gate 31030Sstevel@tonic-gate static void 31040Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir) 31050Sstevel@tonic-gate { 31060Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 31070Sstevel@tonic-gate 31080Sstevel@tonic-gate switch (mir->mir_type) { 31090Sstevel@tonic-gate case RPC_CLIENT: 31100Sstevel@tonic-gate /* 31110Sstevel@tonic-gate * We are disconnecting, but not necessarily 31120Sstevel@tonic-gate * closing. By not closing, we will fail to 31130Sstevel@tonic-gate * pick up a possibly changed global timeout value, 31140Sstevel@tonic-gate * unless we store it now. 31150Sstevel@tonic-gate */ 31160Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 31170Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir); 31180Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 31190Sstevel@tonic-gate 31200Sstevel@tonic-gate /* 31210Sstevel@tonic-gate * T_DISCON_REQ is passed to KRPC as an integer value 31220Sstevel@tonic-gate * (this is not a TPI message). It is used as a 31230Sstevel@tonic-gate * convenient value to indicate a sanity check 31240Sstevel@tonic-gate * failure -- the same KRPC routine is also called 31250Sstevel@tonic-gate * for T_DISCON_INDs and T_ORDREL_INDs. 31260Sstevel@tonic-gate */ 31270Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0); 31280Sstevel@tonic-gate break; 31290Sstevel@tonic-gate 31300Sstevel@tonic-gate case RPC_SERVER: 31310Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1; 31320Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 31330Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 31340Sstevel@tonic-gate RPCLOG(16, "mir_disconnect: telling " 31350Sstevel@tonic-gate "stream head listener to disconnect stream " 31360Sstevel@tonic-gate "(0x%p)\n", (void *) q); 31370Sstevel@tonic-gate (void) mir_svc_policy_notify(q, 2); 31380Sstevel@tonic-gate break; 31390Sstevel@tonic-gate 31400Sstevel@tonic-gate default: 31410Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 31420Sstevel@tonic-gate break; 31430Sstevel@tonic-gate } 31440Sstevel@tonic-gate } 31450Sstevel@tonic-gate 31460Sstevel@tonic-gate /* 31470Sstevel@tonic-gate * do a sanity check on the length of the fragment. 31480Sstevel@tonic-gate * returns 1 if bad else 0. 31490Sstevel@tonic-gate */ 31500Sstevel@tonic-gate static int 31510Sstevel@tonic-gate mir_check_len(queue_t *q, int32_t frag_len, 31520Sstevel@tonic-gate mblk_t *head_mp) 31530Sstevel@tonic-gate { 31540Sstevel@tonic-gate mir_t *mir; 31550Sstevel@tonic-gate 31560Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 31570Sstevel@tonic-gate 31580Sstevel@tonic-gate /* 31590Sstevel@tonic-gate * Do a sanity check on the message length. If this message is 31600Sstevel@tonic-gate * getting excessively large, shut down the connection. 31610Sstevel@tonic-gate */ 31620Sstevel@tonic-gate 31630Sstevel@tonic-gate if ((frag_len <= 0) || (mir->mir_max_msg_sizep == NULL) || 31640Sstevel@tonic-gate (frag_len <= *mir->mir_max_msg_sizep)) { 31650Sstevel@tonic-gate return (0); 31660Sstevel@tonic-gate } 31670Sstevel@tonic-gate 31680Sstevel@tonic-gate freemsg(head_mp); 31690Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 31700Sstevel@tonic-gate mir->mir_frag_len = -(int)sizeof (uint32_t); 31710Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) { 31720Sstevel@tonic-gate cmn_err(CE_NOTE, 31730Sstevel@tonic-gate "KRPC: record fragment from %s of size(%d) exceeds " 31740Sstevel@tonic-gate "maximum (%u). Disconnecting", 31750Sstevel@tonic-gate (mir->mir_type == RPC_CLIENT) ? "server" : 31760Sstevel@tonic-gate (mir->mir_type == RPC_SERVER) ? "client" : 31770Sstevel@tonic-gate "test tool", 31780Sstevel@tonic-gate frag_len, *mir->mir_max_msg_sizep); 31790Sstevel@tonic-gate } 31800Sstevel@tonic-gate 31810Sstevel@tonic-gate mir_disconnect(q, mir); 31820Sstevel@tonic-gate return (1); 31830Sstevel@tonic-gate } 3184