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 /* 23 * Copyright 2006 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 39 */ 40 41 #include <sys/errno.h> 42 #include <rpc/types.h> 43 #include <sys/socket.h> 44 #include <netinet/in.h> 45 #include "socket_inet.h" 46 #include "ipv4.h" 47 #include "clnt.h" 48 #include <rpc/rpc.h> 49 #include "brpc.h" 50 #include "pmap.h" 51 #include <sys/promif.h> 52 #include <rpc/xdr.h> 53 #include <rpc/auth.h> 54 #include <rpc/auth_sys.h> 55 #include "auth_inet.h" 56 #include <rpc/rpc_msg.h> 57 #include <sys/salib.h> 58 #include <sys/bootdebug.h> 59 60 #define dprintf if (boothowto & RB_DEBUG) printf 61 62 /* retries to send RPC message when sendto fails */ 63 #define RPC_UDP_SEND_RETRIES 3 64 65 extern int errno; 66 67 /* 68 * If we create another clnt type this should be 69 * moved to a common file 70 */ 71 struct rpc_createerr rpc_createerr; 72 73 static struct clnt_ops *clntbudp_ops(); 74 75 /* 76 * Private data kept per client handle 77 */ 78 struct cu_data { 79 int cu_sock; 80 bool_t cu_closeit; 81 struct sockaddr_in cu_raddr; 82 int cu_rlen; 83 struct timeval cu_wait; 84 struct timeval cu_total; 85 struct rpc_err cu_error; 86 XDR cu_outxdrs; 87 uint_t cu_xdrpos; 88 uint_t cu_sendsz; 89 char *cu_outbuf; 90 uint_t cu_recvsz; 91 char cu_inbuf[1]; 92 }; 93 94 /* 95 * Create a UDP based client handle. 96 * If *sockp<0, *sockp is set to a newly created UPD socket. 97 * If raddr->sin_port is 0 a binder on the remote machine 98 * is consulted for the correct port number. 99 * NB: It is the clients responsibility to close *sockp. 100 * NB: The rpch->cl_auth is initialized to null authentication. 101 * Caller may wish to set this something more useful. 102 * 103 * wait is the amount of time used between retransmitting a call if 104 * no response has been heard; retransmition occurs until the actual 105 * rpc call times out. 106 * 107 * sendsz and recvsz are the maximum allowable packet sizes that can be 108 * sent and received. 109 */ 110 CLIENT * 111 clntbudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) 112 struct sockaddr_in *raddr; 113 rpcprog_t program; 114 rpcvers_t version; 115 struct timeval wait; 116 int *sockp; 117 uint_t sendsz; 118 uint_t recvsz; 119 { 120 CLIENT *cl; 121 struct cu_data *cu; 122 struct rpc_msg call_msg; 123 124 cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT)); 125 if (cl == NULL) { 126 errno = ENOMEM; 127 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 128 rpc_createerr.cf_error.re_errno = errno; 129 return ((CLIENT *)NULL); 130 } 131 sendsz = ((sendsz + 3) / 4) * 4; 132 recvsz = ((recvsz + 3) / 4) * 4; 133 cu = (struct cu_data *)bkmem_alloc(sizeof (*cu) + sendsz + recvsz); 134 if (cu == NULL) { 135 errno = ENOMEM; 136 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 137 rpc_createerr.cf_error.re_errno = errno; 138 goto fooy; 139 } 140 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 141 142 if (raddr->sin_port == 0) { 143 ushort_t port; 144 if ((port = bpmap_getport(program, version, 145 &(rpc_createerr.cf_stat), raddr, NULL)) == 0) { 146 goto fooy; 147 } 148 raddr->sin_port = htons(port); 149 } 150 cl->cl_ops = clntbudp_ops(); 151 cl->cl_private = (caddr_t)cu; 152 cu->cu_raddr = *raddr; 153 cu->cu_rlen = sizeof (cu->cu_raddr); 154 cu->cu_wait = wait; 155 cu->cu_total.tv_sec = -1; 156 cu->cu_total.tv_usec = -1; 157 cu->cu_sendsz = sendsz; 158 cu->cu_recvsz = recvsz; 159 call_msg.rm_xid = (uint_t)prom_gettime() + 1; 160 call_msg.rm_direction = CALL; 161 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 162 call_msg.rm_call.cb_prog = program; 163 call_msg.rm_call.cb_vers = version; 164 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, 165 sendsz, XDR_ENCODE); 166 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 167 goto fooy; 168 } 169 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 170 cu->cu_closeit = FALSE; 171 172 if (*sockp < 0) { 173 struct sockaddr_in from; 174 175 *sockp = socket(PF_INET, SOCK_DGRAM, 0); 176 if (*sockp < 0) { 177 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 178 rpc_createerr.cf_error.re_errno = errno; 179 goto fooy; 180 } 181 182 if (dontroute) { 183 (void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE, 184 (const void *)&dontroute, sizeof (dontroute)); 185 } 186 187 /* attempt to bind to priv port */ 188 from.sin_family = AF_INET; 189 ipv4_getipaddr(&from.sin_addr); 190 from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 191 from.sin_port = get_source_port(TRUE); 192 193 if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) { 194 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 195 rpc_createerr.cf_error.re_errno = errno; 196 goto fooy; 197 } 198 199 cu->cu_closeit = TRUE; 200 } 201 202 cu->cu_sock = *sockp; 203 cl->cl_auth = authnone_create(); 204 return (cl); 205 fooy: 206 if (cu) 207 bkmem_free((caddr_t)cu, sizeof (*cu) + sendsz + recvsz); 208 if (cl) 209 bkmem_free((caddr_t)cl, sizeof (CLIENT)); 210 return ((CLIENT *)NULL); 211 } 212 213 CLIENT * 214 clntbudp_create(raddr, program, version, wait, sockp) 215 struct sockaddr_in *raddr; 216 rpcprog_t program; 217 rpcvers_t version; 218 struct timeval wait; 219 int *sockp; 220 { 221 222 return (clntbudp_bufcreate(raddr, program, version, wait, sockp, 223 UDPMSGSIZE, UDPMSGSIZE)); 224 } 225 226 static enum clnt_stat 227 clntbudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 228 CLIENT *cl; /* client handle */ 229 rpcproc_t proc; /* procedure number */ 230 xdrproc_t xargs; /* xdr routine for args */ 231 caddr_t argsp; /* pointer to args */ 232 xdrproc_t xresults; /* xdr routine for results */ 233 caddr_t resultsp; /* pointer to results */ 234 struct timeval utimeout; /* seconds to wait before giving up */ 235 { 236 struct cu_data *cu; 237 XDR *xdrs; 238 int outlen; 239 int inlen; 240 socklen_t fromlen; 241 struct sockaddr_in from; 242 struct rpc_msg reply_msg; 243 XDR reply_xdrs; 244 uint_t xdelay; 245 int wait_time; 246 bool_t ok; 247 int nrefreshes = 2; /* number of times to refresh cred */ 248 struct timeval timeout; 249 int errors; 250 short send_retries = RPC_UDP_SEND_RETRIES; 251 252 cu = (struct cu_data *)cl->cl_private; 253 if (cu->cu_total.tv_usec == -1) 254 timeout = utimeout; /* use supplied timeout */ 255 else 256 timeout = cu->cu_total; /* use default timeout */ 257 258 /* 259 * set a media level timeout 260 */ 261 xdelay = cu->cu_wait.tv_sec + 1000 + cu->cu_wait.tv_usec / 1000; 262 (void) setsockopt(cu->cu_sock, SOL_SOCKET, SO_RCVTIMEO, 263 (void *)&xdelay, sizeof (xdelay)); 264 265 wait_time = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000); 266 if (wait_time == 0) 267 wait_time = RPC_RCVWAIT_MSEC; 268 wait_time += prom_gettime(); 269 270 errors = 0; 271 272 call_again: 273 xdrs = &(cu->cu_outxdrs); 274 xdrs->x_op = XDR_ENCODE; 275 XDR_SETPOS(xdrs, cu->cu_xdrpos); 276 /* 277 * the transaction is the first thing in the out buffer 278 */ 279 (*(ushort_t *)(cu->cu_outbuf))++; 280 if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 281 (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || 282 (! (*xargs)(xdrs, argsp))) 283 return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 284 outlen = (int)XDR_GETPOS(xdrs); 285 286 send_again: 287 if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, 288 (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) 289 != outlen) { 290 if (errno == ETIMEDOUT) { 291 /* 292 * sendto() times out probably because 293 * ARP times out while waiting for reply. 294 * We retry sending RPC message again. 295 */ 296 if (send_retries-- > 0) { 297 dprintf("clntbudp_call: timedout, try sending" 298 "RPC again\n"); 299 errno = 0; 300 goto send_again; 301 } 302 cu->cu_error.re_status = RPC_TIMEDOUT; 303 } else { 304 cu->cu_error.re_status = RPC_CANTSEND; 305 } 306 cu->cu_error.re_errno = errno; 307 return (cu->cu_error.re_status); 308 } 309 310 /* 311 * sub-optimal code appears here because we have 312 * some clock time to spare while the packets are in flight. 313 * (We assume that this is actually only executed once.) 314 */ 315 recv_again: 316 reply_msg.acpted_rply.ar_verf = _null_auth; 317 reply_msg.acpted_rply.ar_results.where = resultsp; 318 reply_msg.acpted_rply.ar_results.proc = xresults; 319 320 for (;;) { 321 if (errors >= RPC_ALLOWABLE_ERRORS) 322 return (cu->cu_error.re_status); 323 324 if (prom_gettime() >= wait_time) { 325 cu->cu_error.re_errno = ETIMEDOUT; 326 return (cu->cu_error.re_status = RPC_TIMEDOUT); 327 } 328 329 /* 330 * Use MSG_DONTWAIT because we have set 331 * a media level timeout above. 332 */ 333 fromlen = sizeof (struct sockaddr); 334 335 inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 336 (int)cu->cu_recvsz, MSG_DONTWAIT, 337 (struct sockaddr *)&from, &fromlen); 338 339 if (inlen < 0) { 340 if (errno == EWOULDBLOCK) { 341 /* 342 * Media level has timedout 343 * and no more data in buffers. 344 */ 345 goto send_again; 346 } 347 348 cu->cu_error.re_status = RPC_CANTRECV; 349 if (errno == ETIMEDOUT) { 350 errno = ETIMEDOUT; 351 cu->cu_error.re_status = RPC_TIMEDOUT; 352 } 353 354 cu->cu_error.re_errno = errno; 355 return (cu->cu_error.re_status); 356 } 357 358 if (inlen < sizeof (uint32_t)) 359 continue; 360 361 /* see if reply transaction id matches sent id */ 362 if (*((uint32_t *)(cu->cu_inbuf)) != 363 *((uint32_t *)(cu->cu_outbuf))) { 364 dprintf("clntbudp_call: xid: 0x%x != 0x%x\n", 365 *(uint32_t *)(cu->cu_inbuf), 366 *(uint32_t *)(cu->cu_outbuf)); 367 continue; 368 } 369 /* we now assume we have the proper reply */ 370 break; 371 } 372 373 /* 374 * now decode and validate the response 375 */ 376 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)inlen, XDR_DECODE); 377 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 378 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 379 if (!ok) { 380 cu->cu_error.re_status = RPC_CANTDECODERES; 381 return (cu->cu_error.re_status); 382 } 383 384 _seterr_reply(&reply_msg, &(cu->cu_error)); 385 if (cu->cu_error.re_status == RPC_SUCCESS) { 386 if (! AUTH_VALIDATE(cl->cl_auth, 387 &reply_msg.acpted_rply.ar_verf)) { 388 cu->cu_error.re_status = RPC_AUTHERROR; 389 cu->cu_error.re_why = AUTH_INVALIDRESP; 390 errors++; 391 goto call_again; 392 } 393 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 394 xdrs->x_op = XDR_FREE; 395 (void) xdr_opaque_auth(xdrs, 396 &(reply_msg.acpted_rply.ar_verf)); 397 } 398 return (cu->cu_error.re_status); 399 } /* end successful completion */ 400 401 if (cu->cu_error.re_status == RPC_AUTHERROR) { 402 /* maybe our credentials need to be refreshed ... */ 403 if (nrefreshes > 0 && 404 AUTH_REFRESH(cl->cl_auth, NULL, NULL)) { 405 nrefreshes--; 406 } 407 errors++; 408 goto call_again; 409 } 410 411 /* Just keep trying till there's no data... */ 412 errors++; 413 dprintf("clntbudp_call: from: %s, error: ", 414 inet_ntoa(from.sin_addr)); 415 rpc_disperr(&cu->cu_error); 416 goto recv_again; 417 } 418 419 static void 420 clntbudp_geterr(cl, errp) 421 CLIENT *cl; 422 struct rpc_err *errp; 423 { 424 struct cu_data *cu = (struct cu_data *)cl->cl_private; 425 426 *errp = cu->cu_error; 427 } 428 429 430 static bool_t 431 clntbudp_freeres(cl, xdr_res, res_ptr) 432 CLIENT *cl; 433 xdrproc_t xdr_res; 434 caddr_t res_ptr; 435 { 436 struct cu_data *cu = (struct cu_data *)cl->cl_private; 437 XDR *xdrs = &(cu->cu_outxdrs); 438 439 xdrs->x_op = XDR_FREE; 440 return ((*xdr_res)(xdrs, res_ptr)); 441 } 442 443 static void 444 clntbudp_abort() 445 /* CLIENT *h; */ 446 { 447 } 448 449 /* ARGSUSED */ 450 static bool_t 451 clntbudp_control(cl, request, info) 452 CLIENT *cl; 453 int request; 454 char *info; 455 { 456 /* CLNT_CONTROL is not used in boot */ 457 return (FALSE); 458 } 459 460 static void 461 clntbudp_destroy(cl) 462 CLIENT *cl; 463 { 464 struct cu_data *cu = (struct cu_data *)cl->cl_private; 465 466 if (cu->cu_closeit) { 467 (void) socket_close(cu->cu_sock); 468 } 469 XDR_DESTROY(&(cu->cu_outxdrs)); 470 bkmem_free((caddr_t)cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 471 bkmem_free((caddr_t)cl, sizeof (CLIENT)); 472 } 473 474 static struct clnt_ops * 475 clntbudp_ops() 476 { 477 static struct clnt_ops ops; 478 479 if (ops.cl_call == NULL) { 480 ops.cl_call = clntbudp_call; 481 ops.cl_abort = clntbudp_abort; 482 ops.cl_geterr = clntbudp_geterr; 483 ops.cl_freeres = clntbudp_freeres; 484 ops.cl_destroy = clntbudp_destroy; 485 ops.cl_control = clntbudp_control; 486 } 487 return (&ops); 488 } 489