1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate /* 35*7c478bd9Sstevel@tonic-gate * Kernel RPC filtering module 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/timod.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/pcb.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/inline.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/callb.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 64*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_com.h> 65*7c478bd9Sstevel@tonic-gate #include <inet/common.h> 66*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 67*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 68*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 69*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 70*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 71*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 72*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 73*7c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 74*7c478bd9Sstevel@tonic-gate #include <rpc/rpcsys.h> 75*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_rdma.h> 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 81*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 82*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate extern struct streamtab rpcinfo; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate static struct fmodsw fsw = { 87*7c478bd9Sstevel@tonic-gate "rpcmod", 88*7c478bd9Sstevel@tonic-gate &rpcinfo, 89*7c478bd9Sstevel@tonic-gate D_NEW|D_MP, 90*7c478bd9Sstevel@tonic-gate }; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = { 97*7c478bd9Sstevel@tonic-gate &mod_strmodops, "rpc interface str mod", &fsw 98*7c478bd9Sstevel@tonic-gate }; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* 101*7c478bd9Sstevel@tonic-gate * For the RPC system call. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate static struct sysent rpcsysent = { 104*7c478bd9Sstevel@tonic-gate 2, 105*7c478bd9Sstevel@tonic-gate SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD, 106*7c478bd9Sstevel@tonic-gate rpcsys 107*7c478bd9Sstevel@tonic-gate }; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys = { 110*7c478bd9Sstevel@tonic-gate &mod_syscallops, 111*7c478bd9Sstevel@tonic-gate "RPC syscall", 112*7c478bd9Sstevel@tonic-gate &rpcsysent 113*7c478bd9Sstevel@tonic-gate }; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 116*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = { 117*7c478bd9Sstevel@tonic-gate &mod_syscallops32, 118*7c478bd9Sstevel@tonic-gate "32-bit RPC syscall", 119*7c478bd9Sstevel@tonic-gate &rpcsysent 120*7c478bd9Sstevel@tonic-gate }; 121*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 124*7c478bd9Sstevel@tonic-gate MODREV_1, 125*7c478bd9Sstevel@tonic-gate { 126*7c478bd9Sstevel@tonic-gate &modlsys, 127*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 128*7c478bd9Sstevel@tonic-gate &modlsys32, 129*7c478bd9Sstevel@tonic-gate #endif 130*7c478bd9Sstevel@tonic-gate &modlstrmod, 131*7c478bd9Sstevel@tonic-gate NULL 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate }; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate int 136*7c478bd9Sstevel@tonic-gate _init(void) 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate int error = 0; 139*7c478bd9Sstevel@tonic-gate callb_id_t cid; 140*7c478bd9Sstevel@tonic-gate int status; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate svc_init(); 143*7c478bd9Sstevel@tonic-gate clnt_init(); 144*7c478bd9Sstevel@tonic-gate cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc"); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate if (error = mod_install(&modlinkage)) { 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * Could not install module, cleanup previous 149*7c478bd9Sstevel@tonic-gate * initialization work. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate clnt_fini(); 152*7c478bd9Sstevel@tonic-gate if (cid != NULL) 153*7c478bd9Sstevel@tonic-gate (void) callb_delete(cid); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate return (error); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate * Load up the RDMA plugins and initialize the stats. Even if the 160*7c478bd9Sstevel@tonic-gate * plugins loadup fails, but rpcmod was successfully installed the 161*7c478bd9Sstevel@tonic-gate * counters still get initialized. 162*7c478bd9Sstevel@tonic-gate */ 163*7c478bd9Sstevel@tonic-gate rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL); 164*7c478bd9Sstevel@tonic-gate mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL); 165*7c478bd9Sstevel@tonic-gate mt_kstat_init(); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate /* 168*7c478bd9Sstevel@tonic-gate * Get our identification into ldi. This is used for loading 169*7c478bd9Sstevel@tonic-gate * other modules, e.g. rpcib. 170*7c478bd9Sstevel@tonic-gate */ 171*7c478bd9Sstevel@tonic-gate status = ldi_ident_from_mod(&modlinkage, &rpcmod_li); 172*7c478bd9Sstevel@tonic-gate if (status != 0) { 173*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status); 174*7c478bd9Sstevel@tonic-gate rpcmod_li = NULL; 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate return (error); 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * The unload entry point fails, because we advertise entry points into 182*7c478bd9Sstevel@tonic-gate * rpcmod from the rest of kRPC: rpcmod_release(). 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate int 185*7c478bd9Sstevel@tonic-gate _fini(void) 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate return (EBUSY); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate int 191*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate extern int nulldev(); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate #define RPCMOD_ID 2049 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate int rmm_open(), rmm_close(); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value 204*7c478bd9Sstevel@tonic-gate * from these functions, they are defined as void here. Kind of icky, but... 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *); 207*7c478bd9Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *); 208*7c478bd9Sstevel@tonic-gate void rmm_rsrv(queue_t *); 209*7c478bd9Sstevel@tonic-gate void rmm_wsrv(queue_t *); 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate int rpcmodopen(), rpcmodclose(); 212*7c478bd9Sstevel@tonic-gate void rpcmodrput(), rpcmodwput(); 213*7c478bd9Sstevel@tonic-gate void rpcmodrsrv(), rpcmodwsrv(); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate static void rpcmodwput_other(queue_t *, mblk_t *); 216*7c478bd9Sstevel@tonic-gate static int mir_close(queue_t *q); 217*7c478bd9Sstevel@tonic-gate static int mir_open(queue_t *q, dev_t *devp, int flag, int sflag, 218*7c478bd9Sstevel@tonic-gate cred_t *credp); 219*7c478bd9Sstevel@tonic-gate static void mir_rput(queue_t *q, mblk_t *mp); 220*7c478bd9Sstevel@tonic-gate static void mir_rsrv(queue_t *q); 221*7c478bd9Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp); 222*7c478bd9Sstevel@tonic-gate static void mir_wsrv(queue_t *q); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate static struct module_info rpcmod_info = 225*7c478bd9Sstevel@tonic-gate {RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024}; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate /* 228*7c478bd9Sstevel@tonic-gate * Read side has no service procedure. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate static struct qinit rpcmodrinit = { 231*7c478bd9Sstevel@tonic-gate (int (*)())rmm_rput, 232*7c478bd9Sstevel@tonic-gate (int (*)())rmm_rsrv, 233*7c478bd9Sstevel@tonic-gate rmm_open, 234*7c478bd9Sstevel@tonic-gate rmm_close, 235*7c478bd9Sstevel@tonic-gate nulldev, 236*7c478bd9Sstevel@tonic-gate &rpcmod_info, 237*7c478bd9Sstevel@tonic-gate NULL 238*7c478bd9Sstevel@tonic-gate }; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate /* 241*7c478bd9Sstevel@tonic-gate * The write put procedure is simply putnext to conserve stack space. 242*7c478bd9Sstevel@tonic-gate * The write service procedure is not used to queue data, but instead to 243*7c478bd9Sstevel@tonic-gate * synchronize with flow control. 244*7c478bd9Sstevel@tonic-gate */ 245*7c478bd9Sstevel@tonic-gate static struct qinit rpcmodwinit = { 246*7c478bd9Sstevel@tonic-gate (int (*)())rmm_wput, 247*7c478bd9Sstevel@tonic-gate (int (*)())rmm_wsrv, 248*7c478bd9Sstevel@tonic-gate rmm_open, 249*7c478bd9Sstevel@tonic-gate rmm_close, 250*7c478bd9Sstevel@tonic-gate nulldev, 251*7c478bd9Sstevel@tonic-gate &rpcmod_info, 252*7c478bd9Sstevel@tonic-gate NULL 253*7c478bd9Sstevel@tonic-gate }; 254*7c478bd9Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL }; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate struct xprt_style_ops { 257*7c478bd9Sstevel@tonic-gate int (*xo_open)(); 258*7c478bd9Sstevel@tonic-gate int (*xo_close)(); 259*7c478bd9Sstevel@tonic-gate void (*xo_wput)(); 260*7c478bd9Sstevel@tonic-gate void (*xo_wsrv)(); 261*7c478bd9Sstevel@tonic-gate void (*xo_rput)(); 262*7c478bd9Sstevel@tonic-gate void (*xo_rsrv)(); 263*7c478bd9Sstevel@tonic-gate }; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = { 266*7c478bd9Sstevel@tonic-gate rpcmodopen, 267*7c478bd9Sstevel@tonic-gate rpcmodclose, 268*7c478bd9Sstevel@tonic-gate rpcmodwput, 269*7c478bd9Sstevel@tonic-gate rpcmodwsrv, 270*7c478bd9Sstevel@tonic-gate rpcmodrput, 271*7c478bd9Sstevel@tonic-gate NULL 272*7c478bd9Sstevel@tonic-gate }; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = { 275*7c478bd9Sstevel@tonic-gate mir_open, 276*7c478bd9Sstevel@tonic-gate mir_close, 277*7c478bd9Sstevel@tonic-gate mir_wput, 278*7c478bd9Sstevel@tonic-gate mir_wsrv, 279*7c478bd9Sstevel@tonic-gate mir_rput, 280*7c478bd9Sstevel@tonic-gate mir_rsrv 281*7c478bd9Sstevel@tonic-gate }; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate /* 284*7c478bd9Sstevel@tonic-gate * Per rpcmod "slot" data structure. q->q_ptr points to one of these. 285*7c478bd9Sstevel@tonic-gate */ 286*7c478bd9Sstevel@tonic-gate struct rpcm { 287*7c478bd9Sstevel@tonic-gate void *rm_krpc_cell; /* Reserved for use by KRPC */ 288*7c478bd9Sstevel@tonic-gate struct xprt_style_ops *rm_ops; 289*7c478bd9Sstevel@tonic-gate int rm_type; /* Client or server side stream */ 290*7c478bd9Sstevel@tonic-gate #define RM_CLOSING 0x1 /* somebody is trying to close slot */ 291*7c478bd9Sstevel@tonic-gate uint_t rm_state; /* state of the slot. see above */ 292*7c478bd9Sstevel@tonic-gate uint_t rm_ref; /* cnt of external references to slot */ 293*7c478bd9Sstevel@tonic-gate kmutex_t rm_lock; /* mutex protecting above fields */ 294*7c478bd9Sstevel@tonic-gate kcondvar_t rm_cwait; /* condition for closing */ 295*7c478bd9Sstevel@tonic-gate zoneid_t rm_zoneid; /* zone which pushed rpcmod */ 296*7c478bd9Sstevel@tonic-gate }; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate struct temp_slot { 299*7c478bd9Sstevel@tonic-gate void *cell; 300*7c478bd9Sstevel@tonic-gate struct xprt_style_ops *ops; 301*7c478bd9Sstevel@tonic-gate int type; 302*7c478bd9Sstevel@tonic-gate mblk_t *info_ack; 303*7c478bd9Sstevel@tonic-gate kmutex_t lock; 304*7c478bd9Sstevel@tonic-gate kcondvar_t wait; 305*7c478bd9Sstevel@tonic-gate }; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp); 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate struct xprt_style_ops tmpops = { 310*7c478bd9Sstevel@tonic-gate NULL, 311*7c478bd9Sstevel@tonic-gate NULL, 312*7c478bd9Sstevel@tonic-gate putnext, 313*7c478bd9Sstevel@tonic-gate NULL, 314*7c478bd9Sstevel@tonic-gate tmp_rput, 315*7c478bd9Sstevel@tonic-gate NULL 316*7c478bd9Sstevel@tonic-gate }; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate void 319*7c478bd9Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp) 320*7c478bd9Sstevel@tonic-gate { 321*7c478bd9Sstevel@tonic-gate struct temp_slot *t = (struct temp_slot *)(q->q_ptr); 322*7c478bd9Sstevel@tonic-gate struct T_info_ack *pptr; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 325*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 326*7c478bd9Sstevel@tonic-gate pptr = (struct T_info_ack *)mp->b_rptr; 327*7c478bd9Sstevel@tonic-gate switch (pptr->PRIM_type) { 328*7c478bd9Sstevel@tonic-gate case T_INFO_ACK: 329*7c478bd9Sstevel@tonic-gate mutex_enter(&t->lock); 330*7c478bd9Sstevel@tonic-gate t->info_ack = mp; 331*7c478bd9Sstevel@tonic-gate cv_signal(&t->wait); 332*7c478bd9Sstevel@tonic-gate mutex_exit(&t->lock); 333*7c478bd9Sstevel@tonic-gate return; 334*7c478bd9Sstevel@tonic-gate default: 335*7c478bd9Sstevel@tonic-gate break; 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate default: 338*7c478bd9Sstevel@tonic-gate break; 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * Not an info-ack, so free it. This is ok because we should 343*7c478bd9Sstevel@tonic-gate * not be receiving data until the open finishes: rpcmod 344*7c478bd9Sstevel@tonic-gate * is pushed well before the end-point is bound to an address. 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate freemsg(mp); 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate int 350*7c478bd9Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 351*7c478bd9Sstevel@tonic-gate { 352*7c478bd9Sstevel@tonic-gate mblk_t *bp; 353*7c478bd9Sstevel@tonic-gate struct temp_slot ts, *t; 354*7c478bd9Sstevel@tonic-gate struct T_info_ack *pptr; 355*7c478bd9Sstevel@tonic-gate int error = 0; 356*7c478bd9Sstevel@tonic-gate int procson = 0; 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 359*7c478bd9Sstevel@tonic-gate /* 360*7c478bd9Sstevel@tonic-gate * Check for re-opens. 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate if (q->q_ptr) { 363*7c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, 364*7c478bd9Sstevel@tonic-gate "rpcmodopen_end:(%s)", "q->qptr"); 365*7c478bd9Sstevel@tonic-gate return (0); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate t = &ts; 369*7c478bd9Sstevel@tonic-gate bzero(t, sizeof (*t)); 370*7c478bd9Sstevel@tonic-gate q->q_ptr = (void *)t; 371*7c478bd9Sstevel@tonic-gate /* WR(q)->q_ptr = (void *)t; */ 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* 374*7c478bd9Sstevel@tonic-gate * Allocate the required messages upfront. 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate if ((bp = allocb(sizeof (struct T_info_req) + 377*7c478bd9Sstevel@tonic-gate sizeof (struct T_info_ack), BPRI_LO)) == (mblk_t *)NULL) { 378*7c478bd9Sstevel@tonic-gate return (ENOBUFS); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL); 382*7c478bd9Sstevel@tonic-gate cv_init(&t->wait, NULL, CV_DEFAULT, NULL); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate t->ops = &tmpops; 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate qprocson(q); 387*7c478bd9Sstevel@tonic-gate procson = 1; 388*7c478bd9Sstevel@tonic-gate bp->b_datap->db_type = M_PCPROTO; 389*7c478bd9Sstevel@tonic-gate *(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ; 390*7c478bd9Sstevel@tonic-gate bp->b_wptr += sizeof (struct T_info_req); 391*7c478bd9Sstevel@tonic-gate putnext(WR(q), bp); 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate mutex_enter(&t->lock); 394*7c478bd9Sstevel@tonic-gate while ((bp = t->info_ack) == NULL) { 395*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&t->wait, &t->lock) == 0) { 396*7c478bd9Sstevel@tonic-gate error = EINTR; 397*7c478bd9Sstevel@tonic-gate break; 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate mutex_exit(&t->lock); 401*7c478bd9Sstevel@tonic-gate mutex_destroy(&t->lock); 402*7c478bd9Sstevel@tonic-gate cv_destroy(&t->wait); 403*7c478bd9Sstevel@tonic-gate if (error) 404*7c478bd9Sstevel@tonic-gate goto out; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate pptr = (struct T_info_ack *)t->info_ack->b_rptr; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if (pptr->SERV_type == T_CLTS) { 409*7c478bd9Sstevel@tonic-gate error = rpcmodopen(q, devp, flag, sflag, crp); 410*7c478bd9Sstevel@tonic-gate if (error == 0) { 411*7c478bd9Sstevel@tonic-gate t = (struct temp_slot *)q->q_ptr; 412*7c478bd9Sstevel@tonic-gate t->ops = &xprt_clts_ops; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate } else { 415*7c478bd9Sstevel@tonic-gate error = mir_open(q, devp, flag, sflag, crp); 416*7c478bd9Sstevel@tonic-gate if (error == 0) { 417*7c478bd9Sstevel@tonic-gate t = (struct temp_slot *)q->q_ptr; 418*7c478bd9Sstevel@tonic-gate t->ops = &xprt_cots_ops; 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate out: 423*7c478bd9Sstevel@tonic-gate freemsg(bp); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate if (error && procson) 426*7c478bd9Sstevel@tonic-gate qprocsoff(q); 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate return (error); 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate void 432*7c478bd9Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t *mp) 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate void 438*7c478bd9Sstevel@tonic-gate rmm_rsrv(queue_t *q) 439*7c478bd9Sstevel@tonic-gate { 440*7c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate void 444*7c478bd9Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp) 445*7c478bd9Sstevel@tonic-gate { 446*7c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp); 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate void 450*7c478bd9Sstevel@tonic-gate rmm_wsrv(queue_t *q) 451*7c478bd9Sstevel@tonic-gate { 452*7c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate int 456*7c478bd9Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp) 457*7c478bd9Sstevel@tonic-gate { 458*7c478bd9Sstevel@tonic-gate return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp)); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* 462*7c478bd9Sstevel@tonic-gate * rpcmodopen - open routine gets called when the module gets pushed 463*7c478bd9Sstevel@tonic-gate * onto the stream. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 466*7c478bd9Sstevel@tonic-gate int 467*7c478bd9Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 468*7c478bd9Sstevel@tonic-gate { 469*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate extern void (*rpc_rele)(queue_t *, mblk_t *); 472*7c478bd9Sstevel@tonic-gate static void rpcmod_release(queue_t *, mblk_t *); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:"); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * Initialize entry points to release a rpcmod slot (and an input 478*7c478bd9Sstevel@tonic-gate * message if supplied) and to send an output message to the module 479*7c478bd9Sstevel@tonic-gate * below rpcmod. 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate if (rpc_rele == NULL) 482*7c478bd9Sstevel@tonic-gate rpc_rele = rpcmod_release; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate * Only sufficiently privileged users can use this module, and it 486*7c478bd9Sstevel@tonic-gate * is assumed that they will use this module properly, and NOT send 487*7c478bd9Sstevel@tonic-gate * bulk data from downstream. 488*7c478bd9Sstevel@tonic-gate */ 489*7c478bd9Sstevel@tonic-gate if (secpolicy_rpcmod_open(crp) != 0) 490*7c478bd9Sstevel@tonic-gate return (EPERM); 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate /* 493*7c478bd9Sstevel@tonic-gate * Allocate slot data structure. 494*7c478bd9Sstevel@tonic-gate */ 495*7c478bd9Sstevel@tonic-gate rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP); 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL); 498*7c478bd9Sstevel@tonic-gate cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL); 499*7c478bd9Sstevel@tonic-gate rmp->rm_zoneid = getzoneid(); 500*7c478bd9Sstevel@tonic-gate /* 501*7c478bd9Sstevel@tonic-gate * slot type will be set by kRPC client and server ioctl's 502*7c478bd9Sstevel@tonic-gate */ 503*7c478bd9Sstevel@tonic-gate rmp->rm_type = 0; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate q->q_ptr = (void *)rmp; 506*7c478bd9Sstevel@tonic-gate WR(q)->q_ptr = (void *)rmp; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end"); 509*7c478bd9Sstevel@tonic-gate return (0); 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * rpcmodclose - This routine gets called when the module gets popped 514*7c478bd9Sstevel@tonic-gate * off of the stream. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 517*7c478bd9Sstevel@tonic-gate int 518*7c478bd9Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp) 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 523*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Mark our state as closing. 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 529*7c478bd9Sstevel@tonic-gate rmp->rm_state |= RM_CLOSING; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * Check and see if there are any messages on the queue. If so, send 533*7c478bd9Sstevel@tonic-gate * the messages, regardless whether the downstream module is ready to 534*7c478bd9Sstevel@tonic-gate * accept data. 535*7c478bd9Sstevel@tonic-gate */ 536*7c478bd9Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER) { 537*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate qenable(WR(q)); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate if (rmp->rm_ref) { 542*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate * call into SVC to clean the queue 545*7c478bd9Sstevel@tonic-gate */ 546*7c478bd9Sstevel@tonic-gate svc_queueclean(q); 547*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * Block while there are kRPC threads with a reference 551*7c478bd9Sstevel@tonic-gate * to this message. 552*7c478bd9Sstevel@tonic-gate */ 553*7c478bd9Sstevel@tonic-gate while (rmp->rm_ref) 554*7c478bd9Sstevel@tonic-gate cv_wait(&rmp->rm_cwait, &rmp->rm_lock); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /* 560*7c478bd9Sstevel@tonic-gate * It is now safe to remove this queue from the stream. No kRPC 561*7c478bd9Sstevel@tonic-gate * threads have a reference to the stream, and none ever will, 562*7c478bd9Sstevel@tonic-gate * because RM_CLOSING is set. 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate qprocsoff(q); 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate /* Notify kRPC that this stream is going away. */ 567*7c478bd9Sstevel@tonic-gate svc_queueclose(q); 568*7c478bd9Sstevel@tonic-gate } else { 569*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 570*7c478bd9Sstevel@tonic-gate qprocsoff(q); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate q->q_ptr = NULL; 574*7c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL; 575*7c478bd9Sstevel@tonic-gate mutex_destroy(&rmp->rm_lock); 576*7c478bd9Sstevel@tonic-gate cv_destroy(&rmp->rm_cwait); 577*7c478bd9Sstevel@tonic-gate kmem_free(rmp, sizeof (*rmp)); 578*7c478bd9Sstevel@tonic-gate return (0); 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 582*7c478bd9Sstevel@tonic-gate int rpcmod_send_msg_up = 0; 583*7c478bd9Sstevel@tonic-gate int rpcmod_send_uderr = 0; 584*7c478bd9Sstevel@tonic-gate int rpcmod_send_dup = 0; 585*7c478bd9Sstevel@tonic-gate int rpcmod_send_dup_cnt = 0; 586*7c478bd9Sstevel@tonic-gate #endif 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * rpcmodrput - Module read put procedure. This is called from 590*7c478bd9Sstevel@tonic-gate * the module, driver, or stream head downstream. 591*7c478bd9Sstevel@tonic-gate */ 592*7c478bd9Sstevel@tonic-gate void 593*7c478bd9Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp) 594*7c478bd9Sstevel@tonic-gate { 595*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 596*7c478bd9Sstevel@tonic-gate union T_primitives *pptr; 597*7c478bd9Sstevel@tonic-gate int hdrsz; 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:"); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 602*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate if (rmp->rm_type == 0) { 605*7c478bd9Sstevel@tonic-gate freemsg(mp); 606*7c478bd9Sstevel@tonic-gate return; 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 610*7c478bd9Sstevel@tonic-gate if (rpcmod_send_msg_up > 0) { 611*7c478bd9Sstevel@tonic-gate mblk_t *nmp = copymsg(mp); 612*7c478bd9Sstevel@tonic-gate if (nmp) { 613*7c478bd9Sstevel@tonic-gate putnext(q, nmp); 614*7c478bd9Sstevel@tonic-gate rpcmod_send_msg_up--; 615*7c478bd9Sstevel@tonic-gate } 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate if ((rpcmod_send_uderr > 0) && mp->b_datap->db_type == M_PROTO) { 618*7c478bd9Sstevel@tonic-gate mblk_t *nmp; 619*7c478bd9Sstevel@tonic-gate struct T_unitdata_ind *data; 620*7c478bd9Sstevel@tonic-gate struct T_uderror_ind *ud; 621*7c478bd9Sstevel@tonic-gate int d; 622*7c478bd9Sstevel@tonic-gate data = (struct T_unitdata_ind *)mp->b_rptr; 623*7c478bd9Sstevel@tonic-gate if (data->PRIM_type == T_UNITDATA_IND) { 624*7c478bd9Sstevel@tonic-gate d = sizeof (*ud) - sizeof (*data); 625*7c478bd9Sstevel@tonic-gate nmp = allocb(mp->b_wptr - mp->b_rptr + d, BPRI_HI); 626*7c478bd9Sstevel@tonic-gate if (nmp) { 627*7c478bd9Sstevel@tonic-gate ud = (struct T_uderror_ind *)nmp->b_rptr; 628*7c478bd9Sstevel@tonic-gate ud->PRIM_type = T_UDERROR_IND; 629*7c478bd9Sstevel@tonic-gate ud->DEST_length = data->SRC_length; 630*7c478bd9Sstevel@tonic-gate ud->DEST_offset = data->SRC_offset + d; 631*7c478bd9Sstevel@tonic-gate ud->OPT_length = data->OPT_length; 632*7c478bd9Sstevel@tonic-gate ud->OPT_offset = data->OPT_offset + d; 633*7c478bd9Sstevel@tonic-gate ud->ERROR_type = ENETDOWN; 634*7c478bd9Sstevel@tonic-gate if (data->SRC_length) { 635*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + 636*7c478bd9Sstevel@tonic-gate data->SRC_offset, 637*7c478bd9Sstevel@tonic-gate nmp->b_rptr + 638*7c478bd9Sstevel@tonic-gate ud->DEST_offset, 639*7c478bd9Sstevel@tonic-gate data->SRC_length); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate if (data->OPT_length) { 642*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + 643*7c478bd9Sstevel@tonic-gate data->OPT_offset, 644*7c478bd9Sstevel@tonic-gate nmp->b_rptr + 645*7c478bd9Sstevel@tonic-gate ud->OPT_offset, 646*7c478bd9Sstevel@tonic-gate data->OPT_length); 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate nmp->b_wptr += d; 649*7c478bd9Sstevel@tonic-gate nmp->b_wptr += (mp->b_wptr - mp->b_rptr); 650*7c478bd9Sstevel@tonic-gate nmp->b_datap->db_type = M_PROTO; 651*7c478bd9Sstevel@tonic-gate putnext(q, nmp); 652*7c478bd9Sstevel@tonic-gate rpcmod_send_uderr--; 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate #endif 657*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 658*7c478bd9Sstevel@tonic-gate default: 659*7c478bd9Sstevel@tonic-gate putnext(q, mp); 660*7c478bd9Sstevel@tonic-gate break; 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate case M_PROTO: 663*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 664*7c478bd9Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t)); 665*7c478bd9Sstevel@tonic-gate pptr = (union T_primitives *)mp->b_rptr; 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * Forward this message to krpc if it is data. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate if (pptr->type == T_UNITDATA_IND) { 671*7c478bd9Sstevel@tonic-gate mblk_t *nmp; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * Check if the module is being popped. 675*7c478bd9Sstevel@tonic-gate */ 676*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 677*7c478bd9Sstevel@tonic-gate if (rmp->rm_state & RM_CLOSING) { 678*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 679*7c478bd9Sstevel@tonic-gate putnext(q, mp); 680*7c478bd9Sstevel@tonic-gate break; 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate switch (rmp->rm_type) { 684*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 685*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 686*7c478bd9Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr; 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate /* 689*7c478bd9Sstevel@tonic-gate * Make sure the header is sane. 690*7c478bd9Sstevel@tonic-gate */ 691*7c478bd9Sstevel@tonic-gate if (hdrsz < TUNITDATAINDSZ || 692*7c478bd9Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.OPT_length + 693*7c478bd9Sstevel@tonic-gate pptr->unitdata_ind.OPT_offset) || 694*7c478bd9Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.SRC_length + 695*7c478bd9Sstevel@tonic-gate pptr->unitdata_ind.SRC_offset)) { 696*7c478bd9Sstevel@tonic-gate freemsg(mp); 697*7c478bd9Sstevel@tonic-gate return; 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate /* 701*7c478bd9Sstevel@tonic-gate * Call clnt_clts_dispatch_notify, so that it can 702*7c478bd9Sstevel@tonic-gate * pass the message to the proper caller. Don't 703*7c478bd9Sstevel@tonic-gate * discard the header just yet since the client may 704*7c478bd9Sstevel@tonic-gate * need the sender's address. 705*7c478bd9Sstevel@tonic-gate */ 706*7c478bd9Sstevel@tonic-gate clnt_clts_dispatch_notify(mp, hdrsz, rmp->rm_zoneid); 707*7c478bd9Sstevel@tonic-gate return; 708*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 709*7c478bd9Sstevel@tonic-gate /* 710*7c478bd9Sstevel@tonic-gate * rm_krpc_cell is exclusively used by the kRPC 711*7c478bd9Sstevel@tonic-gate * CLTS server 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate if (rmp->rm_krpc_cell) { 714*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 715*7c478bd9Sstevel@tonic-gate /* 716*7c478bd9Sstevel@tonic-gate * Test duplicate request cache and 717*7c478bd9Sstevel@tonic-gate * rm_ref count handling by sending a 718*7c478bd9Sstevel@tonic-gate * duplicate every so often, if 719*7c478bd9Sstevel@tonic-gate * desired. 720*7c478bd9Sstevel@tonic-gate */ 721*7c478bd9Sstevel@tonic-gate if (rpcmod_send_dup && 722*7c478bd9Sstevel@tonic-gate rpcmod_send_dup_cnt++ % 723*7c478bd9Sstevel@tonic-gate rpcmod_send_dup) 724*7c478bd9Sstevel@tonic-gate nmp = copymsg(mp); 725*7c478bd9Sstevel@tonic-gate else 726*7c478bd9Sstevel@tonic-gate nmp = NULL; 727*7c478bd9Sstevel@tonic-gate #endif 728*7c478bd9Sstevel@tonic-gate /* 729*7c478bd9Sstevel@tonic-gate * Raise the reference count on this 730*7c478bd9Sstevel@tonic-gate * module to prevent it from being 731*7c478bd9Sstevel@tonic-gate * popped before krpc generates the 732*7c478bd9Sstevel@tonic-gate * reply. 733*7c478bd9Sstevel@tonic-gate */ 734*7c478bd9Sstevel@tonic-gate rmp->rm_ref++; 735*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* 738*7c478bd9Sstevel@tonic-gate * Submit the message to krpc. 739*7c478bd9Sstevel@tonic-gate */ 740*7c478bd9Sstevel@tonic-gate svc_queuereq(q, mp); 741*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 742*7c478bd9Sstevel@tonic-gate /* 743*7c478bd9Sstevel@tonic-gate * Send duplicate if we created one. 744*7c478bd9Sstevel@tonic-gate */ 745*7c478bd9Sstevel@tonic-gate if (nmp) { 746*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 747*7c478bd9Sstevel@tonic-gate rmp->rm_ref++; 748*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 749*7c478bd9Sstevel@tonic-gate svc_queuereq(q, nmp); 750*7c478bd9Sstevel@tonic-gate } 751*7c478bd9Sstevel@tonic-gate #endif 752*7c478bd9Sstevel@tonic-gate } else { 753*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 754*7c478bd9Sstevel@tonic-gate freemsg(mp); 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate return; 757*7c478bd9Sstevel@tonic-gate default: 758*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 759*7c478bd9Sstevel@tonic-gate freemsg(mp); 760*7c478bd9Sstevel@tonic-gate return; 761*7c478bd9Sstevel@tonic-gate } /* end switch(rmp->rm_type) */ 762*7c478bd9Sstevel@tonic-gate } else if (pptr->type == T_UDERROR_IND) { 763*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 764*7c478bd9Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr; 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate /* 767*7c478bd9Sstevel@tonic-gate * Make sure the header is sane 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate if (hdrsz < TUDERRORINDSZ || 770*7c478bd9Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.OPT_length + 771*7c478bd9Sstevel@tonic-gate pptr->uderror_ind.OPT_offset) || 772*7c478bd9Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.DEST_length + 773*7c478bd9Sstevel@tonic-gate pptr->uderror_ind.DEST_offset)) { 774*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 775*7c478bd9Sstevel@tonic-gate freemsg(mp); 776*7c478bd9Sstevel@tonic-gate return; 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate /* 780*7c478bd9Sstevel@tonic-gate * In the case where a unit data error has been 781*7c478bd9Sstevel@tonic-gate * received, all we need to do is clear the message from 782*7c478bd9Sstevel@tonic-gate * the queue. 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 785*7c478bd9Sstevel@tonic-gate freemsg(mp); 786*7c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmodrput: unitdata error received at " 787*7c478bd9Sstevel@tonic-gate "%ld\n", gethrestime_sec()); 788*7c478bd9Sstevel@tonic-gate return; 789*7c478bd9Sstevel@tonic-gate } /* end else if (pptr->type == T_UDERROR_IND) */ 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate putnext(q, mp); 792*7c478bd9Sstevel@tonic-gate break; 793*7c478bd9Sstevel@tonic-gate } /* end switch (mp->b_datap->db_type) */ 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END, 796*7c478bd9Sstevel@tonic-gate "rpcmodrput_end:"); 797*7c478bd9Sstevel@tonic-gate /* 798*7c478bd9Sstevel@tonic-gate * Return codes are not looked at by the STREAMS framework. 799*7c478bd9Sstevel@tonic-gate */ 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * write put procedure 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate void 806*7c478bd9Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp) 807*7c478bd9Sstevel@tonic-gate { 808*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 813*7c478bd9Sstevel@tonic-gate case M_PROTO: 814*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 815*7c478bd9Sstevel@tonic-gate break; 816*7c478bd9Sstevel@tonic-gate default: 817*7c478bd9Sstevel@tonic-gate rpcmodwput_other(q, mp); 818*7c478bd9Sstevel@tonic-gate return; 819*7c478bd9Sstevel@tonic-gate } 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate /* 822*7c478bd9Sstevel@tonic-gate * Check to see if we can send the message downstream. 823*7c478bd9Sstevel@tonic-gate */ 824*7c478bd9Sstevel@tonic-gate if (canputnext(q)) { 825*7c478bd9Sstevel@tonic-gate putnext(q, mp); 826*7c478bd9Sstevel@tonic-gate return; 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 830*7c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* 833*7c478bd9Sstevel@tonic-gate * The first canputnext failed. Try again except this time with the 834*7c478bd9Sstevel@tonic-gate * lock held, so that we can check the state of the stream to see if 835*7c478bd9Sstevel@tonic-gate * it is closing. If either of these conditions evaluate to true 836*7c478bd9Sstevel@tonic-gate * then send the meesage. 837*7c478bd9Sstevel@tonic-gate */ 838*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 839*7c478bd9Sstevel@tonic-gate if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) { 840*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 841*7c478bd9Sstevel@tonic-gate putnext(q, mp); 842*7c478bd9Sstevel@tonic-gate } else { 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * canputnext failed again and the stream is not closing. 845*7c478bd9Sstevel@tonic-gate * Place the message on the queue and let the service 846*7c478bd9Sstevel@tonic-gate * procedure handle the message. 847*7c478bd9Sstevel@tonic-gate */ 848*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 849*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 850*7c478bd9Sstevel@tonic-gate } 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate static void 854*7c478bd9Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp) 855*7c478bd9Sstevel@tonic-gate { 856*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 857*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 860*7c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 863*7c478bd9Sstevel@tonic-gate case M_IOCTL: 864*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 865*7c478bd9Sstevel@tonic-gate ASSERT(iocp != NULL); 866*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 867*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 868*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 869*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 870*7c478bd9Sstevel@tonic-gate rmp->rm_type = iocp->ioc_cmd; 871*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 872*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 873*7c478bd9Sstevel@tonic-gate qreply(q, mp); 874*7c478bd9Sstevel@tonic-gate return; 875*7c478bd9Sstevel@tonic-gate default: 876*7c478bd9Sstevel@tonic-gate /* 877*7c478bd9Sstevel@tonic-gate * pass the ioctl downstream and hope someone 878*7c478bd9Sstevel@tonic-gate * down there knows how to handle it. 879*7c478bd9Sstevel@tonic-gate */ 880*7c478bd9Sstevel@tonic-gate putnext(q, mp); 881*7c478bd9Sstevel@tonic-gate return; 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate default: 884*7c478bd9Sstevel@tonic-gate break; 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate /* 887*7c478bd9Sstevel@tonic-gate * This is something we definitely do not know how to handle, just 888*7c478bd9Sstevel@tonic-gate * pass the message downstream 889*7c478bd9Sstevel@tonic-gate */ 890*7c478bd9Sstevel@tonic-gate putnext(q, mp); 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate /* 894*7c478bd9Sstevel@tonic-gate * Module write service procedure. This is called by downstream modules 895*7c478bd9Sstevel@tonic-gate * for back enabling during flow control. 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate void 898*7c478bd9Sstevel@tonic-gate rpcmodwsrv(queue_t *q) 899*7c478bd9Sstevel@tonic-gate { 900*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 901*7c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 904*7c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL); 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* 907*7c478bd9Sstevel@tonic-gate * Get messages that may be queued and send them down stream 908*7c478bd9Sstevel@tonic-gate */ 909*7c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 910*7c478bd9Sstevel@tonic-gate /* 911*7c478bd9Sstevel@tonic-gate * Optimize the service procedure for the server-side, by 912*7c478bd9Sstevel@tonic-gate * avoiding a call to canputnext(). 913*7c478bd9Sstevel@tonic-gate */ 914*7c478bd9Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER || canputnext(q)) { 915*7c478bd9Sstevel@tonic-gate putnext(q, mp); 916*7c478bd9Sstevel@tonic-gate continue; 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 919*7c478bd9Sstevel@tonic-gate return; 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate static void 924*7c478bd9Sstevel@tonic-gate rpcmod_release(queue_t *q, mblk_t *bp) 925*7c478bd9Sstevel@tonic-gate { 926*7c478bd9Sstevel@tonic-gate struct rpcm *rmp; 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate /* 929*7c478bd9Sstevel@tonic-gate * For now, just free the message. 930*7c478bd9Sstevel@tonic-gate */ 931*7c478bd9Sstevel@tonic-gate if (bp) 932*7c478bd9Sstevel@tonic-gate freemsg(bp); 933*7c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock); 936*7c478bd9Sstevel@tonic-gate rmp->rm_ref--; 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) { 939*7c478bd9Sstevel@tonic-gate cv_broadcast(&rmp->rm_cwait); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock); 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate * This part of rpcmod is pushed on a connection-oriented transport for use 947*7c478bd9Sstevel@tonic-gate * by RPC. It serves to bypass the Stream head, implements 948*7c478bd9Sstevel@tonic-gate * the record marking protocol, and dispatches incoming RPC messages. 949*7c478bd9Sstevel@tonic-gate */ 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate /* Default idle timer values */ 952*7c478bd9Sstevel@tonic-gate #define MIR_CLNT_IDLE_TIMEOUT (5 * (60 * 1000L)) /* 5 minutes */ 953*7c478bd9Sstevel@tonic-gate #define MIR_SVC_IDLE_TIMEOUT (6 * (60 * 1000L)) /* 6 minutes */ 954*7c478bd9Sstevel@tonic-gate #define MIR_SVC_ORDREL_TIMEOUT (10 * (60 * 1000L)) /* 10 minutes */ 955*7c478bd9Sstevel@tonic-gate #define MIR_LASTFRAG 0x80000000 /* Record marker */ 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate #define DLEN(mp) (mp->b_cont ? msgdsize(mp) : (mp->b_wptr - mp->b_rptr)) 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate typedef struct mir_s { 960*7c478bd9Sstevel@tonic-gate void *mir_krpc_cell; /* Reserved for KRPC use. This field */ 961*7c478bd9Sstevel@tonic-gate /* must be first in the structure. */ 962*7c478bd9Sstevel@tonic-gate struct xprt_style_ops *rm_ops; 963*7c478bd9Sstevel@tonic-gate int mir_type; /* Client or server side stream */ 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate mblk_t *mir_head_mp; /* RPC msg in progress */ 966*7c478bd9Sstevel@tonic-gate /* 967*7c478bd9Sstevel@tonic-gate * mir_head_mp points the first mblk being collected in 968*7c478bd9Sstevel@tonic-gate * the current RPC message. Record headers are removed 969*7c478bd9Sstevel@tonic-gate * before data is linked into mir_head_mp. 970*7c478bd9Sstevel@tonic-gate */ 971*7c478bd9Sstevel@tonic-gate mblk_t *mir_tail_mp; /* Last mblk in mir_head_mp */ 972*7c478bd9Sstevel@tonic-gate /* 973*7c478bd9Sstevel@tonic-gate * mir_tail_mp points to the last mblk in the message 974*7c478bd9Sstevel@tonic-gate * chain starting at mir_head_mp. It is only valid 975*7c478bd9Sstevel@tonic-gate * if mir_head_mp is non-NULL and is used to add new 976*7c478bd9Sstevel@tonic-gate * data blocks to the end of chain quickly. 977*7c478bd9Sstevel@tonic-gate */ 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate int32_t mir_frag_len; /* Bytes seen in the current frag */ 980*7c478bd9Sstevel@tonic-gate /* 981*7c478bd9Sstevel@tonic-gate * mir_frag_len starts at -4 for beginning of each fragment. 982*7c478bd9Sstevel@tonic-gate * When this length is negative, it indicates the number of 983*7c478bd9Sstevel@tonic-gate * bytes that rpcmod needs to complete the record marker 984*7c478bd9Sstevel@tonic-gate * header. When it is positive or zero, it holds the number 985*7c478bd9Sstevel@tonic-gate * of bytes that have arrived for the current fragment and 986*7c478bd9Sstevel@tonic-gate * are held in mir_header_mp. 987*7c478bd9Sstevel@tonic-gate */ 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate int32_t mir_frag_header; 990*7c478bd9Sstevel@tonic-gate /* 991*7c478bd9Sstevel@tonic-gate * Fragment header as collected for the current fragment. 992*7c478bd9Sstevel@tonic-gate * It holds the last-fragment indicator and the number 993*7c478bd9Sstevel@tonic-gate * of bytes in the fragment. 994*7c478bd9Sstevel@tonic-gate */ 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate unsigned int 997*7c478bd9Sstevel@tonic-gate mir_ordrel_pending : 1, /* Sent T_ORDREL_REQ */ 998*7c478bd9Sstevel@tonic-gate mir_hold_inbound : 1, /* Hold inbound messages on server */ 999*7c478bd9Sstevel@tonic-gate /* side until outbound flow control */ 1000*7c478bd9Sstevel@tonic-gate /* is relieved. */ 1001*7c478bd9Sstevel@tonic-gate mir_closing : 1, /* The stream is being closed */ 1002*7c478bd9Sstevel@tonic-gate mir_inrservice : 1, /* data queued or rd srv proc running */ 1003*7c478bd9Sstevel@tonic-gate mir_inwservice : 1, /* data queued or wr srv proc running */ 1004*7c478bd9Sstevel@tonic-gate mir_inwflushdata : 1, /* flush M_DATAs when srv runs */ 1005*7c478bd9Sstevel@tonic-gate /* 1006*7c478bd9Sstevel@tonic-gate * On client streams, mir_clntreq is 0 or 1; it is set 1007*7c478bd9Sstevel@tonic-gate * to 1 whenever a new request is sent out (mir_wput) 1008*7c478bd9Sstevel@tonic-gate * and cleared when the timer fires (mir_timer). If 1009*7c478bd9Sstevel@tonic-gate * the timer fires with this value equal to 0, then the 1010*7c478bd9Sstevel@tonic-gate * stream is considered idle and KRPC is notified. 1011*7c478bd9Sstevel@tonic-gate */ 1012*7c478bd9Sstevel@tonic-gate mir_clntreq : 1, 1013*7c478bd9Sstevel@tonic-gate /* 1014*7c478bd9Sstevel@tonic-gate * On server streams, stop accepting messages 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate mir_svc_no_more_msgs : 1, 1017*7c478bd9Sstevel@tonic-gate mir_listen_stream : 1, /* listen end point */ 1018*7c478bd9Sstevel@tonic-gate mir_setup_complete : 1, /* server has initialized everything */ 1019*7c478bd9Sstevel@tonic-gate mir_timer_call : 1, 1020*7c478bd9Sstevel@tonic-gate mir_junk_fill_thru_bit_31 : 21; 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate timeout_id_t mir_timer_id; /* Timer for idle checks */ 1023*7c478bd9Sstevel@tonic-gate clock_t mir_idle_timeout; /* Allowed idle time before shutdown */ 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * This value is copied from clnt_idle_timeout or 1026*7c478bd9Sstevel@tonic-gate * svc_idle_timeout during the appropriate ioctl. 1027*7c478bd9Sstevel@tonic-gate * Kept in milliseconds 1028*7c478bd9Sstevel@tonic-gate */ 1029*7c478bd9Sstevel@tonic-gate clock_t mir_use_timestamp; /* updated on client with each use */ 1030*7c478bd9Sstevel@tonic-gate /* 1031*7c478bd9Sstevel@tonic-gate * This value is set to lbolt 1032*7c478bd9Sstevel@tonic-gate * every time a client stream sends or receives data. 1033*7c478bd9Sstevel@tonic-gate * Even if the timer message arrives, we don't shutdown 1034*7c478bd9Sstevel@tonic-gate * client unless: 1035*7c478bd9Sstevel@tonic-gate * lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp. 1036*7c478bd9Sstevel@tonic-gate * This value is kept in HZ. 1037*7c478bd9Sstevel@tonic-gate */ 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate uint_t *mir_max_msg_sizep; /* Reference to sanity check size */ 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * This pointer is set to &clnt_max_msg_size or 1042*7c478bd9Sstevel@tonic-gate * &svc_max_msg_size during the appropriate ioctl. 1043*7c478bd9Sstevel@tonic-gate */ 1044*7c478bd9Sstevel@tonic-gate zoneid_t mir_zoneid; /* zone which pushed rpcmod */ 1045*7c478bd9Sstevel@tonic-gate /* Server-side fields. */ 1046*7c478bd9Sstevel@tonic-gate int mir_ref_cnt; /* Reference count: server side only */ 1047*7c478bd9Sstevel@tonic-gate /* counts the number of references */ 1048*7c478bd9Sstevel@tonic-gate /* that a kernel RPC server thread */ 1049*7c478bd9Sstevel@tonic-gate /* (see svc_run()) has on this rpcmod */ 1050*7c478bd9Sstevel@tonic-gate /* slot. Effectively, it is the */ 1051*7c478bd9Sstevel@tonic-gate /* number * of unprocessed messages */ 1052*7c478bd9Sstevel@tonic-gate /* that have been passed up to the */ 1053*7c478bd9Sstevel@tonic-gate /* KRPC layer */ 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate mblk_t *mir_svc_pend_mp; /* Pending T_ORDREL_IND or */ 1056*7c478bd9Sstevel@tonic-gate /* T_DISCON_IND */ 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate /* 1059*7c478bd9Sstevel@tonic-gate * these fields are for both client and server, but for debugging, 1060*7c478bd9Sstevel@tonic-gate * it is easier to have these last in the structure. 1061*7c478bd9Sstevel@tonic-gate */ 1062*7c478bd9Sstevel@tonic-gate kmutex_t mir_mutex; /* Mutex and condvar for close */ 1063*7c478bd9Sstevel@tonic-gate kcondvar_t mir_condvar; /* synchronization. */ 1064*7c478bd9Sstevel@tonic-gate kcondvar_t mir_timer_cv; /* Timer routine sync. */ 1065*7c478bd9Sstevel@tonic-gate } mir_t; 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate #define MIR_SVC_QUIESCED(mir) \ 1068*7c478bd9Sstevel@tonic-gate (mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0) 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate #define MIR_CLEAR_INRSRV(mir_ptr) { \ 1071*7c478bd9Sstevel@tonic-gate (mir_ptr)->mir_inrservice = 0; \ 1072*7c478bd9Sstevel@tonic-gate if ((mir_ptr)->mir_type == RPC_SERVER && \ 1073*7c478bd9Sstevel@tonic-gate (mir_ptr)->mir_closing) \ 1074*7c478bd9Sstevel@tonic-gate cv_signal(&(mir_ptr)->mir_condvar); \ 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* 1078*7c478bd9Sstevel@tonic-gate * Don't block service procedure (and mir_close) if 1079*7c478bd9Sstevel@tonic-gate * we are in the process of closing. 1080*7c478bd9Sstevel@tonic-gate */ 1081*7c478bd9Sstevel@tonic-gate #define MIR_WCANPUTNEXT(mir_ptr, write_q) \ 1082*7c478bd9Sstevel@tonic-gate (canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1)) 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate static int mir_clnt_dup_request(queue_t *q, mblk_t *mp); 1085*7c478bd9Sstevel@tonic-gate static void mir_rput_proto(queue_t *q, mblk_t *mp); 1086*7c478bd9Sstevel@tonic-gate static int mir_svc_policy_notify(queue_t *q, int event); 1087*7c478bd9Sstevel@tonic-gate static void mir_svc_release(queue_t *wq, mblk_t *mp); 1088*7c478bd9Sstevel@tonic-gate static void mir_svc_start(queue_t *wq); 1089*7c478bd9Sstevel@tonic-gate static void mir_svc_idle_start(queue_t *, mir_t *); 1090*7c478bd9Sstevel@tonic-gate static void mir_svc_idle_stop(queue_t *, mir_t *); 1091*7c478bd9Sstevel@tonic-gate static void mir_svc_start_close(queue_t *, mir_t *); 1092*7c478bd9Sstevel@tonic-gate static void mir_clnt_idle_do_stop(queue_t *); 1093*7c478bd9Sstevel@tonic-gate static void mir_clnt_idle_stop(queue_t *, mir_t *); 1094*7c478bd9Sstevel@tonic-gate static void mir_clnt_idle_start(queue_t *, mir_t *); 1095*7c478bd9Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp); 1096*7c478bd9Sstevel@tonic-gate static void mir_wput_other(queue_t *q, mblk_t *mp); 1097*7c478bd9Sstevel@tonic-gate static void mir_wsrv(queue_t *q); 1098*7c478bd9Sstevel@tonic-gate static void mir_disconnect(queue_t *, mir_t *ir); 1099*7c478bd9Sstevel@tonic-gate static int mir_check_len(queue_t *, int32_t, mblk_t *); 1100*7c478bd9Sstevel@tonic-gate static void mir_timer(void *); 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate extern void (*mir_rele)(queue_t *, mblk_t *); 1103*7c478bd9Sstevel@tonic-gate extern void (*mir_start)(queue_t *); 1104*7c478bd9Sstevel@tonic-gate extern void (*clnt_stop_idle)(queue_t *); 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate clock_t clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT; 1107*7c478bd9Sstevel@tonic-gate clock_t svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT; 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate /* 1110*7c478bd9Sstevel@tonic-gate * Timeout for subsequent notifications of idle connection. This is 1111*7c478bd9Sstevel@tonic-gate * typically used to clean up after a wedged orderly release. 1112*7c478bd9Sstevel@tonic-gate */ 1113*7c478bd9Sstevel@tonic-gate clock_t svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */ 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate extern uint_t *clnt_max_msg_sizep; 1116*7c478bd9Sstevel@tonic-gate extern uint_t *svc_max_msg_sizep; 1117*7c478bd9Sstevel@tonic-gate uint_t clnt_max_msg_size = RPC_MAXDATASIZE; 1118*7c478bd9Sstevel@tonic-gate uint_t svc_max_msg_size = RPC_MAXDATASIZE; 1119*7c478bd9Sstevel@tonic-gate uint_t mir_krpc_cell_null; 1120*7c478bd9Sstevel@tonic-gate 1121*7c478bd9Sstevel@tonic-gate static void 1122*7c478bd9Sstevel@tonic-gate mir_timer_stop(mir_t *mir) 1123*7c478bd9Sstevel@tonic-gate { 1124*7c478bd9Sstevel@tonic-gate timeout_id_t tid; 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 1127*7c478bd9Sstevel@tonic-gate 1128*7c478bd9Sstevel@tonic-gate /* 1129*7c478bd9Sstevel@tonic-gate * Since the mir_mutex lock needs to be released to call 1130*7c478bd9Sstevel@tonic-gate * untimeout(), we need to make sure that no other thread 1131*7c478bd9Sstevel@tonic-gate * can start/stop the timer (changing mir_timer_id) during 1132*7c478bd9Sstevel@tonic-gate * that time. The mir_timer_call bit and the mir_timer_cv 1133*7c478bd9Sstevel@tonic-gate * condition variable are used to synchronize this. Setting 1134*7c478bd9Sstevel@tonic-gate * mir_timer_call also tells mir_timer() (refer to the comments 1135*7c478bd9Sstevel@tonic-gate * in mir_timer()) that it does not need to do anything. 1136*7c478bd9Sstevel@tonic-gate */ 1137*7c478bd9Sstevel@tonic-gate while (mir->mir_timer_call) 1138*7c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex); 1139*7c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_TRUE; 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) { 1142*7c478bd9Sstevel@tonic-gate mir->mir_timer_id = 0; 1143*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1144*7c478bd9Sstevel@tonic-gate (void) untimeout(tid); 1145*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_FALSE; 1148*7c478bd9Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv); 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate static void 1152*7c478bd9Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl) 1153*7c478bd9Sstevel@tonic-gate { 1154*7c478bd9Sstevel@tonic-gate timeout_id_t tid; 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate while (mir->mir_timer_call) 1159*7c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex); 1160*7c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_TRUE; 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) { 1163*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1164*7c478bd9Sstevel@tonic-gate (void) untimeout(tid); 1165*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate /* Only start the timer when it is not closing. */ 1168*7c478bd9Sstevel@tonic-gate if (!mir->mir_closing) { 1169*7c478bd9Sstevel@tonic-gate mir->mir_timer_id = timeout(mir_timer, q, 1170*7c478bd9Sstevel@tonic-gate MSEC_TO_TICK(intrvl)); 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_FALSE; 1173*7c478bd9Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv); 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate static int 1177*7c478bd9Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp) 1178*7c478bd9Sstevel@tonic-gate { 1179*7c478bd9Sstevel@tonic-gate mblk_t *mp1; 1180*7c478bd9Sstevel@tonic-gate uint32_t new_xid; 1181*7c478bd9Sstevel@tonic-gate uint32_t old_xid; 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex)); 1184*7c478bd9Sstevel@tonic-gate new_xid = BE32_TO_U32(&mp->b_rptr[4]); 1185*7c478bd9Sstevel@tonic-gate /* 1186*7c478bd9Sstevel@tonic-gate * This loop is a bit tacky -- it walks the STREAMS list of 1187*7c478bd9Sstevel@tonic-gate * flow-controlled messages. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate if ((mp1 = q->q_first) != NULL) { 1190*7c478bd9Sstevel@tonic-gate do { 1191*7c478bd9Sstevel@tonic-gate old_xid = BE32_TO_U32(&mp1->b_rptr[4]); 1192*7c478bd9Sstevel@tonic-gate if (new_xid == old_xid) 1193*7c478bd9Sstevel@tonic-gate return (1); 1194*7c478bd9Sstevel@tonic-gate } while ((mp1 = mp1->b_next) != NULL); 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate return (0); 1197*7c478bd9Sstevel@tonic-gate } 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate static int 1200*7c478bd9Sstevel@tonic-gate mir_close(queue_t *q) 1201*7c478bd9Sstevel@tonic-gate { 1202*7c478bd9Sstevel@tonic-gate mir_t *mir; 1203*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1204*7c478bd9Sstevel@tonic-gate bool_t queue_cleaned = FALSE; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q); 1207*7c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 1208*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 1209*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1210*7c478bd9Sstevel@tonic-gate if ((mp = mir->mir_head_mp) != NULL) { 1211*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 1212*7c478bd9Sstevel@tonic-gate freemsg(mp); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * Set mir_closing so we get notified when MIR_SVC_QUIESCED() 1216*7c478bd9Sstevel@tonic-gate * is TRUE. And mir_timer_start() won't start the timer again. 1217*7c478bd9Sstevel@tonic-gate */ 1218*7c478bd9Sstevel@tonic-gate mir->mir_closing = B_TRUE; 1219*7c478bd9Sstevel@tonic-gate mir_timer_stop(mir); 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER) { 1222*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* Ditch anything waiting on read q */ 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate /* 1225*7c478bd9Sstevel@tonic-gate * This will prevent more requests from arriving and 1226*7c478bd9Sstevel@tonic-gate * will force rpcmod to ignore flow control. 1227*7c478bd9Sstevel@tonic-gate */ 1228*7c478bd9Sstevel@tonic-gate mir_svc_start_close(WR(q), mir); 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) { 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt && !mir->mir_inrservice && 1233*7c478bd9Sstevel@tonic-gate (queue_cleaned == FALSE)) { 1234*7c478bd9Sstevel@tonic-gate /* 1235*7c478bd9Sstevel@tonic-gate * call into SVC to clean the queue 1236*7c478bd9Sstevel@tonic-gate */ 1237*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1238*7c478bd9Sstevel@tonic-gate svc_queueclean(q); 1239*7c478bd9Sstevel@tonic-gate queue_cleaned = TRUE; 1240*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1241*7c478bd9Sstevel@tonic-gate continue; 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate /* 1245*7c478bd9Sstevel@tonic-gate * Bugid 1253810 - Force the write service 1246*7c478bd9Sstevel@tonic-gate * procedure to send its messages, regardless 1247*7c478bd9Sstevel@tonic-gate * whether the downstream module is ready 1248*7c478bd9Sstevel@tonic-gate * to accept data. 1249*7c478bd9Sstevel@tonic-gate */ 1250*7c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 1) 1251*7c478bd9Sstevel@tonic-gate qenable(WR(q)); 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_condvar, &mir->mir_mutex); 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1257*7c478bd9Sstevel@tonic-gate qprocsoff(q); 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate /* Notify KRPC that this stream is going away. */ 1260*7c478bd9Sstevel@tonic-gate svc_queueclose(q); 1261*7c478bd9Sstevel@tonic-gate } else { 1262*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1263*7c478bd9Sstevel@tonic-gate qprocsoff(q); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate mutex_destroy(&mir->mir_mutex); 1267*7c478bd9Sstevel@tonic-gate cv_destroy(&mir->mir_condvar); 1268*7c478bd9Sstevel@tonic-gate cv_destroy(&mir->mir_timer_cv); 1269*7c478bd9Sstevel@tonic-gate kmem_free(mir, sizeof (mir_t)); 1270*7c478bd9Sstevel@tonic-gate return (0); 1271*7c478bd9Sstevel@tonic-gate } 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate /* 1274*7c478bd9Sstevel@tonic-gate * This is server side only (RPC_SERVER). 1275*7c478bd9Sstevel@tonic-gate * 1276*7c478bd9Sstevel@tonic-gate * Exit idle mode. 1277*7c478bd9Sstevel@tonic-gate */ 1278*7c478bd9Sstevel@tonic-gate static void 1279*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir) 1280*7c478bd9Sstevel@tonic-gate { 1281*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 1282*7c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0); 1283*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 1284*7c478bd9Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q); 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate mir_timer_stop(mir); 1287*7c478bd9Sstevel@tonic-gate } 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate /* 1290*7c478bd9Sstevel@tonic-gate * This is server side only (RPC_SERVER). 1291*7c478bd9Sstevel@tonic-gate * 1292*7c478bd9Sstevel@tonic-gate * Start idle processing, which will include setting idle timer if the 1293*7c478bd9Sstevel@tonic-gate * stream is not being closed. 1294*7c478bd9Sstevel@tonic-gate */ 1295*7c478bd9Sstevel@tonic-gate static void 1296*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir) 1297*7c478bd9Sstevel@tonic-gate { 1298*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 1299*7c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0); 1300*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 1301*7c478bd9Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q); 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate /* 1304*7c478bd9Sstevel@tonic-gate * Don't re-start idle timer if we are closing queues. 1305*7c478bd9Sstevel@tonic-gate */ 1306*7c478bd9Sstevel@tonic-gate if (mir->mir_closing) { 1307*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n", 1308*7c478bd9Sstevel@tonic-gate (void *)q); 1309*7c478bd9Sstevel@tonic-gate 1310*7c478bd9Sstevel@tonic-gate /* 1311*7c478bd9Sstevel@tonic-gate * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED() 1312*7c478bd9Sstevel@tonic-gate * is true. When it is true, and we are in the process of 1313*7c478bd9Sstevel@tonic-gate * closing the stream, signal any thread waiting in 1314*7c478bd9Sstevel@tonic-gate * mir_close(). 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 0) 1317*7c478bd9Sstevel@tonic-gate cv_signal(&mir->mir_condvar); 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate } else { 1320*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - reset %s timer\n", 1321*7c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending ? "ordrel" : "normal"); 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * Normal condition, start the idle timer. If an orderly 1324*7c478bd9Sstevel@tonic-gate * release has been sent, set the timeout to wait for the 1325*7c478bd9Sstevel@tonic-gate * client to close its side of the connection. Otherwise, 1326*7c478bd9Sstevel@tonic-gate * use the normal idle timeout. 1327*7c478bd9Sstevel@tonic-gate */ 1328*7c478bd9Sstevel@tonic-gate mir_timer_start(q, mir, mir->mir_ordrel_pending ? 1329*7c478bd9Sstevel@tonic-gate svc_ordrel_timeout : mir->mir_idle_timeout); 1330*7c478bd9Sstevel@tonic-gate } 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1334*7c478bd9Sstevel@tonic-gate static int 1335*7c478bd9Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 1336*7c478bd9Sstevel@tonic-gate { 1337*7c478bd9Sstevel@tonic-gate mir_t *mir; 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q); 1340*7c478bd9Sstevel@tonic-gate /* Set variables used directly by KRPC. */ 1341*7c478bd9Sstevel@tonic-gate if (!mir_rele) 1342*7c478bd9Sstevel@tonic-gate mir_rele = mir_svc_release; 1343*7c478bd9Sstevel@tonic-gate if (!mir_start) 1344*7c478bd9Sstevel@tonic-gate mir_start = mir_svc_start; 1345*7c478bd9Sstevel@tonic-gate if (!clnt_stop_idle) 1346*7c478bd9Sstevel@tonic-gate clnt_stop_idle = mir_clnt_idle_do_stop; 1347*7c478bd9Sstevel@tonic-gate if (!clnt_max_msg_sizep) 1348*7c478bd9Sstevel@tonic-gate clnt_max_msg_sizep = &clnt_max_msg_size; 1349*7c478bd9Sstevel@tonic-gate if (!svc_max_msg_sizep) 1350*7c478bd9Sstevel@tonic-gate svc_max_msg_sizep = &svc_max_msg_size; 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate /* Allocate a zero'ed out mir structure for this stream. */ 1353*7c478bd9Sstevel@tonic-gate mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP); 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate /* 1356*7c478bd9Sstevel@tonic-gate * We set hold inbound here so that incoming messages will 1357*7c478bd9Sstevel@tonic-gate * be held on the read-side queue until the stream is completely 1358*7c478bd9Sstevel@tonic-gate * initialized with a RPC_CLIENT or RPC_SERVER ioctl. During 1359*7c478bd9Sstevel@tonic-gate * the ioctl processing, the flag is cleared and any messages that 1360*7c478bd9Sstevel@tonic-gate * arrived between the open and the ioctl are delivered to KRPC. 1361*7c478bd9Sstevel@tonic-gate * 1362*7c478bd9Sstevel@tonic-gate * Early data should never arrive on a client stream since 1363*7c478bd9Sstevel@tonic-gate * servers only respond to our requests and we do not send any. 1364*7c478bd9Sstevel@tonic-gate * until after the stream is initialized. Early data is 1365*7c478bd9Sstevel@tonic-gate * very common on a server stream where the client will start 1366*7c478bd9Sstevel@tonic-gate * sending data as soon as the connection is made (and this 1367*7c478bd9Sstevel@tonic-gate * is especially true with TCP where the protocol accepts the 1368*7c478bd9Sstevel@tonic-gate * connection before nfsd or KRPC is notified about it). 1369*7c478bd9Sstevel@tonic-gate */ 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 1; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate /* 1374*7c478bd9Sstevel@tonic-gate * Start the record marker looking for a 4-byte header. When 1375*7c478bd9Sstevel@tonic-gate * this length is negative, it indicates that rpcmod is looking 1376*7c478bd9Sstevel@tonic-gate * for bytes to consume for the record marker header. When it 1377*7c478bd9Sstevel@tonic-gate * is positive, it holds the number of bytes that have arrived 1378*7c478bd9Sstevel@tonic-gate * for the current fragment and are being held in mir_header_mp. 1379*7c478bd9Sstevel@tonic-gate */ 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t); 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate mir->mir_zoneid = getzoneid(); 1384*7c478bd9Sstevel@tonic-gate mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL); 1385*7c478bd9Sstevel@tonic-gate cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL); 1386*7c478bd9Sstevel@tonic-gate cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL); 1387*7c478bd9Sstevel@tonic-gate 1388*7c478bd9Sstevel@tonic-gate q->q_ptr = (char *)mir; 1389*7c478bd9Sstevel@tonic-gate WR(q)->q_ptr = (char *)mir; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate /* 1392*7c478bd9Sstevel@tonic-gate * We noenable the read-side queue because we don't want it 1393*7c478bd9Sstevel@tonic-gate * automatically enabled by putq. We enable it explicitly 1394*7c478bd9Sstevel@tonic-gate * in mir_wsrv when appropriate. (See additional comments on 1395*7c478bd9Sstevel@tonic-gate * flow control at the beginning of mir_rsrv.) 1396*7c478bd9Sstevel@tonic-gate */ 1397*7c478bd9Sstevel@tonic-gate noenable(q); 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate qprocson(q); 1400*7c478bd9Sstevel@tonic-gate return (0); 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate /* 1404*7c478bd9Sstevel@tonic-gate * Read-side put routine for both the client and server side. Does the 1405*7c478bd9Sstevel@tonic-gate * record marking for incoming RPC messages, and when complete, dispatches 1406*7c478bd9Sstevel@tonic-gate * the message to either the client or server. 1407*7c478bd9Sstevel@tonic-gate */ 1408*7c478bd9Sstevel@tonic-gate static void 1409*7c478bd9Sstevel@tonic-gate mir_do_rput(queue_t *q, mblk_t *mp, int srv) 1410*7c478bd9Sstevel@tonic-gate { 1411*7c478bd9Sstevel@tonic-gate mblk_t *cont_mp; 1412*7c478bd9Sstevel@tonic-gate int excess; 1413*7c478bd9Sstevel@tonic-gate int32_t frag_len; 1414*7c478bd9Sstevel@tonic-gate int32_t frag_header; 1415*7c478bd9Sstevel@tonic-gate mblk_t *head_mp; 1416*7c478bd9Sstevel@tonic-gate int len; 1417*7c478bd9Sstevel@tonic-gate mir_t *mir; 1418*7c478bd9Sstevel@tonic-gate mblk_t *mp1; 1419*7c478bd9Sstevel@tonic-gate unsigned char *rptr; 1420*7c478bd9Sstevel@tonic-gate mblk_t *tail_mp; 1421*7c478bd9Sstevel@tonic-gate unsigned char *wptr; 1422*7c478bd9Sstevel@tonic-gate boolean_t stop_timer = B_FALSE; 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 1425*7c478bd9Sstevel@tonic-gate ASSERT(mir != NULL); 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate /* 1428*7c478bd9Sstevel@tonic-gate * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER 1429*7c478bd9Sstevel@tonic-gate * with the corresponding ioctl, then don't accept 1430*7c478bd9Sstevel@tonic-gate * any inbound data. This should never happen for streams 1431*7c478bd9Sstevel@tonic-gate * created by nfsd or client-side KRPC because they are careful 1432*7c478bd9Sstevel@tonic-gate * to set the mode of the stream before doing anything else. 1433*7c478bd9Sstevel@tonic-gate */ 1434*7c478bd9Sstevel@tonic-gate if (mir->mir_type == 0) { 1435*7c478bd9Sstevel@tonic-gate freemsg(mp); 1436*7c478bd9Sstevel@tonic-gate return; 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 1442*7c478bd9Sstevel@tonic-gate case M_DATA: 1443*7c478bd9Sstevel@tonic-gate break; 1444*7c478bd9Sstevel@tonic-gate case M_PROTO: 1445*7c478bd9Sstevel@tonic-gate case M_PCPROTO: 1446*7c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 1447*7c478bd9Sstevel@tonic-gate if (mp->b_wptr - rptr < sizeof (uint32_t)) { 1448*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n", 1449*7c478bd9Sstevel@tonic-gate (int)(mp->b_wptr - rptr)); 1450*7c478bd9Sstevel@tonic-gate freemsg(mp); 1451*7c478bd9Sstevel@tonic-gate return; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate if (((union T_primitives *)rptr)->type != T_DATA_IND) { 1454*7c478bd9Sstevel@tonic-gate mir_rput_proto(q, mp); 1455*7c478bd9Sstevel@tonic-gate return; 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate /* Throw away the T_DATA_IND block and continue with data. */ 1459*7c478bd9Sstevel@tonic-gate mp1 = mp; 1460*7c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1461*7c478bd9Sstevel@tonic-gate freeb(mp1); 1462*7c478bd9Sstevel@tonic-gate break; 1463*7c478bd9Sstevel@tonic-gate case M_SETOPTS: 1464*7c478bd9Sstevel@tonic-gate /* 1465*7c478bd9Sstevel@tonic-gate * If a module on the stream is trying set the Stream head's 1466*7c478bd9Sstevel@tonic-gate * high water mark, then set our hiwater to the requested 1467*7c478bd9Sstevel@tonic-gate * value. We are the "stream head" for all inbound 1468*7c478bd9Sstevel@tonic-gate * data messages since messages are passed directly to KRPC. 1469*7c478bd9Sstevel@tonic-gate */ 1470*7c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) >= sizeof (struct stroptions)) { 1471*7c478bd9Sstevel@tonic-gate struct stroptions *stropts; 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate stropts = (struct stroptions *)mp->b_rptr; 1474*7c478bd9Sstevel@tonic-gate if ((stropts->so_flags & SO_HIWAT) && 1475*7c478bd9Sstevel@tonic-gate !(stropts->so_flags & SO_BAND)) { 1476*7c478bd9Sstevel@tonic-gate (void) strqset(q, QHIWAT, 0, stropts->so_hiwat); 1477*7c478bd9Sstevel@tonic-gate } 1478*7c478bd9Sstevel@tonic-gate } 1479*7c478bd9Sstevel@tonic-gate putnext(q, mp); 1480*7c478bd9Sstevel@tonic-gate return; 1481*7c478bd9Sstevel@tonic-gate case M_FLUSH: 1482*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: ignoring M_FLUSH on q 0x%p. ", 1483*7c478bd9Sstevel@tonic-gate (void *)q); 1484*7c478bd9Sstevel@tonic-gate RPCLOG(32, "M_FLUSH is %x\n", (uint_t)*mp->b_rptr); 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate putnext(q, mp); 1487*7c478bd9Sstevel@tonic-gate return; 1488*7c478bd9Sstevel@tonic-gate default: 1489*7c478bd9Sstevel@tonic-gate putnext(q, mp); 1490*7c478bd9Sstevel@tonic-gate return; 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate /* 1496*7c478bd9Sstevel@tonic-gate * If this connection is closing, don't accept any new messages. 1497*7c478bd9Sstevel@tonic-gate */ 1498*7c478bd9Sstevel@tonic-gate if (mir->mir_svc_no_more_msgs) { 1499*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 1500*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1501*7c478bd9Sstevel@tonic-gate freemsg(mp); 1502*7c478bd9Sstevel@tonic-gate return; 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate /* Get local copies for quicker access. */ 1506*7c478bd9Sstevel@tonic-gate frag_len = mir->mir_frag_len; 1507*7c478bd9Sstevel@tonic-gate frag_header = mir->mir_frag_header; 1508*7c478bd9Sstevel@tonic-gate head_mp = mir->mir_head_mp; 1509*7c478bd9Sstevel@tonic-gate tail_mp = mir->mir_tail_mp; 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate /* Loop, processing each message block in the mp chain separately. */ 1512*7c478bd9Sstevel@tonic-gate do { 1513*7c478bd9Sstevel@tonic-gate /* 1514*7c478bd9Sstevel@tonic-gate * cont_mp is used in the do/while condition below to 1515*7c478bd9Sstevel@tonic-gate * walk to the next block in the STREAMS message. 1516*7c478bd9Sstevel@tonic-gate * mp->b_cont may be nil'ed during processing so we 1517*7c478bd9Sstevel@tonic-gate * can't rely on it to find the next block. 1518*7c478bd9Sstevel@tonic-gate */ 1519*7c478bd9Sstevel@tonic-gate cont_mp = mp->b_cont; 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate /* 1522*7c478bd9Sstevel@tonic-gate * Get local copies of rptr and wptr for our processing. 1523*7c478bd9Sstevel@tonic-gate * These always point into "mp" (the current block being 1524*7c478bd9Sstevel@tonic-gate * processed), but rptr is updated as we consume any 1525*7c478bd9Sstevel@tonic-gate * record header in this message, and wptr is updated to 1526*7c478bd9Sstevel@tonic-gate * point to the end of the data for the current fragment, 1527*7c478bd9Sstevel@tonic-gate * if it ends in this block. The main point is that 1528*7c478bd9Sstevel@tonic-gate * they are not always the same as b_rptr and b_wptr. 1529*7c478bd9Sstevel@tonic-gate * b_rptr and b_wptr will be updated when appropriate. 1530*7c478bd9Sstevel@tonic-gate */ 1531*7c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 1532*7c478bd9Sstevel@tonic-gate wptr = mp->b_wptr; 1533*7c478bd9Sstevel@tonic-gate same_mblk:; 1534*7c478bd9Sstevel@tonic-gate len = (int)(wptr - rptr); 1535*7c478bd9Sstevel@tonic-gate if (len <= 0) { 1536*7c478bd9Sstevel@tonic-gate /* 1537*7c478bd9Sstevel@tonic-gate * If we have processed all of the data in the message 1538*7c478bd9Sstevel@tonic-gate * or the block is empty to begin with, then we're 1539*7c478bd9Sstevel@tonic-gate * done with this block and can go on to cont_mp, 1540*7c478bd9Sstevel@tonic-gate * if there is one. 1541*7c478bd9Sstevel@tonic-gate * 1542*7c478bd9Sstevel@tonic-gate * First, we check to see if the current block is 1543*7c478bd9Sstevel@tonic-gate * now zero-length and, if so, we free it. 1544*7c478bd9Sstevel@tonic-gate * This happens when either the block was empty 1545*7c478bd9Sstevel@tonic-gate * to begin with or we consumed all of the data 1546*7c478bd9Sstevel@tonic-gate * for the record marking header. 1547*7c478bd9Sstevel@tonic-gate */ 1548*7c478bd9Sstevel@tonic-gate if (rptr <= mp->b_rptr) { 1549*7c478bd9Sstevel@tonic-gate /* 1550*7c478bd9Sstevel@tonic-gate * If head_mp is non-NULL, add cont_mp to the 1551*7c478bd9Sstevel@tonic-gate * mblk list. XXX But there is a possibility 1552*7c478bd9Sstevel@tonic-gate * that tail_mp = mp or even head_mp = mp XXX 1553*7c478bd9Sstevel@tonic-gate */ 1554*7c478bd9Sstevel@tonic-gate if (head_mp) { 1555*7c478bd9Sstevel@tonic-gate if (head_mp == mp) 1556*7c478bd9Sstevel@tonic-gate head_mp = NULL; 1557*7c478bd9Sstevel@tonic-gate else if (tail_mp != mp) { 1558*7c478bd9Sstevel@tonic-gate ASSERT((tail_mp->b_cont == NULL) || (tail_mp->b_cont == mp)); 1559*7c478bd9Sstevel@tonic-gate tail_mp->b_cont = cont_mp; 1560*7c478bd9Sstevel@tonic-gate /* 1561*7c478bd9Sstevel@tonic-gate * It's possible that, because 1562*7c478bd9Sstevel@tonic-gate * of a very short mblk (0-3 1563*7c478bd9Sstevel@tonic-gate * bytes), we've ended up here 1564*7c478bd9Sstevel@tonic-gate * and that cont_mp could be 1565*7c478bd9Sstevel@tonic-gate * NULL (if we're at the end 1566*7c478bd9Sstevel@tonic-gate * of an mblk chain). If so, 1567*7c478bd9Sstevel@tonic-gate * don't set tail_mp to 1568*7c478bd9Sstevel@tonic-gate * cont_mp, because the next 1569*7c478bd9Sstevel@tonic-gate * time we access it, we'll 1570*7c478bd9Sstevel@tonic-gate * dereference a NULL pointer 1571*7c478bd9Sstevel@tonic-gate * and crash. Just leave 1572*7c478bd9Sstevel@tonic-gate * tail_mp pointing at the 1573*7c478bd9Sstevel@tonic-gate * current end of chain. 1574*7c478bd9Sstevel@tonic-gate */ 1575*7c478bd9Sstevel@tonic-gate if (cont_mp) 1576*7c478bd9Sstevel@tonic-gate tail_mp = cont_mp; 1577*7c478bd9Sstevel@tonic-gate } else { 1578*7c478bd9Sstevel@tonic-gate mblk_t *smp = head_mp; 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate while ((smp->b_cont != NULL) && 1581*7c478bd9Sstevel@tonic-gate (smp->b_cont != mp)) 1582*7c478bd9Sstevel@tonic-gate smp = smp->b_cont; 1583*7c478bd9Sstevel@tonic-gate smp->b_cont = cont_mp; 1584*7c478bd9Sstevel@tonic-gate /* 1585*7c478bd9Sstevel@tonic-gate * Don't set tail_mp to cont_mp 1586*7c478bd9Sstevel@tonic-gate * if it's NULL. Instead, set 1587*7c478bd9Sstevel@tonic-gate * tail_mp to smp, which is the 1588*7c478bd9Sstevel@tonic-gate * end of the chain starting 1589*7c478bd9Sstevel@tonic-gate * at head_mp. 1590*7c478bd9Sstevel@tonic-gate */ 1591*7c478bd9Sstevel@tonic-gate if (cont_mp) 1592*7c478bd9Sstevel@tonic-gate tail_mp = cont_mp; 1593*7c478bd9Sstevel@tonic-gate else 1594*7c478bd9Sstevel@tonic-gate tail_mp = smp; 1595*7c478bd9Sstevel@tonic-gate } 1596*7c478bd9Sstevel@tonic-gate } 1597*7c478bd9Sstevel@tonic-gate freeb(mp); 1598*7c478bd9Sstevel@tonic-gate } 1599*7c478bd9Sstevel@tonic-gate continue; 1600*7c478bd9Sstevel@tonic-gate } 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate /* 1603*7c478bd9Sstevel@tonic-gate * frag_len starts at -4 and is incremented past the record 1604*7c478bd9Sstevel@tonic-gate * marking header to 0, and then becomes positive as real data 1605*7c478bd9Sstevel@tonic-gate * bytes are received for the message. While frag_len is less 1606*7c478bd9Sstevel@tonic-gate * than zero, we need more bytes for the record marking 1607*7c478bd9Sstevel@tonic-gate * header. 1608*7c478bd9Sstevel@tonic-gate */ 1609*7c478bd9Sstevel@tonic-gate if (frag_len < 0) { 1610*7c478bd9Sstevel@tonic-gate uchar_t *up = rptr; 1611*7c478bd9Sstevel@tonic-gate /* 1612*7c478bd9Sstevel@tonic-gate * Collect as many bytes as we need for the record 1613*7c478bd9Sstevel@tonic-gate * marking header and that are available in this block. 1614*7c478bd9Sstevel@tonic-gate */ 1615*7c478bd9Sstevel@tonic-gate do { 1616*7c478bd9Sstevel@tonic-gate --len; 1617*7c478bd9Sstevel@tonic-gate frag_len++; 1618*7c478bd9Sstevel@tonic-gate frag_header <<= 8; 1619*7c478bd9Sstevel@tonic-gate frag_header += (*up++ & 0xFF); 1620*7c478bd9Sstevel@tonic-gate } while (len > 0 && frag_len < 0); 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate if (rptr == mp->b_rptr) { 1623*7c478bd9Sstevel@tonic-gate /* 1624*7c478bd9Sstevel@tonic-gate * The record header is located at the 1625*7c478bd9Sstevel@tonic-gate * beginning of the block, so just walk 1626*7c478bd9Sstevel@tonic-gate * b_rptr past it. 1627*7c478bd9Sstevel@tonic-gate */ 1628*7c478bd9Sstevel@tonic-gate mp->b_rptr = rptr = up; 1629*7c478bd9Sstevel@tonic-gate } else { 1630*7c478bd9Sstevel@tonic-gate /* 1631*7c478bd9Sstevel@tonic-gate * The record header is located in the middle 1632*7c478bd9Sstevel@tonic-gate * of a block, so copy any remaining data up. 1633*7c478bd9Sstevel@tonic-gate * This happens when an RPC message is 1634*7c478bd9Sstevel@tonic-gate * fragmented into multiple pieces and 1635*7c478bd9Sstevel@tonic-gate * a middle (or end) fragment immediately 1636*7c478bd9Sstevel@tonic-gate * follows a previous fragment in the same 1637*7c478bd9Sstevel@tonic-gate * message block. 1638*7c478bd9Sstevel@tonic-gate */ 1639*7c478bd9Sstevel@tonic-gate wptr = &rptr[len]; 1640*7c478bd9Sstevel@tonic-gate mp->b_wptr = wptr; 1641*7c478bd9Sstevel@tonic-gate if (len) { 1642*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: copying %d " 1643*7c478bd9Sstevel@tonic-gate "bytes of data up", len); 1644*7c478bd9Sstevel@tonic-gate RPCLOG(32, " db_ref %d\n", 1645*7c478bd9Sstevel@tonic-gate (uint_t)mp->b_datap->db_ref); 1646*7c478bd9Sstevel@tonic-gate bcopy(up, rptr, len); 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate /* 1651*7c478bd9Sstevel@tonic-gate * If we haven't received the complete record header 1652*7c478bd9Sstevel@tonic-gate * yet, then loop around to get the next block in the 1653*7c478bd9Sstevel@tonic-gate * STREAMS message. The logic at same_mblk label will 1654*7c478bd9Sstevel@tonic-gate * free the current block if it has become empty. 1655*7c478bd9Sstevel@tonic-gate */ 1656*7c478bd9Sstevel@tonic-gate if (frag_len < 0) { 1657*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: frag_len is still < 0 " 1658*7c478bd9Sstevel@tonic-gate "(%d)", len); 1659*7c478bd9Sstevel@tonic-gate goto same_mblk; 1660*7c478bd9Sstevel@tonic-gate } 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate #ifdef RPCDEBUG 1663*7c478bd9Sstevel@tonic-gate if ((frag_header & MIR_LASTFRAG) == 0) { 1664*7c478bd9Sstevel@tonic-gate RPCLOG0(32, "mir_do_rput: multi-fragment " 1665*7c478bd9Sstevel@tonic-gate "record\n"); 1666*7c478bd9Sstevel@tonic-gate } 1667*7c478bd9Sstevel@tonic-gate { 1668*7c478bd9Sstevel@tonic-gate uint_t l = frag_header & ~MIR_LASTFRAG; 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate if (l != 0 && mir->mir_max_msg_sizep && 1671*7c478bd9Sstevel@tonic-gate l >= *mir->mir_max_msg_sizep) { 1672*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: fragment size" 1673*7c478bd9Sstevel@tonic-gate " (%d) > maximum", l); 1674*7c478bd9Sstevel@tonic-gate RPCLOG(32, " (%u)\n", 1675*7c478bd9Sstevel@tonic-gate *mir->mir_max_msg_sizep); 1676*7c478bd9Sstevel@tonic-gate } 1677*7c478bd9Sstevel@tonic-gate } 1678*7c478bd9Sstevel@tonic-gate #endif 1679*7c478bd9Sstevel@tonic-gate /* 1680*7c478bd9Sstevel@tonic-gate * At this point we have retrieved the complete record 1681*7c478bd9Sstevel@tonic-gate * header for this fragment. If the current block is 1682*7c478bd9Sstevel@tonic-gate * empty, then we need to free it and walk to the next 1683*7c478bd9Sstevel@tonic-gate * block. 1684*7c478bd9Sstevel@tonic-gate */ 1685*7c478bd9Sstevel@tonic-gate if (mp->b_rptr >= wptr) { 1686*7c478bd9Sstevel@tonic-gate /* 1687*7c478bd9Sstevel@tonic-gate * If this is not the last fragment or if we 1688*7c478bd9Sstevel@tonic-gate * have not received all the data for this 1689*7c478bd9Sstevel@tonic-gate * RPC message, then loop around to the next 1690*7c478bd9Sstevel@tonic-gate * block. 1691*7c478bd9Sstevel@tonic-gate */ 1692*7c478bd9Sstevel@tonic-gate if (!(frag_header & MIR_LASTFRAG) || 1693*7c478bd9Sstevel@tonic-gate (frag_len - 1694*7c478bd9Sstevel@tonic-gate (frag_header & ~MIR_LASTFRAG)) || 1695*7c478bd9Sstevel@tonic-gate !head_mp) 1696*7c478bd9Sstevel@tonic-gate goto same_mblk; 1697*7c478bd9Sstevel@tonic-gate 1698*7c478bd9Sstevel@tonic-gate /* 1699*7c478bd9Sstevel@tonic-gate * Quick walk to next block in the 1700*7c478bd9Sstevel@tonic-gate * STREAMS message. 1701*7c478bd9Sstevel@tonic-gate */ 1702*7c478bd9Sstevel@tonic-gate freeb(mp); 1703*7c478bd9Sstevel@tonic-gate continue; 1704*7c478bd9Sstevel@tonic-gate } 1705*7c478bd9Sstevel@tonic-gate } 1706*7c478bd9Sstevel@tonic-gate 1707*7c478bd9Sstevel@tonic-gate /* 1708*7c478bd9Sstevel@tonic-gate * We've collected the complete record header. The data 1709*7c478bd9Sstevel@tonic-gate * in the current block is added to the end of the RPC 1710*7c478bd9Sstevel@tonic-gate * message. Note that tail_mp is the same as mp after 1711*7c478bd9Sstevel@tonic-gate * this linkage. 1712*7c478bd9Sstevel@tonic-gate */ 1713*7c478bd9Sstevel@tonic-gate if (!head_mp) 1714*7c478bd9Sstevel@tonic-gate head_mp = mp; 1715*7c478bd9Sstevel@tonic-gate else if (tail_mp != mp) { 1716*7c478bd9Sstevel@tonic-gate ASSERT((tail_mp->b_cont == NULL) || 1717*7c478bd9Sstevel@tonic-gate (tail_mp->b_cont == mp)); 1718*7c478bd9Sstevel@tonic-gate tail_mp->b_cont = mp; 1719*7c478bd9Sstevel@tonic-gate } 1720*7c478bd9Sstevel@tonic-gate tail_mp = mp; 1721*7c478bd9Sstevel@tonic-gate 1722*7c478bd9Sstevel@tonic-gate /* 1723*7c478bd9Sstevel@tonic-gate * Add the length of this block to the accumulated 1724*7c478bd9Sstevel@tonic-gate * fragment length. 1725*7c478bd9Sstevel@tonic-gate */ 1726*7c478bd9Sstevel@tonic-gate frag_len += len; 1727*7c478bd9Sstevel@tonic-gate excess = frag_len - (frag_header & ~MIR_LASTFRAG); 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate * If we have not received all the data for this fragment, 1730*7c478bd9Sstevel@tonic-gate * then walk to the next block. 1731*7c478bd9Sstevel@tonic-gate */ 1732*7c478bd9Sstevel@tonic-gate if (excess < 0) 1733*7c478bd9Sstevel@tonic-gate continue; 1734*7c478bd9Sstevel@tonic-gate 1735*7c478bd9Sstevel@tonic-gate /* 1736*7c478bd9Sstevel@tonic-gate * We've received a complete fragment, so reset frag_len 1737*7c478bd9Sstevel@tonic-gate * for the next one. 1738*7c478bd9Sstevel@tonic-gate */ 1739*7c478bd9Sstevel@tonic-gate frag_len = -(int32_t)sizeof (uint32_t); 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate /* 1742*7c478bd9Sstevel@tonic-gate * Update rptr to point to the beginning of the next 1743*7c478bd9Sstevel@tonic-gate * fragment in this block. If there are no more bytes 1744*7c478bd9Sstevel@tonic-gate * in the block (excess is 0), then rptr will be equal 1745*7c478bd9Sstevel@tonic-gate * to wptr. 1746*7c478bd9Sstevel@tonic-gate */ 1747*7c478bd9Sstevel@tonic-gate rptr = wptr - excess; 1748*7c478bd9Sstevel@tonic-gate 1749*7c478bd9Sstevel@tonic-gate /* 1750*7c478bd9Sstevel@tonic-gate * Now we check to see if this fragment is the last one in 1751*7c478bd9Sstevel@tonic-gate * the RPC message. 1752*7c478bd9Sstevel@tonic-gate */ 1753*7c478bd9Sstevel@tonic-gate if (!(frag_header & MIR_LASTFRAG)) { 1754*7c478bd9Sstevel@tonic-gate /* 1755*7c478bd9Sstevel@tonic-gate * This isn't the last one, so start processing the 1756*7c478bd9Sstevel@tonic-gate * next fragment. 1757*7c478bd9Sstevel@tonic-gate */ 1758*7c478bd9Sstevel@tonic-gate frag_header = 0; 1759*7c478bd9Sstevel@tonic-gate 1760*7c478bd9Sstevel@tonic-gate /* 1761*7c478bd9Sstevel@tonic-gate * If excess is 0, the next fragment 1762*7c478bd9Sstevel@tonic-gate * starts at the beginning of the next block -- 1763*7c478bd9Sstevel@tonic-gate * we "continue" to the end of the while loop and 1764*7c478bd9Sstevel@tonic-gate * walk to cont_mp. 1765*7c478bd9Sstevel@tonic-gate */ 1766*7c478bd9Sstevel@tonic-gate if (excess == 0) 1767*7c478bd9Sstevel@tonic-gate continue; 1768*7c478bd9Sstevel@tonic-gate RPCLOG0(32, "mir_do_rput: multi-fragment message with " 1769*7c478bd9Sstevel@tonic-gate "two or more fragments in one mblk\n"); 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate /* 1772*7c478bd9Sstevel@tonic-gate * If excess is non-0, then the next fragment starts 1773*7c478bd9Sstevel@tonic-gate * in this block. rptr points to the beginning 1774*7c478bd9Sstevel@tonic-gate * of the next fragment and we "goto same_mblk" 1775*7c478bd9Sstevel@tonic-gate * to continue processing. 1776*7c478bd9Sstevel@tonic-gate */ 1777*7c478bd9Sstevel@tonic-gate goto same_mblk; 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate /* 1781*7c478bd9Sstevel@tonic-gate * We've got a complete RPC message. Before passing it 1782*7c478bd9Sstevel@tonic-gate * upstream, check to see if there is extra data in this 1783*7c478bd9Sstevel@tonic-gate * message block. If so, then we separate the excess 1784*7c478bd9Sstevel@tonic-gate * from the complete message. The excess data is processed 1785*7c478bd9Sstevel@tonic-gate * after the current message goes upstream. 1786*7c478bd9Sstevel@tonic-gate */ 1787*7c478bd9Sstevel@tonic-gate if (excess > 0) { 1788*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_do_rput: end of record, but excess " 1789*7c478bd9Sstevel@tonic-gate "data (%d bytes) in this mblk. dupb/copyb " 1790*7c478bd9Sstevel@tonic-gate "needed\n", excess); 1791*7c478bd9Sstevel@tonic-gate 1792*7c478bd9Sstevel@tonic-gate /* Duplicate only the overlapping block. */ 1793*7c478bd9Sstevel@tonic-gate mp1 = dupb(tail_mp); 1794*7c478bd9Sstevel@tonic-gate 1795*7c478bd9Sstevel@tonic-gate /* 1796*7c478bd9Sstevel@tonic-gate * dupb() might have failed due to ref count wrap around 1797*7c478bd9Sstevel@tonic-gate * so try a copyb(). 1798*7c478bd9Sstevel@tonic-gate */ 1799*7c478bd9Sstevel@tonic-gate if (mp1 == NULL) 1800*7c478bd9Sstevel@tonic-gate mp1 = copyb(tail_mp); 1801*7c478bd9Sstevel@tonic-gate 1802*7c478bd9Sstevel@tonic-gate /* 1803*7c478bd9Sstevel@tonic-gate * Do not use bufcall() to schedule a "buffer 1804*7c478bd9Sstevel@tonic-gate * availability event." The reason is that 1805*7c478bd9Sstevel@tonic-gate * bufcall() has problems. For example, if memory 1806*7c478bd9Sstevel@tonic-gate * runs out, bufcall() itself will fail since it 1807*7c478bd9Sstevel@tonic-gate * needs to allocate memory. The most appropriate 1808*7c478bd9Sstevel@tonic-gate * action right now is to disconnect this connection 1809*7c478bd9Sstevel@tonic-gate * as the system is under stress. We should try to 1810*7c478bd9Sstevel@tonic-gate * free up resources. 1811*7c478bd9Sstevel@tonic-gate */ 1812*7c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 1813*7c478bd9Sstevel@tonic-gate freemsg(head_mp); 1814*7c478bd9Sstevel@tonic-gate RPCLOG0(1, "mir_do_rput: dupb/copyb failed\n"); 1815*7c478bd9Sstevel@tonic-gate mir->mir_frag_header = 0; 1816*7c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int)sizeof (uint32_t); 1817*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = NULL; 1818*7c478bd9Sstevel@tonic-gate mir->mir_tail_mp = NULL; 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate mir_disconnect(q, mir); 1821*7c478bd9Sstevel@tonic-gate return; 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate 1824*7c478bd9Sstevel@tonic-gate /* 1825*7c478bd9Sstevel@tonic-gate * The new message block is linked with the 1826*7c478bd9Sstevel@tonic-gate * continuation block in cont_mp. We then point 1827*7c478bd9Sstevel@tonic-gate * cont_mp to the new block so that we will 1828*7c478bd9Sstevel@tonic-gate * process it next. 1829*7c478bd9Sstevel@tonic-gate */ 1830*7c478bd9Sstevel@tonic-gate mp1->b_cont = cont_mp; 1831*7c478bd9Sstevel@tonic-gate cont_mp = mp1; 1832*7c478bd9Sstevel@tonic-gate /* 1833*7c478bd9Sstevel@tonic-gate * Data in the new block begins at the 1834*7c478bd9Sstevel@tonic-gate * next fragment (rptr). 1835*7c478bd9Sstevel@tonic-gate */ 1836*7c478bd9Sstevel@tonic-gate cont_mp->b_rptr += (rptr - tail_mp->b_rptr); 1837*7c478bd9Sstevel@tonic-gate ASSERT(cont_mp->b_rptr >= cont_mp->b_datap->db_base); 1838*7c478bd9Sstevel@tonic-gate ASSERT(cont_mp->b_rptr <= cont_mp->b_wptr); 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate /* Data in the current fragment ends at rptr. */ 1841*7c478bd9Sstevel@tonic-gate tail_mp->b_wptr = rptr; 1842*7c478bd9Sstevel@tonic-gate ASSERT(tail_mp->b_wptr <= tail_mp->b_datap->db_lim); 1843*7c478bd9Sstevel@tonic-gate ASSERT(tail_mp->b_wptr >= tail_mp->b_rptr); 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate } 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate /* tail_mp is the last block with data for this RPC message. */ 1848*7c478bd9Sstevel@tonic-gate tail_mp->b_cont = NULL; 1849*7c478bd9Sstevel@tonic-gate 1850*7c478bd9Sstevel@tonic-gate /* Pass the RPC message to the current consumer. */ 1851*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 1852*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 1853*7c478bd9Sstevel@tonic-gate if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) { 1854*7c478bd9Sstevel@tonic-gate /* 1855*7c478bd9Sstevel@tonic-gate * Mark this stream as active. This marker 1856*7c478bd9Sstevel@tonic-gate * is used in mir_timer(). 1857*7c478bd9Sstevel@tonic-gate */ 1858*7c478bd9Sstevel@tonic-gate 1859*7c478bd9Sstevel@tonic-gate mir->mir_clntreq = 1; 1860*7c478bd9Sstevel@tonic-gate mir->mir_use_timestamp = lbolt; 1861*7c478bd9Sstevel@tonic-gate } else 1862*7c478bd9Sstevel@tonic-gate freemsg(head_mp); 1863*7c478bd9Sstevel@tonic-gate break; 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 1866*7c478bd9Sstevel@tonic-gate /* 1867*7c478bd9Sstevel@tonic-gate * Check for flow control before passing the 1868*7c478bd9Sstevel@tonic-gate * message to KRPC. 1869*7c478bd9Sstevel@tonic-gate */ 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate if (!mir->mir_hold_inbound) { 1872*7c478bd9Sstevel@tonic-gate if (mir->mir_krpc_cell) { 1873*7c478bd9Sstevel@tonic-gate /* 1874*7c478bd9Sstevel@tonic-gate * If the reference count is 0 1875*7c478bd9Sstevel@tonic-gate * (not including this request), 1876*7c478bd9Sstevel@tonic-gate * then the stream is transitioning 1877*7c478bd9Sstevel@tonic-gate * from idle to non-idle. In this case, 1878*7c478bd9Sstevel@tonic-gate * we cancel the idle timer. 1879*7c478bd9Sstevel@tonic-gate */ 1880*7c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0) 1881*7c478bd9Sstevel@tonic-gate stop_timer = B_TRUE; 1882*7c478bd9Sstevel@tonic-gate if (mir_check_len(q, 1883*7c478bd9Sstevel@tonic-gate (int32_t)msgdsize(mp), mp)) 1884*7c478bd9Sstevel@tonic-gate return; 1885*7c478bd9Sstevel@tonic-gate svc_queuereq(q, head_mp); /* to KRPC */ 1886*7c478bd9Sstevel@tonic-gate } else { 1887*7c478bd9Sstevel@tonic-gate /* 1888*7c478bd9Sstevel@tonic-gate * Count # of times this happens. Should be 1889*7c478bd9Sstevel@tonic-gate * never, but experience shows otherwise. 1890*7c478bd9Sstevel@tonic-gate */ 1891*7c478bd9Sstevel@tonic-gate mir_krpc_cell_null++; 1892*7c478bd9Sstevel@tonic-gate freemsg(head_mp); 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate 1895*7c478bd9Sstevel@tonic-gate } else { 1896*7c478bd9Sstevel@tonic-gate /* 1897*7c478bd9Sstevel@tonic-gate * If the outbound side of the stream is 1898*7c478bd9Sstevel@tonic-gate * flow controlled, then hold this message 1899*7c478bd9Sstevel@tonic-gate * until client catches up. mir_hold_inbound 1900*7c478bd9Sstevel@tonic-gate * is set in mir_wput and cleared in mir_wsrv. 1901*7c478bd9Sstevel@tonic-gate */ 1902*7c478bd9Sstevel@tonic-gate if (srv) 1903*7c478bd9Sstevel@tonic-gate (void) putbq(q, head_mp); 1904*7c478bd9Sstevel@tonic-gate else 1905*7c478bd9Sstevel@tonic-gate (void) putq(q, head_mp); 1906*7c478bd9Sstevel@tonic-gate mir->mir_inrservice = B_TRUE; 1907*7c478bd9Sstevel@tonic-gate } 1908*7c478bd9Sstevel@tonic-gate break; 1909*7c478bd9Sstevel@tonic-gate default: 1910*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: unknown mir_type %d\n", 1911*7c478bd9Sstevel@tonic-gate mir->mir_type); 1912*7c478bd9Sstevel@tonic-gate freemsg(head_mp); 1913*7c478bd9Sstevel@tonic-gate break; 1914*7c478bd9Sstevel@tonic-gate } 1915*7c478bd9Sstevel@tonic-gate 1916*7c478bd9Sstevel@tonic-gate /* 1917*7c478bd9Sstevel@tonic-gate * Reset head_mp and frag_header since we're starting on a 1918*7c478bd9Sstevel@tonic-gate * new RPC fragment and message. 1919*7c478bd9Sstevel@tonic-gate */ 1920*7c478bd9Sstevel@tonic-gate head_mp = NULL; 1921*7c478bd9Sstevel@tonic-gate tail_mp = NULL; 1922*7c478bd9Sstevel@tonic-gate frag_header = 0; 1923*7c478bd9Sstevel@tonic-gate } while ((mp = cont_mp) != NULL); 1924*7c478bd9Sstevel@tonic-gate 1925*7c478bd9Sstevel@tonic-gate /* 1926*7c478bd9Sstevel@tonic-gate * Do a sanity check on the message length. If this message is 1927*7c478bd9Sstevel@tonic-gate * getting excessively large, shut down the connection. 1928*7c478bd9Sstevel@tonic-gate */ 1929*7c478bd9Sstevel@tonic-gate if (head_mp != NULL && mir->mir_setup_complete && 1930*7c478bd9Sstevel@tonic-gate mir_check_len(q, frag_len, head_mp)) 1931*7c478bd9Sstevel@tonic-gate return; 1932*7c478bd9Sstevel@tonic-gate 1933*7c478bd9Sstevel@tonic-gate /* Save our local copies back in the mir structure. */ 1934*7c478bd9Sstevel@tonic-gate mir->mir_frag_header = frag_header; 1935*7c478bd9Sstevel@tonic-gate mir->mir_frag_len = frag_len; 1936*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = head_mp; 1937*7c478bd9Sstevel@tonic-gate mir->mir_tail_mp = tail_mp; 1938*7c478bd9Sstevel@tonic-gate 1939*7c478bd9Sstevel@tonic-gate /* 1940*7c478bd9Sstevel@tonic-gate * The timer is stopped after the whole message chain is processed. 1941*7c478bd9Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex 1942*7c478bd9Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced 1943*7c478bd9Sstevel@tonic-gate * while we are still processing the message chain. This is not 1944*7c478bd9Sstevel@tonic-gate * good. So we stop the timer here instead. 1945*7c478bd9Sstevel@tonic-gate * 1946*7c478bd9Sstevel@tonic-gate * Note that if the timer fires before we stop it, it will not 1947*7c478bd9Sstevel@tonic-gate * do any harm as MIR_SVC_QUIESCED() is false and mir_timer() 1948*7c478bd9Sstevel@tonic-gate * will just return; 1949*7c478bd9Sstevel@tonic-gate */ 1950*7c478bd9Sstevel@tonic-gate if (stop_timer) { 1951*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_do_rput stopping idle timer on 0x%p because " 1952*7c478bd9Sstevel@tonic-gate "ref cnt going to non zero\n", (void *) WR(q)); 1953*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 1954*7c478bd9Sstevel@tonic-gate } 1955*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate static void 1959*7c478bd9Sstevel@tonic-gate mir_rput(queue_t *q, mblk_t *mp) 1960*7c478bd9Sstevel@tonic-gate { 1961*7c478bd9Sstevel@tonic-gate mir_do_rput(q, mp, 0); 1962*7c478bd9Sstevel@tonic-gate } 1963*7c478bd9Sstevel@tonic-gate 1964*7c478bd9Sstevel@tonic-gate static void 1965*7c478bd9Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp) 1966*7c478bd9Sstevel@tonic-gate { 1967*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 1968*7c478bd9Sstevel@tonic-gate uint32_t type; 1969*7c478bd9Sstevel@tonic-gate uint32_t reason = 0; 1970*7c478bd9Sstevel@tonic-gate 1971*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 1972*7c478bd9Sstevel@tonic-gate 1973*7c478bd9Sstevel@tonic-gate type = ((union T_primitives *)mp->b_rptr)->type; 1974*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 1975*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 1976*7c478bd9Sstevel@tonic-gate switch (type) { 1977*7c478bd9Sstevel@tonic-gate case T_DISCON_IND: 1978*7c478bd9Sstevel@tonic-gate reason = 1979*7c478bd9Sstevel@tonic-gate ((struct T_discon_ind *)(mp->b_rptr))->DISCON_reason; 1980*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 1981*7c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 1982*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 1983*7c478bd9Sstevel@tonic-gate if (mir->mir_head_mp) { 1984*7c478bd9Sstevel@tonic-gate freemsg(mir->mir_head_mp); 1985*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 1986*7c478bd9Sstevel@tonic-gate mir->mir_tail_mp = (mblk_t *)0; 1987*7c478bd9Sstevel@tonic-gate } 1988*7c478bd9Sstevel@tonic-gate /* 1989*7c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily 1990*7c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to 1991*7c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value, 1992*7c478bd9Sstevel@tonic-gate * unless we store it now. 1993*7c478bd9Sstevel@tonic-gate */ 1994*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 1995*7c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(WR(q), mir); 1996*7c478bd9Sstevel@tonic-gate 1997*7c478bd9Sstevel@tonic-gate /* 1998*7c478bd9Sstevel@tonic-gate * Even though we are unconnected, we still 1999*7c478bd9Sstevel@tonic-gate * leave the idle timer going on the client. The 2000*7c478bd9Sstevel@tonic-gate * reason for is that if we've disconnected due 2001*7c478bd9Sstevel@tonic-gate * to a server-side disconnect, reset, or connection 2002*7c478bd9Sstevel@tonic-gate * timeout, there is a possibility the client may 2003*7c478bd9Sstevel@tonic-gate * retry the RPC request. This retry needs to done on 2004*7c478bd9Sstevel@tonic-gate * the same bound address for the server to interpret 2005*7c478bd9Sstevel@tonic-gate * it as such. However, we don't want 2006*7c478bd9Sstevel@tonic-gate * to wait forever for that possibility. If the 2007*7c478bd9Sstevel@tonic-gate * end-point stays unconnected for mir_idle_timeout 2008*7c478bd9Sstevel@tonic-gate * units of time, then that is a signal to the 2009*7c478bd9Sstevel@tonic-gate * connection manager to give up waiting for the 2010*7c478bd9Sstevel@tonic-gate * application (eg. NFS) to send a retry. 2011*7c478bd9Sstevel@tonic-gate */ 2012*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir); 2013*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2014*7c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 2015*7c478bd9Sstevel@tonic-gate freemsg(mp); 2016*7c478bd9Sstevel@tonic-gate return; 2017*7c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 2018*7c478bd9Sstevel@tonic-gate { 2019*7c478bd9Sstevel@tonic-gate struct T_error_ack *terror; 2020*7c478bd9Sstevel@tonic-gate 2021*7c478bd9Sstevel@tonic-gate terror = (struct T_error_ack *)mp->b_rptr; 2022*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p", 2023*7c478bd9Sstevel@tonic-gate (void *)q); 2024*7c478bd9Sstevel@tonic-gate RPCLOG(1, " ERROR_prim: %s,", 2025*7c478bd9Sstevel@tonic-gate rpc_tpiprim2name(terror->ERROR_prim)); 2026*7c478bd9Sstevel@tonic-gate RPCLOG(1, " TLI_error: %s,", 2027*7c478bd9Sstevel@tonic-gate rpc_tpierr2name(terror->TLI_error)); 2028*7c478bd9Sstevel@tonic-gate RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error); 2029*7c478bd9Sstevel@tonic-gate if (terror->ERROR_prim == T_DISCON_REQ) { 2030*7c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 2031*7c478bd9Sstevel@tonic-gate freemsg(mp); 2032*7c478bd9Sstevel@tonic-gate return; 2033*7c478bd9Sstevel@tonic-gate } else { 2034*7c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 2035*7c478bd9Sstevel@tonic-gate return; 2036*7c478bd9Sstevel@tonic-gate } 2037*7c478bd9Sstevel@tonic-gate break; 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate case T_OK_ACK: 2040*7c478bd9Sstevel@tonic-gate { 2041*7c478bd9Sstevel@tonic-gate struct T_ok_ack *tok = (struct T_ok_ack *)mp->b_rptr; 2042*7c478bd9Sstevel@tonic-gate 2043*7c478bd9Sstevel@tonic-gate if (tok->CORRECT_prim == T_DISCON_REQ) { 2044*7c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason); 2045*7c478bd9Sstevel@tonic-gate freemsg(mp); 2046*7c478bd9Sstevel@tonic-gate return; 2047*7c478bd9Sstevel@tonic-gate } else { 2048*7c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 2049*7c478bd9Sstevel@tonic-gate return; 2050*7c478bd9Sstevel@tonic-gate } 2051*7c478bd9Sstevel@tonic-gate break; 2052*7c478bd9Sstevel@tonic-gate } 2053*7c478bd9Sstevel@tonic-gate case T_CONN_CON: 2054*7c478bd9Sstevel@tonic-gate case T_INFO_ACK: 2055*7c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 2056*7c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp)) 2057*7c478bd9Sstevel@tonic-gate return; 2058*7c478bd9Sstevel@tonic-gate break; 2059*7c478bd9Sstevel@tonic-gate case T_BIND_ACK: 2060*7c478bd9Sstevel@tonic-gate break; 2061*7c478bd9Sstevel@tonic-gate default: 2062*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: unexpected message %d " 2063*7c478bd9Sstevel@tonic-gate "for KRPC client\n", 2064*7c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type); 2065*7c478bd9Sstevel@tonic-gate break; 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate break; 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 2070*7c478bd9Sstevel@tonic-gate switch (type) { 2071*7c478bd9Sstevel@tonic-gate case T_BIND_ACK: 2072*7c478bd9Sstevel@tonic-gate { 2073*7c478bd9Sstevel@tonic-gate struct T_bind_ack *tbind; 2074*7c478bd9Sstevel@tonic-gate 2075*7c478bd9Sstevel@tonic-gate /* 2076*7c478bd9Sstevel@tonic-gate * If this is a listening stream, then shut 2077*7c478bd9Sstevel@tonic-gate * off the idle timer. 2078*7c478bd9Sstevel@tonic-gate */ 2079*7c478bd9Sstevel@tonic-gate tbind = (struct T_bind_ack *)mp->b_rptr; 2080*7c478bd9Sstevel@tonic-gate if (tbind->CONIND_number > 0) { 2081*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2082*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate /* 2085*7c478bd9Sstevel@tonic-gate * mark this as a listen endpoint 2086*7c478bd9Sstevel@tonic-gate * for special handling. 2087*7c478bd9Sstevel@tonic-gate */ 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate mir->mir_listen_stream = 1; 2090*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2091*7c478bd9Sstevel@tonic-gate } 2092*7c478bd9Sstevel@tonic-gate break; 2093*7c478bd9Sstevel@tonic-gate } 2094*7c478bd9Sstevel@tonic-gate case T_DISCON_IND: 2095*7c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 2096*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: got %s indication\n", 2097*7c478bd9Sstevel@tonic-gate type == T_DISCON_IND ? "disconnect" 2098*7c478bd9Sstevel@tonic-gate : "orderly release"); 2099*7c478bd9Sstevel@tonic-gate 2100*7c478bd9Sstevel@tonic-gate /* 2101*7c478bd9Sstevel@tonic-gate * For listen endpoint just pass 2102*7c478bd9Sstevel@tonic-gate * on the message. 2103*7c478bd9Sstevel@tonic-gate */ 2104*7c478bd9Sstevel@tonic-gate 2105*7c478bd9Sstevel@tonic-gate if (mir->mir_listen_stream) 2106*7c478bd9Sstevel@tonic-gate break; 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate /* 2111*7c478bd9Sstevel@tonic-gate * If client wants to break off connection, record 2112*7c478bd9Sstevel@tonic-gate * that fact. 2113*7c478bd9Sstevel@tonic-gate */ 2114*7c478bd9Sstevel@tonic-gate mir_svc_start_close(WR(q), mir); 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate /* 2117*7c478bd9Sstevel@tonic-gate * If we are idle, then send the orderly release 2118*7c478bd9Sstevel@tonic-gate * or disconnect indication to nfsd. 2119*7c478bd9Sstevel@tonic-gate */ 2120*7c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 2121*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2122*7c478bd9Sstevel@tonic-gate break; 2123*7c478bd9Sstevel@tonic-gate } 2124*7c478bd9Sstevel@tonic-gate 2125*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: not idle, so " 2126*7c478bd9Sstevel@tonic-gate "disconnect/ord rel indication not passed " 2127*7c478bd9Sstevel@tonic-gate "upstream on 0x%p\n", (void *)q); 2128*7c478bd9Sstevel@tonic-gate 2129*7c478bd9Sstevel@tonic-gate /* 2130*7c478bd9Sstevel@tonic-gate * Hold the indication until we get idle 2131*7c478bd9Sstevel@tonic-gate * If there already is an indication stored, 2132*7c478bd9Sstevel@tonic-gate * replace it if the new one is a disconnect. The 2133*7c478bd9Sstevel@tonic-gate * reasoning is that disconnection takes less time 2134*7c478bd9Sstevel@tonic-gate * to process, and once a client decides to 2135*7c478bd9Sstevel@tonic-gate * disconnect, we should do that. 2136*7c478bd9Sstevel@tonic-gate */ 2137*7c478bd9Sstevel@tonic-gate if (mir->mir_svc_pend_mp) { 2138*7c478bd9Sstevel@tonic-gate if (type == T_DISCON_IND) { 2139*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: replacing" 2140*7c478bd9Sstevel@tonic-gate " held disconnect/ord rel" 2141*7c478bd9Sstevel@tonic-gate " indication with disconnect on" 2142*7c478bd9Sstevel@tonic-gate " 0x%p\n", (void *)q); 2143*7c478bd9Sstevel@tonic-gate 2144*7c478bd9Sstevel@tonic-gate freemsg(mir->mir_svc_pend_mp); 2145*7c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = mp; 2146*7c478bd9Sstevel@tonic-gate } else { 2147*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: already " 2148*7c478bd9Sstevel@tonic-gate "held a disconnect/ord rel " 2149*7c478bd9Sstevel@tonic-gate "indication. freeing ord rel " 2150*7c478bd9Sstevel@tonic-gate "ind on 0x%p\n", (void *)q); 2151*7c478bd9Sstevel@tonic-gate freemsg(mp); 2152*7c478bd9Sstevel@tonic-gate } 2153*7c478bd9Sstevel@tonic-gate } else 2154*7c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = mp; 2155*7c478bd9Sstevel@tonic-gate 2156*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2157*7c478bd9Sstevel@tonic-gate return; 2158*7c478bd9Sstevel@tonic-gate 2159*7c478bd9Sstevel@tonic-gate default: 2160*7c478bd9Sstevel@tonic-gate /* nfsd handles server-side non-data messages. */ 2161*7c478bd9Sstevel@tonic-gate break; 2162*7c478bd9Sstevel@tonic-gate } 2163*7c478bd9Sstevel@tonic-gate break; 2164*7c478bd9Sstevel@tonic-gate 2165*7c478bd9Sstevel@tonic-gate default: 2166*7c478bd9Sstevel@tonic-gate break; 2167*7c478bd9Sstevel@tonic-gate } 2168*7c478bd9Sstevel@tonic-gate 2169*7c478bd9Sstevel@tonic-gate putnext(q, mp); 2170*7c478bd9Sstevel@tonic-gate } 2171*7c478bd9Sstevel@tonic-gate 2172*7c478bd9Sstevel@tonic-gate /* 2173*7c478bd9Sstevel@tonic-gate * The server-side read queues are used to hold inbound messages while 2174*7c478bd9Sstevel@tonic-gate * outbound flow control is exerted. When outbound flow control is 2175*7c478bd9Sstevel@tonic-gate * relieved, mir_wsrv qenables the read-side queue. Read-side queues 2176*7c478bd9Sstevel@tonic-gate * are not enabled by STREAMS and are explicitly noenable'ed in mir_open. 2177*7c478bd9Sstevel@tonic-gate * 2178*7c478bd9Sstevel@tonic-gate * For the server side, we have two types of messages queued. The first type 2179*7c478bd9Sstevel@tonic-gate * are messages that are ready to be XDR decoded and and then sent to the 2180*7c478bd9Sstevel@tonic-gate * RPC program's dispatch routine. The second type are "raw" messages that 2181*7c478bd9Sstevel@tonic-gate * haven't been processed, i.e. assembled from rpc record fragements into 2182*7c478bd9Sstevel@tonic-gate * full requests. The only time we will see the second type of message 2183*7c478bd9Sstevel@tonic-gate * queued is if we have a memory allocation failure while processing a 2184*7c478bd9Sstevel@tonic-gate * a raw message. The field mir_first_non_processed_mblk will mark the 2185*7c478bd9Sstevel@tonic-gate * first such raw message. So the flow for server side is: 2186*7c478bd9Sstevel@tonic-gate * 2187*7c478bd9Sstevel@tonic-gate * - send processed queued messages to kRPC until we run out or find 2188*7c478bd9Sstevel@tonic-gate * one that needs additional processing because we were short on memory 2189*7c478bd9Sstevel@tonic-gate * earlier 2190*7c478bd9Sstevel@tonic-gate * - process a message that was deferred because of lack of 2191*7c478bd9Sstevel@tonic-gate * memory 2192*7c478bd9Sstevel@tonic-gate * - continue processing messages until the queue empties or we 2193*7c478bd9Sstevel@tonic-gate * have to stop because of lack of memory 2194*7c478bd9Sstevel@tonic-gate * - during each of the above phase, if the queue is empty and 2195*7c478bd9Sstevel@tonic-gate * there are no pending messages that were passed to the RPC 2196*7c478bd9Sstevel@tonic-gate * layer, send upstream the pending disconnect/ordrel indication if 2197*7c478bd9Sstevel@tonic-gate * there is one 2198*7c478bd9Sstevel@tonic-gate * 2199*7c478bd9Sstevel@tonic-gate * The read-side queue is also enabled by a bufcall callback if dupmsg 2200*7c478bd9Sstevel@tonic-gate * fails in mir_rput. 2201*7c478bd9Sstevel@tonic-gate */ 2202*7c478bd9Sstevel@tonic-gate static void 2203*7c478bd9Sstevel@tonic-gate mir_rsrv(queue_t *q) 2204*7c478bd9Sstevel@tonic-gate { 2205*7c478bd9Sstevel@tonic-gate mir_t *mir; 2206*7c478bd9Sstevel@tonic-gate mblk_t *mp; 2207*7c478bd9Sstevel@tonic-gate mblk_t *cmp = NULL; 2208*7c478bd9Sstevel@tonic-gate boolean_t stop_timer = B_FALSE; 2209*7c478bd9Sstevel@tonic-gate 2210*7c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 2211*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2212*7c478bd9Sstevel@tonic-gate 2213*7c478bd9Sstevel@tonic-gate mp = NULL; 2214*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 2215*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 2216*7c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt == 0) 2217*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0; 2218*7c478bd9Sstevel@tonic-gate if (mir->mir_hold_inbound) { 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate ASSERT(cmp == NULL); 2221*7c478bd9Sstevel@tonic-gate if (q->q_first == NULL) { 2222*7c478bd9Sstevel@tonic-gate 2223*7c478bd9Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 2224*7c478bd9Sstevel@tonic-gate 2225*7c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 2226*7c478bd9Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 2227*7c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 2228*7c478bd9Sstevel@tonic-gate } 2229*7c478bd9Sstevel@tonic-gate } 2230*7c478bd9Sstevel@tonic-gate 2231*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2232*7c478bd9Sstevel@tonic-gate 2233*7c478bd9Sstevel@tonic-gate if (cmp != NULL) { 2234*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held " 2235*7c478bd9Sstevel@tonic-gate "disconnect/ord rel indication upstream\n", 2236*7c478bd9Sstevel@tonic-gate __LINE__); 2237*7c478bd9Sstevel@tonic-gate putnext(q, cmp); 2238*7c478bd9Sstevel@tonic-gate } 2239*7c478bd9Sstevel@tonic-gate 2240*7c478bd9Sstevel@tonic-gate return; 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate while (mp = getq(q)) { 2243*7c478bd9Sstevel@tonic-gate if (mir->mir_krpc_cell) { 2244*7c478bd9Sstevel@tonic-gate /* 2245*7c478bd9Sstevel@tonic-gate * If we were idle, turn off idle timer since 2246*7c478bd9Sstevel@tonic-gate * we aren't idle any more. 2247*7c478bd9Sstevel@tonic-gate */ 2248*7c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0) 2249*7c478bd9Sstevel@tonic-gate stop_timer = B_TRUE; 2250*7c478bd9Sstevel@tonic-gate if (mir_check_len(q, 2251*7c478bd9Sstevel@tonic-gate (int32_t)msgdsize(mp), mp)) 2252*7c478bd9Sstevel@tonic-gate return; 2253*7c478bd9Sstevel@tonic-gate svc_queuereq(q, mp); 2254*7c478bd9Sstevel@tonic-gate } else { 2255*7c478bd9Sstevel@tonic-gate /* 2256*7c478bd9Sstevel@tonic-gate * Count # of times this happens. Should be 2257*7c478bd9Sstevel@tonic-gate * never, but experience shows otherwise. 2258*7c478bd9Sstevel@tonic-gate */ 2259*7c478bd9Sstevel@tonic-gate mir_krpc_cell_null++; 2260*7c478bd9Sstevel@tonic-gate freemsg(mp); 2261*7c478bd9Sstevel@tonic-gate } 2262*7c478bd9Sstevel@tonic-gate } 2263*7c478bd9Sstevel@tonic-gate break; 2264*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 2265*7c478bd9Sstevel@tonic-gate break; 2266*7c478bd9Sstevel@tonic-gate default: 2267*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type); 2268*7c478bd9Sstevel@tonic-gate 2269*7c478bd9Sstevel@tonic-gate if (q->q_first == NULL) 2270*7c478bd9Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2273*7c478bd9Sstevel@tonic-gate 2274*7c478bd9Sstevel@tonic-gate return; 2275*7c478bd9Sstevel@tonic-gate } 2276*7c478bd9Sstevel@tonic-gate 2277*7c478bd9Sstevel@tonic-gate /* 2278*7c478bd9Sstevel@tonic-gate * The timer is stopped after all the messages are processed. 2279*7c478bd9Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex 2280*7c478bd9Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced 2281*7c478bd9Sstevel@tonic-gate * while we are still processing the message queue. This is not 2282*7c478bd9Sstevel@tonic-gate * good. So we stop the timer here instead. 2283*7c478bd9Sstevel@tonic-gate */ 2284*7c478bd9Sstevel@tonic-gate if (stop_timer) { 2285*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref " 2286*7c478bd9Sstevel@tonic-gate "cnt going to non zero\n", (void *)WR(q)); 2287*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 2288*7c478bd9Sstevel@tonic-gate } 2289*7c478bd9Sstevel@tonic-gate 2290*7c478bd9Sstevel@tonic-gate if (q->q_first == NULL) { 2291*7c478bd9Sstevel@tonic-gate 2292*7c478bd9Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir); 2293*7c478bd9Sstevel@tonic-gate 2294*7c478bd9Sstevel@tonic-gate ASSERT(cmp == NULL); 2295*7c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) { 2296*7c478bd9Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 2297*7c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 2298*7c478bd9Sstevel@tonic-gate } 2299*7c478bd9Sstevel@tonic-gate 2300*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2301*7c478bd9Sstevel@tonic-gate 2302*7c478bd9Sstevel@tonic-gate if (cmp != NULL) { 2303*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held " 2304*7c478bd9Sstevel@tonic-gate "disconnect/ord rel indication upstream\n", 2305*7c478bd9Sstevel@tonic-gate __LINE__); 2306*7c478bd9Sstevel@tonic-gate putnext(q, cmp); 2307*7c478bd9Sstevel@tonic-gate } 2308*7c478bd9Sstevel@tonic-gate 2309*7c478bd9Sstevel@tonic-gate return; 2310*7c478bd9Sstevel@tonic-gate } 2311*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2312*7c478bd9Sstevel@tonic-gate } 2313*7c478bd9Sstevel@tonic-gate 2314*7c478bd9Sstevel@tonic-gate static int mir_svc_policy_fails; 2315*7c478bd9Sstevel@tonic-gate 2316*7c478bd9Sstevel@tonic-gate /* 2317*7c478bd9Sstevel@tonic-gate * Called to send an event code to nfsd/lockd so that it initiates 2318*7c478bd9Sstevel@tonic-gate * connection close. 2319*7c478bd9Sstevel@tonic-gate */ 2320*7c478bd9Sstevel@tonic-gate static int 2321*7c478bd9Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event) 2322*7c478bd9Sstevel@tonic-gate { 2323*7c478bd9Sstevel@tonic-gate mblk_t *mp; 2324*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2325*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 2326*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 2327*7c478bd9Sstevel@tonic-gate #endif 2328*7c478bd9Sstevel@tonic-gate ASSERT(q->q_flag & QREADR); 2329*7c478bd9Sstevel@tonic-gate 2330*7c478bd9Sstevel@tonic-gate /* 2331*7c478bd9Sstevel@tonic-gate * Create an M_DATA message with the event code and pass it to the 2332*7c478bd9Sstevel@tonic-gate * Stream head (nfsd or whoever created the stream will consume it). 2333*7c478bd9Sstevel@tonic-gate */ 2334*7c478bd9Sstevel@tonic-gate mp = allocb(sizeof (int), BPRI_HI); 2335*7c478bd9Sstevel@tonic-gate 2336*7c478bd9Sstevel@tonic-gate if (!mp) { 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate mir_svc_policy_fails++; 2339*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_policy_notify: could not allocate event " 2340*7c478bd9Sstevel@tonic-gate "%d\n", event); 2341*7c478bd9Sstevel@tonic-gate return (ENOMEM); 2342*7c478bd9Sstevel@tonic-gate } 2343*7c478bd9Sstevel@tonic-gate 2344*7c478bd9Sstevel@tonic-gate U32_TO_BE32(event, mp->b_rptr); 2345*7c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (int); 2346*7c478bd9Sstevel@tonic-gate putnext(q, mp); 2347*7c478bd9Sstevel@tonic-gate return (0); 2348*7c478bd9Sstevel@tonic-gate } 2349*7c478bd9Sstevel@tonic-gate 2350*7c478bd9Sstevel@tonic-gate /* 2351*7c478bd9Sstevel@tonic-gate * Server side: start the close phase. We want to get this rpcmod slot in an 2352*7c478bd9Sstevel@tonic-gate * idle state before mir_close() is called. 2353*7c478bd9Sstevel@tonic-gate */ 2354*7c478bd9Sstevel@tonic-gate static void 2355*7c478bd9Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir) 2356*7c478bd9Sstevel@tonic-gate { 2357*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 2358*7c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 2359*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER); 2360*7c478bd9Sstevel@tonic-gate 2361*7c478bd9Sstevel@tonic-gate 2362*7c478bd9Sstevel@tonic-gate /* 2363*7c478bd9Sstevel@tonic-gate * Do not accept any more messages. 2364*7c478bd9Sstevel@tonic-gate */ 2365*7c478bd9Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1; 2366*7c478bd9Sstevel@tonic-gate 2367*7c478bd9Sstevel@tonic-gate /* 2368*7c478bd9Sstevel@tonic-gate * Next two statements will make the read service procedure invoke 2369*7c478bd9Sstevel@tonic-gate * svc_queuereq() on everything stuck in the streams read queue. 2370*7c478bd9Sstevel@tonic-gate * It's not necessary because enabling the write queue will 2371*7c478bd9Sstevel@tonic-gate * have the same effect, but why not speed the process along? 2372*7c478bd9Sstevel@tonic-gate */ 2373*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0; 2374*7c478bd9Sstevel@tonic-gate qenable(RD(wq)); 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate /* 2377*7c478bd9Sstevel@tonic-gate * Meanwhile force the write service procedure to send the 2378*7c478bd9Sstevel@tonic-gate * responses downstream, regardless of flow control. 2379*7c478bd9Sstevel@tonic-gate */ 2380*7c478bd9Sstevel@tonic-gate qenable(wq); 2381*7c478bd9Sstevel@tonic-gate } 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate /* 2384*7c478bd9Sstevel@tonic-gate * This routine is called directly by KRPC after a request is completed, 2385*7c478bd9Sstevel@tonic-gate * whether a reply was sent or the request was dropped. 2386*7c478bd9Sstevel@tonic-gate */ 2387*7c478bd9Sstevel@tonic-gate static void 2388*7c478bd9Sstevel@tonic-gate mir_svc_release(queue_t *wq, mblk_t *mp) 2389*7c478bd9Sstevel@tonic-gate { 2390*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 2391*7c478bd9Sstevel@tonic-gate mblk_t *cmp = NULL; 2392*7c478bd9Sstevel@tonic-gate 2393*7c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 2394*7c478bd9Sstevel@tonic-gate if (mp) 2395*7c478bd9Sstevel@tonic-gate freemsg(mp); 2396*7c478bd9Sstevel@tonic-gate 2397*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2398*7c478bd9Sstevel@tonic-gate mir->mir_ref_cnt--; 2399*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_ref_cnt >= 0); 2400*7c478bd9Sstevel@tonic-gate 2401*7c478bd9Sstevel@tonic-gate /* 2402*7c478bd9Sstevel@tonic-gate * Start idle processing if this is the last reference. 2403*7c478bd9Sstevel@tonic-gate */ 2404*7c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) { 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_release starting idle timer on 0x%p " 2407*7c478bd9Sstevel@tonic-gate "because ref cnt is zero\n", (void *) wq); 2408*7c478bd9Sstevel@tonic-gate 2409*7c478bd9Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp; 2410*7c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL; 2411*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(wq, mir); 2412*7c478bd9Sstevel@tonic-gate } 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2415*7c478bd9Sstevel@tonic-gate 2416*7c478bd9Sstevel@tonic-gate if (cmp) { 2417*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_release: sending a held " 2418*7c478bd9Sstevel@tonic-gate "disconnect/ord rel indication upstream on queue 0x%p\n", 2419*7c478bd9Sstevel@tonic-gate (void *)RD(wq)); 2420*7c478bd9Sstevel@tonic-gate 2421*7c478bd9Sstevel@tonic-gate putnext(RD(wq), cmp); 2422*7c478bd9Sstevel@tonic-gate } 2423*7c478bd9Sstevel@tonic-gate } 2424*7c478bd9Sstevel@tonic-gate 2425*7c478bd9Sstevel@tonic-gate /* 2426*7c478bd9Sstevel@tonic-gate * This routine is called by server-side KRPC when it is ready to 2427*7c478bd9Sstevel@tonic-gate * handle inbound messages on the stream. 2428*7c478bd9Sstevel@tonic-gate */ 2429*7c478bd9Sstevel@tonic-gate static void 2430*7c478bd9Sstevel@tonic-gate mir_svc_start(queue_t *wq) 2431*7c478bd9Sstevel@tonic-gate { 2432*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 2433*7c478bd9Sstevel@tonic-gate 2434*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2435*7c478bd9Sstevel@tonic-gate mir->mir_setup_complete = 1; 2436*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2437*7c478bd9Sstevel@tonic-gate qenable(RD(wq)); 2438*7c478bd9Sstevel@tonic-gate } 2439*7c478bd9Sstevel@tonic-gate 2440*7c478bd9Sstevel@tonic-gate /* 2441*7c478bd9Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout. 2442*7c478bd9Sstevel@tonic-gate */ 2443*7c478bd9Sstevel@tonic-gate static void 2444*7c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir) 2445*7c478bd9Sstevel@tonic-gate { 2446*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 2447*7c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 2448*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT); 2449*7c478bd9Sstevel@tonic-gate 2450*7c478bd9Sstevel@tonic-gate mir_timer_stop(mir); 2451*7c478bd9Sstevel@tonic-gate } 2452*7c478bd9Sstevel@tonic-gate 2453*7c478bd9Sstevel@tonic-gate /* 2454*7c478bd9Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout. 2455*7c478bd9Sstevel@tonic-gate */ 2456*7c478bd9Sstevel@tonic-gate static void 2457*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir) 2458*7c478bd9Sstevel@tonic-gate { 2459*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 2460*7c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0); 2461*7c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT); 2462*7c478bd9Sstevel@tonic-gate 2463*7c478bd9Sstevel@tonic-gate mir_timer_start(wq, mir, mir->mir_idle_timeout); 2464*7c478bd9Sstevel@tonic-gate } 2465*7c478bd9Sstevel@tonic-gate 2466*7c478bd9Sstevel@tonic-gate /* 2467*7c478bd9Sstevel@tonic-gate * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on 2468*7c478bd9Sstevel@tonic-gate * end-points that aren't connected. 2469*7c478bd9Sstevel@tonic-gate */ 2470*7c478bd9Sstevel@tonic-gate static void 2471*7c478bd9Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq) 2472*7c478bd9Sstevel@tonic-gate { 2473*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 2474*7c478bd9Sstevel@tonic-gate 2475*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq); 2476*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 2477*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2478*7c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(wq, mir); 2479*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2480*7c478bd9Sstevel@tonic-gate } 2481*7c478bd9Sstevel@tonic-gate 2482*7c478bd9Sstevel@tonic-gate /* 2483*7c478bd9Sstevel@tonic-gate * Timer handler. It handles idle timeout and memory shortage problem. 2484*7c478bd9Sstevel@tonic-gate */ 2485*7c478bd9Sstevel@tonic-gate static void 2486*7c478bd9Sstevel@tonic-gate mir_timer(void *arg) 2487*7c478bd9Sstevel@tonic-gate { 2488*7c478bd9Sstevel@tonic-gate queue_t *wq = (queue_t *)arg; 2489*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr; 2490*7c478bd9Sstevel@tonic-gate boolean_t notify; 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2493*7c478bd9Sstevel@tonic-gate 2494*7c478bd9Sstevel@tonic-gate /* 2495*7c478bd9Sstevel@tonic-gate * mir_timer_call is set only when either mir_timer_[start|stop] 2496*7c478bd9Sstevel@tonic-gate * is progressing. And mir_timer() can only be run while they 2497*7c478bd9Sstevel@tonic-gate * are progressing if the timer is being stopped. So just 2498*7c478bd9Sstevel@tonic-gate * return. 2499*7c478bd9Sstevel@tonic-gate */ 2500*7c478bd9Sstevel@tonic-gate if (mir->mir_timer_call) { 2501*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2502*7c478bd9Sstevel@tonic-gate return; 2503*7c478bd9Sstevel@tonic-gate } 2504*7c478bd9Sstevel@tonic-gate mir->mir_timer_id = 0; 2505*7c478bd9Sstevel@tonic-gate 2506*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 2507*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate /* 2510*7c478bd9Sstevel@tonic-gate * For clients, the timer fires at clnt_idle_timeout 2511*7c478bd9Sstevel@tonic-gate * intervals. If the activity marker (mir_clntreq) is 2512*7c478bd9Sstevel@tonic-gate * zero, then the stream has been idle since the last 2513*7c478bd9Sstevel@tonic-gate * timer event and we notify KRPC. If mir_clntreq is 2514*7c478bd9Sstevel@tonic-gate * non-zero, then the stream is active and we just 2515*7c478bd9Sstevel@tonic-gate * restart the timer for another interval. mir_clntreq 2516*7c478bd9Sstevel@tonic-gate * is set to 1 in mir_wput for every request passed 2517*7c478bd9Sstevel@tonic-gate * downstream. 2518*7c478bd9Sstevel@tonic-gate * 2519*7c478bd9Sstevel@tonic-gate * If this was a memory shortage timer reset the idle 2520*7c478bd9Sstevel@tonic-gate * timeout regardless; the mir_clntreq will not be a 2521*7c478bd9Sstevel@tonic-gate * valid indicator. 2522*7c478bd9Sstevel@tonic-gate * 2523*7c478bd9Sstevel@tonic-gate * The timer is initially started in mir_wput during 2524*7c478bd9Sstevel@tonic-gate * RPC_CLIENT ioctl processing. 2525*7c478bd9Sstevel@tonic-gate * 2526*7c478bd9Sstevel@tonic-gate * The timer interval can be changed for individual 2527*7c478bd9Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout". 2528*7c478bd9Sstevel@tonic-gate */ 2529*7c478bd9Sstevel@tonic-gate if (mir->mir_clntreq > 0 && mir->mir_use_timestamp + 2530*7c478bd9Sstevel@tonic-gate MSEC_TO_TICK(mir->mir_idle_timeout) - lbolt >= 0) { 2531*7c478bd9Sstevel@tonic-gate clock_t tout; 2532*7c478bd9Sstevel@tonic-gate 2533*7c478bd9Sstevel@tonic-gate tout = mir->mir_idle_timeout - 2534*7c478bd9Sstevel@tonic-gate TICK_TO_MSEC(lbolt - mir->mir_use_timestamp); 2535*7c478bd9Sstevel@tonic-gate if (tout < 0) 2536*7c478bd9Sstevel@tonic-gate tout = 1000; 2537*7c478bd9Sstevel@tonic-gate #if 0 2538*7c478bd9Sstevel@tonic-gate printf("mir_timer[%d < %d + %d]: reset client timer to %d (ms)\n", 2539*7c478bd9Sstevel@tonic-gate TICK_TO_MSEC(lbolt), TICK_TO_MSEC(mir->mir_use_timestamp), 2540*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout, tout); 2541*7c478bd9Sstevel@tonic-gate #endif 2542*7c478bd9Sstevel@tonic-gate mir->mir_clntreq = 0; 2543*7c478bd9Sstevel@tonic-gate mir_timer_start(wq, mir, tout); 2544*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2545*7c478bd9Sstevel@tonic-gate return; 2546*7c478bd9Sstevel@tonic-gate } 2547*7c478bd9Sstevel@tonic-gate #if 0 2548*7c478bd9Sstevel@tonic-gate printf("mir_timer[%d]: doing client timeout\n", lbolt / hz); 2549*7c478bd9Sstevel@tonic-gate #endif 2550*7c478bd9Sstevel@tonic-gate /* 2551*7c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily 2552*7c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to 2553*7c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value, 2554*7c478bd9Sstevel@tonic-gate * unless we store it now. 2555*7c478bd9Sstevel@tonic-gate */ 2556*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 2557*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(wq, mir); 2558*7c478bd9Sstevel@tonic-gate 2559*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2560*7c478bd9Sstevel@tonic-gate /* 2561*7c478bd9Sstevel@tonic-gate * We pass T_ORDREL_REQ as an integer value 2562*7c478bd9Sstevel@tonic-gate * to KRPC as the indication that the stream 2563*7c478bd9Sstevel@tonic-gate * is idle. This is not a T_ORDREL_REQ message, 2564*7c478bd9Sstevel@tonic-gate * it is just a convenient value since we call 2565*7c478bd9Sstevel@tonic-gate * the same KRPC routine for T_ORDREL_INDs and 2566*7c478bd9Sstevel@tonic-gate * T_DISCON_INDs. 2567*7c478bd9Sstevel@tonic-gate */ 2568*7c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0); 2569*7c478bd9Sstevel@tonic-gate return; 2570*7c478bd9Sstevel@tonic-gate 2571*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate /* 2574*7c478bd9Sstevel@tonic-gate * For servers, the timer is only running when the stream 2575*7c478bd9Sstevel@tonic-gate * is really idle or memory is short. The timer is started 2576*7c478bd9Sstevel@tonic-gate * by mir_wput when mir_type is set to RPC_SERVER and 2577*7c478bd9Sstevel@tonic-gate * by mir_svc_idle_start whenever the stream goes idle 2578*7c478bd9Sstevel@tonic-gate * (mir_ref_cnt == 0). The timer is cancelled in 2579*7c478bd9Sstevel@tonic-gate * mir_rput whenever a new inbound request is passed to KRPC 2580*7c478bd9Sstevel@tonic-gate * and the stream was previously idle. 2581*7c478bd9Sstevel@tonic-gate * 2582*7c478bd9Sstevel@tonic-gate * The timer interval can be changed for individual 2583*7c478bd9Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout". 2584*7c478bd9Sstevel@tonic-gate * 2585*7c478bd9Sstevel@tonic-gate * If the stream is not idle do nothing. 2586*7c478bd9Sstevel@tonic-gate */ 2587*7c478bd9Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir)) { 2588*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2589*7c478bd9Sstevel@tonic-gate return; 2590*7c478bd9Sstevel@tonic-gate } 2591*7c478bd9Sstevel@tonic-gate 2592*7c478bd9Sstevel@tonic-gate notify = !mir->mir_inrservice; 2593*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2594*7c478bd9Sstevel@tonic-gate 2595*7c478bd9Sstevel@tonic-gate /* 2596*7c478bd9Sstevel@tonic-gate * If there is no packet queued up in read queue, the stream 2597*7c478bd9Sstevel@tonic-gate * is really idle so notify nfsd to close it. 2598*7c478bd9Sstevel@tonic-gate */ 2599*7c478bd9Sstevel@tonic-gate if (notify) { 2600*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_timer: telling stream head listener " 2601*7c478bd9Sstevel@tonic-gate "to close stream (0x%p)\n", (void *) RD(wq)); 2602*7c478bd9Sstevel@tonic-gate (void) mir_svc_policy_notify(RD(wq), 1); 2603*7c478bd9Sstevel@tonic-gate } 2604*7c478bd9Sstevel@tonic-gate return; 2605*7c478bd9Sstevel@tonic-gate default: 2606*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_timer: unexpected mir_type %d\n", 2607*7c478bd9Sstevel@tonic-gate mir->mir_type); 2608*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2609*7c478bd9Sstevel@tonic-gate return; 2610*7c478bd9Sstevel@tonic-gate } 2611*7c478bd9Sstevel@tonic-gate } 2612*7c478bd9Sstevel@tonic-gate 2613*7c478bd9Sstevel@tonic-gate /* 2614*7c478bd9Sstevel@tonic-gate * Called by the RPC package to send either a call or a return, or a 2615*7c478bd9Sstevel@tonic-gate * transport connection request. Adds the record marking header. 2616*7c478bd9Sstevel@tonic-gate */ 2617*7c478bd9Sstevel@tonic-gate static void 2618*7c478bd9Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp) 2619*7c478bd9Sstevel@tonic-gate { 2620*7c478bd9Sstevel@tonic-gate uint_t frag_header; 2621*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 2622*7c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate if (!mir) { 2625*7c478bd9Sstevel@tonic-gate freemsg(mp); 2626*7c478bd9Sstevel@tonic-gate return; 2627*7c478bd9Sstevel@tonic-gate } 2628*7c478bd9Sstevel@tonic-gate 2629*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 2630*7c478bd9Sstevel@tonic-gate mir_wput_other(q, mp); 2631*7c478bd9Sstevel@tonic-gate return; 2632*7c478bd9Sstevel@tonic-gate } 2633*7c478bd9Sstevel@tonic-gate 2634*7c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) { 2635*7c478bd9Sstevel@tonic-gate freemsg(mp); 2636*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n", 2637*7c478bd9Sstevel@tonic-gate (void *)q); 2638*7c478bd9Sstevel@tonic-gate return; 2639*7c478bd9Sstevel@tonic-gate } 2640*7c478bd9Sstevel@tonic-gate 2641*7c478bd9Sstevel@tonic-gate frag_header = (uint_t)DLEN(mp); 2642*7c478bd9Sstevel@tonic-gate frag_header |= MIR_LASTFRAG; 2643*7c478bd9Sstevel@tonic-gate 2644*7c478bd9Sstevel@tonic-gate /* Stick in the 4 byte record marking header. */ 2645*7c478bd9Sstevel@tonic-gate if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) || 2646*7c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) { 2647*7c478bd9Sstevel@tonic-gate /* 2648*7c478bd9Sstevel@tonic-gate * Since we know that M_DATA messages are created exclusively 2649*7c478bd9Sstevel@tonic-gate * by KRPC, we expect that KRPC will leave room for our header 2650*7c478bd9Sstevel@tonic-gate * and 4 byte align which is normal for XDR. 2651*7c478bd9Sstevel@tonic-gate * If KRPC (or someone else) does not cooperate, then we 2652*7c478bd9Sstevel@tonic-gate * just throw away the message. 2653*7c478bd9Sstevel@tonic-gate */ 2654*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_wput: KRPC did not leave space for record " 2655*7c478bd9Sstevel@tonic-gate "fragment header (%d bytes left)\n", 2656*7c478bd9Sstevel@tonic-gate (int)(rptr - mp->b_datap->db_base)); 2657*7c478bd9Sstevel@tonic-gate freemsg(mp); 2658*7c478bd9Sstevel@tonic-gate return; 2659*7c478bd9Sstevel@tonic-gate } 2660*7c478bd9Sstevel@tonic-gate rptr -= sizeof (uint32_t); 2661*7c478bd9Sstevel@tonic-gate *(uint32_t *)rptr = htonl(frag_header); 2662*7c478bd9Sstevel@tonic-gate mp->b_rptr = rptr; 2663*7c478bd9Sstevel@tonic-gate 2664*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2665*7c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) { 2666*7c478bd9Sstevel@tonic-gate /* 2667*7c478bd9Sstevel@tonic-gate * For the client, set mir_clntreq to indicate that the 2668*7c478bd9Sstevel@tonic-gate * connection is active. 2669*7c478bd9Sstevel@tonic-gate */ 2670*7c478bd9Sstevel@tonic-gate mir->mir_clntreq = 1; 2671*7c478bd9Sstevel@tonic-gate mir->mir_use_timestamp = lbolt; 2672*7c478bd9Sstevel@tonic-gate } 2673*7c478bd9Sstevel@tonic-gate 2674*7c478bd9Sstevel@tonic-gate /* 2675*7c478bd9Sstevel@tonic-gate * If we haven't already queued some data and the downstream module 2676*7c478bd9Sstevel@tonic-gate * can accept more data, send it on, otherwise we queue the message 2677*7c478bd9Sstevel@tonic-gate * and take other actions depending on mir_type. 2678*7c478bd9Sstevel@tonic-gate */ 2679*7c478bd9Sstevel@tonic-gate if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) { 2680*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2681*7c478bd9Sstevel@tonic-gate 2682*7c478bd9Sstevel@tonic-gate /* 2683*7c478bd9Sstevel@tonic-gate * Now we pass the RPC message downstream. 2684*7c478bd9Sstevel@tonic-gate */ 2685*7c478bd9Sstevel@tonic-gate putnext(q, mp); 2686*7c478bd9Sstevel@tonic-gate return; 2687*7c478bd9Sstevel@tonic-gate } 2688*7c478bd9Sstevel@tonic-gate 2689*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 2690*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 2691*7c478bd9Sstevel@tonic-gate /* 2692*7c478bd9Sstevel@tonic-gate * Check for a previous duplicate request on the 2693*7c478bd9Sstevel@tonic-gate * queue. If there is one, then we throw away 2694*7c478bd9Sstevel@tonic-gate * the current message and let the previous one 2695*7c478bd9Sstevel@tonic-gate * go through. If we can't find a duplicate, then 2696*7c478bd9Sstevel@tonic-gate * send this one. This tap dance is an effort 2697*7c478bd9Sstevel@tonic-gate * to reduce traffic and processing requirements 2698*7c478bd9Sstevel@tonic-gate * under load conditions. 2699*7c478bd9Sstevel@tonic-gate */ 2700*7c478bd9Sstevel@tonic-gate if (mir_clnt_dup_request(q, mp)) { 2701*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2702*7c478bd9Sstevel@tonic-gate freemsg(mp); 2703*7c478bd9Sstevel@tonic-gate return; 2704*7c478bd9Sstevel@tonic-gate } 2705*7c478bd9Sstevel@tonic-gate break; 2706*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 2707*7c478bd9Sstevel@tonic-gate /* 2708*7c478bd9Sstevel@tonic-gate * Set mir_hold_inbound so that new inbound RPC 2709*7c478bd9Sstevel@tonic-gate * messages will be held until the client catches 2710*7c478bd9Sstevel@tonic-gate * up on the earlier replies. This flag is cleared 2711*7c478bd9Sstevel@tonic-gate * in mir_wsrv after flow control is relieved; 2712*7c478bd9Sstevel@tonic-gate * the read-side queue is also enabled at that time. 2713*7c478bd9Sstevel@tonic-gate */ 2714*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 1; 2715*7c478bd9Sstevel@tonic-gate break; 2716*7c478bd9Sstevel@tonic-gate default: 2717*7c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type); 2718*7c478bd9Sstevel@tonic-gate break; 2719*7c478bd9Sstevel@tonic-gate } 2720*7c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1; 2721*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 2722*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2723*7c478bd9Sstevel@tonic-gate } 2724*7c478bd9Sstevel@tonic-gate 2725*7c478bd9Sstevel@tonic-gate static void 2726*7c478bd9Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp) 2727*7c478bd9Sstevel@tonic-gate { 2728*7c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr; 2729*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 2730*7c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 2731*7c478bd9Sstevel@tonic-gate bool_t flush_in_svc = FALSE; 2732*7c478bd9Sstevel@tonic-gate 2733*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex)); 2734*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2735*7c478bd9Sstevel@tonic-gate case M_IOCTL: 2736*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)rptr; 2737*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 2738*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 2739*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2740*7c478bd9Sstevel@tonic-gate if (mir->mir_type != 0 && 2741*7c478bd9Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) { 2742*7c478bd9Sstevel@tonic-gate ioc_eperm: 2743*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2744*7c478bd9Sstevel@tonic-gate iocp->ioc_error = EPERM; 2745*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 2746*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 2747*7c478bd9Sstevel@tonic-gate qreply(q, mp); 2748*7c478bd9Sstevel@tonic-gate return; 2749*7c478bd9Sstevel@tonic-gate } 2750*7c478bd9Sstevel@tonic-gate 2751*7c478bd9Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd; 2752*7c478bd9Sstevel@tonic-gate 2753*7c478bd9Sstevel@tonic-gate /* 2754*7c478bd9Sstevel@tonic-gate * Clear mir_hold_inbound which was set to 1 by 2755*7c478bd9Sstevel@tonic-gate * mir_open. This flag is not used on client 2756*7c478bd9Sstevel@tonic-gate * streams. 2757*7c478bd9Sstevel@tonic-gate */ 2758*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0; 2759*7c478bd9Sstevel@tonic-gate mir->mir_max_msg_sizep = &clnt_max_msg_size; 2760*7c478bd9Sstevel@tonic-gate 2761*7c478bd9Sstevel@tonic-gate /* 2762*7c478bd9Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more 2763*7c478bd9Sstevel@tonic-gate * information on how client timers work. 2764*7c478bd9Sstevel@tonic-gate */ 2765*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 2766*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(q, mir); 2767*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2768*7c478bd9Sstevel@tonic-gate 2769*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 2770*7c478bd9Sstevel@tonic-gate qreply(q, mp); 2771*7c478bd9Sstevel@tonic-gate return; 2772*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 2773*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2774*7c478bd9Sstevel@tonic-gate if (mir->mir_type != 0 && 2775*7c478bd9Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) 2776*7c478bd9Sstevel@tonic-gate goto ioc_eperm; 2777*7c478bd9Sstevel@tonic-gate 2778*7c478bd9Sstevel@tonic-gate /* 2779*7c478bd9Sstevel@tonic-gate * We don't clear mir_hold_inbound here because 2780*7c478bd9Sstevel@tonic-gate * mir_hold_inbound is used in the flow control 2781*7c478bd9Sstevel@tonic-gate * model. If we cleared it here, then we'd commit 2782*7c478bd9Sstevel@tonic-gate * a small violation to the model where the transport 2783*7c478bd9Sstevel@tonic-gate * might immediately block downstream flow. 2784*7c478bd9Sstevel@tonic-gate */ 2785*7c478bd9Sstevel@tonic-gate 2786*7c478bd9Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd; 2787*7c478bd9Sstevel@tonic-gate mir->mir_max_msg_sizep = &svc_max_msg_size; 2788*7c478bd9Sstevel@tonic-gate 2789*7c478bd9Sstevel@tonic-gate /* 2790*7c478bd9Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more 2791*7c478bd9Sstevel@tonic-gate * information on how server timers work. 2792*7c478bd9Sstevel@tonic-gate * 2793*7c478bd9Sstevel@tonic-gate * Note that it is important to start the idle timer 2794*7c478bd9Sstevel@tonic-gate * here so that connections time out even if we 2795*7c478bd9Sstevel@tonic-gate * never receive any data on them. 2796*7c478bd9Sstevel@tonic-gate */ 2797*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = svc_idle_timeout; 2798*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other starting idle timer on 0x%p " 2799*7c478bd9Sstevel@tonic-gate "because we got RPC_SERVER ioctl\n", (void *)q); 2800*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir); 2801*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2802*7c478bd9Sstevel@tonic-gate 2803*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 2804*7c478bd9Sstevel@tonic-gate qreply(q, mp); 2805*7c478bd9Sstevel@tonic-gate return; 2806*7c478bd9Sstevel@tonic-gate default: 2807*7c478bd9Sstevel@tonic-gate break; 2808*7c478bd9Sstevel@tonic-gate } 2809*7c478bd9Sstevel@tonic-gate break; 2810*7c478bd9Sstevel@tonic-gate 2811*7c478bd9Sstevel@tonic-gate case M_PROTO: 2812*7c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) { 2813*7c478bd9Sstevel@tonic-gate /* 2814*7c478bd9Sstevel@tonic-gate * We are likely being called from the context of a 2815*7c478bd9Sstevel@tonic-gate * service procedure. So we need to enqueue. However 2816*7c478bd9Sstevel@tonic-gate * enqueing may put our message behind data messages. 2817*7c478bd9Sstevel@tonic-gate * So flush the data first. 2818*7c478bd9Sstevel@tonic-gate */ 2819*7c478bd9Sstevel@tonic-gate flush_in_svc = TRUE; 2820*7c478bd9Sstevel@tonic-gate } 2821*7c478bd9Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (uint32_t) || 2822*7c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(rptr, sizeof (uint32_t))) 2823*7c478bd9Sstevel@tonic-gate break; 2824*7c478bd9Sstevel@tonic-gate 2825*7c478bd9Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 2826*7c478bd9Sstevel@tonic-gate case T_DATA_REQ: 2827*7c478bd9Sstevel@tonic-gate /* Don't pass T_DATA_REQ messages downstream. */ 2828*7c478bd9Sstevel@tonic-gate freemsg(mp); 2829*7c478bd9Sstevel@tonic-gate return; 2830*7c478bd9Sstevel@tonic-gate case T_ORDREL_REQ: 2831*7c478bd9Sstevel@tonic-gate RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n", 2832*7c478bd9Sstevel@tonic-gate (void *)q); 2833*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2834*7c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) { 2835*7c478bd9Sstevel@tonic-gate /* 2836*7c478bd9Sstevel@tonic-gate * We are likely being called from 2837*7c478bd9Sstevel@tonic-gate * clnt_dispatch_notifyall(). Sending 2838*7c478bd9Sstevel@tonic-gate * a T_ORDREL_REQ will result in 2839*7c478bd9Sstevel@tonic-gate * a some kind of _IND message being sent, 2840*7c478bd9Sstevel@tonic-gate * will be another call to 2841*7c478bd9Sstevel@tonic-gate * clnt_dispatch_notifyall(). To keep the stack 2842*7c478bd9Sstevel@tonic-gate * lean, queue this message. 2843*7c478bd9Sstevel@tonic-gate */ 2844*7c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1; 2845*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 2846*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2847*7c478bd9Sstevel@tonic-gate return; 2848*7c478bd9Sstevel@tonic-gate } 2849*7c478bd9Sstevel@tonic-gate 2850*7c478bd9Sstevel@tonic-gate /* 2851*7c478bd9Sstevel@tonic-gate * Mark the structure such that we don't accept any 2852*7c478bd9Sstevel@tonic-gate * more requests from client. We could defer this 2853*7c478bd9Sstevel@tonic-gate * until we actually send the orderly release 2854*7c478bd9Sstevel@tonic-gate * request downstream, but all that does is delay 2855*7c478bd9Sstevel@tonic-gate * the closing of this stream. 2856*7c478bd9Sstevel@tonic-gate */ 2857*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ " 2858*7c478bd9Sstevel@tonic-gate " so calling mir_svc_start_close\n", (void *)q); 2859*7c478bd9Sstevel@tonic-gate 2860*7c478bd9Sstevel@tonic-gate mir_svc_start_close(q, mir); 2861*7c478bd9Sstevel@tonic-gate 2862*7c478bd9Sstevel@tonic-gate /* 2863*7c478bd9Sstevel@tonic-gate * If we have sent down a T_ORDREL_REQ, don't send 2864*7c478bd9Sstevel@tonic-gate * any more. 2865*7c478bd9Sstevel@tonic-gate */ 2866*7c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending) { 2867*7c478bd9Sstevel@tonic-gate freemsg(mp); 2868*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2869*7c478bd9Sstevel@tonic-gate return; 2870*7c478bd9Sstevel@tonic-gate } 2871*7c478bd9Sstevel@tonic-gate 2872*7c478bd9Sstevel@tonic-gate /* 2873*7c478bd9Sstevel@tonic-gate * If the stream is not idle, then we hold the 2874*7c478bd9Sstevel@tonic-gate * orderly release until it becomes idle. This 2875*7c478bd9Sstevel@tonic-gate * ensures that KRPC will be able to reply to 2876*7c478bd9Sstevel@tonic-gate * all requests that we have passed to it. 2877*7c478bd9Sstevel@tonic-gate * 2878*7c478bd9Sstevel@tonic-gate * We also queue the request if there is data already 2879*7c478bd9Sstevel@tonic-gate * queued, because we cannot allow the T_ORDREL_REQ 2880*7c478bd9Sstevel@tonic-gate * to go before data. When we had a separate reply 2881*7c478bd9Sstevel@tonic-gate * count, this was not a problem, because the 2882*7c478bd9Sstevel@tonic-gate * reply count was reconciled when mir_wsrv() 2883*7c478bd9Sstevel@tonic-gate * completed. 2884*7c478bd9Sstevel@tonic-gate */ 2885*7c478bd9Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir) || 2886*7c478bd9Sstevel@tonic-gate mir->mir_inwservice == 1) { 2887*7c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1; 2888*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 2889*7c478bd9Sstevel@tonic-gate 2890*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: queuing " 2891*7c478bd9Sstevel@tonic-gate "T_ORDREL_REQ on 0x%p\n", (void *)q); 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2894*7c478bd9Sstevel@tonic-gate return; 2895*7c478bd9Sstevel@tonic-gate } 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate /* 2898*7c478bd9Sstevel@tonic-gate * Mark the structure so that we know we sent 2899*7c478bd9Sstevel@tonic-gate * an orderly release request, and reset the idle timer. 2900*7c478bd9Sstevel@tonic-gate */ 2901*7c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending = 1; 2902*7c478bd9Sstevel@tonic-gate 2903*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start" 2904*7c478bd9Sstevel@tonic-gate " on 0x%p because we got T_ORDREL_REQ\n", 2905*7c478bd9Sstevel@tonic-gate (void *)q); 2906*7c478bd9Sstevel@tonic-gate 2907*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir); 2908*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2909*7c478bd9Sstevel@tonic-gate 2910*7c478bd9Sstevel@tonic-gate /* 2911*7c478bd9Sstevel@tonic-gate * When we break, we will putnext the T_ORDREL_REQ. 2912*7c478bd9Sstevel@tonic-gate */ 2913*7c478bd9Sstevel@tonic-gate break; 2914*7c478bd9Sstevel@tonic-gate 2915*7c478bd9Sstevel@tonic-gate case T_CONN_REQ: 2916*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2917*7c478bd9Sstevel@tonic-gate if (mir->mir_head_mp != NULL) { 2918*7c478bd9Sstevel@tonic-gate freemsg(mir->mir_head_mp); 2919*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = NULL; 2920*7c478bd9Sstevel@tonic-gate mir->mir_tail_mp = NULL; 2921*7c478bd9Sstevel@tonic-gate } 2922*7c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t); 2923*7c478bd9Sstevel@tonic-gate /* 2924*7c478bd9Sstevel@tonic-gate * Restart timer in case mir_clnt_idle_do_stop() was 2925*7c478bd9Sstevel@tonic-gate * called. 2926*7c478bd9Sstevel@tonic-gate */ 2927*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 2928*7c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(q, mir); 2929*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(q, mir); 2930*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2931*7c478bd9Sstevel@tonic-gate break; 2932*7c478bd9Sstevel@tonic-gate 2933*7c478bd9Sstevel@tonic-gate default: 2934*7c478bd9Sstevel@tonic-gate /* 2935*7c478bd9Sstevel@tonic-gate * T_DISCON_REQ is one of the interesting default 2936*7c478bd9Sstevel@tonic-gate * cases here. Ideally, an M_FLUSH is done before 2937*7c478bd9Sstevel@tonic-gate * T_DISCON_REQ is done. However, that is somewhat 2938*7c478bd9Sstevel@tonic-gate * cumbersome for clnt_cots.c to do. So we queue 2939*7c478bd9Sstevel@tonic-gate * T_DISCON_REQ, and let the service procedure 2940*7c478bd9Sstevel@tonic-gate * flush all M_DATA. 2941*7c478bd9Sstevel@tonic-gate */ 2942*7c478bd9Sstevel@tonic-gate break; 2943*7c478bd9Sstevel@tonic-gate } 2944*7c478bd9Sstevel@tonic-gate /* fallthru */; 2945*7c478bd9Sstevel@tonic-gate default: 2946*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type >= QPCTL) { 2947*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_FLUSH) { 2948*7c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT && 2949*7c478bd9Sstevel@tonic-gate *mp->b_rptr & FLUSHW) { 2950*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: flushing " 2951*7c478bd9Sstevel@tonic-gate "wq 0x%p\n", (void *)q); 2952*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHBAND) { 2953*7c478bd9Sstevel@tonic-gate flushband(q, *(mp->b_rptr + 1), 2954*7c478bd9Sstevel@tonic-gate FLUSHDATA); 2955*7c478bd9Sstevel@tonic-gate } else { 2956*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 2957*7c478bd9Sstevel@tonic-gate } 2958*7c478bd9Sstevel@tonic-gate } else { 2959*7c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: ignoring " 2960*7c478bd9Sstevel@tonic-gate "M_FLUSH on wq 0x%p\n", (void *)q); 2961*7c478bd9Sstevel@tonic-gate } 2962*7c478bd9Sstevel@tonic-gate } 2963*7c478bd9Sstevel@tonic-gate break; 2964*7c478bd9Sstevel@tonic-gate } 2965*7c478bd9Sstevel@tonic-gate 2966*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2967*7c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) { 2968*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2969*7c478bd9Sstevel@tonic-gate break; 2970*7c478bd9Sstevel@tonic-gate } 2971*7c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1; 2972*7c478bd9Sstevel@tonic-gate mir->mir_inwflushdata = flush_in_svc; 2973*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 2974*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 2975*7c478bd9Sstevel@tonic-gate qenable(q); 2976*7c478bd9Sstevel@tonic-gate 2977*7c478bd9Sstevel@tonic-gate return; 2978*7c478bd9Sstevel@tonic-gate } 2979*7c478bd9Sstevel@tonic-gate putnext(q, mp); 2980*7c478bd9Sstevel@tonic-gate } 2981*7c478bd9Sstevel@tonic-gate 2982*7c478bd9Sstevel@tonic-gate static void 2983*7c478bd9Sstevel@tonic-gate mir_wsrv(queue_t *q) 2984*7c478bd9Sstevel@tonic-gate { 2985*7c478bd9Sstevel@tonic-gate mblk_t *mp; 2986*7c478bd9Sstevel@tonic-gate mir_t *mir; 2987*7c478bd9Sstevel@tonic-gate bool_t flushdata; 2988*7c478bd9Sstevel@tonic-gate 2989*7c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 2990*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 2991*7c478bd9Sstevel@tonic-gate 2992*7c478bd9Sstevel@tonic-gate flushdata = mir->mir_inwflushdata; 2993*7c478bd9Sstevel@tonic-gate mir->mir_inwflushdata = 0; 2994*7c478bd9Sstevel@tonic-gate 2995*7c478bd9Sstevel@tonic-gate while (mp = getq(q)) { 2996*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 2997*7c478bd9Sstevel@tonic-gate /* 2998*7c478bd9Sstevel@tonic-gate * Do not send any more data if we have sent 2999*7c478bd9Sstevel@tonic-gate * a T_ORDREL_REQ. 3000*7c478bd9Sstevel@tonic-gate */ 3001*7c478bd9Sstevel@tonic-gate if (flushdata || mir->mir_ordrel_pending == 1) { 3002*7c478bd9Sstevel@tonic-gate freemsg(mp); 3003*7c478bd9Sstevel@tonic-gate continue; 3004*7c478bd9Sstevel@tonic-gate } 3005*7c478bd9Sstevel@tonic-gate 3006*7c478bd9Sstevel@tonic-gate /* 3007*7c478bd9Sstevel@tonic-gate * Make sure that the stream can really handle more 3008*7c478bd9Sstevel@tonic-gate * data. 3009*7c478bd9Sstevel@tonic-gate */ 3010*7c478bd9Sstevel@tonic-gate if (!MIR_WCANPUTNEXT(mir, q)) { 3011*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 3012*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3013*7c478bd9Sstevel@tonic-gate return; 3014*7c478bd9Sstevel@tonic-gate } 3015*7c478bd9Sstevel@tonic-gate 3016*7c478bd9Sstevel@tonic-gate /* 3017*7c478bd9Sstevel@tonic-gate * Now we pass the RPC message downstream. 3018*7c478bd9Sstevel@tonic-gate */ 3019*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3020*7c478bd9Sstevel@tonic-gate putnext(q, mp); 3021*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 3022*7c478bd9Sstevel@tonic-gate continue; 3023*7c478bd9Sstevel@tonic-gate } 3024*7c478bd9Sstevel@tonic-gate 3025*7c478bd9Sstevel@tonic-gate /* 3026*7c478bd9Sstevel@tonic-gate * This is not an RPC message, pass it downstream 3027*7c478bd9Sstevel@tonic-gate * (ignoring flow control) if the server side is not sending a 3028*7c478bd9Sstevel@tonic-gate * T_ORDREL_REQ downstream. 3029*7c478bd9Sstevel@tonic-gate */ 3030*7c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || 3031*7c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type != 3032*7c478bd9Sstevel@tonic-gate T_ORDREL_REQ) { 3033*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3034*7c478bd9Sstevel@tonic-gate putnext(q, mp); 3035*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 3036*7c478bd9Sstevel@tonic-gate continue; 3037*7c478bd9Sstevel@tonic-gate } 3038*7c478bd9Sstevel@tonic-gate 3039*7c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) { 3040*7c478bd9Sstevel@tonic-gate /* 3041*7c478bd9Sstevel@tonic-gate * Don't send two T_ORDRELs 3042*7c478bd9Sstevel@tonic-gate */ 3043*7c478bd9Sstevel@tonic-gate freemsg(mp); 3044*7c478bd9Sstevel@tonic-gate continue; 3045*7c478bd9Sstevel@tonic-gate } 3046*7c478bd9Sstevel@tonic-gate 3047*7c478bd9Sstevel@tonic-gate /* 3048*7c478bd9Sstevel@tonic-gate * Mark the structure so that we know we sent an orderly 3049*7c478bd9Sstevel@tonic-gate * release request. We will check to see slot is idle at the 3050*7c478bd9Sstevel@tonic-gate * end of this routine, and if so, reset the idle timer to 3051*7c478bd9Sstevel@tonic-gate * handle orderly release timeouts. 3052*7c478bd9Sstevel@tonic-gate */ 3053*7c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending = 1; 3054*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n", 3055*7c478bd9Sstevel@tonic-gate (void *)q); 3056*7c478bd9Sstevel@tonic-gate /* 3057*7c478bd9Sstevel@tonic-gate * Send the orderly release downstream. If there are other 3058*7c478bd9Sstevel@tonic-gate * pending replies we won't be able to send them. However, 3059*7c478bd9Sstevel@tonic-gate * the only reason we should send the orderly release is if 3060*7c478bd9Sstevel@tonic-gate * we were idle, or if an unusual event occurred. 3061*7c478bd9Sstevel@tonic-gate */ 3062*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3063*7c478bd9Sstevel@tonic-gate putnext(q, mp); 3064*7c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex); 3065*7c478bd9Sstevel@tonic-gate } 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate if (q->q_first == NULL) 3068*7c478bd9Sstevel@tonic-gate /* 3069*7c478bd9Sstevel@tonic-gate * If we call mir_svc_idle_start() below, then 3070*7c478bd9Sstevel@tonic-gate * clearing mir_inwservice here will also result in 3071*7c478bd9Sstevel@tonic-gate * any thread waiting in mir_close() to be signaled. 3072*7c478bd9Sstevel@tonic-gate */ 3073*7c478bd9Sstevel@tonic-gate mir->mir_inwservice = 0; 3074*7c478bd9Sstevel@tonic-gate 3075*7c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) { 3076*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3077*7c478bd9Sstevel@tonic-gate return; 3078*7c478bd9Sstevel@tonic-gate } 3079*7c478bd9Sstevel@tonic-gate 3080*7c478bd9Sstevel@tonic-gate /* 3081*7c478bd9Sstevel@tonic-gate * If idle we call mir_svc_idle_start to start the timer (or wakeup 3082*7c478bd9Sstevel@tonic-gate * a close). Also make sure not to start the idle timer on the 3083*7c478bd9Sstevel@tonic-gate * listener stream. This can cause nfsd to send an orderly release 3084*7c478bd9Sstevel@tonic-gate * command on the listener stream. 3085*7c478bd9Sstevel@tonic-gate */ 3086*7c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) { 3087*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p " 3088*7c478bd9Sstevel@tonic-gate "because mir slot is idle\n", (void *)q); 3089*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir); 3090*7c478bd9Sstevel@tonic-gate } 3091*7c478bd9Sstevel@tonic-gate 3092*7c478bd9Sstevel@tonic-gate /* 3093*7c478bd9Sstevel@tonic-gate * If outbound flow control has been relieved, then allow new 3094*7c478bd9Sstevel@tonic-gate * inbound requests to be processed. 3095*7c478bd9Sstevel@tonic-gate */ 3096*7c478bd9Sstevel@tonic-gate if (mir->mir_hold_inbound) { 3097*7c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0; 3098*7c478bd9Sstevel@tonic-gate qenable(RD(q)); 3099*7c478bd9Sstevel@tonic-gate } 3100*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3101*7c478bd9Sstevel@tonic-gate } 3102*7c478bd9Sstevel@tonic-gate 3103*7c478bd9Sstevel@tonic-gate static void 3104*7c478bd9Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir) 3105*7c478bd9Sstevel@tonic-gate { 3106*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex)); 3107*7c478bd9Sstevel@tonic-gate 3108*7c478bd9Sstevel@tonic-gate switch (mir->mir_type) { 3109*7c478bd9Sstevel@tonic-gate case RPC_CLIENT: 3110*7c478bd9Sstevel@tonic-gate /* 3111*7c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily 3112*7c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to 3113*7c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value, 3114*7c478bd9Sstevel@tonic-gate * unless we store it now. 3115*7c478bd9Sstevel@tonic-gate */ 3116*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout; 3117*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir); 3118*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3119*7c478bd9Sstevel@tonic-gate 3120*7c478bd9Sstevel@tonic-gate /* 3121*7c478bd9Sstevel@tonic-gate * T_DISCON_REQ is passed to KRPC as an integer value 3122*7c478bd9Sstevel@tonic-gate * (this is not a TPI message). It is used as a 3123*7c478bd9Sstevel@tonic-gate * convenient value to indicate a sanity check 3124*7c478bd9Sstevel@tonic-gate * failure -- the same KRPC routine is also called 3125*7c478bd9Sstevel@tonic-gate * for T_DISCON_INDs and T_ORDREL_INDs. 3126*7c478bd9Sstevel@tonic-gate */ 3127*7c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0); 3128*7c478bd9Sstevel@tonic-gate break; 3129*7c478bd9Sstevel@tonic-gate 3130*7c478bd9Sstevel@tonic-gate case RPC_SERVER: 3131*7c478bd9Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1; 3132*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir); 3133*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3134*7c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_disconnect: telling " 3135*7c478bd9Sstevel@tonic-gate "stream head listener to disconnect stream " 3136*7c478bd9Sstevel@tonic-gate "(0x%p)\n", (void *) q); 3137*7c478bd9Sstevel@tonic-gate (void) mir_svc_policy_notify(q, 2); 3138*7c478bd9Sstevel@tonic-gate break; 3139*7c478bd9Sstevel@tonic-gate 3140*7c478bd9Sstevel@tonic-gate default: 3141*7c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex); 3142*7c478bd9Sstevel@tonic-gate break; 3143*7c478bd9Sstevel@tonic-gate } 3144*7c478bd9Sstevel@tonic-gate } 3145*7c478bd9Sstevel@tonic-gate 3146*7c478bd9Sstevel@tonic-gate /* 3147*7c478bd9Sstevel@tonic-gate * do a sanity check on the length of the fragment. 3148*7c478bd9Sstevel@tonic-gate * returns 1 if bad else 0. 3149*7c478bd9Sstevel@tonic-gate */ 3150*7c478bd9Sstevel@tonic-gate static int 3151*7c478bd9Sstevel@tonic-gate mir_check_len(queue_t *q, int32_t frag_len, 3152*7c478bd9Sstevel@tonic-gate mblk_t *head_mp) 3153*7c478bd9Sstevel@tonic-gate { 3154*7c478bd9Sstevel@tonic-gate mir_t *mir; 3155*7c478bd9Sstevel@tonic-gate 3156*7c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr; 3157*7c478bd9Sstevel@tonic-gate 3158*7c478bd9Sstevel@tonic-gate /* 3159*7c478bd9Sstevel@tonic-gate * Do a sanity check on the message length. If this message is 3160*7c478bd9Sstevel@tonic-gate * getting excessively large, shut down the connection. 3161*7c478bd9Sstevel@tonic-gate */ 3162*7c478bd9Sstevel@tonic-gate 3163*7c478bd9Sstevel@tonic-gate if ((frag_len <= 0) || (mir->mir_max_msg_sizep == NULL) || 3164*7c478bd9Sstevel@tonic-gate (frag_len <= *mir->mir_max_msg_sizep)) { 3165*7c478bd9Sstevel@tonic-gate return (0); 3166*7c478bd9Sstevel@tonic-gate } 3167*7c478bd9Sstevel@tonic-gate 3168*7c478bd9Sstevel@tonic-gate freemsg(head_mp); 3169*7c478bd9Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0; 3170*7c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int)sizeof (uint32_t); 3171*7c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) { 3172*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 3173*7c478bd9Sstevel@tonic-gate "KRPC: record fragment from %s of size(%d) exceeds " 3174*7c478bd9Sstevel@tonic-gate "maximum (%u). Disconnecting", 3175*7c478bd9Sstevel@tonic-gate (mir->mir_type == RPC_CLIENT) ? "server" : 3176*7c478bd9Sstevel@tonic-gate (mir->mir_type == RPC_SERVER) ? "client" : 3177*7c478bd9Sstevel@tonic-gate "test tool", 3178*7c478bd9Sstevel@tonic-gate frag_len, *mir->mir_max_msg_sizep); 3179*7c478bd9Sstevel@tonic-gate } 3180*7c478bd9Sstevel@tonic-gate 3181*7c478bd9Sstevel@tonic-gate mir_disconnect(q, mir); 3182*7c478bd9Sstevel@tonic-gate return (1); 3183*7c478bd9Sstevel@tonic-gate } 3184