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