krpc_subr.c revision 1.6 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.6 pgoyette __RCSID("$NetBSD: krpc_subr.c,v 1.6 2016/11/18 22:37:50 pgoyette 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.1 dholland if (m) {
342 1.1 dholland m_freem(m);
343 1.1 dholland m = NULL;
344 1.1 dholland }
345 1.1 dholland bzero(&auio, sizeof(auio));
346 1.1 dholland auio.uio_resid = len = 1<<16;
347 1.1 dholland rcvflg = 0;
348 1.1 dholland error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
349 1.1 dholland if (error == EWOULDBLOCK) {
350 1.1 dholland secs--;
351 1.1 dholland continue;
352 1.1 dholland }
353 1.1 dholland if (error)
354 1.1 dholland goto out;
355 1.1 dholland len -= auio.uio_resid;
356 1.1 dholland
357 1.1 dholland /* Does the reply contain at least a header? */
358 1.1 dholland if (len < MIN_REPLY_HDR)
359 1.1 dholland continue;
360 1.1 dholland if (m->m_len < MIN_REPLY_HDR)
361 1.1 dholland continue;
362 1.1 dholland reply = mtod(m, struct krpc_reply *);
363 1.1 dholland
364 1.1 dholland /* Is it the right reply? */
365 1.1 dholland if (reply->rp_direction != txdr_unsigned(REPLY))
366 1.1 dholland continue;
367 1.1 dholland
368 1.1 dholland if (reply->rp_xid != txdr_unsigned(xid))
369 1.1 dholland continue;
370 1.1 dholland
371 1.1 dholland /* Was RPC accepted? (authorization OK) */
372 1.1 dholland if (reply->rp_astatus != 0) {
373 1.1 dholland error = fxdr_unsigned(u_int32_t, reply->rp_errno);
374 1.1 dholland printf("rpc denied, error=%d\n", error);
375 1.1 dholland continue;
376 1.1 dholland }
377 1.1 dholland
378 1.1 dholland /* Did the call succeed? */
379 1.1 dholland if (reply->rp_status != 0) {
380 1.1 dholland error = fxdr_unsigned(u_int32_t, reply->rp_status);
381 1.1 dholland if (error == PROG_MISMATCH) {
382 1.1 dholland error = EBADRPC;
383 1.1 dholland goto out;
384 1.1 dholland }
385 1.1 dholland printf("rpc denied, status=%d\n", error);
386 1.1 dholland continue;
387 1.1 dholland }
388 1.1 dholland
389 1.1 dholland goto gotreply; /* break two levels */
390 1.1 dholland
391 1.1 dholland } /* while secs */
392 1.1 dholland } /* forever send/receive */
393 1.1 dholland
394 1.1 dholland error = ETIMEDOUT;
395 1.1 dholland goto out;
396 1.1 dholland
397 1.1 dholland gotreply:
398 1.1 dholland
399 1.1 dholland /*
400 1.1 dholland * Get RPC reply header into first mbuf,
401 1.1 dholland * get its length, then strip it off.
402 1.1 dholland */
403 1.1 dholland len = sizeof(*reply);
404 1.1 dholland if (m->m_len < len) {
405 1.1 dholland m = m_pullup(m, len);
406 1.1 dholland if (m == NULL) {
407 1.1 dholland error = ENOBUFS;
408 1.1 dholland goto out;
409 1.1 dholland }
410 1.1 dholland }
411 1.1 dholland reply = mtod(m, struct krpc_reply *);
412 1.1 dholland if (reply->rp_auth.authtype != 0) {
413 1.1 dholland len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
414 1.1 dholland len = (len + 3) & ~3; /* XXX? */
415 1.1 dholland }
416 1.1 dholland m_adj(m, len);
417 1.1 dholland
418 1.1 dholland /* result */
419 1.1 dholland *data = m;
420 1.1 dholland if (from_p) {
421 1.1 dholland *from_p = from;
422 1.1 dholland from = NULL;
423 1.1 dholland }
424 1.1 dholland
425 1.1 dholland out:
426 1.1 dholland if (mhead) m_freem(mhead);
427 1.1 dholland if (from) free(from, M_SONAME);
428 1.1 dholland soclose(so);
429 1.1 dholland return error;
430 1.1 dholland }
431 1.1 dholland
432 1.1 dholland /*
433 1.1 dholland * eXternal Data Representation routines.
434 1.1 dholland * (but with non-standard args...)
435 1.1 dholland */
436 1.1 dholland
437 1.1 dholland /*
438 1.1 dholland * String representation for RPC.
439 1.1 dholland */
440 1.1 dholland struct xdr_string {
441 1.1 dholland u_int32_t len; /* length without null or padding */
442 1.1 dholland char data[4]; /* data (longer, of course) */
443 1.1 dholland /* data is padded to a long-word boundary */
444 1.1 dholland };
445 1.1 dholland
446 1.1 dholland struct mbuf *
447 1.1 dholland xdr_string_encode(char *str, int len)
448 1.1 dholland {
449 1.1 dholland struct mbuf *m;
450 1.1 dholland struct xdr_string *xs;
451 1.1 dholland int dlen; /* padded string length */
452 1.1 dholland int mlen; /* message length */
453 1.1 dholland
454 1.1 dholland dlen = (len + 3) & ~3;
455 1.1 dholland mlen = dlen + 4;
456 1.1 dholland
457 1.1 dholland if (mlen > MCLBYTES) /* If too big, we just can't do it. */
458 1.1 dholland return (NULL);
459 1.1 dholland
460 1.1 dholland m = m_get2(mlen, M_WAITOK, MT_DATA, 0);
461 1.1 dholland xs = mtod(m, struct xdr_string *);
462 1.1 dholland m->m_len = mlen;
463 1.1 dholland xs->len = txdr_unsigned(len);
464 1.1 dholland bcopy(str, xs->data, len);
465 1.1 dholland return (m);
466 1.1 dholland }
467