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