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