1 /* $NetBSD: krpc_subr.c,v 1.36 2009/03/14 21:04:25 dsl 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.36 2009/03/14 21:04:25 dsl 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(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(struct sockaddr_in
*sin
, u_int prog
, u_int vers
, u_int proto
, u_int16_t
*portp
, struct lwp
*l
)
135 /* sin: server address */
136 /* prog, vers, proto: host order */
137 /* portp: network order */
140 u_int32_t prog
; /* call program */
141 u_int32_t vers
; /* call version */
142 u_int32_t proto
; /* call protocol */
143 u_int32_t port
; /* call port (unused) */
152 /* The portmapper port is fixed. */
153 if (prog
== PMAPPROG
) {
154 *portp
= htons(PMAPPORT
);
158 m
= m_get(M_WAIT
, MT_DATA
);
159 sdata
= mtod(m
, struct sdata
*);
160 m
->m_len
= sizeof(*sdata
);
162 /* Do the RPC to get it. */
163 sdata
->prog
= txdr_unsigned(prog
);
164 sdata
->vers
= txdr_unsigned(vers
);
165 sdata
->proto
= txdr_unsigned(proto
);
168 sin
->sin_port
= htons(PMAPPORT
);
169 error
= krpc_call(sin
, PMAPPROG
, PMAPVERS
,
170 PMAPPROC_GETPORT
, &m
, NULL
, l
);
174 if (m
->m_len
< sizeof(*rdata
)) {
175 m
= m_pullup(m
, sizeof(*rdata
));
179 rdata
= mtod(m
, struct rdata
*);
180 *portp
= rdata
->port
;
186 static int krpccheck(struct mbuf
*m
, void *context
)
188 struct rpc_reply
*reply
;
190 /* Does the reply contain at least a header? */
191 if (m
->m_pkthdr
.len
< MIN_REPLY_HDR
)
193 if (m
->m_len
< sizeof(struct rpc_reply
)) {
194 m
= m_pullup(m
, sizeof(struct rpc_reply
));
198 reply
= mtod(m
, struct rpc_reply
*);
200 /* Is it the right reply? */
201 if (reply
->rp_direction
!= txdr_unsigned(RPC_REPLY
))
204 if (reply
->rp_xid
!= txdr_unsigned(*(u_int32_t
*)context
))
211 * Do a remote procedure call (RPC) and wait for its reply.
212 * If from_p is non-null, then we are doing broadcast, and
213 * the address from whence the response came is saved there.
216 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
)
217 /* data: input/output */
221 struct sockaddr_in
*sin
;
222 struct mbuf
*m
, *nam
, *mhead
, *from
;
223 struct rpc_call
*call
;
224 struct rpc_reply
*reply
;
226 static u_int32_t xid
= ~0xFF;
230 * Validate address family.
231 * Sorry, this is INET specific...
233 if (sa
->sin_family
!= AF_INET
)
234 return (EAFNOSUPPORT
);
236 /* Free at end if not null. */
241 * Create socket and set its receive timeout.
243 if ((error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0, l
, NULL
)))
246 if ((error
= nfs_boot_setrecvtimo(so
)))
250 * Enable broadcast if necessary.
253 if ((error
= nfs_boot_enbroadcast(so
)))
258 * Bind the local endpoint to a reserved port,
259 * because some NFS servers refuse requests from
260 * non-reserved (non-privileged) ports.
262 tport
= IPPORT_RESERVED
;
265 error
= nfs_boot_sobind_ipport(so
, tport
, l
);
266 } while (error
== EADDRINUSE
&&
267 tport
> IPPORT_RESERVED
/ 2);
269 printf("bind failed\n");
274 * Setup socket address for the server.
276 nam
= m_get(M_WAIT
, MT_SONAME
);
277 sin
= mtod(nam
, struct sockaddr_in
*);
278 memcpy((void *)sin
, (void *)sa
,
279 (nam
->m_len
= sa
->sin_len
));
282 * Prepend RPC message header.
284 mhead
= m_gethdr(M_WAIT
, MT_DATA
);
285 mhead
->m_next
= *data
;
286 call
= mtod(mhead
, struct rpc_call
*);
287 mhead
->m_len
= sizeof(*call
);
288 memset((void *)call
, 0, sizeof(*call
));
291 call
->rp_xid
= txdr_unsigned(xid
);
292 /* call->rp_direction = 0; */
293 call
->rp_rpcvers
= txdr_unsigned(2);
294 call
->rp_prog
= txdr_unsigned(prog
);
295 call
->rp_vers
= txdr_unsigned(vers
);
296 call
->rp_proc
= txdr_unsigned(func
);
297 /* rpc_auth part (auth_unix as root) */
298 call
->rpc_auth
.authtype
= txdr_unsigned(RPCAUTH_UNIX
);
299 call
->rpc_auth
.authlen
= txdr_unsigned(sizeof(struct auth_unix
));
300 /* rpc_verf part (auth_null) */
301 call
->rpc_verf
.authtype
= 0;
302 call
->rpc_verf
.authlen
= 0;
305 * Setup packet header
313 mhead
->m_pkthdr
.len
= len
;
314 mhead
->m_pkthdr
.rcvif
= NULL
;
316 error
= nfs_boot_sendrecv(so
, nam
, 0, mhead
, krpccheck
, &m
, &from
,
321 /* m_pullup() was done in krpccheck() */
322 reply
= mtod(m
, struct rpc_reply
*);
324 /* Was RPC accepted? (authorization OK) */
325 if (reply
->rp_astatus
!= 0) {
326 /* Note: This is NOT an error code! */
327 error
= fxdr_unsigned(u_int32_t
, reply
->rp_rstat
);
330 /* .re_status = RPC_VERSMISMATCH; */
331 error
= ERPCMISMATCH
;
334 /* .re_status = RPC_AUTHERROR; */
345 /* Did the call succeed? */
346 if (reply
->rp_status
!= 0) {
347 /* Note: This is NOT an error code! */
348 error
= fxdr_unsigned(u_int32_t
, reply
->rp_status
);
350 case RPC_PROGUNAVAIL
:
351 error
= EPROGUNAVAIL
;
353 case RPC_PROGMISMATCH
:
354 error
= EPROGMISMATCH
;
356 case RPC_PROCUNAVAIL
:
357 error
= EPROCUNAVAIL
;
367 * OK, we have received a good reply!
368 * Get its length, then strip it off.
370 len
= sizeof(*reply
);
371 if (reply
->rp_auth
.authtype
!= 0) {
372 len
+= fxdr_unsigned(u_int32_t
, reply
->rp_auth
.authlen
);
373 len
= (len
+ 3) & ~3; /* XXX? */
379 if (from_p
&& error
== 0) {
385 if (nam
) m_freem(nam
);
386 if (mhead
) m_freem(mhead
);
387 if (from
) m_freem(from
);
393 * eXternal Data Representation routines.
394 * (but with non-standard args...)
398 * String representation for RPC.
401 u_int32_t len
; /* length without null or padding */
402 char data
[4]; /* data (longer, of course) */
403 /* data is padded to a long-word boundary */
407 xdr_string_encode(char *str
, int len
)
410 struct xdr_string
*xs
;
411 int dlen
; /* padded string length */
412 int mlen
; /* message length */
414 dlen
= (len
+ 3) & ~3;
417 if (mlen
> MCLBYTES
) /* If too big, we just can't do it. */
420 m
= m_get(M_WAIT
, MT_DATA
);
423 if ((m
->m_flags
& M_EXT
) == 0) {
424 (void) m_free(m
); /* There can be only one. */
428 xs
= mtod(m
, struct xdr_string
*);
430 xs
->len
= txdr_unsigned(len
);
431 memcpy(xs
->data
, str
, len
);
436 xdr_string_decode(struct mbuf
*m
, char *str
, int *len_p
)
437 /* len_p: bufsize - 1 */
439 struct xdr_string
*xs
;
440 int mlen
; /* message length */
441 int slen
; /* string length */
448 xs
= mtod(m
, struct xdr_string
*);
449 slen
= fxdr_unsigned(u_int32_t
, xs
->len
);
450 mlen
= 4 + ((slen
+ 3) & ~3);
454 m_copydata(m
, 4, slen
, str
);
465 * Inet address in RPC messages
466 * (Note, really four ints, NOT chars. Blech.)
474 xdr_inaddr_encode(struct in_addr
*ia
)
475 /* ia: already in network order */
478 struct xdr_inaddr
*xi
;
482 m
= m_get(M_WAIT
, MT_DATA
);
483 xi
= mtod(m
, struct xdr_inaddr
*);
484 m
->m_len
= sizeof(*xi
);
485 xi
->atype
= txdr_unsigned(1);
487 cp
= (u_int8_t
*)&ia
->s_addr
;
488 *ip
++ = txdr_unsigned(*cp
++);
489 *ip
++ = txdr_unsigned(*cp
++);
490 *ip
++ = txdr_unsigned(*cp
++);
491 *ip
++ = txdr_unsigned(*cp
++);
497 xdr_inaddr_decode(struct mbuf
*m
, struct in_addr
*ia
)
498 /* ia: already in network order */
500 struct xdr_inaddr
*xi
;
504 if (m
->m_len
< sizeof(*xi
)) {
505 m
= m_pullup(m
, sizeof(*xi
));
509 xi
= mtod(m
, struct xdr_inaddr
*);
510 if (xi
->atype
!= txdr_unsigned(1)) {
511 ia
->s_addr
= INADDR_ANY
;
515 cp
= (u_int8_t
*)&ia
->s_addr
;
516 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
517 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
518 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
519 *cp
++ = fxdr_unsigned(u_int8_t
, *ip
++);
522 m_adj(m
, sizeof(*xi
));