1*7c208ed6SRick Macklem /* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ 2*7c208ed6SRick Macklem 3*7c208ed6SRick Macklem /*- 4*7c208ed6SRick Macklem * Copyright (c) 1995 Gordon Ross, Adam Glass 5*7c208ed6SRick Macklem * Copyright (c) 1992 Regents of the University of California. 6*7c208ed6SRick Macklem * All rights reserved. 7*7c208ed6SRick Macklem * 8*7c208ed6SRick Macklem * This software was developed by the Computer Systems Engineering group 9*7c208ed6SRick Macklem * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10*7c208ed6SRick Macklem * contributed to Berkeley. 11*7c208ed6SRick Macklem * 12*7c208ed6SRick Macklem * Redistribution and use in source and binary forms, with or without 13*7c208ed6SRick Macklem * modification, are permitted provided that the following conditions 14*7c208ed6SRick Macklem * are met: 15*7c208ed6SRick Macklem * 1. Redistributions of source code must retain the above copyright 16*7c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer. 17*7c208ed6SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 18*7c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer in the 19*7c208ed6SRick Macklem * documentation and/or other materials provided with the distribution. 20*7c208ed6SRick Macklem * 3. All advertising materials mentioning features or use of this software 21*7c208ed6SRick Macklem * must display the following acknowledgement: 22*7c208ed6SRick Macklem * This product includes software developed by the University of 23*7c208ed6SRick Macklem * California, Lawrence Berkeley Laboratory and its contributors. 24*7c208ed6SRick Macklem * 4. Neither the name of the University nor the names of its contributors 25*7c208ed6SRick Macklem * may be used to endorse or promote products derived from this software 26*7c208ed6SRick Macklem * without specific prior written permission. 27*7c208ed6SRick Macklem * 28*7c208ed6SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29*7c208ed6SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30*7c208ed6SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31*7c208ed6SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32*7c208ed6SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33*7c208ed6SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34*7c208ed6SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35*7c208ed6SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36*7c208ed6SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37*7c208ed6SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38*7c208ed6SRick Macklem * SUCH DAMAGE. 39*7c208ed6SRick Macklem * 40*7c208ed6SRick Macklem * partially based on: 41*7c208ed6SRick Macklem * libnetboot/rpc.c 42*7c208ed6SRick Macklem * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 43*7c208ed6SRick Macklem */ 44*7c208ed6SRick Macklem 45*7c208ed6SRick Macklem #include <sys/cdefs.h> 46*7c208ed6SRick Macklem __FBSDID("$FreeBSD$"); 47*7c208ed6SRick Macklem 48*7c208ed6SRick Macklem #include <sys/param.h> 49*7c208ed6SRick Macklem #include <sys/systm.h> 50*7c208ed6SRick Macklem #include <sys/jail.h> 51*7c208ed6SRick Macklem #include <sys/malloc.h> 52*7c208ed6SRick Macklem #include <sys/mbuf.h> 53*7c208ed6SRick Macklem #include <sys/proc.h> 54*7c208ed6SRick Macklem #include <sys/socket.h> 55*7c208ed6SRick Macklem #include <sys/socketvar.h> 56*7c208ed6SRick Macklem #include <sys/uio.h> 57*7c208ed6SRick Macklem 58*7c208ed6SRick Macklem #include <net/if.h> 59*7c208ed6SRick Macklem #include <net/vnet.h> 60*7c208ed6SRick Macklem 61*7c208ed6SRick Macklem #include <netinet/in.h> 62*7c208ed6SRick Macklem 63*7c208ed6SRick Macklem #include <rpc/types.h> 64*7c208ed6SRick Macklem #include <rpc/auth.h> 65*7c208ed6SRick Macklem #include <rpc/rpc_msg.h> 66*7c208ed6SRick Macklem #include <nfs/krpc.h> 67*7c208ed6SRick Macklem #include <nfs/xdr_subs.h> 68*7c208ed6SRick Macklem 69*7c208ed6SRick Macklem /* 70*7c208ed6SRick Macklem * Kernel support for Sun RPC 71*7c208ed6SRick Macklem * 72*7c208ed6SRick Macklem * Used currently for bootstrapping in nfs diskless configurations. 73*7c208ed6SRick Macklem */ 74*7c208ed6SRick Macklem 75*7c208ed6SRick Macklem /* 76*7c208ed6SRick Macklem * Generic RPC headers 77*7c208ed6SRick Macklem */ 78*7c208ed6SRick Macklem 79*7c208ed6SRick Macklem struct auth_info { 80*7c208ed6SRick Macklem u_int32_t authtype; /* auth type */ 81*7c208ed6SRick Macklem u_int32_t authlen; /* auth length */ 82*7c208ed6SRick Macklem }; 83*7c208ed6SRick Macklem 84*7c208ed6SRick Macklem struct auth_unix { 85*7c208ed6SRick Macklem int32_t ua_time; 86*7c208ed6SRick Macklem int32_t ua_hostname; /* null */ 87*7c208ed6SRick Macklem int32_t ua_uid; 88*7c208ed6SRick Macklem int32_t ua_gid; 89*7c208ed6SRick Macklem int32_t ua_gidlist; /* null */ 90*7c208ed6SRick Macklem }; 91*7c208ed6SRick Macklem 92*7c208ed6SRick Macklem struct krpc_call { 93*7c208ed6SRick Macklem u_int32_t rp_xid; /* request transaction id */ 94*7c208ed6SRick Macklem int32_t rp_direction; /* call direction (0) */ 95*7c208ed6SRick Macklem u_int32_t rp_rpcvers; /* rpc version (2) */ 96*7c208ed6SRick Macklem u_int32_t rp_prog; /* program */ 97*7c208ed6SRick Macklem u_int32_t rp_vers; /* version */ 98*7c208ed6SRick Macklem u_int32_t rp_proc; /* procedure */ 99*7c208ed6SRick Macklem struct auth_info rpc_auth; 100*7c208ed6SRick Macklem struct auth_unix rpc_unix; 101*7c208ed6SRick Macklem struct auth_info rpc_verf; 102*7c208ed6SRick Macklem }; 103*7c208ed6SRick Macklem 104*7c208ed6SRick Macklem struct krpc_reply { 105*7c208ed6SRick Macklem u_int32_t rp_xid; /* request transaction id */ 106*7c208ed6SRick Macklem int32_t rp_direction; /* call direction (1) */ 107*7c208ed6SRick Macklem int32_t rp_astatus; /* accept status (0: accepted) */ 108*7c208ed6SRick Macklem union { 109*7c208ed6SRick Macklem u_int32_t rpu_errno; 110*7c208ed6SRick Macklem struct { 111*7c208ed6SRick Macklem struct auth_info rok_auth; 112*7c208ed6SRick Macklem u_int32_t rok_status; 113*7c208ed6SRick Macklem } rpu_rok; 114*7c208ed6SRick Macklem } rp_u; 115*7c208ed6SRick Macklem }; 116*7c208ed6SRick Macklem #define rp_errno rp_u.rpu_errno 117*7c208ed6SRick Macklem #define rp_auth rp_u.rpu_rok.rok_auth 118*7c208ed6SRick Macklem #define rp_status rp_u.rpu_rok.rok_status 119*7c208ed6SRick Macklem 120*7c208ed6SRick Macklem #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 121*7c208ed6SRick Macklem 122*7c208ed6SRick Macklem /* 123*7c208ed6SRick Macklem * What is the longest we will wait before re-sending a request? 124*7c208ed6SRick Macklem * Note this is also the frequency of "RPC timeout" messages. 125*7c208ed6SRick Macklem * The re-send loop count sup linearly to this maximum, so the 126*7c208ed6SRick Macklem * first complaint will happen after (1+2+3+4+5)=15 seconds. 127*7c208ed6SRick Macklem */ 128*7c208ed6SRick Macklem #define MAX_RESEND_DELAY 5 /* seconds */ 129*7c208ed6SRick Macklem 130*7c208ed6SRick Macklem /* 131*7c208ed6SRick Macklem * Call portmap to lookup a port number for a particular rpc program 132*7c208ed6SRick Macklem * Returns non-zero error on failure. 133*7c208ed6SRick Macklem */ 134*7c208ed6SRick Macklem int 135*7c208ed6SRick Macklem krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp, 136*7c208ed6SRick Macklem struct thread *td) 137*7c208ed6SRick Macklem { 138*7c208ed6SRick Macklem struct sdata { 139*7c208ed6SRick Macklem u_int32_t prog; /* call program */ 140*7c208ed6SRick Macklem u_int32_t vers; /* call version */ 141*7c208ed6SRick Macklem u_int32_t proto; /* call protocol */ 142*7c208ed6SRick Macklem u_int32_t port; /* call port (unused) */ 143*7c208ed6SRick Macklem } *sdata; 144*7c208ed6SRick Macklem struct rdata { 145*7c208ed6SRick Macklem u_int16_t pad; 146*7c208ed6SRick Macklem u_int16_t port; 147*7c208ed6SRick Macklem } *rdata; 148*7c208ed6SRick Macklem struct mbuf *m; 149*7c208ed6SRick Macklem int error; 150*7c208ed6SRick Macklem 151*7c208ed6SRick Macklem /* The portmapper port is fixed. */ 152*7c208ed6SRick Macklem if (prog == PMAPPROG) { 153*7c208ed6SRick Macklem *portp = htons(PMAPPORT); 154*7c208ed6SRick Macklem return 0; 155*7c208ed6SRick Macklem } 156*7c208ed6SRick Macklem 157*7c208ed6SRick Macklem m = m_get(M_WAIT, MT_DATA); 158*7c208ed6SRick Macklem sdata = mtod(m, struct sdata *); 159*7c208ed6SRick Macklem m->m_len = sizeof(*sdata); 160*7c208ed6SRick Macklem 161*7c208ed6SRick Macklem /* Do the RPC to get it. */ 162*7c208ed6SRick Macklem sdata->prog = txdr_unsigned(prog); 163*7c208ed6SRick Macklem sdata->vers = txdr_unsigned(vers); 164*7c208ed6SRick Macklem sdata->proto = txdr_unsigned(IPPROTO_UDP); 165*7c208ed6SRick Macklem sdata->port = 0; 166*7c208ed6SRick Macklem 167*7c208ed6SRick Macklem sin->sin_port = htons(PMAPPORT); 168*7c208ed6SRick Macklem error = krpc_call(sin, PMAPPROG, PMAPVERS, 169*7c208ed6SRick Macklem PMAPPROC_GETPORT, &m, NULL, td); 170*7c208ed6SRick Macklem if (error) 171*7c208ed6SRick Macklem return error; 172*7c208ed6SRick Macklem 173*7c208ed6SRick Macklem if (m->m_len < sizeof(*rdata)) { 174*7c208ed6SRick Macklem m = m_pullup(m, sizeof(*rdata)); 175*7c208ed6SRick Macklem if (m == NULL) 176*7c208ed6SRick Macklem return ENOBUFS; 177*7c208ed6SRick Macklem } 178*7c208ed6SRick Macklem rdata = mtod(m, struct rdata *); 179*7c208ed6SRick Macklem *portp = rdata->port; 180*7c208ed6SRick Macklem 181*7c208ed6SRick Macklem m_freem(m); 182*7c208ed6SRick Macklem return 0; 183*7c208ed6SRick Macklem } 184*7c208ed6SRick Macklem 185*7c208ed6SRick Macklem /* 186*7c208ed6SRick Macklem * Do a remote procedure call (RPC) and wait for its reply. 187*7c208ed6SRick Macklem * If from_p is non-null, then we are doing broadcast, and 188*7c208ed6SRick Macklem * the address from whence the response came is saved there. 189*7c208ed6SRick Macklem */ 190*7c208ed6SRick Macklem int 191*7c208ed6SRick Macklem krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, 192*7c208ed6SRick Macklem struct mbuf **data, struct sockaddr **from_p, struct thread *td) 193*7c208ed6SRick Macklem { 194*7c208ed6SRick Macklem struct socket *so; 195*7c208ed6SRick Macklem struct sockaddr_in *sin, ssin; 196*7c208ed6SRick Macklem struct sockaddr *from; 197*7c208ed6SRick Macklem struct mbuf *m, *nam, *mhead; 198*7c208ed6SRick Macklem struct krpc_call *call; 199*7c208ed6SRick Macklem struct krpc_reply *reply; 200*7c208ed6SRick Macklem struct sockopt sopt; 201*7c208ed6SRick Macklem struct timeval tv; 202*7c208ed6SRick Macklem struct uio auio; 203*7c208ed6SRick Macklem int error, rcvflg, timo, secs, len; 204*7c208ed6SRick Macklem static u_int32_t xid = ~0xFF; 205*7c208ed6SRick Macklem u_int16_t tport; 206*7c208ed6SRick Macklem u_int32_t saddr; 207*7c208ed6SRick Macklem 208*7c208ed6SRick Macklem /* 209*7c208ed6SRick Macklem * Validate address family. 210*7c208ed6SRick Macklem * Sorry, this is INET specific... 211*7c208ed6SRick Macklem */ 212*7c208ed6SRick Macklem if (sa->sin_family != AF_INET) 213*7c208ed6SRick Macklem return (EAFNOSUPPORT); 214*7c208ed6SRick Macklem 215*7c208ed6SRick Macklem /* Free at end if not null. */ 216*7c208ed6SRick Macklem nam = mhead = NULL; 217*7c208ed6SRick Macklem from = NULL; 218*7c208ed6SRick Macklem 219*7c208ed6SRick Macklem /* 220*7c208ed6SRick Macklem * Create socket and set its recieve timeout. 221*7c208ed6SRick Macklem */ 222*7c208ed6SRick Macklem if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td))) 223*7c208ed6SRick Macklem goto out; 224*7c208ed6SRick Macklem 225*7c208ed6SRick Macklem tv.tv_sec = 1; 226*7c208ed6SRick Macklem tv.tv_usec = 0; 227*7c208ed6SRick Macklem bzero(&sopt, sizeof sopt); 228*7c208ed6SRick Macklem sopt.sopt_dir = SOPT_SET; 229*7c208ed6SRick Macklem sopt.sopt_level = SOL_SOCKET; 230*7c208ed6SRick Macklem sopt.sopt_name = SO_RCVTIMEO; 231*7c208ed6SRick Macklem sopt.sopt_val = &tv; 232*7c208ed6SRick Macklem sopt.sopt_valsize = sizeof tv; 233*7c208ed6SRick Macklem 234*7c208ed6SRick Macklem if ((error = sosetopt(so, &sopt)) != 0) 235*7c208ed6SRick Macklem goto out; 236*7c208ed6SRick Macklem 237*7c208ed6SRick Macklem /* 238*7c208ed6SRick Macklem * Enable broadcast if necessary. 239*7c208ed6SRick Macklem */ 240*7c208ed6SRick Macklem if (from_p) { 241*7c208ed6SRick Macklem int on = 1; 242*7c208ed6SRick Macklem sopt.sopt_name = SO_BROADCAST; 243*7c208ed6SRick Macklem sopt.sopt_val = &on; 244*7c208ed6SRick Macklem sopt.sopt_valsize = sizeof on; 245*7c208ed6SRick Macklem if ((error = sosetopt(so, &sopt)) != 0) 246*7c208ed6SRick Macklem goto out; 247*7c208ed6SRick Macklem } 248*7c208ed6SRick Macklem 249*7c208ed6SRick Macklem /* 250*7c208ed6SRick Macklem * Bind the local endpoint to a reserved port, 251*7c208ed6SRick Macklem * because some NFS servers refuse requests from 252*7c208ed6SRick Macklem * non-reserved (non-privileged) ports. 253*7c208ed6SRick Macklem */ 254*7c208ed6SRick Macklem sin = &ssin; 255*7c208ed6SRick Macklem bzero(sin, sizeof *sin); 256*7c208ed6SRick Macklem sin->sin_len = sizeof(*sin); 257*7c208ed6SRick Macklem sin->sin_family = AF_INET; 258*7c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_ANY; 259*7c208ed6SRick Macklem tport = IPPORT_RESERVED; 260*7c208ed6SRick Macklem do { 261*7c208ed6SRick Macklem tport--; 262*7c208ed6SRick Macklem sin->sin_port = htons(tport); 263*7c208ed6SRick Macklem error = sobind(so, (struct sockaddr *)sin, td); 264*7c208ed6SRick Macklem } while (error == EADDRINUSE && 265*7c208ed6SRick Macklem tport > IPPORT_RESERVED / 2); 266*7c208ed6SRick Macklem if (error) { 267*7c208ed6SRick Macklem printf("bind failed\n"); 268*7c208ed6SRick Macklem goto out; 269*7c208ed6SRick Macklem } 270*7c208ed6SRick Macklem 271*7c208ed6SRick Macklem /* 272*7c208ed6SRick Macklem * Setup socket address for the server. 273*7c208ed6SRick Macklem */ 274*7c208ed6SRick Macklem 275*7c208ed6SRick Macklem /* 276*7c208ed6SRick Macklem * Prepend RPC message header. 277*7c208ed6SRick Macklem */ 278*7c208ed6SRick Macklem mhead = m_gethdr(M_WAIT, MT_DATA); 279*7c208ed6SRick Macklem mhead->m_next = *data; 280*7c208ed6SRick Macklem call = mtod(mhead, struct krpc_call *); 281*7c208ed6SRick Macklem mhead->m_len = sizeof(*call); 282*7c208ed6SRick Macklem bzero((caddr_t)call, sizeof(*call)); 283*7c208ed6SRick Macklem /* rpc_call part */ 284*7c208ed6SRick Macklem xid++; 285*7c208ed6SRick Macklem call->rp_xid = txdr_unsigned(xid); 286*7c208ed6SRick Macklem /* call->rp_direction = 0; */ 287*7c208ed6SRick Macklem call->rp_rpcvers = txdr_unsigned(2); 288*7c208ed6SRick Macklem call->rp_prog = txdr_unsigned(prog); 289*7c208ed6SRick Macklem call->rp_vers = txdr_unsigned(vers); 290*7c208ed6SRick Macklem call->rp_proc = txdr_unsigned(func); 291*7c208ed6SRick Macklem /* rpc_auth part (auth_unix as root) */ 292*7c208ed6SRick Macklem call->rpc_auth.authtype = txdr_unsigned(AUTH_UNIX); 293*7c208ed6SRick Macklem call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 294*7c208ed6SRick Macklem /* rpc_verf part (auth_null) */ 295*7c208ed6SRick Macklem call->rpc_verf.authtype = 0; 296*7c208ed6SRick Macklem call->rpc_verf.authlen = 0; 297*7c208ed6SRick Macklem 298*7c208ed6SRick Macklem /* 299*7c208ed6SRick Macklem * Setup packet header 300*7c208ed6SRick Macklem */ 301*7c208ed6SRick Macklem m_fixhdr(mhead); 302*7c208ed6SRick Macklem mhead->m_pkthdr.rcvif = NULL; 303*7c208ed6SRick Macklem 304*7c208ed6SRick Macklem /* 305*7c208ed6SRick Macklem * Send it, repeatedly, until a reply is received, 306*7c208ed6SRick Macklem * but delay each re-send by an increasing amount. 307*7c208ed6SRick Macklem * If the delay hits the maximum, start complaining. 308*7c208ed6SRick Macklem */ 309*7c208ed6SRick Macklem timo = 0; 310*7c208ed6SRick Macklem for (;;) { 311*7c208ed6SRick Macklem /* Send RPC request (or re-send). */ 312*7c208ed6SRick Macklem m = m_copym(mhead, 0, M_COPYALL, M_WAIT); 313*7c208ed6SRick Macklem error = sosend(so, (struct sockaddr *)sa, NULL, m, 314*7c208ed6SRick Macklem NULL, 0, td); 315*7c208ed6SRick Macklem if (error) { 316*7c208ed6SRick Macklem printf("krpc_call: sosend: %d\n", error); 317*7c208ed6SRick Macklem goto out; 318*7c208ed6SRick Macklem } 319*7c208ed6SRick Macklem m = NULL; 320*7c208ed6SRick Macklem 321*7c208ed6SRick Macklem /* Determine new timeout. */ 322*7c208ed6SRick Macklem if (timo < MAX_RESEND_DELAY) 323*7c208ed6SRick Macklem timo++; 324*7c208ed6SRick Macklem else { 325*7c208ed6SRick Macklem saddr = ntohl(sa->sin_addr.s_addr); 326*7c208ed6SRick Macklem printf("RPC timeout for server %d.%d.%d.%d\n", 327*7c208ed6SRick Macklem (saddr >> 24) & 255, 328*7c208ed6SRick Macklem (saddr >> 16) & 255, 329*7c208ed6SRick Macklem (saddr >> 8) & 255, 330*7c208ed6SRick Macklem saddr & 255); 331*7c208ed6SRick Macklem } 332*7c208ed6SRick Macklem 333*7c208ed6SRick Macklem /* 334*7c208ed6SRick Macklem * Wait for up to timo seconds for a reply. 335*7c208ed6SRick Macklem * The socket receive timeout was set to 1 second. 336*7c208ed6SRick Macklem */ 337*7c208ed6SRick Macklem secs = timo; 338*7c208ed6SRick Macklem while (secs > 0) { 339*7c208ed6SRick Macklem if (from) { 340*7c208ed6SRick Macklem free(from, M_SONAME); 341*7c208ed6SRick Macklem from = NULL; 342*7c208ed6SRick Macklem } 343*7c208ed6SRick Macklem if (m) { 344*7c208ed6SRick Macklem m_freem(m); 345*7c208ed6SRick Macklem m = NULL; 346*7c208ed6SRick Macklem } 347*7c208ed6SRick Macklem bzero(&auio, sizeof(auio)); 348*7c208ed6SRick Macklem auio.uio_resid = len = 1<<16; 349*7c208ed6SRick Macklem rcvflg = 0; 350*7c208ed6SRick Macklem error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); 351*7c208ed6SRick Macklem if (error == EWOULDBLOCK) { 352*7c208ed6SRick Macklem secs--; 353*7c208ed6SRick Macklem continue; 354*7c208ed6SRick Macklem } 355*7c208ed6SRick Macklem if (error) 356*7c208ed6SRick Macklem goto out; 357*7c208ed6SRick Macklem len -= auio.uio_resid; 358*7c208ed6SRick Macklem 359*7c208ed6SRick Macklem /* Does the reply contain at least a header? */ 360*7c208ed6SRick Macklem if (len < MIN_REPLY_HDR) 361*7c208ed6SRick Macklem continue; 362*7c208ed6SRick Macklem if (m->m_len < MIN_REPLY_HDR) 363*7c208ed6SRick Macklem continue; 364*7c208ed6SRick Macklem reply = mtod(m, struct krpc_reply *); 365*7c208ed6SRick Macklem 366*7c208ed6SRick Macklem /* Is it the right reply? */ 367*7c208ed6SRick Macklem if (reply->rp_direction != txdr_unsigned(REPLY)) 368*7c208ed6SRick Macklem continue; 369*7c208ed6SRick Macklem 370*7c208ed6SRick Macklem if (reply->rp_xid != txdr_unsigned(xid)) 371*7c208ed6SRick Macklem continue; 372*7c208ed6SRick Macklem 373*7c208ed6SRick Macklem /* Was RPC accepted? (authorization OK) */ 374*7c208ed6SRick Macklem if (reply->rp_astatus != 0) { 375*7c208ed6SRick Macklem error = fxdr_unsigned(u_int32_t, reply->rp_errno); 376*7c208ed6SRick Macklem printf("rpc denied, error=%d\n", error); 377*7c208ed6SRick Macklem continue; 378*7c208ed6SRick Macklem } 379*7c208ed6SRick Macklem 380*7c208ed6SRick Macklem /* Did the call succeed? */ 381*7c208ed6SRick Macklem if (reply->rp_status != 0) { 382*7c208ed6SRick Macklem error = fxdr_unsigned(u_int32_t, reply->rp_status); 383*7c208ed6SRick Macklem if (error == PROG_MISMATCH) { 384*7c208ed6SRick Macklem error = EBADRPC; 385*7c208ed6SRick Macklem goto out; 386*7c208ed6SRick Macklem } 387*7c208ed6SRick Macklem printf("rpc denied, status=%d\n", error); 388*7c208ed6SRick Macklem continue; 389*7c208ed6SRick Macklem } 390*7c208ed6SRick Macklem 391*7c208ed6SRick Macklem goto gotreply; /* break two levels */ 392*7c208ed6SRick Macklem 393*7c208ed6SRick Macklem } /* while secs */ 394*7c208ed6SRick Macklem } /* forever send/receive */ 395*7c208ed6SRick Macklem 396*7c208ed6SRick Macklem error = ETIMEDOUT; 397*7c208ed6SRick Macklem goto out; 398*7c208ed6SRick Macklem 399*7c208ed6SRick Macklem gotreply: 400*7c208ed6SRick Macklem 401*7c208ed6SRick Macklem /* 402*7c208ed6SRick Macklem * Get RPC reply header into first mbuf, 403*7c208ed6SRick Macklem * get its length, then strip it off. 404*7c208ed6SRick Macklem */ 405*7c208ed6SRick Macklem len = sizeof(*reply); 406*7c208ed6SRick Macklem if (m->m_len < len) { 407*7c208ed6SRick Macklem m = m_pullup(m, len); 408*7c208ed6SRick Macklem if (m == NULL) { 409*7c208ed6SRick Macklem error = ENOBUFS; 410*7c208ed6SRick Macklem goto out; 411*7c208ed6SRick Macklem } 412*7c208ed6SRick Macklem } 413*7c208ed6SRick Macklem reply = mtod(m, struct krpc_reply *); 414*7c208ed6SRick Macklem if (reply->rp_auth.authtype != 0) { 415*7c208ed6SRick Macklem len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 416*7c208ed6SRick Macklem len = (len + 3) & ~3; /* XXX? */ 417*7c208ed6SRick Macklem } 418*7c208ed6SRick Macklem m_adj(m, len); 419*7c208ed6SRick Macklem 420*7c208ed6SRick Macklem /* result */ 421*7c208ed6SRick Macklem *data = m; 422*7c208ed6SRick Macklem if (from_p) { 423*7c208ed6SRick Macklem *from_p = from; 424*7c208ed6SRick Macklem from = NULL; 425*7c208ed6SRick Macklem } 426*7c208ed6SRick Macklem 427*7c208ed6SRick Macklem out: 428*7c208ed6SRick Macklem if (mhead) m_freem(mhead); 429*7c208ed6SRick Macklem if (from) free(from, M_SONAME); 430*7c208ed6SRick Macklem soclose(so); 431*7c208ed6SRick Macklem return error; 432*7c208ed6SRick Macklem } 433*7c208ed6SRick Macklem 434*7c208ed6SRick Macklem /* 435*7c208ed6SRick Macklem * eXternal Data Representation routines. 436*7c208ed6SRick Macklem * (but with non-standard args...) 437*7c208ed6SRick Macklem */ 438*7c208ed6SRick Macklem 439*7c208ed6SRick Macklem /* 440*7c208ed6SRick Macklem * String representation for RPC. 441*7c208ed6SRick Macklem */ 442*7c208ed6SRick Macklem struct xdr_string { 443*7c208ed6SRick Macklem u_int32_t len; /* length without null or padding */ 444*7c208ed6SRick Macklem char data[4]; /* data (longer, of course) */ 445*7c208ed6SRick Macklem /* data is padded to a long-word boundary */ 446*7c208ed6SRick Macklem }; 447*7c208ed6SRick Macklem 448*7c208ed6SRick Macklem struct mbuf * 449*7c208ed6SRick Macklem xdr_string_encode(char *str, int len) 450*7c208ed6SRick Macklem { 451*7c208ed6SRick Macklem struct mbuf *m; 452*7c208ed6SRick Macklem struct xdr_string *xs; 453*7c208ed6SRick Macklem int dlen; /* padded string length */ 454*7c208ed6SRick Macklem int mlen; /* message length */ 455*7c208ed6SRick Macklem 456*7c208ed6SRick Macklem dlen = (len + 3) & ~3; 457*7c208ed6SRick Macklem mlen = dlen + 4; 458*7c208ed6SRick Macklem 459*7c208ed6SRick Macklem if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 460*7c208ed6SRick Macklem return (NULL); 461*7c208ed6SRick Macklem 462*7c208ed6SRick Macklem m = m_get(M_WAIT, MT_DATA); 463*7c208ed6SRick Macklem if (mlen > MLEN) 464*7c208ed6SRick Macklem MCLGET(m, M_WAIT); 465*7c208ed6SRick Macklem xs = mtod(m, struct xdr_string *); 466*7c208ed6SRick Macklem m->m_len = mlen; 467*7c208ed6SRick Macklem xs->len = txdr_unsigned(len); 468*7c208ed6SRick Macklem bcopy(str, xs->data, len); 469*7c208ed6SRick Macklem return (m); 470*7c208ed6SRick Macklem } 471