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