17c208ed6SRick Macklem /* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ 27c208ed6SRick Macklem 37c208ed6SRick Macklem /*- 47c208ed6SRick Macklem * Copyright (c) 1995 Gordon Ross, Adam Glass 57c208ed6SRick Macklem * Copyright (c) 1992 Regents of the University of California. 67c208ed6SRick Macklem * All rights reserved. 77c208ed6SRick Macklem * 87c208ed6SRick Macklem * This software was developed by the Computer Systems Engineering group 97c208ed6SRick Macklem * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 107c208ed6SRick Macklem * contributed to Berkeley. 117c208ed6SRick Macklem * 127c208ed6SRick Macklem * Redistribution and use in source and binary forms, with or without 137c208ed6SRick Macklem * modification, are permitted provided that the following conditions 147c208ed6SRick Macklem * are met: 157c208ed6SRick Macklem * 1. Redistributions of source code must retain the above copyright 167c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer. 177c208ed6SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 187c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer in the 197c208ed6SRick Macklem * documentation and/or other materials provided with the distribution. 207c208ed6SRick Macklem * 3. All advertising materials mentioning features or use of this software 217c208ed6SRick Macklem * must display the following acknowledgement: 227c208ed6SRick Macklem * This product includes software developed by the University of 237c208ed6SRick Macklem * California, Lawrence Berkeley Laboratory and its contributors. 247c208ed6SRick Macklem * 4. Neither the name of the University nor the names of its contributors 257c208ed6SRick Macklem * may be used to endorse or promote products derived from this software 267c208ed6SRick Macklem * without specific prior written permission. 277c208ed6SRick Macklem * 287c208ed6SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 297c208ed6SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 307c208ed6SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 317c208ed6SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 327c208ed6SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 337c208ed6SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 347c208ed6SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 357c208ed6SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 367c208ed6SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 377c208ed6SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 387c208ed6SRick Macklem * SUCH DAMAGE. 397c208ed6SRick Macklem * 407c208ed6SRick Macklem * partially based on: 417c208ed6SRick Macklem * libnetboot/rpc.c 427c208ed6SRick Macklem * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 437c208ed6SRick Macklem */ 447c208ed6SRick Macklem 457c208ed6SRick Macklem #include <sys/cdefs.h> 467c208ed6SRick Macklem __FBSDID("$FreeBSD$"); 477c208ed6SRick Macklem 487c208ed6SRick Macklem #include <sys/param.h> 497c208ed6SRick Macklem #include <sys/systm.h> 507c208ed6SRick Macklem #include <sys/jail.h> 517c208ed6SRick Macklem #include <sys/malloc.h> 527c208ed6SRick Macklem #include <sys/mbuf.h> 537c208ed6SRick Macklem #include <sys/proc.h> 547c208ed6SRick Macklem #include <sys/socket.h> 557c208ed6SRick Macklem #include <sys/socketvar.h> 567c208ed6SRick Macklem #include <sys/uio.h> 577c208ed6SRick Macklem 587c208ed6SRick Macklem #include <net/if.h> 597c208ed6SRick Macklem #include <net/vnet.h> 607c208ed6SRick Macklem 617c208ed6SRick Macklem #include <netinet/in.h> 627c208ed6SRick Macklem 637c208ed6SRick Macklem #include <rpc/types.h> 647c208ed6SRick Macklem #include <rpc/auth.h> 657c208ed6SRick Macklem #include <rpc/rpc_msg.h> 667c208ed6SRick Macklem #include <nfs/krpc.h> 677c208ed6SRick Macklem #include <nfs/xdr_subs.h> 687c208ed6SRick Macklem 697c208ed6SRick Macklem /* 707c208ed6SRick Macklem * Kernel support for Sun RPC 717c208ed6SRick Macklem * 727c208ed6SRick Macklem * Used currently for bootstrapping in nfs diskless configurations. 737c208ed6SRick Macklem */ 747c208ed6SRick Macklem 757c208ed6SRick Macklem /* 767c208ed6SRick Macklem * Generic RPC headers 777c208ed6SRick Macklem */ 787c208ed6SRick Macklem 797c208ed6SRick Macklem struct auth_info { 807c208ed6SRick Macklem u_int32_t authtype; /* auth type */ 817c208ed6SRick Macklem u_int32_t authlen; /* auth length */ 827c208ed6SRick Macklem }; 837c208ed6SRick Macklem 847c208ed6SRick Macklem struct auth_unix { 857c208ed6SRick Macklem int32_t ua_time; 867c208ed6SRick Macklem int32_t ua_hostname; /* null */ 877c208ed6SRick Macklem int32_t ua_uid; 887c208ed6SRick Macklem int32_t ua_gid; 897c208ed6SRick Macklem int32_t ua_gidlist; /* null */ 907c208ed6SRick Macklem }; 917c208ed6SRick Macklem 927c208ed6SRick Macklem struct krpc_call { 937c208ed6SRick Macklem u_int32_t rp_xid; /* request transaction id */ 947c208ed6SRick Macklem int32_t rp_direction; /* call direction (0) */ 957c208ed6SRick Macklem u_int32_t rp_rpcvers; /* rpc version (2) */ 967c208ed6SRick Macklem u_int32_t rp_prog; /* program */ 977c208ed6SRick Macklem u_int32_t rp_vers; /* version */ 987c208ed6SRick Macklem u_int32_t rp_proc; /* procedure */ 997c208ed6SRick Macklem struct auth_info rpc_auth; 1007c208ed6SRick Macklem struct auth_unix rpc_unix; 1017c208ed6SRick Macklem struct auth_info rpc_verf; 1027c208ed6SRick Macklem }; 1037c208ed6SRick Macklem 1047c208ed6SRick Macklem struct krpc_reply { 1057c208ed6SRick Macklem u_int32_t rp_xid; /* request transaction id */ 1067c208ed6SRick Macklem int32_t rp_direction; /* call direction (1) */ 1077c208ed6SRick Macklem int32_t rp_astatus; /* accept status (0: accepted) */ 1087c208ed6SRick Macklem union { 1097c208ed6SRick Macklem u_int32_t rpu_errno; 1107c208ed6SRick Macklem struct { 1117c208ed6SRick Macklem struct auth_info rok_auth; 1127c208ed6SRick Macklem u_int32_t rok_status; 1137c208ed6SRick Macklem } rpu_rok; 1147c208ed6SRick Macklem } rp_u; 1157c208ed6SRick Macklem }; 1167c208ed6SRick Macklem #define rp_errno rp_u.rpu_errno 1177c208ed6SRick Macklem #define rp_auth rp_u.rpu_rok.rok_auth 1187c208ed6SRick Macklem #define rp_status rp_u.rpu_rok.rok_status 1197c208ed6SRick Macklem 1207c208ed6SRick Macklem #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 1217c208ed6SRick Macklem 1227c208ed6SRick Macklem /* 1237c208ed6SRick Macklem * What is the longest we will wait before re-sending a request? 1247c208ed6SRick Macklem * Note this is also the frequency of "RPC timeout" messages. 1257c208ed6SRick Macklem * The re-send loop count sup linearly to this maximum, so the 1267c208ed6SRick Macklem * first complaint will happen after (1+2+3+4+5)=15 seconds. 1277c208ed6SRick Macklem */ 1287c208ed6SRick Macklem #define MAX_RESEND_DELAY 5 /* seconds */ 1297c208ed6SRick Macklem 1307c208ed6SRick Macklem /* 1317c208ed6SRick Macklem * Call portmap to lookup a port number for a particular rpc program 1327c208ed6SRick Macklem * Returns non-zero error on failure. 1337c208ed6SRick Macklem */ 1347c208ed6SRick Macklem int 1357c208ed6SRick Macklem krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp, 1367c208ed6SRick Macklem struct thread *td) 1377c208ed6SRick Macklem { 1387c208ed6SRick Macklem struct sdata { 1397c208ed6SRick Macklem u_int32_t prog; /* call program */ 1407c208ed6SRick Macklem u_int32_t vers; /* call version */ 1417c208ed6SRick Macklem u_int32_t proto; /* call protocol */ 1427c208ed6SRick Macklem u_int32_t port; /* call port (unused) */ 1437c208ed6SRick Macklem } *sdata; 1447c208ed6SRick Macklem struct rdata { 1457c208ed6SRick Macklem u_int16_t pad; 1467c208ed6SRick Macklem u_int16_t port; 1477c208ed6SRick Macklem } *rdata; 1487c208ed6SRick Macklem struct mbuf *m; 1497c208ed6SRick Macklem int error; 1507c208ed6SRick Macklem 1517c208ed6SRick Macklem /* The portmapper port is fixed. */ 1527c208ed6SRick Macklem if (prog == PMAPPROG) { 1537c208ed6SRick Macklem *portp = htons(PMAPPORT); 1547c208ed6SRick Macklem return 0; 1557c208ed6SRick Macklem } 1567c208ed6SRick Macklem 157eb1b1807SGleb Smirnoff m = m_get(M_WAITOK, MT_DATA); 1587c208ed6SRick Macklem sdata = mtod(m, struct sdata *); 1597c208ed6SRick Macklem m->m_len = sizeof(*sdata); 1607c208ed6SRick Macklem 1617c208ed6SRick Macklem /* Do the RPC to get it. */ 1627c208ed6SRick Macklem sdata->prog = txdr_unsigned(prog); 1637c208ed6SRick Macklem sdata->vers = txdr_unsigned(vers); 1647c208ed6SRick Macklem sdata->proto = txdr_unsigned(IPPROTO_UDP); 1657c208ed6SRick Macklem sdata->port = 0; 1667c208ed6SRick Macklem 1677c208ed6SRick Macklem sin->sin_port = htons(PMAPPORT); 1687c208ed6SRick Macklem error = krpc_call(sin, PMAPPROG, PMAPVERS, 1697c208ed6SRick Macklem PMAPPROC_GETPORT, &m, NULL, td); 1707c208ed6SRick Macklem if (error) 1717c208ed6SRick Macklem return error; 1727c208ed6SRick Macklem 1737c208ed6SRick Macklem if (m->m_len < sizeof(*rdata)) { 1747c208ed6SRick Macklem m = m_pullup(m, sizeof(*rdata)); 1757c208ed6SRick Macklem if (m == NULL) 1767c208ed6SRick Macklem return ENOBUFS; 1777c208ed6SRick Macklem } 1787c208ed6SRick Macklem rdata = mtod(m, struct rdata *); 1797c208ed6SRick Macklem *portp = rdata->port; 1807c208ed6SRick Macklem 1817c208ed6SRick Macklem m_freem(m); 1827c208ed6SRick Macklem return 0; 1837c208ed6SRick Macklem } 1847c208ed6SRick Macklem 1857c208ed6SRick Macklem /* 1867c208ed6SRick Macklem * Do a remote procedure call (RPC) and wait for its reply. 1877c208ed6SRick Macklem * If from_p is non-null, then we are doing broadcast, and 1887c208ed6SRick Macklem * the address from whence the response came is saved there. 1897c208ed6SRick Macklem */ 1907c208ed6SRick Macklem int 1917c208ed6SRick Macklem krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, 1927c208ed6SRick Macklem struct mbuf **data, struct sockaddr **from_p, struct thread *td) 1937c208ed6SRick Macklem { 1947c208ed6SRick Macklem struct socket *so; 1957c208ed6SRick Macklem struct sockaddr_in *sin, ssin; 1967c208ed6SRick Macklem struct sockaddr *from; 1977c208ed6SRick Macklem struct mbuf *m, *nam, *mhead; 1987c208ed6SRick Macklem struct krpc_call *call; 1997c208ed6SRick Macklem struct krpc_reply *reply; 2007c208ed6SRick Macklem struct sockopt sopt; 2017c208ed6SRick Macklem struct timeval tv; 2027c208ed6SRick Macklem struct uio auio; 2037c208ed6SRick Macklem int error, rcvflg, timo, secs, len; 2047c208ed6SRick Macklem static u_int32_t xid = ~0xFF; 2057c208ed6SRick Macklem u_int16_t tport; 2067c208ed6SRick Macklem u_int32_t saddr; 2077c208ed6SRick Macklem 2087c208ed6SRick Macklem /* 2097c208ed6SRick Macklem * Validate address family. 2107c208ed6SRick Macklem * Sorry, this is INET specific... 2117c208ed6SRick Macklem */ 2127c208ed6SRick Macklem if (sa->sin_family != AF_INET) 2137c208ed6SRick Macklem return (EAFNOSUPPORT); 2147c208ed6SRick Macklem 2157c208ed6SRick Macklem /* Free at end if not null. */ 2167c208ed6SRick Macklem nam = mhead = NULL; 2177c208ed6SRick Macklem from = NULL; 2187c208ed6SRick Macklem 2197c208ed6SRick Macklem /* 2207c208ed6SRick Macklem * Create socket and set its recieve timeout. 2217c208ed6SRick Macklem */ 2227c208ed6SRick Macklem if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td))) 2237c208ed6SRick Macklem goto out; 2247c208ed6SRick Macklem 2257c208ed6SRick Macklem tv.tv_sec = 1; 2267c208ed6SRick Macklem tv.tv_usec = 0; 2277c208ed6SRick Macklem bzero(&sopt, sizeof sopt); 2287c208ed6SRick Macklem sopt.sopt_dir = SOPT_SET; 2297c208ed6SRick Macklem sopt.sopt_level = SOL_SOCKET; 2307c208ed6SRick Macklem sopt.sopt_name = SO_RCVTIMEO; 2317c208ed6SRick Macklem sopt.sopt_val = &tv; 2327c208ed6SRick Macklem sopt.sopt_valsize = sizeof tv; 2337c208ed6SRick Macklem 2347c208ed6SRick Macklem if ((error = sosetopt(so, &sopt)) != 0) 2357c208ed6SRick Macklem goto out; 2367c208ed6SRick Macklem 2377c208ed6SRick Macklem /* 2387c208ed6SRick Macklem * Enable broadcast if necessary. 2397c208ed6SRick Macklem */ 2407c208ed6SRick Macklem if (from_p) { 2417c208ed6SRick Macklem int on = 1; 2427c208ed6SRick Macklem sopt.sopt_name = SO_BROADCAST; 2437c208ed6SRick Macklem sopt.sopt_val = &on; 2447c208ed6SRick Macklem sopt.sopt_valsize = sizeof on; 2457c208ed6SRick Macklem if ((error = sosetopt(so, &sopt)) != 0) 2467c208ed6SRick Macklem goto out; 2477c208ed6SRick Macklem } 2487c208ed6SRick Macklem 2497c208ed6SRick Macklem /* 2507c208ed6SRick Macklem * Bind the local endpoint to a reserved port, 2517c208ed6SRick Macklem * because some NFS servers refuse requests from 2527c208ed6SRick Macklem * non-reserved (non-privileged) ports. 2537c208ed6SRick Macklem */ 2547c208ed6SRick Macklem sin = &ssin; 2557c208ed6SRick Macklem bzero(sin, sizeof *sin); 2567c208ed6SRick Macklem sin->sin_len = sizeof(*sin); 2577c208ed6SRick Macklem sin->sin_family = AF_INET; 2587c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_ANY; 2597c208ed6SRick Macklem tport = IPPORT_RESERVED; 2607c208ed6SRick Macklem do { 2617c208ed6SRick Macklem tport--; 2627c208ed6SRick Macklem sin->sin_port = htons(tport); 2637c208ed6SRick Macklem error = sobind(so, (struct sockaddr *)sin, td); 2647c208ed6SRick Macklem } while (error == EADDRINUSE && 2657c208ed6SRick Macklem tport > IPPORT_RESERVED / 2); 2667c208ed6SRick Macklem if (error) { 2677c208ed6SRick Macklem printf("bind failed\n"); 2687c208ed6SRick Macklem goto out; 2697c208ed6SRick Macklem } 2707c208ed6SRick Macklem 2717c208ed6SRick Macklem /* 2727c208ed6SRick Macklem * Setup socket address for the server. 2737c208ed6SRick Macklem */ 2747c208ed6SRick Macklem 2757c208ed6SRick Macklem /* 2767c208ed6SRick Macklem * Prepend RPC message header. 2777c208ed6SRick Macklem */ 278eb1b1807SGleb Smirnoff mhead = m_gethdr(M_WAITOK, MT_DATA); 2797c208ed6SRick Macklem mhead->m_next = *data; 2807c208ed6SRick Macklem call = mtod(mhead, struct krpc_call *); 2817c208ed6SRick Macklem mhead->m_len = sizeof(*call); 2827c208ed6SRick Macklem bzero((caddr_t)call, sizeof(*call)); 2837c208ed6SRick Macklem /* rpc_call part */ 2847c208ed6SRick Macklem xid++; 2857c208ed6SRick Macklem call->rp_xid = txdr_unsigned(xid); 2867c208ed6SRick Macklem /* call->rp_direction = 0; */ 2877c208ed6SRick Macklem call->rp_rpcvers = txdr_unsigned(2); 2887c208ed6SRick Macklem call->rp_prog = txdr_unsigned(prog); 2897c208ed6SRick Macklem call->rp_vers = txdr_unsigned(vers); 2907c208ed6SRick Macklem call->rp_proc = txdr_unsigned(func); 2917c208ed6SRick Macklem /* rpc_auth part (auth_unix as root) */ 2927c208ed6SRick Macklem call->rpc_auth.authtype = txdr_unsigned(AUTH_UNIX); 2937c208ed6SRick Macklem call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 2947c208ed6SRick Macklem /* rpc_verf part (auth_null) */ 2957c208ed6SRick Macklem call->rpc_verf.authtype = 0; 2967c208ed6SRick Macklem call->rpc_verf.authlen = 0; 2977c208ed6SRick Macklem 2987c208ed6SRick Macklem /* 2997c208ed6SRick Macklem * Setup packet header 3007c208ed6SRick Macklem */ 3017c208ed6SRick Macklem m_fixhdr(mhead); 3027c208ed6SRick Macklem mhead->m_pkthdr.rcvif = NULL; 3037c208ed6SRick Macklem 3047c208ed6SRick Macklem /* 3057c208ed6SRick Macklem * Send it, repeatedly, until a reply is received, 3067c208ed6SRick Macklem * but delay each re-send by an increasing amount. 3077c208ed6SRick Macklem * If the delay hits the maximum, start complaining. 3087c208ed6SRick Macklem */ 3097c208ed6SRick Macklem timo = 0; 3107c208ed6SRick Macklem for (;;) { 3117c208ed6SRick Macklem /* Send RPC request (or re-send). */ 312eb1b1807SGleb Smirnoff m = m_copym(mhead, 0, M_COPYALL, M_WAITOK); 3137c208ed6SRick Macklem error = sosend(so, (struct sockaddr *)sa, NULL, m, 3147c208ed6SRick Macklem NULL, 0, td); 3157c208ed6SRick Macklem if (error) { 3167c208ed6SRick Macklem printf("krpc_call: sosend: %d\n", error); 3177c208ed6SRick Macklem goto out; 3187c208ed6SRick Macklem } 3197c208ed6SRick Macklem m = NULL; 3207c208ed6SRick Macklem 3217c208ed6SRick Macklem /* Determine new timeout. */ 3227c208ed6SRick Macklem if (timo < MAX_RESEND_DELAY) 3237c208ed6SRick Macklem timo++; 3247c208ed6SRick Macklem else { 3257c208ed6SRick Macklem saddr = ntohl(sa->sin_addr.s_addr); 3267c208ed6SRick Macklem printf("RPC timeout for server %d.%d.%d.%d\n", 3277c208ed6SRick Macklem (saddr >> 24) & 255, 3287c208ed6SRick Macklem (saddr >> 16) & 255, 3297c208ed6SRick Macklem (saddr >> 8) & 255, 3307c208ed6SRick Macklem saddr & 255); 3317c208ed6SRick Macklem } 3327c208ed6SRick Macklem 3337c208ed6SRick Macklem /* 3347c208ed6SRick Macklem * Wait for up to timo seconds for a reply. 3357c208ed6SRick Macklem * The socket receive timeout was set to 1 second. 3367c208ed6SRick Macklem */ 3377c208ed6SRick Macklem secs = timo; 3387c208ed6SRick Macklem while (secs > 0) { 3397c208ed6SRick Macklem if (from) { 3407c208ed6SRick Macklem free(from, M_SONAME); 3417c208ed6SRick Macklem from = NULL; 3427c208ed6SRick Macklem } 3437c208ed6SRick Macklem if (m) { 3447c208ed6SRick Macklem m_freem(m); 3457c208ed6SRick Macklem m = NULL; 3467c208ed6SRick Macklem } 3477c208ed6SRick Macklem bzero(&auio, sizeof(auio)); 3487c208ed6SRick Macklem auio.uio_resid = len = 1<<16; 3497c208ed6SRick Macklem rcvflg = 0; 3507c208ed6SRick Macklem error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); 3517c208ed6SRick Macklem if (error == EWOULDBLOCK) { 3527c208ed6SRick Macklem secs--; 3537c208ed6SRick Macklem continue; 3547c208ed6SRick Macklem } 3557c208ed6SRick Macklem if (error) 3567c208ed6SRick Macklem goto out; 3577c208ed6SRick Macklem len -= auio.uio_resid; 3587c208ed6SRick Macklem 3597c208ed6SRick Macklem /* Does the reply contain at least a header? */ 3607c208ed6SRick Macklem if (len < MIN_REPLY_HDR) 3617c208ed6SRick Macklem continue; 3627c208ed6SRick Macklem if (m->m_len < MIN_REPLY_HDR) 3637c208ed6SRick Macklem continue; 3647c208ed6SRick Macklem reply = mtod(m, struct krpc_reply *); 3657c208ed6SRick Macklem 3667c208ed6SRick Macklem /* Is it the right reply? */ 3677c208ed6SRick Macklem if (reply->rp_direction != txdr_unsigned(REPLY)) 3687c208ed6SRick Macklem continue; 3697c208ed6SRick Macklem 3707c208ed6SRick Macklem if (reply->rp_xid != txdr_unsigned(xid)) 3717c208ed6SRick Macklem continue; 3727c208ed6SRick Macklem 3737c208ed6SRick Macklem /* Was RPC accepted? (authorization OK) */ 3747c208ed6SRick Macklem if (reply->rp_astatus != 0) { 3757c208ed6SRick Macklem error = fxdr_unsigned(u_int32_t, reply->rp_errno); 3767c208ed6SRick Macklem printf("rpc denied, error=%d\n", error); 3777c208ed6SRick Macklem continue; 3787c208ed6SRick Macklem } 3797c208ed6SRick Macklem 3807c208ed6SRick Macklem /* Did the call succeed? */ 3817c208ed6SRick Macklem if (reply->rp_status != 0) { 3827c208ed6SRick Macklem error = fxdr_unsigned(u_int32_t, reply->rp_status); 3837c208ed6SRick Macklem if (error == PROG_MISMATCH) { 3847c208ed6SRick Macklem error = EBADRPC; 3857c208ed6SRick Macklem goto out; 3867c208ed6SRick Macklem } 3877c208ed6SRick Macklem printf("rpc denied, status=%d\n", error); 3887c208ed6SRick Macklem continue; 3897c208ed6SRick Macklem } 3907c208ed6SRick Macklem 3917c208ed6SRick Macklem goto gotreply; /* break two levels */ 3927c208ed6SRick Macklem 3937c208ed6SRick Macklem } /* while secs */ 3947c208ed6SRick Macklem } /* forever send/receive */ 3957c208ed6SRick Macklem 3967c208ed6SRick Macklem error = ETIMEDOUT; 3977c208ed6SRick Macklem goto out; 3987c208ed6SRick Macklem 3997c208ed6SRick Macklem gotreply: 4007c208ed6SRick Macklem 4017c208ed6SRick Macklem /* 4027c208ed6SRick Macklem * Get RPC reply header into first mbuf, 4037c208ed6SRick Macklem * get its length, then strip it off. 4047c208ed6SRick Macklem */ 4057c208ed6SRick Macklem len = sizeof(*reply); 4067c208ed6SRick Macklem if (m->m_len < len) { 4077c208ed6SRick Macklem m = m_pullup(m, len); 4087c208ed6SRick Macklem if (m == NULL) { 4097c208ed6SRick Macklem error = ENOBUFS; 4107c208ed6SRick Macklem goto out; 4117c208ed6SRick Macklem } 4127c208ed6SRick Macklem } 4137c208ed6SRick Macklem reply = mtod(m, struct krpc_reply *); 4147c208ed6SRick Macklem if (reply->rp_auth.authtype != 0) { 4157c208ed6SRick Macklem len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 4167c208ed6SRick Macklem len = (len + 3) & ~3; /* XXX? */ 4177c208ed6SRick Macklem } 4187c208ed6SRick Macklem m_adj(m, len); 4197c208ed6SRick Macklem 4207c208ed6SRick Macklem /* result */ 4217c208ed6SRick Macklem *data = m; 4227c208ed6SRick Macklem if (from_p) { 4237c208ed6SRick Macklem *from_p = from; 4247c208ed6SRick Macklem from = NULL; 4257c208ed6SRick Macklem } 4267c208ed6SRick Macklem 4277c208ed6SRick Macklem out: 4287c208ed6SRick Macklem if (mhead) m_freem(mhead); 4297c208ed6SRick Macklem if (from) free(from, M_SONAME); 4307c208ed6SRick Macklem soclose(so); 4317c208ed6SRick Macklem return error; 4327c208ed6SRick Macklem } 4337c208ed6SRick Macklem 4347c208ed6SRick Macklem /* 4357c208ed6SRick Macklem * eXternal Data Representation routines. 4367c208ed6SRick Macklem * (but with non-standard args...) 4377c208ed6SRick Macklem */ 4387c208ed6SRick Macklem 4397c208ed6SRick Macklem /* 4407c208ed6SRick Macklem * String representation for RPC. 4417c208ed6SRick Macklem */ 4427c208ed6SRick Macklem struct xdr_string { 4437c208ed6SRick Macklem u_int32_t len; /* length without null or padding */ 4447c208ed6SRick Macklem char data[4]; /* data (longer, of course) */ 4457c208ed6SRick Macklem /* data is padded to a long-word boundary */ 4467c208ed6SRick Macklem }; 4477c208ed6SRick Macklem 4487c208ed6SRick Macklem struct mbuf * 4497c208ed6SRick Macklem xdr_string_encode(char *str, int len) 4507c208ed6SRick Macklem { 4517c208ed6SRick Macklem struct mbuf *m; 4527c208ed6SRick Macklem struct xdr_string *xs; 4537c208ed6SRick Macklem int dlen; /* padded string length */ 4547c208ed6SRick Macklem int mlen; /* message length */ 4557c208ed6SRick Macklem 4567c208ed6SRick Macklem dlen = (len + 3) & ~3; 4577c208ed6SRick Macklem mlen = dlen + 4; 4587c208ed6SRick Macklem 4597c208ed6SRick Macklem if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 4607c208ed6SRick Macklem return (NULL); 4617c208ed6SRick Macklem 46241a7572bSGleb Smirnoff m = m_get2(mlen, M_WAITOK, MT_DATA, 0); 4637c208ed6SRick Macklem xs = mtod(m, struct xdr_string *); 4647c208ed6SRick Macklem m->m_len = mlen; 4657c208ed6SRick Macklem xs->len = txdr_unsigned(len); 4667c208ed6SRick Macklem bcopy(str, xs->data, len); 4677c208ed6SRick Macklem return (m); 4687c208ed6SRick Macklem } 469