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 * 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 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 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 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 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 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 491 clntbtcp_abort() 492 /* CLIENT *h; */ 493 { 494 } 495 496 /* ARGSUSED */ 497 static bool_t 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 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 * 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