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