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