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