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