krpc_subr.c revision 38412
1248484Sneel/* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ 2248484Sneel/* $Id: krpc_subr.c,v 1.9 1998/03/28 10:33:15 bde Exp $ */ 3248484Sneel 4248484Sneel/* 5248484Sneel * Copyright (c) 1995 Gordon Ross, Adam Glass 6248484Sneel * Copyright (c) 1992 Regents of the University of California. 7248484Sneel * All rights reserved. 8248484Sneel * 9248484Sneel * This software was developed by the Computer Systems Engineering group 10248484Sneel * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11248484Sneel * contributed to Berkeley. 12248484Sneel * 13248484Sneel * Redistribution and use in source and binary forms, with or without 14248484Sneel * modification, are permitted provided that the following conditions 15248484Sneel * are met: 16248484Sneel * 1. Redistributions of source code must retain the above copyright 17248484Sneel * notice, this list of conditions and the following disclaimer. 18248484Sneel * 2. Redistributions in binary form must reproduce the above copyright 19248484Sneel * notice, this list of conditions and the following disclaimer in the 20248484Sneel * documentation and/or other materials provided with the distribution. 21248484Sneel * 3. All advertising materials mentioning features or use of this software 22248484Sneel * must display the following acknowledgement: 23248484Sneel * This product includes software developed by the University of 24248484Sneel * California, Lawrence Berkeley Laboratory and its contributors. 25248484Sneel * 4. Neither the name of the University nor the names of its contributors 26248484Sneel * may be used to endorse or promote products derived from this software 27248484Sneel * without specific prior written permission. 28248484Sneel * 29248484Sneel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30248484Sneel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31248484Sneel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32248484Sneel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33248484Sneel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34256176Sneel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35248484Sneel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36248484Sneel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37269397Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38248484Sneel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39248484Sneel * SUCH DAMAGE. 40248484Sneel * 41248484Sneel * partially based on: 42284894Sneel * libnetboot/rpc.c 43284894Sneel * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 44284894Sneel */ 45284894Sneel 46248484Sneel#include <sys/param.h> 47284894Sneel#include <sys/systm.h> 48284894Sneel#include <sys/malloc.h> 49327998Savg#include <sys/mbuf.h> 50269397Sjhb#include <sys/socket.h> 51295124Sgrehan#include <sys/socketvar.h> 52295124Sgrehan#include <sys/uio.h> 53269397Sjhb 54248484Sneel#include <net/if.h> 55269397Sjhb#include <netinet/in.h> 56327998Savg 57248484Sneel#include <nfs/rpcv2.h> 58269397Sjhb#include <nfs/krpc.h> 59248484Sneel#include <nfs/xdr_subs.h> 60269397Sjhb 61248840Sneel/* 62269397Sjhb * Kernel support for Sun RPC 63248484Sneel * 64248484Sneel * Used currently for bootstrapping in nfs diskless configurations. 65295124Sgrehan */ 66256176Sneel 67284899Sneel/* 68248484Sneel * Generic RPC headers 69317303Srgrimes */ 70317303Srgrimes 71248484Sneelstruct auth_info { 72284894Sneel u_int32_t authtype; /* auth type */ 73248484Sneel u_int32_t authlen; /* auth length */ 74248484Sneel}; 75248484Sneel 76248484Sneelstruct auth_unix { 77284894Sneel int32_t ua_time; 78284894Sneel int32_t ua_hostname; /* null */ 79248484Sneel int32_t ua_uid; 80248484Sneel int32_t ua_gid; 81248484Sneel int32_t ua_gidlist; /* null */ 82248484Sneel}; 83284894Sneel 84248484Sneelstruct rpc_call { 85248484Sneel u_int32_t rp_xid; /* request transaction id */ 86248484Sneel int32_t rp_direction; /* call direction (0) */ 87248484Sneel u_int32_t rp_rpcvers; /* rpc version (2) */ 88248484Sneel u_int32_t rp_prog; /* program */ 89248484Sneel u_int32_t rp_vers; /* version */ 90269397Sjhb u_int32_t rp_proc; /* procedure */ 91248484Sneel struct auth_info rpc_auth; 92269397Sjhb struct auth_unix rpc_unix; 93269397Sjhb struct auth_info rpc_verf; 94327998Savg}; 95248840Sneel 96269397Sjhbstruct rpc_reply { 97295124Sgrehan u_int32_t rp_xid; /* request transaction id */ 98284899Sneel int32_t rp_direction; /* call direction (1) */ 99248484Sneel int32_t rp_astatus; /* accept status (0: accepted) */ 100317303Srgrimes union { 101248484Sneel u_int32_t rpu_errno; 102248484Sneel struct { 103295124Sgrehan struct auth_info rok_auth; 104248484Sneel u_int32_t rok_status; 105327998Savg } rpu_rok; 106327998Savg } rp_u; 107327998Savg}; 108269397Sjhb#define rp_errno rp_u.rpu_errno 109269397Sjhb#define rp_auth rp_u.rpu_rok.rok_auth 110269397Sjhb#define rp_status rp_u.rpu_rok.rok_status 111269397Sjhb 112269397Sjhb#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 113269397Sjhb 114248484Sneel/* 115284413Savg * What is the longest we will wait before re-sending a request? 116284413Savg * Note this is also the frequency of "RPC timeout" messages. 117284413Savg * The re-send loop count sup linearly to this maximum, so the 118284413Savg * first complaint will happen after (1+2+3+4+5)=15 seconds. 119269397Sjhb */ 120248484Sneel#define MAX_RESEND_DELAY 5 /* seconds */ 121269397Sjhb 122269397Sjhb/* 123248840Sneel * Call portmap to lookup a port number for a particular rpc program 124269397Sjhb * Returns non-zero error on failure. 125269397Sjhb */ 126269397Sjhbint 127269397Sjhbkrpc_portmap(sin, prog, vers, portp, procp) 128269397Sjhb struct sockaddr_in *sin; /* server address */ 129269397Sjhb u_int prog, vers; /* host order */ 130248484Sneel u_int16_t *portp; /* network order */ 131248484Sneel struct proc *procp; 132248484Sneel{ 133248484Sneel struct sdata { 134248484Sneel u_int32_t prog; /* call program */ 135248484Sneel u_int32_t vers; /* call version */ 136295124Sgrehan u_int32_t proto; /* call protocol */ 137295124Sgrehan u_int32_t port; /* call port (unused) */ 138295124Sgrehan } *sdata; 139248484Sneel struct rdata { 140248484Sneel u_int16_t pad; 141248484Sneel u_int16_t port; 142284899Sneel } *rdata; 143284899Sneel struct mbuf *m; 144284899Sneel int error; 145284899Sneel 146248484Sneel /* The portmapper port is fixed. */ 147269397Sjhb if (prog == PMAPPROG) { 148269397Sjhb *portp = htons(PMAPPORT); 149248484Sneel return 0; 150317303Srgrimes } 151317303Srgrimes 152317303Srgrimes m = m_get(M_WAIT, MT_DATA); 153317303Srgrimes if (m == NULL) 154317303Srgrimes return ENOBUFS; 155317303Srgrimes sdata = mtod(m, struct sdata *); 156269397Sjhb m->m_len = sizeof(*sdata); 157248484Sneel 158248484Sneel /* Do the RPC to get it. */ 159248484Sneel sdata->prog = txdr_unsigned(prog); 160248484Sneel sdata->vers = txdr_unsigned(vers); 161248484Sneel sdata->proto = txdr_unsigned(IPPROTO_UDP); 162269397Sjhb sdata->port = 0; 163269397Sjhb 164269397Sjhb sin->sin_port = htons(PMAPPORT); 165269397Sjhb error = krpc_call(sin, PMAPPROG, PMAPVERS, 166269397Sjhb PMAPPROC_GETPORT, &m, NULL, procp); 167269397Sjhb if (error) 168269397Sjhb return error; 169269397Sjhb 170269397Sjhb if (m->m_len < sizeof(*rdata)) { 171269397Sjhb m = m_pullup(m, sizeof(*rdata)); 172248484Sneel if (m == NULL) 173248484Sneel return ENOBUFS; 174248484Sneel } 175284894Sneel rdata = mtod(m, struct rdata *); 176248484Sneel *portp = rdata->port; 177248484Sneel 178248484Sneel m_freem(m); 179269397Sjhb return 0; 180269397Sjhb} 181248484Sneel 182248484Sneel/* 183295124Sgrehan * Do a remote procedure call (RPC) and wait for its reply. 184295124Sgrehan * If from_p is non-null, then we are doing broadcast, and 185295124Sgrehan * the address from whence the response came is saved there. 186295124Sgrehan */ 187295124Sgrehanint 188295124Sgrehankrpc_call(sa, prog, vers, func, data, from_p, procp) 189269397Sjhb struct sockaddr_in *sa; 190269397Sjhb u_int prog, vers, func; 191269397Sjhb struct mbuf **data; /* input/output */ 192269397Sjhb struct sockaddr **from_p; /* output */ 193303925Sjhb struct proc *procp; 194269397Sjhb{ 195269397Sjhb struct socket *so; 196269397Sjhb struct sockaddr_in *sin, ssin; 197269397Sjhb struct sockaddr *from; 198248484Sneel struct mbuf *m, *nam, *mhead; 199269397Sjhb struct rpc_call *call; 200269397Sjhb struct rpc_reply *reply; 201269397Sjhb struct uio auio; 202269397Sjhb int error, rcvflg, timo, secs, len; 203248484Sneel static u_int32_t xid = ~0xFF; 204269397Sjhb u_int16_t tport; 205269397Sjhb 206269397Sjhb /* 207269397Sjhb * Validate address family. 208269397Sjhb * Sorry, this is INET specific... 209269397Sjhb */ 210248484Sneel if (sa->sin_family != AF_INET) 211248484Sneel return (EAFNOSUPPORT); 212284414Savg 213269397Sjhb /* Free at end if not null. */ 214271106Srodrigc nam = mhead = NULL; 215271106Srodrigc from = NULL; 216248484Sneel 217248484Sneel /* 218284414Savg * Create socket and set its recieve timeout. 219248484Sneel */ 220248484Sneel if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, procp))) 221284414Savg goto out; 222248484Sneel 223248484Sneel m = m_get(M_WAIT, MT_SOOPTS); 224248484Sneel if (m == NULL) { 225248484Sneel error = ENOBUFS; 226248484Sneel goto out; 227248484Sneel } else { 228248484Sneel struct timeval *tv; 229248484Sneel tv = mtod(m, struct timeval *); 230248484Sneel m->m_len = sizeof(*tv); 231248484Sneel tv->tv_sec = 1; 232248484Sneel tv->tv_usec = 0; 233248484Sneel if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m, procp))) 234248484Sneel goto out; 235248484Sneel } 236284414Savg 237284414Savg /* 238248484Sneel * Enable broadcast if necessary. 239284414Savg */ 240284414Savg if (from_p) { 241284414Savg int32_t *on; 242284414Savg m = m_get(M_WAIT, MT_SOOPTS); 243284414Savg if (m == NULL) { 244284414Savg error = ENOBUFS; 245284414Savg goto out; 246284414Savg } 247284414Savg on = mtod(m, int32_t *); 248248484Sneel m->m_len = sizeof(*on); 249248484Sneel *on = 1; 250248484Sneel if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m, procp))) 251284414Savg goto out; 252269397Sjhb } 253272058Srodrigc 254272058Srodrigc /* 255248484Sneel * Bind the local endpoint to a reserved port, 256248484Sneel * because some NFS servers refuse requests from 257248484Sneel * non-reserved (non-privileged) ports. 258269397Sjhb */ 259269397Sjhb sin = &ssin; 260269397Sjhb bzero(sin, sizeof *sin); 261269397Sjhb sin->sin_len = sizeof(*sin); 262269397Sjhb sin->sin_family = AF_INET; 263269397Sjhb sin->sin_addr.s_addr = INADDR_ANY; 264269397Sjhb tport = IPPORT_RESERVED; 265269397Sjhb do { 266269397Sjhb tport--; 267269397Sjhb sin->sin_port = htons(tport); 268269397Sjhb error = sobind(so, (struct sockaddr *)sin, procp); 269269397Sjhb } while (error == EADDRINUSE && 270269397Sjhb tport > IPPORT_RESERVED / 2); 271269397Sjhb if (error) { 272269397Sjhb printf("bind failed\n"); 273269397Sjhb goto out; 274284413Savg } 275269397Sjhb 276327998Savg /* 277269397Sjhb * Setup socket address for the server. 278269397Sjhb */ 279269397Sjhb 280269397Sjhb /* 281284899Sneel * Prepend RPC message header. 282284899Sneel */ 283284899Sneel mhead = m_gethdr(M_WAIT, MT_DATA); 284284899Sneel mhead->m_next = *data; 285284899Sneel call = mtod(mhead, struct rpc_call *); 286284899Sneel mhead->m_len = sizeof(*call); 287284899Sneel bzero((caddr_t)call, sizeof(*call)); 288284899Sneel /* rpc_call part */ 289295124Sgrehan xid++; 290248840Sneel call->rp_xid = txdr_unsigned(xid); 291248484Sneel /* call->rp_direction = 0; */ 292257396Sneel call->rp_rpcvers = txdr_unsigned(2); 293269397Sjhb call->rp_prog = txdr_unsigned(prog); 294269397Sjhb call->rp_vers = txdr_unsigned(vers); 295248484Sneel call->rp_proc = txdr_unsigned(func); 296248484Sneel /* rpc_auth part (auth_unix as root) */ 297271106Srodrigc call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); 298272058Srodrigc call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 299271106Srodrigc /* rpc_verf part (auth_null) */ 300271106Srodrigc call->rpc_verf.authtype = 0; 301271106Srodrigc call->rpc_verf.authlen = 0; 302271106Srodrigc 303271106Srodrigc /* 304271106Srodrigc * Setup packet header 305271106Srodrigc */ 306272058Srodrigc len = 0; 307248484Sneel m = mhead; 308248484Sneel while (m) { 309248484Sneel len += m->m_len; 310248484Sneel m = m->m_next; 311272058Srodrigc } 312272058Srodrigc mhead->m_pkthdr.len = len; 313272058Srodrigc mhead->m_pkthdr.rcvif = NULL; 314272058Srodrigc 315272058Srodrigc /* 316272058Srodrigc * Send it, repeatedly, until a reply is received, 317272058Srodrigc * but delay each re-send by an increasing amount. 318272058Srodrigc * If the delay hits the maximum, start complaining. 319272058Srodrigc */ 320272058Srodrigc timo = 0; 321 for (;;) { 322 /* Send RPC request (or re-send). */ 323 m = m_copym(mhead, 0, M_COPYALL, M_WAIT); 324 if (m == NULL) { 325 error = ENOBUFS; 326 goto out; 327 } 328 error = sosend(so, (struct sockaddr *)sa, NULL, m, 329 NULL, 0, 0); 330 if (error) { 331 printf("krpc_call: sosend: %d\n", error); 332 goto out; 333 } 334 m = NULL; 335 336 /* Determine new timeout. */ 337 if (timo < MAX_RESEND_DELAY) 338 timo++; 339 else 340 printf("RPC timeout for server 0x%lx\n", 341 (u_long)ntohl(sa->sin_addr.s_addr)); 342 343 /* 344 * Wait for up to timo seconds for a reply. 345 * The socket receive timeout was set to 1 second. 346 */ 347 secs = timo; 348 while (secs > 0) { 349 if (from) { 350 FREE(from, M_SONAME); 351 from = NULL; 352 } 353 if (m) { 354 m_freem(m); 355 m = NULL; 356 } 357 bzero(&auio,sizeof(auio)); 358 auio.uio_resid = len = 1<<16; 359 rcvflg = 0; 360 error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); 361 if (error == EWOULDBLOCK) { 362 secs--; 363 continue; 364 } 365 if (error) 366 goto out; 367 len -= auio.uio_resid; 368 369 /* Does the reply contain at least a header? */ 370 if (len < MIN_REPLY_HDR) 371 continue; 372 if (m->m_len < MIN_REPLY_HDR) 373 continue; 374 reply = mtod(m, struct rpc_reply *); 375 376 /* Is it the right reply? */ 377 if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) 378 continue; 379 380 if (reply->rp_xid != txdr_unsigned(xid)) 381 continue; 382 383 /* Was RPC accepted? (authorization OK) */ 384 if (reply->rp_astatus != 0) { 385 error = fxdr_unsigned(u_int32_t, reply->rp_errno); 386 printf("rpc denied, error=%d\n", error); 387 continue; 388 } 389 390 /* Did the call succeed? */ 391 if (reply->rp_status != 0) { 392 error = fxdr_unsigned(u_int32_t, reply->rp_status); 393 if (error == RPC_PROGMISMATCH) { 394 error = EBADRPC; 395 goto out; 396 } 397 printf("rpc denied, status=%d\n", error); 398 continue; 399 } 400 401 goto gotreply; /* break two levels */ 402 403 } /* while secs */ 404 } /* forever send/receive */ 405 406 error = ETIMEDOUT; 407 goto out; 408 409 gotreply: 410 411 /* 412 * Get RPC reply header into first mbuf, 413 * get its length, then strip it off. 414 */ 415 len = sizeof(*reply); 416 if (m->m_len < len) { 417 m = m_pullup(m, len); 418 if (m == NULL) { 419 error = ENOBUFS; 420 goto out; 421 } 422 } 423 reply = mtod(m, struct rpc_reply *); 424 if (reply->rp_auth.authtype != 0) { 425 len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 426 len = (len + 3) & ~3; /* XXX? */ 427 } 428 m_adj(m, len); 429 430 /* result */ 431 *data = m; 432 if (from_p) { 433 *from_p = from; 434 from = NULL; 435 } 436 437 out: 438 if (mhead) m_freem(mhead); 439 if (from) free(from, M_SONAME); 440 soclose(so); 441 return error; 442} 443 444/* 445 * eXternal Data Representation routines. 446 * (but with non-standard args...) 447 */ 448 449/* 450 * String representation for RPC. 451 */ 452struct xdr_string { 453 u_int32_t len; /* length without null or padding */ 454 char data[4]; /* data (longer, of course) */ 455 /* data is padded to a long-word boundary */ 456}; 457 458struct mbuf * 459xdr_string_encode(str, len) 460 char *str; 461 int len; 462{ 463 struct mbuf *m; 464 struct xdr_string *xs; 465 int dlen; /* padded string length */ 466 int mlen; /* message length */ 467 468 dlen = (len + 3) & ~3; 469 mlen = dlen + 4; 470 471 if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 472 return (NULL); 473 474 m = m_get(M_WAIT, MT_DATA); 475 if (mlen > MLEN) { 476 MCLGET(m, M_WAIT); 477 if ((m->m_flags & M_EXT) == 0) { 478 (void) m_free(m); /* There can be only one. */ 479 return (NULL); 480 } 481 } 482 xs = mtod(m, struct xdr_string *); 483 m->m_len = mlen; 484 xs->len = txdr_unsigned(len); 485 bcopy(str, xs->data, len); 486 return (m); 487} 488