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