1*c94bf7cbSmlelstv /* $NetBSD: krpc_subr.c,v 1.44 2024/10/20 14:01:52 mlelstv Exp $ */ 2fccfa11aScgd 3a3b04214Sglass /* 4d73db495Sgwr * Copyright (c) 1995 Gordon Ross, Adam Glass 5a3b04214Sglass * Copyright (c) 1992 Regents of the University of California. 6a3b04214Sglass * All rights reserved. 7a3b04214Sglass * 8a3b04214Sglass * This software was developed by the Computer Systems Engineering group 9a3b04214Sglass * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10a3b04214Sglass * contributed to Berkeley. 11a3b04214Sglass * 12a3b04214Sglass * Redistribution and use in source and binary forms, with or without 13a3b04214Sglass * modification, are permitted provided that the following conditions 14a3b04214Sglass * are met: 15a3b04214Sglass * 1. Redistributions of source code must retain the above copyright 16a3b04214Sglass * notice, this list of conditions and the following disclaimer. 17a3b04214Sglass * 2. Redistributions in binary form must reproduce the above copyright 18a3b04214Sglass * notice, this list of conditions and the following disclaimer in the 19a3b04214Sglass * documentation and/or other materials provided with the distribution. 20a3b04214Sglass * 3. All advertising materials mentioning features or use of this software 21a3b04214Sglass * must display the following acknowledgement: 22a3b04214Sglass * This product includes software developed by the University of 23a3b04214Sglass * California, Lawrence Berkeley Laboratory and its contributors. 24a3b04214Sglass * 4. Neither the name of the University nor the names of its contributors 25a3b04214Sglass * may be used to endorse or promote products derived from this software 26a3b04214Sglass * without specific prior written permission. 27a3b04214Sglass * 28a3b04214Sglass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29a3b04214Sglass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30a3b04214Sglass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31a3b04214Sglass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32a3b04214Sglass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33a3b04214Sglass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34a3b04214Sglass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35a3b04214Sglass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36a3b04214Sglass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37a3b04214Sglass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38a3b04214Sglass * SUCH DAMAGE. 39a3b04214Sglass * 40a3b04214Sglass * partially based on: 41a3b04214Sglass * libnetboot/rpc.c 42a3b04214Sglass * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 43a3b04214Sglass */ 44a3b04214Sglass 450ffad693Slukem #include <sys/cdefs.h> 46*c94bf7cbSmlelstv __KERNEL_RCSID(0, "$NetBSD: krpc_subr.c,v 1.44 2024/10/20 14:01:52 mlelstv Exp $"); 470ffad693Slukem 48a3b04214Sglass #include <sys/param.h> 49d73db495Sgwr #include <sys/systm.h> 50a3b04214Sglass #include <sys/ioctl.h> 51a3b04214Sglass #include <sys/proc.h> 52a3b04214Sglass #include <sys/mount.h> 53a3b04214Sglass #include <sys/mbuf.h> 54a3b04214Sglass #include <sys/reboot.h> 55d73db495Sgwr #include <sys/socket.h> 56d73db495Sgwr #include <sys/socketvar.h> 57a3b04214Sglass 58a3b04214Sglass #include <netinet/in.h> 59a3b04214Sglass 60a3b04214Sglass #include <nfs/rpcv2.h> 6162f18b1dSgwr #include <nfs/krpc.h> 62f6ff0fbaSmycroft #include <nfs/xdr_subs.h> 6334f6ce85Sdrochner #include <nfs/nfsproto.h> /* XXX NFSX_V3FHMAX for next */ 64e5bc90f4Sfvdl #include <nfs/nfs.h> 65e5bc90f4Sfvdl #include <nfs/nfsmount.h> 6634f6ce85Sdrochner #include <nfs/nfsdiskless.h> /* XXX decl nfs_boot_sendrecv */ 67a3b04214Sglass 68a3b04214Sglass /* 69a3b04214Sglass * Kernel support for Sun RPC 70a3b04214Sglass * 71a3b04214Sglass * Used currently for bootstrapping in nfs diskless configurations. 72a3b04214Sglass */ 73a3b04214Sglass 74a3b04214Sglass /* 75a3b04214Sglass * Generic RPC headers 76a3b04214Sglass */ 77a3b04214Sglass 78a3b04214Sglass struct auth_info { 7919969f2fSgwr u_int32_t authtype; /* auth type */ 8019969f2fSgwr u_int32_t authlen; /* auth length */ 8119969f2fSgwr }; 8219969f2fSgwr 8319969f2fSgwr struct auth_unix { 8419969f2fSgwr int32_t ua_time; 8519969f2fSgwr int32_t ua_hostname; /* null */ 8619969f2fSgwr int32_t ua_uid; 8719969f2fSgwr int32_t ua_gid; 8819969f2fSgwr int32_t ua_gidlist; /* null */ 89a3b04214Sglass }; 90a3b04214Sglass 91a3b04214Sglass struct rpc_call { 92d73db495Sgwr u_int32_t rp_xid; /* request transaction id */ 93d73db495Sgwr int32_t rp_direction; /* call direction (0) */ 94d73db495Sgwr u_int32_t rp_rpcvers; /* rpc version (2) */ 95d73db495Sgwr u_int32_t rp_prog; /* program */ 96d73db495Sgwr u_int32_t rp_vers; /* version */ 97d73db495Sgwr u_int32_t rp_proc; /* procedure */ 9819969f2fSgwr struct auth_info rpc_auth; 9919969f2fSgwr struct auth_unix rpc_unix; 10019969f2fSgwr struct auth_info rpc_verf; 101a3b04214Sglass }; 102a3b04214Sglass 103a3b04214Sglass struct rpc_reply { 104d73db495Sgwr u_int32_t rp_xid; /* request transaction id */ 105d73db495Sgwr int32_t rp_direction; /* call direction (1) */ 106d73db495Sgwr int32_t rp_astatus; /* accept status (0: accepted) */ 107a3b04214Sglass union { 1082f81e6c9Sgwr /* rejected */ 1092f81e6c9Sgwr struct { 1102f81e6c9Sgwr u_int32_t rej_stat; 1112f81e6c9Sgwr u_int32_t rej_val1; 1122f81e6c9Sgwr u_int32_t rej_val2; 1132f81e6c9Sgwr } rpu_rej; 1142f81e6c9Sgwr /* accepted */ 115a3b04214Sglass struct { 11619969f2fSgwr struct auth_info rok_auth; 11719969f2fSgwr u_int32_t rok_status; 11819969f2fSgwr } rpu_rok; 119a3b04214Sglass } rp_u; 120a3b04214Sglass }; 1212f81e6c9Sgwr #define rp_rstat rp_u.rpu_rej.rej_stat 12219969f2fSgwr #define rp_auth rp_u.rpu_rok.rok_auth 12319969f2fSgwr #define rp_status rp_u.rpu_rok.rok_status 124a3b04214Sglass 125a3b04214Sglass #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 126a3b04214Sglass 127638842f1Shikaru static int krpccheck(struct mbuf**, void*); 1280784b58dSgwr 1290784b58dSgwr /* 130a3b04214Sglass * Call portmap to lookup a port number for a particular rpc program 1310784b58dSgwr * Returns non-zero error on failure. 132a3b04214Sglass */ 133a3b04214Sglass int 13482357f6dSdsl krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int proto, u_int16_t *portp, struct lwp *l) 13582357f6dSdsl /* sin: server address */ 13682357f6dSdsl /* prog, vers, proto: host order */ 13782357f6dSdsl /* portp: network order */ 138a3b04214Sglass { 139a3b04214Sglass struct sdata { 140d73db495Sgwr u_int32_t prog; /* call program */ 141d73db495Sgwr u_int32_t vers; /* call version */ 142d73db495Sgwr u_int32_t proto; /* call protocol */ 143d73db495Sgwr u_int32_t port; /* call port (unused) */ 144a3b04214Sglass } *sdata; 145a3b04214Sglass struct rdata { 146d73db495Sgwr u_int16_t pad; 147d73db495Sgwr u_int16_t port; 148a3b04214Sglass } *rdata; 149a3b04214Sglass struct mbuf *m; 150a3b04214Sglass int error; 151a3b04214Sglass 152a3b04214Sglass /* The portmapper port is fixed. */ 153a3b04214Sglass if (prog == PMAPPROG) { 154a3b04214Sglass *portp = htons(PMAPPORT); 155a3b04214Sglass return 0; 156a3b04214Sglass } 157a3b04214Sglass 158d73db495Sgwr m = m_get(M_WAIT, MT_DATA); 159a3b04214Sglass sdata = mtod(m, struct sdata *); 160d73db495Sgwr m->m_len = sizeof(*sdata); 161a3b04214Sglass 162a3b04214Sglass /* Do the RPC to get it. */ 163f6ff0fbaSmycroft sdata->prog = txdr_unsigned(prog); 164f6ff0fbaSmycroft sdata->vers = txdr_unsigned(vers); 16573594440Sfvdl sdata->proto = txdr_unsigned(proto); 166a3b04214Sglass sdata->port = 0; 167a3b04214Sglass 16862f18b1dSgwr sin->sin_port = htons(PMAPPORT); 16962f18b1dSgwr error = krpc_call(sin, PMAPPROG, PMAPVERS, 17095e1ffb1Schristos PMAPPROC_GETPORT, &m, NULL, l); 171a3b04214Sglass if (error) 172a3b04214Sglass return error; 173a3b04214Sglass 174d73db495Sgwr if (m->m_len < sizeof(*rdata)) { 175d73db495Sgwr m = m_pullup(m, sizeof(*rdata)); 176d73db495Sgwr if (m == NULL) 177d73db495Sgwr return ENOBUFS; 178d73db495Sgwr } 179a3b04214Sglass rdata = mtod(m, struct rdata *); 180a3b04214Sglass *portp = rdata->port; 181a3b04214Sglass 182a3b04214Sglass m_freem(m); 183a3b04214Sglass return 0; 184a3b04214Sglass } 185a3b04214Sglass 186638842f1Shikaru static int krpccheck(struct mbuf **mp, void *context) 18734f6ce85Sdrochner { 18834f6ce85Sdrochner struct rpc_reply *reply; 189638842f1Shikaru struct mbuf *m = *mp; 19034f6ce85Sdrochner 19134f6ce85Sdrochner /* Does the reply contain at least a header? */ 19234f6ce85Sdrochner if (m->m_pkthdr.len < MIN_REPLY_HDR) 19334f6ce85Sdrochner return(-1); 19434f6ce85Sdrochner if (m->m_len < sizeof(struct rpc_reply)) { 195638842f1Shikaru m = *mp = m_pullup(m, sizeof(struct rpc_reply)); 19634f6ce85Sdrochner if (m == NULL) 19734f6ce85Sdrochner return(-1); 19834f6ce85Sdrochner } 19934f6ce85Sdrochner reply = mtod(m, struct rpc_reply *); 20034f6ce85Sdrochner 20134f6ce85Sdrochner /* Is it the right reply? */ 20234f6ce85Sdrochner if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) 20334f6ce85Sdrochner return(-1); 20434f6ce85Sdrochner 20534f6ce85Sdrochner if (reply->rp_xid != txdr_unsigned(*(u_int32_t*)context)) 20634f6ce85Sdrochner return(-1); 20734f6ce85Sdrochner 20834f6ce85Sdrochner return(0); 20934f6ce85Sdrochner } 21034f6ce85Sdrochner 211a3b04214Sglass /* 212a3b04214Sglass * Do a remote procedure call (RPC) and wait for its reply. 21362f18b1dSgwr * If from_p is non-null, then we are doing broadcast, and 21462f18b1dSgwr * the address from whence the response came is saved there. 215a3b04214Sglass */ 216a3b04214Sglass int 21782357f6dSdsl krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, struct mbuf **data, struct mbuf **from_p, struct lwp *l) 21882357f6dSdsl /* data: input/output */ 21982357f6dSdsl /* from_p: output */ 220a3b04214Sglass { 221a3b04214Sglass struct socket *so; 222d458601fSrtr struct sockaddr_in sin; 223d458601fSrtr struct mbuf *m, *mhead, *from; 224a3b04214Sglass struct rpc_call *call; 225a3b04214Sglass struct rpc_reply *reply; 22634f6ce85Sdrochner int error, len; 227d73db495Sgwr static u_int32_t xid = ~0xFF; 2283e0efb4dScgd u_int16_t tport; 229a3b04214Sglass 230a3b04214Sglass /* 231a3b04214Sglass * Validate address family. 232a3b04214Sglass * Sorry, this is INET specific... 233a3b04214Sglass */ 23462f18b1dSgwr if (sa->sin_family != AF_INET) 235a3b04214Sglass return (EAFNOSUPPORT); 236a3b04214Sglass 237a3b04214Sglass /* Free at end if not null. */ 238d458601fSrtr mhead = NULL; 23962f18b1dSgwr from = NULL; 240a3b04214Sglass 241a3b04214Sglass /* 2420a600be8Swiz * Create socket and set its receive timeout. 243a3b04214Sglass */ 24415e29e98Sad if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, l, NULL))) 2458bf6e1b1Smaxv return error; 246a3b04214Sglass 24734f6ce85Sdrochner if ((error = nfs_boot_setrecvtimo(so))) 248a3b04214Sglass goto out; 24962f18b1dSgwr 25062f18b1dSgwr /* 25162f18b1dSgwr * Enable broadcast if necessary. 25262f18b1dSgwr */ 25362f18b1dSgwr if (from_p) { 25434f6ce85Sdrochner if ((error = nfs_boot_enbroadcast(so))) 25562f18b1dSgwr goto out; 25662f18b1dSgwr } 257a3b04214Sglass 258a3b04214Sglass /* 25938cca967Sgwr * Bind the local endpoint to a reserved port, 26038cca967Sgwr * because some NFS servers refuse requests from 26138cca967Sgwr * non-reserved (non-privileged) ports. 26238cca967Sgwr */ 26338cca967Sgwr tport = IPPORT_RESERVED; 26438cca967Sgwr do { 26538cca967Sgwr tport--; 26695e1ffb1Schristos error = nfs_boot_sobind_ipport(so, tport, l); 26738cca967Sgwr } while (error == EADDRINUSE && 26838cca967Sgwr tport > IPPORT_RESERVED / 2); 26938cca967Sgwr if (error) { 270bcf4552fSchristos printf("bind failed\n"); 27138cca967Sgwr goto out; 27238cca967Sgwr } 27338cca967Sgwr 27438cca967Sgwr /* 275a3b04214Sglass * Setup socket address for the server. 276a3b04214Sglass */ 277d458601fSrtr sin = *sa; 278a3b04214Sglass 279a3b04214Sglass /* 2800784b58dSgwr * Prepend RPC message header. 281a3b04214Sglass */ 282d73db495Sgwr mhead = m_gethdr(M_WAIT, MT_DATA); 283*c94bf7cbSmlelstv MCLAIM(mhead, &nfs_mowner); 284d73db495Sgwr mhead->m_next = *data; 285a3b04214Sglass call = mtod(mhead, struct rpc_call *); 286d73db495Sgwr mhead->m_len = sizeof(*call); 28753524e44Schristos memset((void *)call, 0, sizeof(*call)); 28819969f2fSgwr /* rpc_call part */ 28962f18b1dSgwr xid++; 290f6ff0fbaSmycroft call->rp_xid = txdr_unsigned(xid); 291a3b04214Sglass /* call->rp_direction = 0; */ 292f6ff0fbaSmycroft call->rp_rpcvers = txdr_unsigned(2); 293f6ff0fbaSmycroft call->rp_prog = txdr_unsigned(prog); 294f6ff0fbaSmycroft call->rp_vers = txdr_unsigned(vers); 295f6ff0fbaSmycroft call->rp_proc = txdr_unsigned(func); 29619969f2fSgwr /* rpc_auth part (auth_unix as root) */ 29719969f2fSgwr call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); 29819969f2fSgwr call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 29919969f2fSgwr /* rpc_verf part (auth_null) */ 30019969f2fSgwr call->rpc_verf.authtype = 0; 30119969f2fSgwr call->rpc_verf.authlen = 0; 302a3b04214Sglass 303a3b04214Sglass /* 304d73db495Sgwr * Setup packet header 305d73db495Sgwr */ 306d73db495Sgwr len = 0; 307d73db495Sgwr m = mhead; 308d73db495Sgwr while (m) { 309d73db495Sgwr len += m->m_len; 310d73db495Sgwr m = m->m_next; 311d73db495Sgwr } 312d73db495Sgwr mhead->m_pkthdr.len = len; 313d938d837Sozaki-r m_reset_rcvif(mhead); 314d73db495Sgwr 315d458601fSrtr error = nfs_boot_sendrecv(so, &sin, NULL, mhead, krpccheck, &m, &from, 31695e1ffb1Schristos &xid, l); 317a3b04214Sglass if (error) 318a3b04214Sglass goto out; 319a3b04214Sglass 32034f6ce85Sdrochner /* m_pullup() was done in krpccheck() */ 321a3b04214Sglass reply = mtod(m, struct rpc_reply *); 32262f18b1dSgwr 32362f18b1dSgwr /* Was RPC accepted? (authorization OK) */ 32462f18b1dSgwr if (reply->rp_astatus != 0) { 3252f81e6c9Sgwr /* Note: This is NOT an error code! */ 3262f81e6c9Sgwr error = fxdr_unsigned(u_int32_t, reply->rp_rstat); 3272f81e6c9Sgwr switch (error) { 3282f81e6c9Sgwr case RPC_MISMATCH: 3292f81e6c9Sgwr /* .re_status = RPC_VERSMISMATCH; */ 3302f81e6c9Sgwr error = ERPCMISMATCH; 3312f81e6c9Sgwr break; 3322f81e6c9Sgwr case RPC_AUTHERR: 3332f81e6c9Sgwr /* .re_status = RPC_AUTHERROR; */ 3342f81e6c9Sgwr error = EAUTH; 3352f81e6c9Sgwr break; 3362f81e6c9Sgwr default: 3372f81e6c9Sgwr /* unexpected */ 3382f81e6c9Sgwr error = EBADRPC; 3392f81e6c9Sgwr break; 3402f81e6c9Sgwr } 3412f81e6c9Sgwr goto out; 34262f18b1dSgwr } 34362f18b1dSgwr 34462f18b1dSgwr /* Did the call succeed? */ 34519969f2fSgwr if (reply->rp_status != 0) { 3462f81e6c9Sgwr /* Note: This is NOT an error code! */ 34719969f2fSgwr error = fxdr_unsigned(u_int32_t, reply->rp_status); 3482f81e6c9Sgwr switch (error) { 3492f81e6c9Sgwr case RPC_PROGUNAVAIL: 3502f81e6c9Sgwr error = EPROGUNAVAIL; 3512f81e6c9Sgwr break; 3522f81e6c9Sgwr case RPC_PROGMISMATCH: 3532f81e6c9Sgwr error = EPROGMISMATCH; 3542f81e6c9Sgwr break; 3552f81e6c9Sgwr case RPC_PROCUNAVAIL: 3562f81e6c9Sgwr error = EPROCUNAVAIL; 3572f81e6c9Sgwr break; 3582f81e6c9Sgwr case RPC_GARBAGE: 3592f81e6c9Sgwr default: 3602f81e6c9Sgwr error = EBADRPC; 36162f18b1dSgwr } 36240706984Spk goto out; 3632f81e6c9Sgwr } 364a3b04214Sglass 365a3b04214Sglass /* 3662f81e6c9Sgwr * OK, we have received a good reply! 36734f6ce85Sdrochner * Get its length, then strip it off. 3680784b58dSgwr */ 369d73db495Sgwr len = sizeof(*reply); 37019969f2fSgwr if (reply->rp_auth.authtype != 0) { 37119969f2fSgwr len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 372a3b04214Sglass len = (len + 3) & ~3; /* XXX? */ 373a3b04214Sglass } 374a3b04214Sglass m_adj(m, len); 3750784b58dSgwr 376a3b04214Sglass /* result */ 377a3b04214Sglass *data = m; 378b2bd5616Schristos if (from_p && error == 0) { 37962f18b1dSgwr *from_p = from; 38062f18b1dSgwr from = NULL; 38162f18b1dSgwr } 382a3b04214Sglass 383a3b04214Sglass out: 384481d3881Srin m_freem(mhead); 385481d3881Srin m_freem(from); 386a3b04214Sglass soclose(so); 387a3b04214Sglass return error; 388a3b04214Sglass } 389d73db495Sgwr 390d73db495Sgwr /* 391d73db495Sgwr * eXternal Data Representation routines. 392d73db495Sgwr * (but with non-standard args...) 393d73db495Sgwr */ 394d73db495Sgwr 395d73db495Sgwr /* 396d73db495Sgwr * String representation for RPC. 397d73db495Sgwr */ 398d73db495Sgwr struct xdr_string { 399d73db495Sgwr u_int32_t len; /* length without null or padding */ 400d73db495Sgwr char data[4]; /* data (longer, of course) */ 401d73db495Sgwr /* data is padded to a long-word boundary */ 402d73db495Sgwr }; 403d73db495Sgwr 404d73db495Sgwr struct mbuf * 405454af1c0Sdsl xdr_string_encode(char *str, int len) 406d73db495Sgwr { 407d73db495Sgwr struct mbuf *m; 408d73db495Sgwr struct xdr_string *xs; 409d73db495Sgwr int dlen; /* padded string length */ 410d73db495Sgwr int mlen; /* message length */ 411d73db495Sgwr 412d73db495Sgwr dlen = (len + 3) & ~3; 413d73db495Sgwr mlen = dlen + 4; 414d73db495Sgwr 415d9d0cc22Scgd if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 416d9d0cc22Scgd return (NULL); 417d9d0cc22Scgd 418d73db495Sgwr m = m_get(M_WAIT, MT_DATA); 419d73db495Sgwr if (mlen > MLEN) { 42065e5548aSmatt m_clget(m, M_WAIT); 421d9d0cc22Scgd if ((m->m_flags & M_EXT) == 0) { 422d9d0cc22Scgd (void) m_free(m); /* There can be only one. */ 423d9d0cc22Scgd return (NULL); 424d9d0cc22Scgd } 425d73db495Sgwr } 426d73db495Sgwr xs = mtod(m, struct xdr_string *); 427d73db495Sgwr m->m_len = mlen; 428f6ff0fbaSmycroft xs->len = txdr_unsigned(len); 4294522c799Sperry memcpy(xs->data, str, len); 430d73db495Sgwr return (m); 431d73db495Sgwr } 432d73db495Sgwr 433d73db495Sgwr struct mbuf * 43482357f6dSdsl xdr_string_decode(struct mbuf *m, char *str, int *len_p) 43582357f6dSdsl /* len_p: bufsize - 1 */ 436d73db495Sgwr { 437d73db495Sgwr struct xdr_string *xs; 438d73db495Sgwr int mlen; /* message length */ 439d73db495Sgwr int slen; /* string length */ 440d73db495Sgwr 441d73db495Sgwr if (m->m_len < 4) { 442d73db495Sgwr m = m_pullup(m, 4); 443d73db495Sgwr if (m == NULL) 444d73db495Sgwr return (NULL); 445d73db495Sgwr } 446d73db495Sgwr xs = mtod(m, struct xdr_string *); 447f6ff0fbaSmycroft slen = fxdr_unsigned(u_int32_t, xs->len); 448d73db495Sgwr mlen = 4 + ((slen + 3) & ~3); 449d73db495Sgwr 450d73db495Sgwr if (slen > *len_p) 451d73db495Sgwr slen = *len_p; 452d73db495Sgwr m_copydata(m, 4, slen, str); 453d73db495Sgwr m_adj(m, mlen); 454d73db495Sgwr 455d73db495Sgwr str[slen] = '\0'; 456d73db495Sgwr *len_p = slen; 457d73db495Sgwr 458d73db495Sgwr return (m); 459d73db495Sgwr } 460d73db495Sgwr 461d73db495Sgwr 462d73db495Sgwr /* 463d73db495Sgwr * Inet address in RPC messages 464d73db495Sgwr * (Note, really four ints, NOT chars. Blech.) 465d73db495Sgwr */ 466d73db495Sgwr struct xdr_inaddr { 467d73db495Sgwr u_int32_t atype; 468f6ff0fbaSmycroft u_int32_t addr[4]; 469d73db495Sgwr }; 470d73db495Sgwr 471d73db495Sgwr struct mbuf * 47282357f6dSdsl xdr_inaddr_encode(struct in_addr *ia) 47382357f6dSdsl /* ia: already in network order */ 474d73db495Sgwr { 475d73db495Sgwr struct mbuf *m; 476d73db495Sgwr struct xdr_inaddr *xi; 477f6ff0fbaSmycroft u_int8_t *cp; 478f6ff0fbaSmycroft u_int32_t *ip; 479d73db495Sgwr 480d73db495Sgwr m = m_get(M_WAIT, MT_DATA); 481d73db495Sgwr xi = mtod(m, struct xdr_inaddr *); 482d73db495Sgwr m->m_len = sizeof(*xi); 483f6ff0fbaSmycroft xi->atype = txdr_unsigned(1); 484d73db495Sgwr ip = xi->addr; 485f6ff0fbaSmycroft cp = (u_int8_t *)&ia->s_addr; 486f6ff0fbaSmycroft *ip++ = txdr_unsigned(*cp++); 487f6ff0fbaSmycroft *ip++ = txdr_unsigned(*cp++); 488f6ff0fbaSmycroft *ip++ = txdr_unsigned(*cp++); 489f6ff0fbaSmycroft *ip++ = txdr_unsigned(*cp++); 490d73db495Sgwr 491d73db495Sgwr return (m); 492d73db495Sgwr } 493d73db495Sgwr 494d73db495Sgwr struct mbuf * 49582357f6dSdsl xdr_inaddr_decode(struct mbuf *m, struct in_addr *ia) 49682357f6dSdsl /* ia: already in network order */ 497d73db495Sgwr { 498d73db495Sgwr struct xdr_inaddr *xi; 499f6ff0fbaSmycroft u_int8_t *cp; 500f6ff0fbaSmycroft u_int32_t *ip; 501d73db495Sgwr 502d73db495Sgwr if (m->m_len < sizeof(*xi)) { 503d73db495Sgwr m = m_pullup(m, sizeof(*xi)); 504d73db495Sgwr if (m == NULL) 505d73db495Sgwr return (NULL); 506d73db495Sgwr } 507d73db495Sgwr xi = mtod(m, struct xdr_inaddr *); 508f6ff0fbaSmycroft if (xi->atype != txdr_unsigned(1)) { 509d73db495Sgwr ia->s_addr = INADDR_ANY; 510d73db495Sgwr goto out; 511d73db495Sgwr } 512d73db495Sgwr ip = xi->addr; 513f6ff0fbaSmycroft cp = (u_int8_t *)&ia->s_addr; 514f6ff0fbaSmycroft *cp++ = fxdr_unsigned(u_int8_t, *ip++); 515f6ff0fbaSmycroft *cp++ = fxdr_unsigned(u_int8_t, *ip++); 516f6ff0fbaSmycroft *cp++ = fxdr_unsigned(u_int8_t, *ip++); 517f6ff0fbaSmycroft *cp++ = fxdr_unsigned(u_int8_t, *ip++); 518d73db495Sgwr 519d73db495Sgwr out: 520d73db495Sgwr m_adj(m, sizeof(*xi)); 521d73db495Sgwr return (m); 522d73db495Sgwr } 523