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 2004 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 /*
38 * Boot subsystem client side rpc (TCP)
39 */
40
41 #include <sys/salib.h>
42 #include <sys/errno.h>
43 #include <rpc/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include "socket_inet.h"
47 #include "ipv4.h"
48 #include "clnt.h"
49 #include <rpc/rpc.h>
50 #include "brpc.h"
51 #include "pmap.h"
52 #include <sys/promif.h>
53 #include <rpc/xdr.h>
54 #include <rpc/auth.h>
55 #include <rpc/auth_sys.h>
56 #include "auth_inet.h"
57 #include <rpc/rpc_msg.h>
58 #include <sys/bootdebug.h>
59
60 #define dprintf if (boothowto & RB_DEBUG) printf
61
62 #define MCALL_MSG_SIZE 24
63
64 extern int errno;
65
66 extern void xdrrec_create();
67 extern bool_t xdrrec_endofrecord();
68 extern bool_t xdrrec_skiprecord();
69
70 /*
71 * If we create another clnt type this should be
72 * moved to a common file
73 */
74 struct rpc_createerr rpc_createerr;
75
76 static int readtcp();
77 static int writetcp();
78
79 static struct clnt_ops *clntbtcp_ops();
80
81 /*
82 * Private data kept per client handle
83 */
84 struct ct_data {
85 int ct_sock;
86 bool_t ct_closeit;
87 struct sockaddr_in ct_raddr;
88 uint_t ct_wait_msec;
89 struct timeval ct_total;
90 struct rpc_err ct_error;
91 XDR ct_xdrs;
92 char ct_mcall[MCALL_MSG_SIZE];
93 uint_t ct_mpos;
94 uint_t ct_xdrpos;
95 };
96
97 /*
98 * Create a TCP based client handle.
99 * If *sockp<0, *sockp is set to a newly created TCP socket.
100 * If raddr->sin_port is 0 a binder on the remote machine
101 * is consulted for the correct port number.
102 * NB: It is the clients responsibility to close *sockp.
103 * NB: The rpch->cl_auth is initialized to null authentication.
104 * Caller may wish to set this something more useful.
105 *
106 * wait is the amount of time used between retransmitting a call if
107 * no response has been heard; retransmition occurs until the actual
108 * rpc call times out.
109 *
110 * sendsz and recvsz are the maximum allowable packet sizes that can be
111 * sent and received.
112 */
113 CLIENT *
clntbtcp_create(struct sockaddr_in * raddr,rpcprog_t program,rpcvers_t version,struct timeval wait,int * sockp,uint_t sendsz,uint_t recvsz)114 clntbtcp_create(
115 struct sockaddr_in *raddr,
116 rpcprog_t program,
117 rpcvers_t version,
118 struct timeval wait,
119 int *sockp,
120 uint_t sendsz,
121 uint_t recvsz)
122 {
123 CLIENT *cl;
124 struct ct_data *ct;
125 struct rpc_msg call_msg;
126 #if 0 /* XXX not yet */
127 int min_buf_sz;
128 int pref_buf_sz = 64 * 1024; /* 64 KB */
129 socklen_t optlen;
130 #endif /* not yet */
131 cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT));
132 if (cl == NULL) {
133 errno = ENOMEM;
134 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
135 rpc_createerr.cf_error.re_errno = errno;
136 return ((CLIENT *)NULL);
137 }
138
139 ct = (struct ct_data *)bkmem_alloc(sizeof (*ct));
140 if (ct == NULL) {
141 errno = ENOMEM;
142 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
143 rpc_createerr.cf_error.re_errno = errno;
144 goto fooy;
145 }
146
147 if (raddr->sin_port == 0) {
148 ushort_t port;
149 if ((port = bpmap_getport(program, version,
150 &(rpc_createerr.cf_stat), raddr, NULL)) == 0) {
151 goto fooy;
152 }
153 raddr->sin_port = htons(port);
154 }
155
156 if (*sockp < 0) {
157 struct sockaddr_in from;
158
159 *sockp = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
160 if (*sockp < 0) {
161 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
162 rpc_createerr.cf_error.re_errno = errno;
163 goto fooy;
164 }
165 /*
166 * Bootparams assumes a local net, so be sure to let lower
167 * layer protocols know not to route.
168 */
169 if (dontroute) {
170 (void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE,
171 (const void *)&dontroute, sizeof (dontroute));
172 }
173
174 /* attempt to bind to priv port */
175 from.sin_family = AF_INET;
176 ipv4_getipaddr(&from.sin_addr);
177 from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
178 from.sin_port = get_source_port(TRUE);
179
180 if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) {
181 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
182 rpc_createerr.cf_error.re_errno = errno;
183 if (*sockp > 0)
184 close(*sockp);
185 goto fooy;
186 }
187
188 if (connect(*sockp, (struct sockaddr *)raddr,
189 sizeof (struct sockaddr_in)) < 0) {
190 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
191 rpc_createerr.cf_error.re_errno = errno;
192 if (*sockp > 0)
193 close(*sockp);
194 goto fooy;
195 }
196
197 #if 0 /* XXX not yet */
198 /*
199 * In the future we may want RPC to use larger transfer sizes
200 * over TCP. In this case we will want to increase the
201 * window size.
202 */
203 /*
204 * Resize the receive window if possible
205 */
206 optlen = sizeof (int);
207 if (getsockopt(*sockp, SOL_SOCKET, SO_RCVBUF,
208 (void *)&min_buf_sz, &optlen) != 0)
209 goto keep_going;
210
211 if (min_buf_sz < pref_buf_sz)
212 (void) setsockopt(*sockp, SOL_SOCKET, SO_RCVBUF,
213 (const void *)&pref_buf_sz, sizeof (int));
214
215 keep_going:
216 #endif /* not yet */
217 ct->ct_closeit = TRUE;
218 } else
219 ct->ct_closeit = FALSE;
220
221 /*
222 * Set up the private data
223 */
224 ct->ct_sock = *sockp;
225 ct->ct_wait_msec = 0;
226 ct->ct_total.tv_sec = wait.tv_sec;
227 ct->ct_total.tv_usec = -1;
228 ct->ct_raddr = *raddr;
229
230 /*
231 * Initialize the call message
232 */
233
234 /*
235 * XXX - The xid might need to be randomized more. Imagine if there
236 * are a rack of blade servers all booting at the same time. They
237 * may cause havoc on the server with xid replays.
238 */
239 call_msg.rm_xid = (uint_t)prom_gettime() + 1;
240 call_msg.rm_direction = CALL;
241 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
242 call_msg.rm_call.cb_prog = program;
243 call_msg.rm_call.cb_vers = version;
244
245 /*
246 * pre-serialize the static part of the call msg and stash it away
247 */
248 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
249 XDR_ENCODE);
250 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
251 if (ct->ct_closeit)
252 (void) close(*sockp);
253 goto fooy;
254 }
255 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
256 XDR_DESTROY(&(ct->ct_xdrs));
257
258 /*
259 * XXX - Memory allocations can fail in xdrrec_create, so we need to
260 * be able to catch those errors.
261 */
262 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, readtcp,
263 writetcp);
264
265 cl->cl_ops = clntbtcp_ops();
266 cl->cl_private = (caddr_t)ct;
267 cl->cl_auth = authnone_create();
268 return (cl);
269
270 fooy:
271 if (ct)
272 bkmem_free((caddr_t)ct, sizeof (*ct));
273 if (cl)
274 bkmem_free((caddr_t)cl, sizeof (CLIENT));
275 return ((CLIENT *)NULL);
276 }
277
278 static enum clnt_stat
clntbtcp_call(CLIENT * cl,rpcproc_t proc,xdrproc_t xargs,caddr_t argsp,xdrproc_t xdr_results,caddr_t resultsp,struct timeval utimeout)279 clntbtcp_call(
280 CLIENT *cl,
281 rpcproc_t proc,
282 xdrproc_t xargs,
283 caddr_t argsp,
284 xdrproc_t xdr_results,
285 caddr_t resultsp,
286 struct timeval utimeout)
287 {
288 struct ct_data *ct;
289 XDR *xdrs;
290 struct rpc_msg reply_msg;
291 uint32_t x_id;
292 uint32_t *msg_x_id;
293 bool_t shipnow;
294 int nrefreshes = 2; /* number of times to refresh cred */
295 struct timeval timeout;
296
297 ct = (struct ct_data *)cl->cl_private;
298 msg_x_id = (uint32_t *)ct->ct_mcall;
299
300 xdrs = &(ct->ct_xdrs);
301
302 ct->ct_total = utimeout;
303
304 /*
305 * We have to be able to wait for some non-zero period of time, so
306 * use a default timeout.
307 */
308 if (ct->ct_total.tv_sec == 0)
309 ct->ct_total.tv_sec = RPC_RCVWAIT_MSEC / 1000;
310
311 ct->ct_wait_msec = ct->ct_total.tv_sec * 1000 +
312 ct->ct_total.tv_usec / 1000;
313
314 timeout = ct->ct_total;
315
316 shipnow = (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 &&
317 timeout.tv_usec == 0) ? FALSE : TRUE;
318
319 call_again:
320 xdrs->x_op = XDR_ENCODE;
321 ct->ct_error.re_status = RPC_SUCCESS;
322 x_id = ntohl(++(*msg_x_id));
323 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
324 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
325 (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) ||
326 (! (*xargs)(xdrs, argsp))) {
327 (void) xdrrec_endofrecord(xdrs, TRUE);
328 ct->ct_error.re_status = RPC_CANTENCODEARGS;
329 printf("clntbtcp_call: xdr encode args failed\n");
330 return (ct->ct_error.re_status);
331 }
332
333 if (!xdrrec_endofrecord(xdrs, shipnow)) {
334 printf("clntbtcp_call: rpc cansend error\n");
335 ct->ct_error.re_status = RPC_CANTSEND;
336 return (ct->ct_error.re_status);
337 }
338
339 if (!shipnow)
340 return (RPC_SUCCESS);
341
342 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
343 ct->ct_error.re_status = RPC_TIMEDOUT;
344 return (ct->ct_error.re_status);
345 }
346
347 xdrs->x_op = XDR_DECODE;
348
349 /* CONSTCOND */
350 while (TRUE) {
351 reply_msg.acpted_rply.ar_verf = _null_auth;
352 reply_msg.acpted_rply.ar_results.where = NULL;
353 reply_msg.acpted_rply.ar_results.proc = xdr_void;
354 if (!xdrrec_skiprecord(xdrs)) {
355 return (ct->ct_error.re_status);
356 }
357
358 if (!xdr_replymsg(xdrs, &reply_msg)) {
359 if (ct->ct_error.re_status == RPC_SUCCESS)
360 continue;
361 return (ct->ct_error.re_status);
362 }
363 if (reply_msg.rm_xid == x_id) {
364 break;
365 }
366 }
367
368 /*
369 * process header
370 */
371 _seterr_reply(&reply_msg, &(ct->ct_error));
372 if (ct->ct_error.re_status == RPC_SUCCESS) {
373 if (!AUTH_VALIDATE(cl->cl_auth,
374 &reply_msg.acpted_rply.ar_verf)) {
375 ct->ct_error.re_status = RPC_AUTHERROR;
376 ct->ct_error.re_why = AUTH_INVALIDRESP;
377 } else if (!(*xdr_results)(xdrs, resultsp)) {
378 if (ct->ct_error.re_status == RPC_SUCCESS) {
379 ct->ct_error.re_status = RPC_CANTDECODERES;
380 }
381 }
382 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
383 xdrs->x_op = XDR_FREE;
384 (void) xdr_opaque_auth(xdrs,
385 &(reply_msg.acpted_rply.ar_verf));
386 }
387 } else {
388 if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg,
389 NULL)) {
390 goto call_again;
391 }
392 }
393 return (ct->ct_error.re_status);
394 }
395
396 /*
397 * Interface between xdr serializer and tcp connection.
398 * Behaves like the system calls, read & write, but keeps some error state
399 * around for the rpc level.
400 */
401 static int
readtcp(struct ct_data * ct,caddr_t buf,int len)402 readtcp(struct ct_data *ct,
403 caddr_t buf,
404 int len)
405 {
406 int inlen = 0;
407 uint_t start, diff;
408 struct sockaddr from;
409 uint_t fromlen = sizeof (from);
410
411 if (len <= 0)
412 return (0);
413
414 /*
415 * Do non-blocking reads here until we get some data or timeout
416 */
417 start = prom_gettime();
418 while ((inlen = recvfrom(ct->ct_sock, buf, len, 0, &from,
419 &fromlen)) == 0) {
420 diff = (uint_t)(prom_gettime() - start);
421 if (diff > ct->ct_wait_msec) {
422 errno = ETIMEDOUT;
423 inlen = -1;
424 break;
425 }
426 }
427 #ifdef DEBUG
428 printf("readtcp: inlen = %d\n", inlen);
429 #endif
430 switch (inlen) {
431 case 0:
432 /* premature eof */
433 ct->ct_error.re_errno = ECONNRESET;
434 ct->ct_error.re_status = RPC_CANTRECV;
435 inlen = -1; /* it's really an error */
436 break;
437 case -1:
438 ct->ct_error.re_errno = errno;
439 ct->ct_error.re_status = RPC_CANTRECV;
440 break;
441 }
442
443 return (inlen);
444 }
445
446 static int
writetcp(ct,buf,len)447 writetcp(ct, buf, len)
448 struct ct_data *ct;
449 caddr_t buf;
450 int len;
451 {
452 register int i, cnt;
453
454 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
455 if ((i = sendto(ct->ct_sock, (void *)buf, cnt, 0,
456 (struct sockaddr *)&(ct->ct_raddr),
457 sizeof (ct->ct_raddr))) == -1) {
458 ct->ct_error.re_errno = errno;
459 ct->ct_error.re_status = RPC_CANTSEND;
460 return (-1);
461 }
462 }
463 return (len);
464 }
465
466 static void
clntbtcp_geterr(CLIENT * cl,struct rpc_err * errp)467 clntbtcp_geterr(
468 CLIENT *cl,
469 struct rpc_err *errp)
470 {
471 struct ct_data *ct = (struct ct_data *)cl->cl_private;
472
473 *errp = ct->ct_error;
474 }
475
476
477 static bool_t
clntbtcp_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)478 clntbtcp_freeres(
479 CLIENT *cl,
480 xdrproc_t xdr_res,
481 caddr_t res_ptr)
482 {
483 struct ct_data *ct = (struct ct_data *)cl->cl_private;
484 XDR *xdrs = &(ct->ct_xdrs);
485
486 xdrs->x_op = XDR_FREE;
487 return ((*xdr_res)(xdrs, res_ptr));
488 }
489
490 static void
clntbtcp_abort()491 clntbtcp_abort()
492 /* CLIENT *h; */
493 {
494 }
495
496 /* ARGSUSED */
497 static bool_t
clntbtcp_control(CLIENT * cl,int request,char * info)498 clntbtcp_control(
499 CLIENT *cl,
500 int request,
501 char *info)
502 {
503 /* Not implemented in boot */
504 return (FALSE);
505 }
506
507 static void
clntbtcp_destroy(CLIENT * cl)508 clntbtcp_destroy(CLIENT *cl)
509 {
510 struct ct_data *ct = (struct ct_data *)cl->cl_private;
511
512 if (ct->ct_closeit) {
513 (void) socket_close(ct->ct_sock);
514 }
515 XDR_DESTROY(&(ct->ct_xdrs));
516 bkmem_free((caddr_t)ct, (sizeof (struct ct_data)));
517 bkmem_free((caddr_t)cl, sizeof (CLIENT));
518 }
519
520 static struct clnt_ops *
clntbtcp_ops()521 clntbtcp_ops()
522 {
523 static struct clnt_ops ops;
524
525 if (ops.cl_call == NULL) {
526 ops.cl_call = clntbtcp_call;
527 ops.cl_abort = clntbtcp_abort;
528 ops.cl_geterr = clntbtcp_geterr;
529 ops.cl_freeres = clntbtcp_freeres;
530 ops.cl_destroy = clntbtcp_destroy;
531 ops.cl_control = clntbtcp_control;
532 }
533 return (&ops);
534 }
535