1 /* $NetBSD: krpc_subr.c,v 1.31 2006/04/15 01:25:54 christos Exp $ */
4 * Copyright (c) 1995 Gordon Ross, Adam Glass
5 * Copyright (c) 1992 Regents of the University of California.
8 * This software was developed by the Computer Systems Engineering group
9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 * contributed to Berkeley.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Lawrence Berkeley Laboratory and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: krpc_subr.c,v 1.31 2006/04/15 01:25:54 christos Exp $");
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/ioctl.h>
52 #include <sys/mount.h>
54 #include <sys/reboot.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
58 #include <netinet/in.h>
60 #include <nfs/rpcv2.h>
62 #include <nfs/xdr_subs.h>
63 #include <nfs/nfsproto.h> /* XXX NFSX_V3FHMAX for next */
65 #include <nfs/nfsmount.h>
66 #include <nfs/nfsdiskless.h> /* XXX decl nfs_boot_sendrecv */
69 * Kernel support for Sun RPC
71 * Used currently for bootstrapping in nfs diskless configurations.
79 u_int32_t authtype
; /* auth type */
80 u_int32_t authlen
; /* auth length */
85 int32_t ua_hostname
; /* null */
88 int32_t ua_gidlist
; /* null */
92 u_int32_t rp_xid
; /* request transaction id */
93 int32_t rp_direction
; /* call direction (0) */
94 u_int32_t rp_rpcvers
; /* rpc version (2) */
95 u_int32_t rp_prog
; /* program */
96 u_int32_t rp_vers
; /* version */
97 u_int32_t rp_proc
; /* procedure */
98 struct auth_info rpc_auth
;
99 struct auth_unix rpc_unix
;
100 struct auth_info rpc_verf
;
104 u_int32_t rp_xid
; /* request transaction id */
105 int32_t rp_direction
; /* call direction (1) */
106 int32_t rp_astatus
; /* accept status (0: accepted) */
116 struct auth_info rok_auth
;
117 u_int32_t rok_status
;
121 #define rp_rstat rp_u.rpu_rej.rej_stat
122 #define rp_auth rp_u.rpu_rok.rok_auth
123 #define rp_status rp_u.rpu_rok.rok_status
125 #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
127 static int krpccheck
__P((struct mbuf
*, void*));
130 * Call portmap to lookup a port number for a particular rpc program
131 * Returns non-zero error on failure.
134 krpc_portmap(sin
, prog
, vers
, proto
, portp
, l
)
135 struct sockaddr_in
*sin
; /* server address */
136 u_int prog
, vers
, proto
; /* host order */
137 u_int16_t
*portp
; /* network order */
141 u_int32_t prog
; /* call program */
142 u_int32_t vers
; /* call version */
143 u_int32_t proto
; /* call protocol */
144 u_int32_t port
; /* call port (unused) */
153 /* The portmapper port is fixed. */
154 if (prog
== PMAPPROG
) {
155 *portp
= htons(PMAPPORT
);
159 m
= m_get(M_WAIT
, MT_DATA
);
160 sdata
= mtod(m
, struct sdata
*);
161 m
->m_len
= sizeof(*sdata
);
163 /* Do the RPC to get it. */
164 sdata
->prog
= txdr_unsigned(prog
);
165 sdata
->vers
= txdr_unsigned(vers
);
166 sdata
->proto
= txdr_unsigned(proto
);
169 sin
->sin_port
= htons(PMAPPORT
);
170 error
= krpc_call(sin
, PMAPPROG
, PMAPVERS
,
171 PMAPPROC_GETPORT
, &m
, NULL
, l
);
175 if (m
->m_len
< sizeof(*rdata
)) {
176 m
= m_pullup(m
, sizeof(*rdata
));
180 rdata
= mtod(m
, struct rdata
*);
181 *portp
= rdata
->port
;
187 static int krpccheck(m
, context
)
191 struct rpc_reply
*reply
;
193 /* Does the reply contain at least a header? */
194 if (m
->m_pkthdr
.len
< MIN_REPLY_HDR
)
196 if (m
->m_len
< sizeof(struct rpc_reply
)) {
197 m
= m_pullup(m
, sizeof(struct rpc_reply
));
201 reply
= mtod(m
, struct rpc_reply
*);
203 /* Is it the right reply? */
204 if (reply
->rp_direction
!= txdr_unsigned(RPC_REPLY
))
207 if (reply
->rp_xid
!= txdr_unsigned(*(u_int32_t
*)context
))
214 * Do a remote procedure call (RPC) and wait for its reply.
215 * If from_p is non-null, then we are doing broadcast, and
216 * the address from whence the response came is saved there.
219 krpc_call(sa
, prog
, vers
, func
, data
, from_p
, l
)
220 struct sockaddr_in
*sa
;
221 u_int prog
, vers
, func
;
222 struct mbuf
**data
; /* input/output */
223 struct mbuf
**from_p
; /* output */
227 struct sockaddr_in
*sin
;
228 struct mbuf
*m
, *nam
, *mhead
, *from
;
229 struct rpc_call
*call
;
230 struct rpc_reply
*reply
;
232 static u_int32_t xid
= ~0xFF;
236 * Validate address family.
237 * Sorry, this is INET specific...
239 if (sa
->sin_family
!= AF_INET
)
240 return (EAFNOSUPPORT
);
242 /* Free at end if not null. */
247 * Create socket and set its receive timeout.
249 if ((error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0, l
)))
252 if ((error
= nfs_boot_setrecvtimo(so
)))
256 * Enable broadcast if necessary.
259 if ((error
= nfs_boot_enbroadcast(so
)))
264 * Bind the local endpoint to a reserved port,
265 * because some NFS servers refuse requests from
266 * non-reserved (non-privileged) ports.
268 tport
= IPPORT_RESERVED
;
271 error
= nfs_boot_sobind_ipport(so
, tport
, l
);
272 } while (error
== EADDRINUSE
&&
273 tport
> IPPORT_RESERVED
/ 2);
275 printf("bind failed\n");
280 * Setup socket address for the server.
282 nam
= m_get(M_WAIT
, MT_SONAME
);
283 sin
= mtod(nam
, struct sockaddr_in
*);
284 memcpy((void *)sin
, (void *)sa
,
285 (nam
->m_len
= sa
->sin_len
));
288 * Prepend RPC message header.
290 mhead
= m_gethdr(M_WAIT
, MT_DATA
);
291 mhead
->m_next
= *data
;
292 call
= mtod(mhead
, struct rpc_call
*);
293 mhead
->m_len
= sizeof(*call
);
294 memset((void *)call
, 0, sizeof(*call
));
297 call
->rp_xid
= txdr_unsigned(xid
);
298 /* call->rp_direction = 0; */
299 call
->rp_rpcvers
= txdr_unsigned(2);
300 call
->rp_prog
= txdr_unsigned(prog
);
301 call
->rp_vers
= txdr_unsigned(vers
);
302 call
->rp_proc
= txdr_unsigned(func
);
303 /* rpc_auth part (auth_unix as root) */
304 call
->rpc_auth
.authtype
= txdr_unsigned(RPCAUTH_UNIX
);
305 call
->rpc_auth
.authlen
= txdr_unsigned(sizeof(struct auth_unix
));
306 /* rpc_verf part (auth_null) */
307 call
->rpc_verf
.authtype
= 0;
308 call
->rpc_verf
.authlen
= 0;
311 * Setup packet header
319 mhead
->m_pkthdr
.len
= len
;
320 mhead
->m_pkthdr
.rcvif
= NULL
;
322 error
= nfs_boot_sendrecv(so
, nam
, 0, mhead
, krpccheck
, &m
, &from
,
327 /* m_pullup() was done in krpccheck() */
328 reply
= mtod(m
, struct rpc_reply
*);
330 /* Was RPC accepted? (authorization OK) */
331 if (reply
->rp_astatus
!= 0) {
332 /* Note: This is NOT an error code! */
333 error
= fxdr_unsigned(u_int32_t
, reply
->rp_rstat
);
336 /* .re_status = RPC_VERSMISMATCH; */
337 error
= ERPCMISMATCH
;
340 /* .re_status = RPC_AUTHERROR; */
351 /* Did the call succeed? */
352 if (reply
->rp_status
!= 0) {
353 /* Note: This is NOT an error code! */
354 error
= fxdr_unsigned(u_int32_t
, reply
->rp_status
);
356 case RPC_PROGUNAVAIL
:
357 error
= EPROGUNAVAIL
;
359 case RPC_PROGMISMATCH
:
360 error
= EPROGMISMATCH
;
362 case RPC_PROCUNAVAIL
:
363 error
= EPROCUNAVAIL
;
373 * OK, we have received a good reply!
374 * Get its length, then strip it off.
376 len
= sizeof(*reply
);
377 if (reply
->rp_auth
.authtype
!= 0) {
378 len
+= fxdr_unsigned(u_int32_t
, reply
->rp_auth
.authlen
);
379 len
= (len
+ 3) & ~3; /* XXX? */
385 if (from_p
&& error
== 0) {
391 if (nam
) m_freem(nam
);
392 if (mhead
) m_freem(mhead
);
393 if (from
) m_freem(from
);
399 * eXternal Data Representation routines.
400 * (but with non-standard args...)
404 * String representation for RPC.
407 u_int32_t len
; /* length without null or padding */
408 char data
[4]; /* data (longer, of course) */
409 /* data is padded to a long-word boundary */
413 xdr_string_encode(str
, len
)
418 struct xdr_string
*xs
;
419 int dlen
; /* padded string length */
420 int mlen
; /* message length */
422 dlen
= (len
+ 3) & ~3;
425 if (mlen
> MCLBYTES
) /* If too big, we just can't do it. */
428 m
= m_get(M_WAIT
, MT_DATA
);
431 if ((m
->m_flags
& M_EXT
) == 0) {
432 (void) m_free(m
); /* There can be only one. */
436 xs
= mtod(m
, struct xdr_string
*);
438 xs
->len
= txdr_unsigned(len
);
439 memcpy(xs
->data
, str
, len
);
444 xdr_string_decode(m
, str
, len_p
)
447 int *len_p
; /* bufsize - 1 */
449 struct xdr_string
*xs
;
450 int mlen
; /* message length */
451 int slen
; /* string length */
458 xs
= mtod(m
, struct xdr_string
*);
459 slen
= fxdr_unsigned(u_int32_t
, xs
->len
);
460 mlen
= 4 + ((slen
+ 3) & ~3);
464 m_copydata(m
, 4, slen
, str
);
475 * Inet address in RPC messages
476 * (Note, really four ints, NOT chars. Blech.)
484 xdr_inaddr_encode(ia
)
485 struct in_addr
*ia
; /* already in network order */
488 struct xdr_inaddr
*xi
;
492 m
= m_get(M_WAIT
, MT_DATA
);
493 xi
= mtod(m
, struct xdr_inaddr
*);
494 m
->m_len
= sizeof(*xi
);
495 xi
->atype
= txdr_unsigned(1);
497 cp
= (u_int8_t
*)&ia
->s_addr
;
498 *ip
++ = txdr_unsigned(*cp
++);
499 *ip
++ = txdr_unsigned(*cp
++);
500 *ip
++ = txdr_unsigned(*cp
++);
501 *ip
++ = txdr_unsigned(*cp
++);
507 xdr_inaddr_decode(m
, ia
)
509 struct in_addr
*ia
; /* already in network order */
511 struct xdr_inaddr
*xi
;
515 if (m
->m_len
< sizeof(*xi
)) {
516 m
= m_pullup(m
, sizeof(*xi
));
520 xi
= mtod(m
, struct xdr_inaddr
*);
521 if (xi
->atype
!= txdr_unsigned(1)) {
522 ia
->s_addr
= INADDR_ANY
;
526 cp
= (u_int8_t
*)&ia
->s_addr
;
527 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
528 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
529 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
530 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
533 m_adj(m
, sizeof(*xi
));