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