1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 32*0Sstevel@tonic-gate * under license from the Regents of the University of California. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include <sys/param.h> 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <rpc/types.h> 40*0Sstevel@tonic-gate #include <netinet/in.h> 41*0Sstevel@tonic-gate #include <rpc/auth.h> 42*0Sstevel@tonic-gate #include <rpc/clnt.h> 43*0Sstevel@tonic-gate #include <sys/tiuser.h> 44*0Sstevel@tonic-gate #include <sys/t_kuser.h> 45*0Sstevel@tonic-gate #include <rpc/svc.h> 46*0Sstevel@tonic-gate #include <rpc/xdr.h> 47*0Sstevel@tonic-gate #include <sys/file.h> 48*0Sstevel@tonic-gate #include <sys/user.h> 49*0Sstevel@tonic-gate #include <sys/proc.h> 50*0Sstevel@tonic-gate #include <sys/vnode.h> 51*0Sstevel@tonic-gate #include <sys/stream.h> 52*0Sstevel@tonic-gate #include <sys/tihdr.h> 53*0Sstevel@tonic-gate #include <sys/fcntl.h> 54*0Sstevel@tonic-gate #include <sys/socket.h> 55*0Sstevel@tonic-gate #include <sys/sysmacros.h> 56*0Sstevel@tonic-gate #include <sys/errno.h> 57*0Sstevel@tonic-gate #include <sys/cred.h> 58*0Sstevel@tonic-gate #include <sys/systm.h> 59*0Sstevel@tonic-gate #include <sys/cmn_err.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #define NC_INET "inet" 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #define MAX_PRIV (IPPORT_RESERVED-1) 64*0Sstevel@tonic-gate #define MIN_PRIV (IPPORT_RESERVED/2) 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate ushort_t clnt_udp_last_used = MIN_PRIV; 67*0Sstevel@tonic-gate ushort_t clnt_tcp_last_used = MIN_PRIV; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate /* 70*0Sstevel@tonic-gate * PSARC 2003/523 Contract Private Interface 71*0Sstevel@tonic-gate * clnt_tli_kcreate 72*0Sstevel@tonic-gate * Changes must be reviewed by Solaris File Sharing 73*0Sstevel@tonic-gate * Changes must be communicated to contract-2003-523@sun.com 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate int 76*0Sstevel@tonic-gate clnt_tli_kcreate( 77*0Sstevel@tonic-gate struct knetconfig *config, 78*0Sstevel@tonic-gate struct netbuf *svcaddr, /* Servers address */ 79*0Sstevel@tonic-gate rpcprog_t prog, /* Program number */ 80*0Sstevel@tonic-gate rpcvers_t vers, /* Version number */ 81*0Sstevel@tonic-gate uint_t max_msgsize, 82*0Sstevel@tonic-gate int retries, 83*0Sstevel@tonic-gate struct cred *cred, 84*0Sstevel@tonic-gate CLIENT **ncl) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate CLIENT *cl; /* Client handle */ 87*0Sstevel@tonic-gate int error; 88*0Sstevel@tonic-gate int family = AF_UNSPEC; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate error = 0; 91*0Sstevel@tonic-gate cl = NULL; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate RPCLOG(8, "clnt_tli_kcreate: prog %x", prog); 94*0Sstevel@tonic-gate RPCLOG(8, ", vers %d", vers); 95*0Sstevel@tonic-gate RPCLOG(8, ", knc_semantics %d", config->knc_semantics); 96*0Sstevel@tonic-gate RPCLOG(8, ", knc_protofmly %s", config->knc_protofmly); 97*0Sstevel@tonic-gate RPCLOG(8, ", knc_proto %s\n", config->knc_proto); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (config == NULL || config->knc_protofmly == NULL || ncl == NULL) { 100*0Sstevel@tonic-gate RPCLOG0(1, "clnt_tli_kcreate: bad config or handle\n"); 101*0Sstevel@tonic-gate return (EINVAL); 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate switch (config->knc_semantics) { 105*0Sstevel@tonic-gate case NC_TPI_CLTS: 106*0Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: CLTS selected\n"); 107*0Sstevel@tonic-gate error = clnt_clts_kcreate(config, svcaddr, prog, vers, 108*0Sstevel@tonic-gate retries, cred, &cl); 109*0Sstevel@tonic-gate if (error != 0) { 110*0Sstevel@tonic-gate RPCLOG(1, 111*0Sstevel@tonic-gate "clnt_tli_kcreate: clnt_clts_kcreate failed error %d\n", 112*0Sstevel@tonic-gate error); 113*0Sstevel@tonic-gate return (error); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate break; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate case NC_TPI_COTS: 118*0Sstevel@tonic-gate case NC_TPI_COTS_ORD: 119*0Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: COTS selected\n"); 120*0Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0) 121*0Sstevel@tonic-gate family = AF_INET; 122*0Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0) 123*0Sstevel@tonic-gate family = AF_INET6; 124*0Sstevel@tonic-gate error = clnt_cots_kcreate(config->knc_rdev, svcaddr, family, 125*0Sstevel@tonic-gate prog, vers, max_msgsize, cred, &cl); 126*0Sstevel@tonic-gate if (error != 0) { 127*0Sstevel@tonic-gate RPCLOG(1, 128*0Sstevel@tonic-gate "clnt_tli_kcreate: clnt_cots_kcreate failed error %d\n", 129*0Sstevel@tonic-gate error); 130*0Sstevel@tonic-gate return (error); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate break; 133*0Sstevel@tonic-gate case NC_TPI_RDMA: 134*0Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: RDMA selected\n"); 135*0Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0) 136*0Sstevel@tonic-gate family = AF_INET; 137*0Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0) 138*0Sstevel@tonic-gate family = AF_INET6; 139*0Sstevel@tonic-gate error = clnt_rdma_kcreate(config->knc_proto, 140*0Sstevel@tonic-gate (void *)config->knc_rdev, svcaddr, family, prog, vers, cred, 141*0Sstevel@tonic-gate &cl); 142*0Sstevel@tonic-gate if (error != 0) { 143*0Sstevel@tonic-gate RPCLOG(1, 144*0Sstevel@tonic-gate "clnt_tli_kcreate: clnt_rdma_kcreate failed error %d\n", 145*0Sstevel@tonic-gate error); 146*0Sstevel@tonic-gate return (error); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate break; 149*0Sstevel@tonic-gate default: 150*0Sstevel@tonic-gate error = EINVAL; 151*0Sstevel@tonic-gate RPCLOG(1, "clnt_tli_kcreate: Bad service type %d\n", 152*0Sstevel@tonic-gate config->knc_semantics); 153*0Sstevel@tonic-gate return (error); 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate *ncl = cl; 156*0Sstevel@tonic-gate return (0); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * "Kinit" a client handle by calling the appropriate cots or clts routine. 161*0Sstevel@tonic-gate * 162*0Sstevel@tonic-gate * PSARC 2003/523 Contract Private Interface 163*0Sstevel@tonic-gate * clnt_tli_kinit 164*0Sstevel@tonic-gate * Changes must be reviewed by Solaris File Sharing 165*0Sstevel@tonic-gate * Changes must be communicated to contract-2003-523@sun.com 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate int 168*0Sstevel@tonic-gate clnt_tli_kinit( 169*0Sstevel@tonic-gate CLIENT *h, 170*0Sstevel@tonic-gate struct knetconfig *config, 171*0Sstevel@tonic-gate struct netbuf *addr, 172*0Sstevel@tonic-gate uint_t max_msgsize, 173*0Sstevel@tonic-gate int retries, 174*0Sstevel@tonic-gate struct cred *cred) 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate int error = 0; 177*0Sstevel@tonic-gate int family = AF_UNSPEC; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate switch (config->knc_semantics) { 180*0Sstevel@tonic-gate case NC_TPI_CLTS: 181*0Sstevel@tonic-gate clnt_clts_kinit(h, addr, retries, cred); 182*0Sstevel@tonic-gate break; 183*0Sstevel@tonic-gate case NC_TPI_COTS: 184*0Sstevel@tonic-gate case NC_TPI_COTS_ORD: 185*0Sstevel@tonic-gate RPCLOG0(2, "clnt_tli_kinit: COTS selected\n"); 186*0Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0) 187*0Sstevel@tonic-gate family = AF_INET; 188*0Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0) 189*0Sstevel@tonic-gate family = AF_INET6; 190*0Sstevel@tonic-gate clnt_cots_kinit(h, config->knc_rdev, family, 191*0Sstevel@tonic-gate addr, max_msgsize, cred); 192*0Sstevel@tonic-gate break; 193*0Sstevel@tonic-gate case NC_TPI_RDMA: 194*0Sstevel@tonic-gate RPCLOG0(2, "clnt_tli_kinit: RDMA selected\n"); 195*0Sstevel@tonic-gate clnt_rdma_kinit(h, config->knc_proto, 196*0Sstevel@tonic-gate (void *)config->knc_rdev, addr, cred); 197*0Sstevel@tonic-gate break; 198*0Sstevel@tonic-gate default: 199*0Sstevel@tonic-gate error = EINVAL; 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate return (error); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* 207*0Sstevel@tonic-gate * try to bind to a reserved port 208*0Sstevel@tonic-gate */ 209*0Sstevel@tonic-gate int 210*0Sstevel@tonic-gate bindresvport( 211*0Sstevel@tonic-gate TIUSER *tiptr, 212*0Sstevel@tonic-gate struct netbuf *addr, 213*0Sstevel@tonic-gate struct netbuf *bound_addr, 214*0Sstevel@tonic-gate bool_t tcp) 215*0Sstevel@tonic-gate { 216*0Sstevel@tonic-gate struct sockaddr_in *sin; 217*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 218*0Sstevel@tonic-gate bool_t ipv6_flag = 0; 219*0Sstevel@tonic-gate int i; 220*0Sstevel@tonic-gate struct t_bind *req; 221*0Sstevel@tonic-gate struct t_bind *ret; 222*0Sstevel@tonic-gate int error; 223*0Sstevel@tonic-gate bool_t loop_twice; 224*0Sstevel@tonic-gate int start; 225*0Sstevel@tonic-gate int stop; 226*0Sstevel@tonic-gate ushort_t *last_used; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&req)) != 0) { 229*0Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kalloc %d\n", error); 230*0Sstevel@tonic-gate return (error); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&ret)) != 0) { 234*0Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kalloc %d\n", error); 235*0Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)req, T_BIND); 236*0Sstevel@tonic-gate return (error); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate /* now separate IPv4 and IPv6 by looking at len of tiptr.addr */ 240*0Sstevel@tonic-gate if (tiptr->tp_info.addr == sizeof (struct sockaddr_in6)) { 241*0Sstevel@tonic-gate /* it's IPv6 */ 242*0Sstevel@tonic-gate ipv6_flag = 1; 243*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)req->addr.buf; 244*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 245*0Sstevel@tonic-gate bzero((char *)&sin6->sin6_addr, sizeof (struct in6_addr)); 246*0Sstevel@tonic-gate req->addr.len = sizeof (struct sockaddr_in6); 247*0Sstevel@tonic-gate } else { 248*0Sstevel@tonic-gate /* LINTED pointer alignment */ 249*0Sstevel@tonic-gate sin = (struct sockaddr_in *)req->addr.buf; 250*0Sstevel@tonic-gate sin->sin_family = AF_INET; 251*0Sstevel@tonic-gate sin->sin_addr.s_addr = INADDR_ANY; 252*0Sstevel@tonic-gate req->addr.len = sizeof (struct sockaddr_in); 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * Caller wants to bind to a specific port, so don't bother with the 257*0Sstevel@tonic-gate * loop that binds to the next free one. 258*0Sstevel@tonic-gate */ 259*0Sstevel@tonic-gate if (addr) { 260*0Sstevel@tonic-gate if (ipv6_flag) { 261*0Sstevel@tonic-gate sin6->sin6_port = 262*0Sstevel@tonic-gate ((struct sockaddr_in6 *)addr->buf)->sin6_port; 263*0Sstevel@tonic-gate } else { 264*0Sstevel@tonic-gate sin->sin_port = 265*0Sstevel@tonic-gate ((struct sockaddr_in *)addr->buf)->sin_port; 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate RPCLOG(8, "bindresvport: calling t_kbind tiptr = %p\n", 268*0Sstevel@tonic-gate (void *)tiptr); 269*0Sstevel@tonic-gate if ((error = t_kbind(tiptr, req, ret)) != 0) { 270*0Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kbind: %d\n", error); 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * The unbind is called in case the bind failed 273*0Sstevel@tonic-gate * with an EINTR potentially leaving the 274*0Sstevel@tonic-gate * transport in bound state. 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate if (error == EINTR) 277*0Sstevel@tonic-gate (void) t_kunbind(tiptr); 278*0Sstevel@tonic-gate } else if (bcmp(req->addr.buf, ret->addr.buf, 279*0Sstevel@tonic-gate ret->addr.len) != 0) { 280*0Sstevel@tonic-gate RPCLOG0(1, "bindresvport: bcmp error\n"); 281*0Sstevel@tonic-gate (void) t_kunbind(tiptr); 282*0Sstevel@tonic-gate error = EADDRINUSE; 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate } else { 285*0Sstevel@tonic-gate if (tcp) 286*0Sstevel@tonic-gate last_used = &clnt_tcp_last_used; 287*0Sstevel@tonic-gate else 288*0Sstevel@tonic-gate last_used = &clnt_udp_last_used; 289*0Sstevel@tonic-gate error = EADDRINUSE; 290*0Sstevel@tonic-gate stop = MIN_PRIV; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate start = (*last_used == MIN_PRIV ? MAX_PRIV : *last_used - 1); 293*0Sstevel@tonic-gate loop_twice = (start < MAX_PRIV ? TRUE : FALSE); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate bindresvport_again: 296*0Sstevel@tonic-gate for (i = start; 297*0Sstevel@tonic-gate (error == EADDRINUSE || error == EADDRNOTAVAIL) && 298*0Sstevel@tonic-gate i >= stop; i--) { 299*0Sstevel@tonic-gate if (ipv6_flag) 300*0Sstevel@tonic-gate sin6->sin6_port = htons(i); 301*0Sstevel@tonic-gate else 302*0Sstevel@tonic-gate sin->sin_port = htons(i); 303*0Sstevel@tonic-gate RPCLOG(8, "bindresvport: calling t_kbind tiptr = 0%p\n", 304*0Sstevel@tonic-gate (void *)tiptr); 305*0Sstevel@tonic-gate if ((error = t_kbind(tiptr, req, ret)) != 0) { 306*0Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kbind: %d\n", error); 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * The unbind is called in case the bind failed 309*0Sstevel@tonic-gate * with an EINTR potentially leaving the 310*0Sstevel@tonic-gate * transport in bound state. 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate if (error == EINTR) 313*0Sstevel@tonic-gate (void) t_kunbind(tiptr); 314*0Sstevel@tonic-gate } else if (bcmp(req->addr.buf, ret->addr.buf, 315*0Sstevel@tonic-gate ret->addr.len) != 0) { 316*0Sstevel@tonic-gate RPCLOG0(1, "bindresvport: bcmp error\n"); 317*0Sstevel@tonic-gate (void) t_kunbind(tiptr); 318*0Sstevel@tonic-gate error = EADDRINUSE; 319*0Sstevel@tonic-gate } else 320*0Sstevel@tonic-gate error = 0; 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate if (!error) { 323*0Sstevel@tonic-gate if (ipv6_flag) { 324*0Sstevel@tonic-gate RPCLOG(8, "bindresvport: port assigned %d\n", 325*0Sstevel@tonic-gate sin6->sin6_port); 326*0Sstevel@tonic-gate *last_used = ntohs(sin6->sin6_port); 327*0Sstevel@tonic-gate } else { 328*0Sstevel@tonic-gate RPCLOG(8, "bindresvport: port assigned %d\n", 329*0Sstevel@tonic-gate sin->sin_port); 330*0Sstevel@tonic-gate *last_used = ntohs(sin->sin_port); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate } else if (loop_twice) { 333*0Sstevel@tonic-gate loop_twice = FALSE; 334*0Sstevel@tonic-gate start = MAX_PRIV; 335*0Sstevel@tonic-gate stop = *last_used + 1; 336*0Sstevel@tonic-gate goto bindresvport_again; 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate if (!error && bound_addr) { 341*0Sstevel@tonic-gate bcopy(ret->addr.buf, bound_addr->buf, ret->addr.len); 342*0Sstevel@tonic-gate bound_addr->len = ret->addr.len; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)req, T_BIND); 345*0Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)ret, T_BIND); 346*0Sstevel@tonic-gate return (error); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate void 350*0Sstevel@tonic-gate clnt_init(void) 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate clnt_cots_init(); 353*0Sstevel@tonic-gate clnt_clts_init(); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate void 357*0Sstevel@tonic-gate clnt_fini(void) 358*0Sstevel@tonic-gate { 359*0Sstevel@tonic-gate clnt_clts_fini(); 360*0Sstevel@tonic-gate clnt_cots_fini(); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate call_table_t * 364*0Sstevel@tonic-gate call_table_init(int size) 365*0Sstevel@tonic-gate { 366*0Sstevel@tonic-gate call_table_t *ctp; 367*0Sstevel@tonic-gate int i; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate ctp = kmem_alloc(sizeof (call_table_t) * size, KM_SLEEP); 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate for (i = 0; i < size; i++) { 372*0Sstevel@tonic-gate ctp[i].ct_call_next = (calllist_t *)&ctp[i]; 373*0Sstevel@tonic-gate ctp[i].ct_call_prev = (calllist_t *)&ctp[i]; 374*0Sstevel@tonic-gate mutex_init(&ctp[i].ct_lock, NULL, MUTEX_DEFAULT, NULL); 375*0Sstevel@tonic-gate ctp[i].ct_len = 0; 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate return (ctp); 379*0Sstevel@tonic-gate } 380