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