]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/krpc_subr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1994 Gordon Ross, Adam Glass
25 * Copyright (c) 1992 Regents of the University of California.
26 * All rights reserved.
28 * This software was developed by the Computer Systems Engineering group
29 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
30 * contributed to Berkeley.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Lawrence Berkeley Laboratory and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 #include <sys/param.h>
64 #include <sys/ioctl.h>
66 #include <sys/mount.h>
68 #include <sys/malloc.h>
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/systm.h>
72 #include <sys/reboot.h>
75 #include <netinet/in.h>
77 #include <nfs/rpcv2.h>
81 * Kernel support for Sun RPC
83 * Used currently for bootstrapping in nfs diskless configurations.
85 * Note: will not work on variable-sized rpc args/results.
86 * implicit size-limit of an mbuf.
94 u_int32_t rp_atype
; /* auth type */
95 u_int32_t rp_alen
; /* auth length */
99 u_int32_t rp_xid
; /* request transaction id */
100 int32_t rp_direction
; /* call direction (0) */
101 u_int32_t rp_rpcvers
; /* rpc version (2) */
102 u_int32_t rp_prog
; /* program */
103 u_int32_t rp_vers
; /* version */
104 u_int32_t rp_proc
; /* procedure */
105 struct auth_info rp_auth
;
106 struct auth_info rp_verf
;
110 u_int32_t rp_xid
; /* request transaction id */
111 int32_t rp_direction
; /* call direction (1) */
112 int32_t rp_astatus
; /* accept status (0: accepted) */
116 struct auth_info rp_auth
;
117 u_int32_t rp_rstatus
;
122 #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
125 * What is the longest we will wait before re-sending a request?
126 * Note this is also the frequency of "RPC timeout" messages.
127 * The re-send loop count sup linearly to this maximum, so the
128 * first complaint will happen after (1+2+3+4+5)=15 seconds.
130 #define MAX_RESEND_DELAY 5 /* seconds */
132 /* copied over from nfs_boot.c for printf format. could put in .h file... */
133 #define IP_FORMAT "%d.%d.%d.%d"
134 #define IP_CH(ip) ((u_char *)ip)
135 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
139 * Call portmap to lookup a port number for a particular rpc program
140 * Returns non-zero error on failure.
143 krpc_portmap(sin
, prog
, vers
, portp
)
144 struct sockaddr_in
*sin
; /* server address */
145 u_int prog
, vers
; /* host order */
146 u_int16_t
*portp
; /* network order */
149 u_int32_t prog
; /* call program */
150 u_int32_t vers
; /* call version */
151 u_int32_t proto
; /* call protocol */
152 u_int32_t port
; /* call port (unused) */
161 /* The portmapper port is fixed. */
162 if (prog
== PMAPPROG
) {
163 *portp
= htons(PMAPPORT
);
167 m
= m_gethdr(M_WAIT
, MT_DATA
);
170 m
->m_len
= sizeof(*sdata
);
171 m
->m_pkthdr
.len
= m
->m_len
;
172 sdata
= mtod(m
, struct sdata
*);
174 /* Do the RPC to get it. */
175 sdata
->prog
= htonl(prog
);
176 sdata
->vers
= htonl(vers
);
177 sdata
->proto
= htonl(IPPROTO_UDP
);
180 sin
->sin_port
= htons(PMAPPORT
);
181 error
= krpc_call(sin
, PMAPPROG
, PMAPVERS
,
182 PMAPPROC_GETPORT
, &m
, NULL
);
186 rdata
= mtod(m
, struct rdata
*);
187 *portp
= rdata
->port
;
194 * Do a remote procedure call (RPC) and wait for its reply.
195 * If from_p is non-null, then we are doing broadcast, and
196 * the address from whence the response came is saved there.
199 krpc_call(sa
, prog
, vers
, func
, data
, from_p
)
200 struct sockaddr_in
*sa
;
201 u_int prog
, vers
, func
;
202 struct mbuf
**data
; /* input/output */
203 struct sockaddr_in
**from_p
; /* output */
206 struct sockaddr_in
*sin
;
207 struct mbuf
*m
, *nam
, *mhead
, *mhck
;
208 struct rpc_call
*call
;
209 struct rpc_reply
*reply
;
211 int error
, rcvflg
, timo
, secs
, len
;
212 static u_int32_t xid
= ~0xFF;
217 * Validate address family.
218 * Sorry, this is INET specific...
220 if (sa
->sin_family
!= AF_INET
)
221 return (EAFNOSUPPORT
);
223 /* Free at end if not null. */
229 * Create socket and set its recieve timeout.
231 if ((error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0)))
239 bzero(&sopt
, sizeof sopt
);
240 sopt
.sopt_level
= SOL_SOCKET
;
241 sopt
.sopt_name
= SO_RCVTIMEO
;
243 sopt
.sopt_valsize
= sizeof tv
;
245 if (error
= sosetopt(so
, &sopt
))
251 * Enable broadcast if necessary.
256 sopt
.sopt_name
= SO_BROADCAST
;
258 sopt
.sopt_valsize
= sizeof on
;
259 if (error
= sosetopt(so
, &sopt
))
264 * Bind the local endpoint to a reserved port,
265 * because some NFS servers refuse requests from
266 * non-reserved (non-privileged) ports.
268 m
= m_getclr(M_WAIT
, MT_SONAME
);
269 sin
= mtod(m
, struct sockaddr_in
*);
270 sin
->sin_len
= m
->m_len
= sizeof(*sin
);
271 sin
->sin_family
= AF_INET
;
272 sin
->sin_addr
.s_addr
= INADDR_ANY
;
273 tport
= IPPORT_RESERVED
;
276 sin
->sin_port
= htons(tport
);
277 error
= sobind(so
, mtod(m
, struct sockaddr
*));
278 } while (error
== EADDRINUSE
&&
279 tport
> IPPORT_RESERVED
/ 2);
282 printf("bind failed\n");
287 * Setup socket address for the server.
289 nam
= m_get(M_WAIT
, MT_SONAME
);
294 sin
= mtod(nam
, struct sockaddr_in
*);
295 bcopy((caddr_t
)sa
, (caddr_t
)sin
, (nam
->m_len
= sa
->sin_len
));
298 * Prepend RPC message header.
303 if ((m
->m_flags
& M_PKTHDR
) == 0)
304 panic("krpc_call: send data w/o pkthdr");
305 if (m
->m_pkthdr
.len
< m
->m_len
)
306 panic("krpc_call: pkthdr.len not set");
308 mhead
= m_prepend(m
, sizeof(*call
), M_WAIT
);
313 mhead
->m_pkthdr
.len
+= sizeof(*call
);
314 mhead
->m_pkthdr
.rcvif
= NULL
;
317 * Fill in the RPC header
319 call
= mtod(mhead
, struct rpc_call
*);
320 bzero((caddr_t
)call
, sizeof(*call
));
322 call
->rp_xid
= htonl(xid
);
323 /* call->rp_direction = 0; */
324 call
->rp_rpcvers
= htonl(2);
325 call
->rp_prog
= htonl(prog
);
326 call
->rp_vers
= htonl(vers
);
327 call
->rp_proc
= htonl(func
);
328 /* call->rp_auth = 0; */
329 /* call->rp_verf = 0; */
332 * Send it, repeatedly, until a reply is received,
333 * but delay each re-send by an increasing amount.
334 * If the delay hits the maximum, start complaining.
338 /* Send RPC request (or re-send). */
339 m
= m_copym(mhead
, 0, M_COPYALL
, M_WAIT
);
344 error
= sosend(so
, mtod(nam
, struct sockaddr
*), NULL
, m
, NULL
, 0);
346 printf("krpc_call: sosend: %d\n", error
);
351 /* Determine new timeout. */
352 if (timo
< MAX_RESEND_DELAY
)
355 printf("RPC timeout for server " IP_FORMAT
"\n",
356 IP_LIST(&(sin
->sin_addr
.s_addr
)));
359 * Wait for up to timo seconds for a reply.
360 * The socket receive timeout was set to 1 second.
364 if ((from_p
) && (*from_p
)){
365 FREE(*from_p
, M_SONAME
);
373 auio
.uio_resid
= len
= 1<<16;
376 error
= soreceive(so
, (struct sockaddr
**) from_p
, &auio
, &m
, NULL
, &rcvflg
);
378 if (error
== EWOULDBLOCK
) {
384 len
-= auio
.uio_resid
;
386 /* Does the reply contain at least a header? */
387 if (len
< MIN_REPLY_HDR
)
389 if (m
->m_len
< MIN_REPLY_HDR
)
391 reply
= mtod(m
, struct rpc_reply
*);
393 /* Is it the right reply? */
394 if (reply
->rp_direction
!= htonl(RPC_REPLY
))
397 if (reply
->rp_xid
!= htonl(xid
))
400 /* Was RPC accepted? (authorization OK) */
401 if (reply
->rp_astatus
!= 0) {
402 error
= ntohl(reply
->rp_u
.rpu_errno
);
403 printf("rpc denied, error=%d\n", error
);
407 /* Did the call succeed? */
408 if ((error
= ntohl(reply
->rp_u
.rpu_ok
.rp_rstatus
)) != 0) {
409 printf("rpc status=%d\n", error
);
413 goto gotreply
; /* break two levels */
416 } /* forever send/receive */
424 * Pull as much as we can into first mbuf, to make
425 * result buffer contiguous. Note that if the entire
426 * result won't fit into one mbuf, you're out of luck.
427 * XXX - Should not rely on making the entire reply
428 * contiguous (fix callers instead). -gwr
431 if ((m
->m_flags
& M_PKTHDR
) == 0)
432 panic("krpc_call: received pkt w/o header?");
434 len
= m
->m_pkthdr
.len
;
435 if (m
->m_len
< len
) {
436 m
= m_pullup(m
, len
);
441 reply
= mtod(m
, struct rpc_reply
*);
447 len
= sizeof(*reply
);
448 if (reply
->rp_u
.rpu_ok
.rp_auth
.rp_atype
!= 0) {
449 len
+= ntohl(reply
->rp_u
.rpu_ok
.rp_auth
.rp_alen
);
450 len
= (len
+ 3) & ~3; /* XXX? */
457 if (nam
) m_freem(nam
);
458 if (mhead
) m_freem(mhead
);