10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52416Sjarrett * Common Development and Distribution License (the "License").
62416Sjarrett * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
222416Sjarrett * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
310Sstevel@tonic-gate * under license from the Regents of the University of California.
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
350Sstevel@tonic-gate
360Sstevel@tonic-gate #include <sys/param.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <rpc/types.h>
390Sstevel@tonic-gate #include <netinet/in.h>
400Sstevel@tonic-gate #include <rpc/auth.h>
410Sstevel@tonic-gate #include <rpc/clnt.h>
420Sstevel@tonic-gate #include <sys/tiuser.h>
430Sstevel@tonic-gate #include <sys/t_kuser.h>
440Sstevel@tonic-gate #include <rpc/svc.h>
450Sstevel@tonic-gate #include <rpc/xdr.h>
460Sstevel@tonic-gate #include <sys/file.h>
470Sstevel@tonic-gate #include <sys/user.h>
480Sstevel@tonic-gate #include <sys/proc.h>
490Sstevel@tonic-gate #include <sys/vnode.h>
500Sstevel@tonic-gate #include <sys/stream.h>
510Sstevel@tonic-gate #include <sys/tihdr.h>
520Sstevel@tonic-gate #include <sys/fcntl.h>
530Sstevel@tonic-gate #include <sys/socket.h>
540Sstevel@tonic-gate #include <sys/sysmacros.h>
550Sstevel@tonic-gate #include <sys/errno.h>
560Sstevel@tonic-gate #include <sys/cred.h>
570Sstevel@tonic-gate #include <sys/systm.h>
580Sstevel@tonic-gate #include <sys/cmn_err.h>
590Sstevel@tonic-gate
600Sstevel@tonic-gate #define NC_INET "inet"
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define MAX_PRIV (IPPORT_RESERVED-1)
630Sstevel@tonic-gate #define MIN_PRIV (IPPORT_RESERVED/2)
640Sstevel@tonic-gate
650Sstevel@tonic-gate ushort_t clnt_udp_last_used = MIN_PRIV;
660Sstevel@tonic-gate ushort_t clnt_tcp_last_used = MIN_PRIV;
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * PSARC 2003/523 Contract Private Interface
700Sstevel@tonic-gate * clnt_tli_kcreate
710Sstevel@tonic-gate * Changes must be reviewed by Solaris File Sharing
720Sstevel@tonic-gate * Changes must be communicated to contract-2003-523@sun.com
730Sstevel@tonic-gate */
740Sstevel@tonic-gate int
clnt_tli_kcreate(struct knetconfig * config,struct netbuf * svcaddr,rpcprog_t prog,rpcvers_t vers,uint_t max_msgsize,int retries,struct cred * cred,CLIENT ** ncl)750Sstevel@tonic-gate clnt_tli_kcreate(
760Sstevel@tonic-gate struct knetconfig *config,
770Sstevel@tonic-gate struct netbuf *svcaddr, /* Servers address */
780Sstevel@tonic-gate rpcprog_t prog, /* Program number */
790Sstevel@tonic-gate rpcvers_t vers, /* Version number */
800Sstevel@tonic-gate uint_t max_msgsize,
810Sstevel@tonic-gate int retries,
820Sstevel@tonic-gate struct cred *cred,
830Sstevel@tonic-gate CLIENT **ncl)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate CLIENT *cl; /* Client handle */
860Sstevel@tonic-gate int error;
870Sstevel@tonic-gate int family = AF_UNSPEC;
880Sstevel@tonic-gate
890Sstevel@tonic-gate error = 0;
900Sstevel@tonic-gate cl = NULL;
910Sstevel@tonic-gate
920Sstevel@tonic-gate RPCLOG(8, "clnt_tli_kcreate: prog %x", prog);
930Sstevel@tonic-gate RPCLOG(8, ", vers %d", vers);
940Sstevel@tonic-gate RPCLOG(8, ", knc_semantics %d", config->knc_semantics);
950Sstevel@tonic-gate RPCLOG(8, ", knc_protofmly %s", config->knc_protofmly);
960Sstevel@tonic-gate RPCLOG(8, ", knc_proto %s\n", config->knc_proto);
970Sstevel@tonic-gate
980Sstevel@tonic-gate if (config == NULL || config->knc_protofmly == NULL || ncl == NULL) {
990Sstevel@tonic-gate RPCLOG0(1, "clnt_tli_kcreate: bad config or handle\n");
1000Sstevel@tonic-gate return (EINVAL);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate switch (config->knc_semantics) {
1040Sstevel@tonic-gate case NC_TPI_CLTS:
1050Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: CLTS selected\n");
1060Sstevel@tonic-gate error = clnt_clts_kcreate(config, svcaddr, prog, vers,
1070Sstevel@tonic-gate retries, cred, &cl);
1080Sstevel@tonic-gate if (error != 0) {
1090Sstevel@tonic-gate RPCLOG(1,
1100Sstevel@tonic-gate "clnt_tli_kcreate: clnt_clts_kcreate failed error %d\n",
1110Sstevel@tonic-gate error);
1120Sstevel@tonic-gate return (error);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate break;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate case NC_TPI_COTS:
1170Sstevel@tonic-gate case NC_TPI_COTS_ORD:
1180Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: COTS selected\n");
1190Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0)
1200Sstevel@tonic-gate family = AF_INET;
1210Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
1220Sstevel@tonic-gate family = AF_INET6;
1230Sstevel@tonic-gate error = clnt_cots_kcreate(config->knc_rdev, svcaddr, family,
1240Sstevel@tonic-gate prog, vers, max_msgsize, cred, &cl);
1250Sstevel@tonic-gate if (error != 0) {
1260Sstevel@tonic-gate RPCLOG(1,
1270Sstevel@tonic-gate "clnt_tli_kcreate: clnt_cots_kcreate failed error %d\n",
1280Sstevel@tonic-gate error);
1290Sstevel@tonic-gate return (error);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate break;
1320Sstevel@tonic-gate case NC_TPI_RDMA:
1330Sstevel@tonic-gate RPCLOG0(8, "clnt_tli_kcreate: RDMA selected\n");
1342416Sjarrett /*
1352416Sjarrett * RDMA doesn't support TSOL. It's better to
1362416Sjarrett * disallow it here.
1372416Sjarrett */
1382416Sjarrett if (is_system_labeled()) {
1392416Sjarrett RPCLOG0(1, "clnt_tli_kcreate: tsol not supported\n");
1402416Sjarrett return (EPROTONOSUPPORT);
1412416Sjarrett }
1422416Sjarrett
1430Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0)
1440Sstevel@tonic-gate family = AF_INET;
1450Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
1460Sstevel@tonic-gate family = AF_INET6;
1470Sstevel@tonic-gate error = clnt_rdma_kcreate(config->knc_proto,
1480Sstevel@tonic-gate (void *)config->knc_rdev, svcaddr, family, prog, vers, cred,
1490Sstevel@tonic-gate &cl);
1500Sstevel@tonic-gate if (error != 0) {
1510Sstevel@tonic-gate RPCLOG(1,
1520Sstevel@tonic-gate "clnt_tli_kcreate: clnt_rdma_kcreate failed error %d\n",
1530Sstevel@tonic-gate error);
1540Sstevel@tonic-gate return (error);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate break;
1570Sstevel@tonic-gate default:
1580Sstevel@tonic-gate error = EINVAL;
1590Sstevel@tonic-gate RPCLOG(1, "clnt_tli_kcreate: Bad service type %d\n",
1600Sstevel@tonic-gate config->knc_semantics);
1610Sstevel@tonic-gate return (error);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate *ncl = cl;
1640Sstevel@tonic-gate return (0);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate * "Kinit" a client handle by calling the appropriate cots or clts routine.
1690Sstevel@tonic-gate *
1700Sstevel@tonic-gate * PSARC 2003/523 Contract Private Interface
1710Sstevel@tonic-gate * clnt_tli_kinit
1720Sstevel@tonic-gate * Changes must be reviewed by Solaris File Sharing
1730Sstevel@tonic-gate * Changes must be communicated to contract-2003-523@sun.com
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate int
clnt_tli_kinit(CLIENT * h,struct knetconfig * config,struct netbuf * addr,uint_t max_msgsize,int retries,struct cred * cred)1760Sstevel@tonic-gate clnt_tli_kinit(
1770Sstevel@tonic-gate CLIENT *h,
1780Sstevel@tonic-gate struct knetconfig *config,
1790Sstevel@tonic-gate struct netbuf *addr,
1800Sstevel@tonic-gate uint_t max_msgsize,
1810Sstevel@tonic-gate int retries,
1820Sstevel@tonic-gate struct cred *cred)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate int error = 0;
1850Sstevel@tonic-gate int family = AF_UNSPEC;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate switch (config->knc_semantics) {
1880Sstevel@tonic-gate case NC_TPI_CLTS:
1890Sstevel@tonic-gate clnt_clts_kinit(h, addr, retries, cred);
1900Sstevel@tonic-gate break;
1910Sstevel@tonic-gate case NC_TPI_COTS:
1920Sstevel@tonic-gate case NC_TPI_COTS_ORD:
1930Sstevel@tonic-gate RPCLOG0(2, "clnt_tli_kinit: COTS selected\n");
1940Sstevel@tonic-gate if (strcmp(config->knc_protofmly, NC_INET) == 0)
1950Sstevel@tonic-gate family = AF_INET;
1960Sstevel@tonic-gate else if (strcmp(config->knc_protofmly, NC_INET6) == 0)
1970Sstevel@tonic-gate family = AF_INET6;
1980Sstevel@tonic-gate clnt_cots_kinit(h, config->knc_rdev, family,
1990Sstevel@tonic-gate addr, max_msgsize, cred);
2000Sstevel@tonic-gate break;
2010Sstevel@tonic-gate case NC_TPI_RDMA:
2020Sstevel@tonic-gate RPCLOG0(2, "clnt_tli_kinit: RDMA selected\n");
2030Sstevel@tonic-gate clnt_rdma_kinit(h, config->knc_proto,
2040Sstevel@tonic-gate (void *)config->knc_rdev, addr, cred);
2050Sstevel@tonic-gate break;
2060Sstevel@tonic-gate default:
2070Sstevel@tonic-gate error = EINVAL;
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate return (error);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * try to bind to a reserved port
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate int
bindresvport(TIUSER * tiptr,struct netbuf * addr,struct netbuf * bound_addr,bool_t tcp)2180Sstevel@tonic-gate bindresvport(
2190Sstevel@tonic-gate TIUSER *tiptr,
2200Sstevel@tonic-gate struct netbuf *addr,
2210Sstevel@tonic-gate struct netbuf *bound_addr,
2220Sstevel@tonic-gate bool_t tcp)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate struct sockaddr_in *sin;
2250Sstevel@tonic-gate struct sockaddr_in6 *sin6;
2260Sstevel@tonic-gate bool_t ipv6_flag = 0;
2270Sstevel@tonic-gate int i;
2280Sstevel@tonic-gate struct t_bind *req;
2290Sstevel@tonic-gate struct t_bind *ret;
2300Sstevel@tonic-gate int error;
2310Sstevel@tonic-gate bool_t loop_twice;
2320Sstevel@tonic-gate int start;
2330Sstevel@tonic-gate int stop;
2340Sstevel@tonic-gate ushort_t *last_used;
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&req)) != 0) {
2370Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kalloc %d\n", error);
2380Sstevel@tonic-gate return (error);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate if ((error = t_kalloc(tiptr, T_BIND, T_ADDR, (char **)&ret)) != 0) {
2420Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kalloc %d\n", error);
2430Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)req, T_BIND);
2440Sstevel@tonic-gate return (error);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /* now separate IPv4 and IPv6 by looking at len of tiptr.addr */
2480Sstevel@tonic-gate if (tiptr->tp_info.addr == sizeof (struct sockaddr_in6)) {
2490Sstevel@tonic-gate /* it's IPv6 */
2500Sstevel@tonic-gate ipv6_flag = 1;
2510Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)req->addr.buf;
2520Sstevel@tonic-gate sin6->sin6_family = AF_INET6;
2530Sstevel@tonic-gate bzero((char *)&sin6->sin6_addr, sizeof (struct in6_addr));
2540Sstevel@tonic-gate req->addr.len = sizeof (struct sockaddr_in6);
2550Sstevel@tonic-gate } else {
2560Sstevel@tonic-gate /* LINTED pointer alignment */
2570Sstevel@tonic-gate sin = (struct sockaddr_in *)req->addr.buf;
2580Sstevel@tonic-gate sin->sin_family = AF_INET;
2590Sstevel@tonic-gate sin->sin_addr.s_addr = INADDR_ANY;
2600Sstevel@tonic-gate req->addr.len = sizeof (struct sockaddr_in);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Caller wants to bind to a specific port, so don't bother with the
2650Sstevel@tonic-gate * loop that binds to the next free one.
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate if (addr) {
2680Sstevel@tonic-gate if (ipv6_flag) {
2690Sstevel@tonic-gate sin6->sin6_port =
2700Sstevel@tonic-gate ((struct sockaddr_in6 *)addr->buf)->sin6_port;
2710Sstevel@tonic-gate } else {
2720Sstevel@tonic-gate sin->sin_port =
2730Sstevel@tonic-gate ((struct sockaddr_in *)addr->buf)->sin_port;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate RPCLOG(8, "bindresvport: calling t_kbind tiptr = %p\n",
2760Sstevel@tonic-gate (void *)tiptr);
2770Sstevel@tonic-gate if ((error = t_kbind(tiptr, req, ret)) != 0) {
2780Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kbind: %d\n", error);
2790Sstevel@tonic-gate /*
2800Sstevel@tonic-gate * The unbind is called in case the bind failed
2810Sstevel@tonic-gate * with an EINTR potentially leaving the
2820Sstevel@tonic-gate * transport in bound state.
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate if (error == EINTR)
2850Sstevel@tonic-gate (void) t_kunbind(tiptr);
2860Sstevel@tonic-gate } else if (bcmp(req->addr.buf, ret->addr.buf,
2870Sstevel@tonic-gate ret->addr.len) != 0) {
2880Sstevel@tonic-gate RPCLOG0(1, "bindresvport: bcmp error\n");
2890Sstevel@tonic-gate (void) t_kunbind(tiptr);
2900Sstevel@tonic-gate error = EADDRINUSE;
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate } else {
2930Sstevel@tonic-gate if (tcp)
2940Sstevel@tonic-gate last_used = &clnt_tcp_last_used;
2950Sstevel@tonic-gate else
2960Sstevel@tonic-gate last_used = &clnt_udp_last_used;
2970Sstevel@tonic-gate error = EADDRINUSE;
2980Sstevel@tonic-gate stop = MIN_PRIV;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate start = (*last_used == MIN_PRIV ? MAX_PRIV : *last_used - 1);
3010Sstevel@tonic-gate loop_twice = (start < MAX_PRIV ? TRUE : FALSE);
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate bindresvport_again:
3040Sstevel@tonic-gate for (i = start;
3050Sstevel@tonic-gate (error == EADDRINUSE || error == EADDRNOTAVAIL) &&
3060Sstevel@tonic-gate i >= stop; i--) {
3070Sstevel@tonic-gate if (ipv6_flag)
3080Sstevel@tonic-gate sin6->sin6_port = htons(i);
3090Sstevel@tonic-gate else
3100Sstevel@tonic-gate sin->sin_port = htons(i);
3110Sstevel@tonic-gate RPCLOG(8, "bindresvport: calling t_kbind tiptr = 0%p\n",
3120Sstevel@tonic-gate (void *)tiptr);
3130Sstevel@tonic-gate if ((error = t_kbind(tiptr, req, ret)) != 0) {
3140Sstevel@tonic-gate RPCLOG(1, "bindresvport: t_kbind: %d\n", error);
3150Sstevel@tonic-gate /*
3160Sstevel@tonic-gate * The unbind is called in case the bind failed
3170Sstevel@tonic-gate * with an EINTR potentially leaving the
3180Sstevel@tonic-gate * transport in bound state.
3190Sstevel@tonic-gate */
3200Sstevel@tonic-gate if (error == EINTR)
3210Sstevel@tonic-gate (void) t_kunbind(tiptr);
3220Sstevel@tonic-gate } else if (bcmp(req->addr.buf, ret->addr.buf,
3230Sstevel@tonic-gate ret->addr.len) != 0) {
3240Sstevel@tonic-gate RPCLOG0(1, "bindresvport: bcmp error\n");
3250Sstevel@tonic-gate (void) t_kunbind(tiptr);
3260Sstevel@tonic-gate error = EADDRINUSE;
3270Sstevel@tonic-gate } else
3280Sstevel@tonic-gate error = 0;
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate if (!error) {
3310Sstevel@tonic-gate if (ipv6_flag) {
3320Sstevel@tonic-gate RPCLOG(8, "bindresvport: port assigned %d\n",
3330Sstevel@tonic-gate sin6->sin6_port);
3340Sstevel@tonic-gate *last_used = ntohs(sin6->sin6_port);
3350Sstevel@tonic-gate } else {
3360Sstevel@tonic-gate RPCLOG(8, "bindresvport: port assigned %d\n",
3370Sstevel@tonic-gate sin->sin_port);
3380Sstevel@tonic-gate *last_used = ntohs(sin->sin_port);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate } else if (loop_twice) {
3410Sstevel@tonic-gate loop_twice = FALSE;
3420Sstevel@tonic-gate start = MAX_PRIV;
3430Sstevel@tonic-gate stop = *last_used + 1;
3440Sstevel@tonic-gate goto bindresvport_again;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate if (!error && bound_addr) {
349*2712Snn35248 if (bound_addr->maxlen < ret->addr.len) {
350*2712Snn35248 kmem_free(bound_addr->buf, bound_addr->maxlen);
351*2712Snn35248 bound_addr->buf = kmem_zalloc(ret->addr.len, KM_SLEEP);
352*2712Snn35248 bound_addr->maxlen = ret->addr.len;
353*2712Snn35248 }
3540Sstevel@tonic-gate bcopy(ret->addr.buf, bound_addr->buf, ret->addr.len);
3550Sstevel@tonic-gate bound_addr->len = ret->addr.len;
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)req, T_BIND);
3580Sstevel@tonic-gate (void) t_kfree(tiptr, (char *)ret, T_BIND);
3590Sstevel@tonic-gate return (error);
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate void
clnt_init(void)3630Sstevel@tonic-gate clnt_init(void)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate clnt_cots_init();
3660Sstevel@tonic-gate clnt_clts_init();
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate void
clnt_fini(void)3700Sstevel@tonic-gate clnt_fini(void)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate clnt_clts_fini();
3730Sstevel@tonic-gate clnt_cots_fini();
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate call_table_t *
call_table_init(int size)3770Sstevel@tonic-gate call_table_init(int size)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate call_table_t *ctp;
3800Sstevel@tonic-gate int i;
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate ctp = kmem_alloc(sizeof (call_table_t) * size, KM_SLEEP);
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate for (i = 0; i < size; i++) {
3850Sstevel@tonic-gate ctp[i].ct_call_next = (calllist_t *)&ctp[i];
3860Sstevel@tonic-gate ctp[i].ct_call_prev = (calllist_t *)&ctp[i];
3870Sstevel@tonic-gate mutex_init(&ctp[i].ct_lock, NULL, MUTEX_DEFAULT, NULL);
3880Sstevel@tonic-gate ctp[i].ct_len = 0;
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate return (ctp);
3920Sstevel@tonic-gate }
393