1139749Simp/* $OpenBSD: krpc_subr.c,v 1.39 2024/05/01 13:15:59 jsg Exp $ */ 2123474Swpaul/* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ 3123474Swpaul 4123474Swpaul/* 5123474Swpaul * Copyright (c) 1995 Gordon Ross, Adam Glass 6123474Swpaul * Copyright (c) 1992 Regents of the University of California. 7123474Swpaul * All rights reserved. 8123474Swpaul * 9123474Swpaul * This software was developed by the Computer Systems Engineering group 10123474Swpaul * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11123474Swpaul * contributed to Berkeley. 12123474Swpaul * 13123474Swpaul * Redistribution and use in source and binary forms, with or without 14123474Swpaul * modification, are permitted provided that the following conditions 15123474Swpaul * are met: 16123474Swpaul * 1. Redistributions of source code must retain the above copyright 17123474Swpaul * notice, this list of conditions and the following disclaimer. 18123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 19123474Swpaul * notice, this list of conditions and the following disclaimer in the 20123474Swpaul * documentation and/or other materials provided with the distribution. 21123474Swpaul * 3. All advertising materials mentioning features or use of this software 22123474Swpaul * must display the following acknowledgement: 23123474Swpaul * This product includes software developed by the University of 24123474Swpaul * California, Lawrence Berkeley Laboratory and its contributors. 25123474Swpaul * 4. Neither the name of the University nor the names of its contributors 26123474Swpaul * may be used to endorse or promote products derived from this software 27123474Swpaul * without specific prior written permission. 28123474Swpaul * 29123474Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31145283Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32151207Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33151207Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34123474Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35123474Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36123474Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37123474Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38123474Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39123474Swpaul * SUCH DAMAGE. 40123474Swpaul * 41123474Swpaul * partially based on: 42123474Swpaul * libnetboot/rpc.c 43123474Swpaul * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 44171390Sthompsa */ 45164033Srwatson 46123474Swpaul#include <sys/param.h> 47123474Swpaul#include <sys/systm.h> 48123474Swpaul#include <sys/proc.h> 49141524Swpaul#include <sys/mbuf.h> 50143204Swpaul#include <sys/socket.h> 51123474Swpaul#include <sys/socketvar.h> 52171390Sthompsa 53123474Swpaul#include <netinet/in.h> 54123474Swpaul 55123474Swpaul#include <nfs/rpcv2.h> 56123474Swpaul#include <nfs/krpc.h> 57123474Swpaul#include <nfs/xdr_subs.h> 58123474Swpaul#include <crypto/idgen.h> 59147256Sbrooks 60129002Sandre/* 61123474Swpaul * Kernel support for Sun RPC 62123474Swpaul * 63123474Swpaul * Used currently for bootstrapping in nfs diskless configurations. 64123474Swpaul */ 65123474Swpaul 66123474Swpaul/* 67123474Swpaul * Generic RPC headers 68123474Swpaul */ 69123695Swpaul 70123695Swpaulstruct auth_info { 71171390Sthompsa u_int32_t authtype; /* auth type */ 72123695Swpaul u_int32_t authlen; /* auth length */ 73123474Swpaul}; 74123474Swpaul 75189488Sweongyostruct auth_unix { 76194677Sthompsa int32_t ua_time; 77123474Swpaul int32_t ua_hostname; /* null */ 78123474Swpaul int32_t ua_uid; 79145485Swpaul int32_t ua_gid; 80123474Swpaul int32_t ua_gidlist; /* null */ 81132953Swpaul}; 82128229Swpaul 83123474Swpaulstruct rpc_call { 84186507Sweongyo u_int32_t rp_xid; /* request transaction id */ 85123474Swpaul int32_t rp_direction; /* call direction (0) */ 86123474Swpaul u_int32_t rp_rpcvers; /* rpc version (2) */ 87171602Sthompsa u_int32_t rp_prog; /* program */ 88171390Sthompsa u_int32_t rp_vers; /* version */ 89171602Sthompsa u_int32_t rp_proc; /* procedure */ 90171602Sthompsa struct auth_info rpc_auth; 91171602Sthompsa struct auth_unix rpc_unix; 92171602Sthompsa struct auth_info rpc_verf; 93171390Sthompsa}; 94171390Sthompsa 95171390Sthompsastruct rpc_reply { 96171390Sthompsa u_int32_t rp_xid; /* request transaction id */ 97186507Sweongyo int32_t rp_direction; /* call direction (1) */ 98186507Sweongyo int32_t rp_astatus; /* accept status (0: accepted) */ 99186507Sweongyo union { 100186507Sweongyo u_int32_t rpu_errno; 101186507Sweongyo struct { 102187104Sthompsa struct auth_info rok_auth; 103189550Ssam u_int32_t rok_status; 104187104Sthompsa } rpu_rok; 105187104Sthompsa } rp_u; 106187104Sthompsa}; 107187104Sthompsa#define rp_errno rp_u.rpu_errno 108187104Sthompsa#define rp_auth rp_u.rpu_rok.rok_auth 109187104Sthompsa#define rp_status rp_u.rpu_rok.rok_status 110187104Sthompsa 111187104Sthompsa#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 112187104Sthompsa 113145485Swpaulu_int32_t krpc_get_xid(void); 114145485Swpaul 115145485Swpaul/* 116126706Swpaul * Return an unpredictable XID. 117145485Swpaul */ 118123474Swpaulu_int32_t 119126706Swpaulkrpc_get_xid(void) 120126706Swpaul{ 121126706Swpaul static struct idgen32_ctx krpc_xid_ctx; 122126706Swpaul static int called = 0; 123126706Swpaul 124123474Swpaul if (!called) { 125141524Swpaul called = 1; 126141524Swpaul idgen32_init(&krpc_xid_ctx); 127144888Swpaul } 128144888Swpaul return idgen32(&krpc_xid_ctx); 129146230Swpaul} 130146230Swpaul 131146230Swpaul/* 132146230Swpaul * What is the longest we will wait before re-sending a request? 133146230Swpaul * Note this is also the frequency of "RPC timeout" messages. 134146230Swpaul * The re-send loop count sup linearly to this maximum, so the 135144888Swpaul * first complaint will happen after (1+2+3+4+5)=15 seconds. 136144888Swpaul */ 137123695Swpaul#define MAX_RESEND_DELAY 5 /* seconds */ 138141963Swpaul 139141963Swpaul/* 140141963Swpaul * Call portmap to lookup a port number for a particular rpc program 141146230Swpaul * Returns non-zero error on failure. 142146230Swpaul */ 143146230Swpaulint 144146230Swpaulkrpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp) 145141963Swpaul{ 146141963Swpaul struct sdata { 147145895Swpaul u_int32_t prog; /* call program */ 148145895Swpaul u_int32_t vers; /* call version */ 149145895Swpaul u_int32_t proto; /* call protocol */ 150151451Swpaul u_int32_t port; /* call port (unused) */ 151141963Swpaul } *sdata; 152178354Ssam struct rdata { 153228621Sbschmidt u_int16_t pad; 154228621Sbschmidt u_int16_t port; 155228621Sbschmidt } *rdata; 156178354Ssam struct mbuf *m; 157123474Swpaul int error; 158151207Swpaul 159178354Ssam /* The portmapper port is fixed. */ 160178354Ssam if (prog == PMAPPROG) { 161185485Ssam *portp = htons(PMAPPORT); 162185485Ssam return 0; 163123474Swpaul } 164151207Swpaul 165151207Swpaul m = m_get(M_WAIT, MT_DATA); 166151451Swpaul sdata = mtod(m, struct sdata *); 167123474Swpaul m->m_len = sizeof(*sdata); 168178704Sthompsa 169178354Ssam /* Do the RPC to get it. */ 170171390Sthompsa sdata->prog = txdr_unsigned(prog); 171171602Sthompsa sdata->vers = txdr_unsigned(vers); 172171602Sthompsa sdata->proto = txdr_unsigned(IPPROTO_UDP); 173191746Sthompsa sdata->port = 0; 174171390Sthompsa 175171390Sthompsa sin->sin_port = htons(PMAPPORT); 176171390Sthompsa error = krpc_call(sin, PMAPPROG, PMAPVERS, 177171390Sthompsa PMAPPROC_GETPORT, &m, NULL, -1); 178178354Ssam if (error) 179178354Ssam return error; 180123474Swpaul 181123474Swpaul if (m->m_len < sizeof(*rdata)) { 182123474Swpaul m = m_pullup(m, sizeof(*rdata)); 183123474Swpaul if (m == NULL) 184194706Scokane return ENOBUFS; 185194706Scokane } 186127349Swpaul rdata = mtod(m, struct rdata *); 187124821Swpaul *portp = rdata->port; 188124821Swpaul 189123695Swpaul m_freem(m); 190123695Swpaul return 0; 191178929Sthompsa} 192201620Srpaulo 193151207Swpaul/* 194178354Ssam * Do a remote procedure call (RPC) and wait for its reply. 195178354Ssam * If from_p is non-null, then we are doing broadcast, and 196151207Swpaul * the address from whence the response came is saved there. 197178354Ssam * data: input/output 198151207Swpaul * from_p: output 199123474Swpaul */ 200123474Swpaulint 201123474Swpaulkrpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, 202123474Swpaul struct mbuf **data, struct mbuf **from_p, int retries) 203123474Swpaul{ 204141524Swpaul struct socket *so; 205123474Swpaul struct sockaddr_in *sin; 206123474Swpaul struct mbuf *m, *nam, *mhead, *from, *mopt; 207141524Swpaul struct rpc_call *call; 208141524Swpaul struct rpc_reply *reply; 209141524Swpaul struct uio auio; 210141524Swpaul int error, rcvflg, timo, secs, len, authlen; 211141524Swpaul static u_int32_t xid = 0; 212141524Swpaul char addr[INET_ADDRSTRLEN]; 213141524Swpaul int *ip; 214141524Swpaul struct timeval tv; 215141524Swpaul 216141524Swpaul /* 217141524Swpaul * Validate address family. 218141524Swpaul * Sorry, this is INET specific... 219141524Swpaul */ 220141524Swpaul if (sa->sin_family != AF_INET) 221141524Swpaul return (EAFNOSUPPORT); 222141524Swpaul 223141524Swpaul /* Free at end if not null. */ 224141524Swpaul nam = mhead = NULL; 225144888Swpaul from = NULL; 226144888Swpaul 227146230Swpaul /* 228146230Swpaul * Create socket and set its receive timeout. 229146230Swpaul */ 230146230Swpaul if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0))) 231146230Swpaul goto out; 232146230Swpaul 233146230Swpaul m = m_get(M_WAIT, MT_SOOPTS); 234146230Swpaul tv.tv_sec = 1; 235144888Swpaul tv.tv_usec = 0; 236144888Swpaul memcpy(mtod(m, struct timeval *), &tv, sizeof tv); 237144888Swpaul m->m_len = sizeof(tv); 238144888Swpaul error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m); 239141963Swpaul m_freem(m); 240144888Swpaul if (error) 241145895Swpaul goto out; 242145895Swpaul 243145895Swpaul /* 244145895Swpaul * Enable broadcast if necessary. 245145895Swpaul */ 246145895Swpaul if (from_p) { 247151451Swpaul int32_t *on; 248151451Swpaul m = m_get(M_WAIT, MT_SOOPTS); 249141524Swpaul on = mtod(m, int32_t *); 250141524Swpaul m->m_len = sizeof(*on); 251141524Swpaul *on = 1; 252141524Swpaul error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m); 253141524Swpaul m_freem(m); 254145895Swpaul if (error) 255141524Swpaul goto out; 256141963Swpaul } 257146230Swpaul 258146230Swpaul /* 259146230Swpaul * Bind the local endpoint to a reserved port, 260146230Swpaul * because some NFS servers refuse requests from 261141963Swpaul * non-reserved (non-privileged) ports. 262141963Swpaul */ 263141963Swpaul MGET(mopt, M_WAIT, MT_SOOPTS); 264145895Swpaul mopt->m_len = sizeof(int); 265145895Swpaul ip = mtod(mopt, int *); 266145895Swpaul *ip = IP_PORTRANGE_LOW; 267151451Swpaul error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); 268141524Swpaul m_freem(mopt); 269141524Swpaul if (error) 270141524Swpaul goto out; 271141524Swpaul 272141524Swpaul MGET(m, M_WAIT, MT_SONAME); 273141524Swpaul sin = mtod(m, struct sockaddr_in *); 274141524Swpaul memset(sin, 0, sizeof(*sin)); 275141524Swpaul sin->sin_len = m->m_len = sizeof(struct sockaddr_in); 276141524Swpaul sin->sin_family = AF_INET; 277141524Swpaul sin->sin_addr.s_addr = INADDR_ANY; 278123474Swpaul sin->sin_port = htons(0); 279123474Swpaul solock(so); 280123474Swpaul error = sobind(so, m, &proc0); 281123474Swpaul sounlock(so); 282123474Swpaul m_freem(m); 283123474Swpaul if (error) { 284124709Swpaul printf("bind failed\n"); 285124709Swpaul goto out; 286124709Swpaul } 287124709Swpaul 288124709Swpaul MGET(mopt, M_WAIT, MT_SOOPTS); 289147256Sbrooks mopt->m_len = sizeof(int); 290124709Swpaul ip = mtod(mopt, int *); 291131750Swpaul *ip = IP_PORTRANGE_DEFAULT; 292124709Swpaul error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); 293124709Swpaul m_freem(mopt); 294124709Swpaul if (error) 295124709Swpaul goto out; 296124709Swpaul 297124709Swpaul /* 298124709Swpaul * Setup socket address for the server. 299124709Swpaul */ 300198786Srpaulo nam = m_get(M_WAIT, MT_SONAME); 301151207Swpaul sin = mtod(nam, struct sockaddr_in *); 302124709Swpaul bcopy(sa, sin, (nam->m_len = sa->sin_len)); 303124709Swpaul 304124709Swpaul /* 305127552Swpaul * Prepend RPC message header. 306127552Swpaul */ 307124709Swpaul mhead = m_gethdr(M_WAIT, MT_DATA); 308124709Swpaul mhead->m_next = *data; 309124709Swpaul call = mtod(mhead, struct rpc_call *); 310124709Swpaul mhead->m_len = sizeof(*call); 311125061Swpaul memset(call, 0, sizeof(*call)); 312124709Swpaul /* rpc_call part */ 313124709Swpaul xid = krpc_get_xid(); 314124709Swpaul call->rp_xid = txdr_unsigned(xid); 315124709Swpaul /* call->rp_direction = 0; */ 316124709Swpaul call->rp_rpcvers = txdr_unsigned(2); 317124709Swpaul call->rp_prog = txdr_unsigned(prog); 318124709Swpaul call->rp_vers = txdr_unsigned(vers); 319124709Swpaul call->rp_proc = txdr_unsigned(func); 320124709Swpaul /* rpc_auth part (auth_unix as root) */ 321195049Srwatson call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); 322124709Swpaul call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); 323124709Swpaul /* rpc_verf part (auth_null) */ 324124709Swpaul call->rpc_verf.authtype = 0; 325124709Swpaul call->rpc_verf.authlen = 0; 326124709Swpaul 327124709Swpaul /* 328124709Swpaul * Setup packet header 329195049Srwatson */ 330124709Swpaul m_calchdrlen(mhead); 331124709Swpaul mhead->m_pkthdr.ph_ifidx = 0; 332124709Swpaul 333124709Swpaul /* 334124709Swpaul * Send it, repeatedly, until a reply is received, 335195049Srwatson * but delay each re-send by an increasing amount. 336124709Swpaul * If the delay hits the maximum, start complaining. 337124709Swpaul */ 338124709Swpaul for (timo = 0; retries; retries--) { 339124709Swpaul /* Send RPC request (or re-send). */ 340198786Srpaulo m = m_copym(mhead, 0, M_COPYALL, M_WAIT); 341124709Swpaul if (m == NULL) { 342124709Swpaul error = ENOBUFS; 343124709Swpaul goto out; 344124709Swpaul } 345124709Swpaul error = sosend(so, nam, NULL, m, NULL, 0); 346124709Swpaul if (error) { 347124709Swpaul printf("krpc_call: sosend: %d\n", error); 348124709Swpaul goto out; 349124709Swpaul } 350124709Swpaul m = NULL; 351124709Swpaul 352198786Srpaulo /* Determine new timeout. */ 353123474Swpaul if (timo < MAX_RESEND_DELAY) 354123474Swpaul timo++; 355123474Swpaul else 356124821Swpaul printf("RPC timeout for server %s (0x%x) prog %u\n", 357124821Swpaul inet_ntop(AF_INET, &sin->sin_addr, 358124821Swpaul addr, sizeof(addr)), 359124821Swpaul ntohl(sin->sin_addr.s_addr), prog); 360124821Swpaul 361124821Swpaul /* 362124821Swpaul * Wait for up to timo seconds for a reply. 363124821Swpaul * The socket receive timeout was set to 1 second. 364124821Swpaul */ 365147256Sbrooks secs = timo; 366124821Swpaul while (secs > 0) { 367131750Swpaul m_freem(from); 368198786Srpaulo from = NULL; 369124821Swpaul 370124821Swpaul m_freem(m); 371124821Swpaul m = NULL; 372124821Swpaul 373124821Swpaul auio.uio_resid = len = 1<<16; 374198786Srpaulo auio.uio_procp = NULL; 375124821Swpaul rcvflg = 0; 376124821Swpaul error = soreceive(so, &from, &auio, &m, NULL, &rcvflg, 377198786Srpaulo 0); 378124821Swpaul if (error == EWOULDBLOCK) { 379124821Swpaul secs--; 380124821Swpaul continue; 381124821Swpaul } 382124821Swpaul if (error) 383124821Swpaul goto out; 384124821Swpaul len -= auio.uio_resid; 385198786Srpaulo 386124821Swpaul /* Does the reply contain at least a header? */ 387124821Swpaul if (len < MIN_REPLY_HDR) 388124821Swpaul continue; 389124821Swpaul if (m->m_len < MIN_REPLY_HDR) 390124821Swpaul continue; 391124821Swpaul reply = mtod(m, struct rpc_reply *); 392124821Swpaul 393124821Swpaul /* Is it the right reply? */ 394124821Swpaul if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) 395124821Swpaul continue; 396124821Swpaul 397124821Swpaul if (reply->rp_xid != txdr_unsigned(xid)) 398124821Swpaul continue; 399124821Swpaul 400124821Swpaul /* Was RPC accepted? (authorization OK) */ 401124821Swpaul if (reply->rp_astatus != 0) { 402124821Swpaul error = fxdr_unsigned(u_int32_t, reply->rp_errno); 403124821Swpaul printf("rpc denied, error=%d\n", error); 404124821Swpaul continue; 405124821Swpaul } 406124821Swpaul 407124821Swpaul /* Did the call succeed? */ 408124821Swpaul if (reply->rp_status != 0) { 409124821Swpaul error = fxdr_unsigned(u_int32_t, reply->rp_status); 410124821Swpaul printf("rpc denied, status=%d\n", error); 411124821Swpaul continue; 412124821Swpaul } 413124821Swpaul 414198786Srpaulo goto gotreply; /* break two levels */ 415124821Swpaul 416124821Swpaul } /* while secs */ 417124821Swpaul } /* forever send/receive */ 418124821Swpaul 419124821Swpaul error = ETIMEDOUT; 420124821Swpaul goto out; 421124821Swpaul 422124821Swpaul gotreply: 423124821Swpaul 424124821Swpaul /* 425124821Swpaul * Get RPC reply header into first mbuf, 426124821Swpaul * get its length, then strip it off. 427147256Sbrooks */ 428124821Swpaul len = sizeof(*reply); 429124821Swpaul KASSERT(m->m_flags & M_PKTHDR); 430124821Swpaul if (m->m_pkthdr.len < len) { 431124821Swpaul error = EBADRPC; 432124821Swpaul goto out; 433198786Srpaulo } 434124821Swpaul if (m->m_len < len) { 435124821Swpaul m = m_pullup(m, len); 436124821Swpaul if (m == NULL) { 437124821Swpaul error = ENOBUFS; 438198786Srpaulo goto out; 439124821Swpaul } 440124821Swpaul } 441124821Swpaul reply = mtod(m, struct rpc_reply *); 442124821Swpaul if (reply->rp_auth.authtype != 0) { 443124821Swpaul authlen = fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); 444124821Swpaul if (authlen < 0 || authlen > RPCAUTH_MAXSIZ) { 445124821Swpaul error = EBADRPC; 446124821Swpaul goto out; 447124821Swpaul } 448124821Swpaul len += (authlen + 3) & ~3; /* XXX? */ 449124821Swpaul } 450198786Srpaulo if (len < 0 || m->m_pkthdr.len < len) { 451124821Swpaul error = EBADRPC; 452124821Swpaul goto out; 453124821Swpaul } 454124821Swpaul m_adj(m, len); 455198786Srpaulo 456124821Swpaul /* result */ 457124821Swpaul *data = m; 458124821Swpaul if (from_p && error == 0) { 459124821Swpaul *from_p = from; 460124821Swpaul from = NULL; 461124821Swpaul } 462124821Swpaul 463124821Swpaul out: 464124821Swpaul m_freem(nam); 465124821Swpaul m_freem(mhead); 466124821Swpaul m_freem(from); 467124821Swpaul soclose(so, 0); 468124821Swpaul return error; 469124821Swpaul} 470124821Swpaul 471124821Swpaul/* 472124821Swpaul * eXternal Data Representation routines. 473124821Swpaul * (but with non-standard args...) 474124821Swpaul */ 475124821Swpaul 476124821Swpaul/* 477124821Swpaul * String representation for RPC. 478124821Swpaul */ 479124821Swpaulstruct xdr_string { 480198786Srpaulo u_int32_t len; /* length without null or padding */ 481124821Swpaul char data[4]; /* data (longer, of course) */ 482124821Swpaul /* data is padded to a long-word boundary */ 483124821Swpaul}; 484124821Swpaul 485124821Swpaulstruct mbuf * 486124821Swpaulxdr_string_encode(char *str, int len) 487124821Swpaul{ 488124821Swpaul struct mbuf *m; 489124821Swpaul struct xdr_string *xs; 490124821Swpaul int dlen; /* padded string length */ 491124821Swpaul int mlen; /* message length */ 492124821Swpaul 493124821Swpaul dlen = (len + 3) & ~3; 494124821Swpaul mlen = dlen + 4; 495124821Swpaul 496124821Swpaul if (mlen > MCLBYTES) /* If too big, we just can't do it. */ 497124821Swpaul return (NULL); 498124821Swpaul 499124821Swpaul m = m_get(M_WAIT, MT_DATA); 500124821Swpaul if (mlen > MLEN) { 501124821Swpaul MCLGET(m, M_WAIT); 502124821Swpaul if ((m->m_flags & M_EXT) == 0) { 503124821Swpaul (void) m_free(m); /* There can be only one. */ 504198786Srpaulo return (NULL); 505124821Swpaul } 506124821Swpaul } 507171602Sthompsa xs = mtod(m, struct xdr_string *); 508171602Sthompsa m->m_len = mlen; 509171602Sthompsa xs->len = txdr_unsigned(len); 510171602Sthompsa bcopy(str, xs->data, len); 511171602Sthompsa return (m); 512171602Sthompsa} 513171602Sthompsa 514171602Sthompsastruct mbuf * 515171602Sthompsaxdr_string_decode(struct mbuf *m, char *str, int *len_p) 516171602Sthompsa{ 517171602Sthompsa struct xdr_string *xs; 518171602Sthompsa int mlen; /* message length */ 519171602Sthompsa int slen; /* string length */ 520171602Sthompsa 521171602Sthompsa mlen = sizeof(u_int32_t); 522171602Sthompsa KASSERT(m->m_flags & M_PKTHDR); 523171602Sthompsa if (m->m_pkthdr.len < mlen) { 524171602Sthompsa m_freem(m); 525171602Sthompsa return (NULL); 526171602Sthompsa } 527171602Sthompsa if (m->m_len < mlen) { 528171602Sthompsa m = m_pullup(m, mlen); 529171602Sthompsa if (m == NULL) 530171602Sthompsa return (NULL); 531171602Sthompsa } 532171602Sthompsa xs = mtod(m, struct xdr_string *); 533123474Swpaul slen = fxdr_unsigned(u_int32_t, xs->len); 534123474Swpaul if (slen < 0 || slen > INT_MAX - 3 - mlen) { 535123474Swpaul m_freem(m); 536123474Swpaul return (NULL); 537126706Swpaul } 538123474Swpaul mlen += (slen + 3) & ~3; 539123474Swpaul 540123474Swpaul if (slen > *len_p) 541123474Swpaul slen = *len_p; 542126706Swpaul if (m->m_pkthdr.len < mlen) { 543142399Swpaul m_freem(m); 544141524Swpaul return (NULL); 545124100Swpaul } 546178354Ssam m_copydata(m, 4, slen, str); 547178354Ssam m_adj(m, mlen); 548171390Sthompsa 549123474Swpaul str[slen] = '\0'; 550123474Swpaul *len_p = slen; 551123474Swpaul 552179723Scokane return (m); 553179723Scokane} 554151451Swpaul 555189719Sweongyo 556189488Sweongyo/* 557151207Swpaul * Inet address in RPC messages 558189719Sweongyo * (Note, really four ints, NOT chars. Blech.) 559189488Sweongyo */ 560179498Scokanestruct xdr_inaddr { 561123474Swpaul u_int32_t atype; 562132953Swpaul u_int32_t addr[4]; 563132953Swpaul}; 564132953Swpaul 565132953Swpaulstruct mbuf * 566132953Swpaulxdr_inaddr_encode(struct in_addr *ia) 567132953Swpaul{ 568132953Swpaul struct mbuf *m; 569132953Swpaul struct xdr_inaddr *xi; 570132953Swpaul u_int8_t *cp; 571123474Swpaul u_int32_t *ip; 572123474Swpaul 573123474Swpaul m = m_get(M_WAIT, MT_DATA); 574142399Swpaul xi = mtod(m, struct xdr_inaddr *); 575142399Swpaul m->m_len = sizeof(*xi); 576142399Swpaul xi->atype = txdr_unsigned(1); 577142804Swpaul ip = xi->addr; 578142399Swpaul cp = (u_int8_t *)&ia->s_addr; 579142804Swpaul *ip++ = txdr_unsigned(*cp++); 580142399Swpaul *ip++ = txdr_unsigned(*cp++); 581142804Swpaul *ip++ = txdr_unsigned(*cp++); 582142399Swpaul *ip++ = txdr_unsigned(*cp++); 583142399Swpaul 584141524Swpaul return (m); 585141524Swpaul} 586141524Swpaul 587141524Swpaulstruct mbuf * 588141524Swpaulxdr_inaddr_decode(struct mbuf *m, struct in_addr *ia) 589141524Swpaul{ 590145485Swpaul struct xdr_inaddr *xi; 591141524Swpaul u_int8_t *cp; 592141524Swpaul u_int32_t *ip; 593141524Swpaul 594141524Swpaul if (m->m_len < sizeof(*xi)) { 595123474Swpaul m = m_pullup(m, sizeof(*xi)); 596124116Swpaul if (m == NULL) 597124116Swpaul return (NULL); 598141524Swpaul } 599141524Swpaul xi = mtod(m, struct xdr_inaddr *); 600124116Swpaul if (xi->atype != txdr_unsigned(1)) { 601123474Swpaul ia->s_addr = INADDR_ANY; 602142399Swpaul goto out; 603142399Swpaul } 604142408Swpaul ip = xi->addr; 605142408Swpaul cp = (u_int8_t *)&ia->s_addr; 606123474Swpaul *cp++ = fxdr_unsigned(u_int8_t, *ip++); 607123474Swpaul *cp++ = fxdr_unsigned(u_int8_t, *ip++); 608141963Swpaul *cp++ = fxdr_unsigned(u_int8_t, *ip++); 609141963Swpaul *cp++ = fxdr_unsigned(u_int8_t, *ip++); 610146230Swpaul 611146230Swpaulout: 612146230Swpaul m_adj(m, sizeof(*xi)); 613123474Swpaul return (m); 614155311Swpaul} 615155311Swpaul