]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/krpc_subr.c
f1412b99fa698cca56815d934e2984ec8a09c92c
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1994 Gordon Ross, Adam Glass
28 * Copyright (c) 1992 Regents of the University of California.
29 * All rights reserved.
31 * This software was developed by the Computer Systems Engineering group
32 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
33 * contributed to Berkeley.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Lawrence Berkeley Laboratory and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 #include <sys/param.h>
67 #include <sys/ioctl.h>
69 #include <sys/mount.h>
71 #include <sys/malloc.h>
72 #include <sys/socket.h>
73 #include <sys/socketvar.h>
74 #include <sys/systm.h>
75 #include <sys/reboot.h>
78 #include <netinet/in.h>
80 #include <nfs/rpcv2.h>
84 * Kernel support for Sun RPC
86 * Used currently for bootstrapping in nfs diskless configurations.
88 * Note: will not work on variable-sized rpc args/results.
89 * implicit size-limit of an mbuf.
97 u_int32_t rp_atype
; /* auth type */
98 u_int32_t rp_alen
; /* auth length */
102 u_int32_t rp_xid
; /* request transaction id */
103 int32_t rp_direction
; /* call direction (0) */
104 u_int32_t rp_rpcvers
; /* rpc version (2) */
105 u_int32_t rp_prog
; /* program */
106 u_int32_t rp_vers
; /* version */
107 u_int32_t rp_proc
; /* procedure */
108 struct auth_info rp_auth
;
109 struct auth_info rp_verf
;
113 u_int32_t rp_xid
; /* request transaction id */
114 int32_t rp_direction
; /* call direction (1) */
115 int32_t rp_astatus
; /* accept status (0: accepted) */
119 struct auth_info rp_auth
;
120 u_int32_t rp_rstatus
;
125 #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
128 * What is the longest we will wait before re-sending a request?
129 * Note this is also the frequency of "RPC timeout" messages.
130 * The re-send loop count sup linearly to this maximum, so the
131 * first complaint will happen after (1+2+3+4+5)=15 seconds.
133 #define MAX_RESEND_DELAY 5 /* seconds */
135 /* copied over from nfs_boot.c for printf format. could put in .h file... */
136 #define IP_FORMAT "%d.%d.%d.%d"
137 #define IP_CH(ip) ((u_char *)ip)
138 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
142 * Call portmap to lookup a port number for a particular rpc program
143 * Returns non-zero error on failure.
146 krpc_portmap(sin
, prog
, vers
, portp
)
147 struct sockaddr_in
*sin
; /* server address */
148 u_int prog
, vers
; /* host order */
149 u_int16_t
*portp
; /* network order */
152 u_int32_t prog
; /* call program */
153 u_int32_t vers
; /* call version */
154 u_int32_t proto
; /* call protocol */
155 u_int32_t port
; /* call port (unused) */
164 /* The portmapper port is fixed. */
165 if (prog
== PMAPPROG
) {
166 *portp
= htons(PMAPPORT
);
170 m
= m_gethdr(M_WAIT
, MT_DATA
);
173 m
->m_len
= sizeof(*sdata
);
174 m
->m_pkthdr
.len
= m
->m_len
;
175 sdata
= mtod(m
, struct sdata
*);
177 /* Do the RPC to get it. */
178 sdata
->prog
= htonl(prog
);
179 sdata
->vers
= htonl(vers
);
180 sdata
->proto
= htonl(IPPROTO_UDP
);
183 sin
->sin_port
= htons(PMAPPORT
);
184 error
= krpc_call(sin
, PMAPPROG
, PMAPVERS
,
185 PMAPPROC_GETPORT
, &m
, NULL
);
189 rdata
= mtod(m
, struct rdata
*);
190 *portp
= rdata
->port
;
197 * Do a remote procedure call (RPC) and wait for its reply.
198 * If from_p is non-null, then we are doing broadcast, and
199 * the address from whence the response came is saved there.
202 krpc_call(sa
, prog
, vers
, func
, data
, from_p
)
203 struct sockaddr_in
*sa
;
204 u_int prog
, vers
, func
;
205 struct mbuf
**data
; /* input/output */
206 struct sockaddr_in
**from_p
; /* output */
209 struct sockaddr_in
*sin
;
210 struct mbuf
*m
, *nam
, *mhead
, *mhck
;
211 struct rpc_call
*call
;
212 struct rpc_reply
*reply
;
214 int error
, rcvflg
, timo
, secs
, len
;
215 static u_int32_t xid
= ~0xFF;
220 * Validate address family.
221 * Sorry, this is INET specific...
223 if (sa
->sin_family
!= AF_INET
)
224 return (EAFNOSUPPORT
);
226 /* Free at end if not null. */
232 * Create socket and set its recieve timeout.
234 if ((error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0)))
242 bzero(&sopt
, sizeof sopt
);
243 sopt
.sopt_level
= SOL_SOCKET
;
244 sopt
.sopt_name
= SO_RCVTIMEO
;
246 sopt
.sopt_valsize
= sizeof tv
;
248 if (error
= sosetopt(so
, &sopt
))
254 * Enable broadcast if necessary.
259 sopt
.sopt_name
= SO_BROADCAST
;
261 sopt
.sopt_valsize
= sizeof on
;
262 if (error
= sosetopt(so
, &sopt
))
267 * Bind the local endpoint to a reserved port,
268 * because some NFS servers refuse requests from
269 * non-reserved (non-privileged) ports.
271 m
= m_getclr(M_WAIT
, MT_SONAME
);
272 sin
= mtod(m
, struct sockaddr_in
*);
273 sin
->sin_len
= m
->m_len
= sizeof(*sin
);
274 sin
->sin_family
= AF_INET
;
275 sin
->sin_addr
.s_addr
= INADDR_ANY
;
276 tport
= IPPORT_RESERVED
;
279 sin
->sin_port
= htons(tport
);
280 error
= sobind(so
, mtod(m
, struct sockaddr
*));
281 } while (error
== EADDRINUSE
&&
282 tport
> IPPORT_RESERVED
/ 2);
285 printf("bind failed\n");
290 * Setup socket address for the server.
292 nam
= m_get(M_WAIT
, MT_SONAME
);
297 sin
= mtod(nam
, struct sockaddr_in
*);
298 bcopy((caddr_t
)sa
, (caddr_t
)sin
, (nam
->m_len
= sa
->sin_len
));
301 * Prepend RPC message header.
306 if ((m
->m_flags
& M_PKTHDR
) == 0)
307 panic("krpc_call: send data w/o pkthdr");
308 if (m
->m_pkthdr
.len
< m
->m_len
)
309 panic("krpc_call: pkthdr.len not set");
311 mhead
= m_prepend(m
, sizeof(*call
), M_WAIT
);
316 mhead
->m_pkthdr
.len
+= sizeof(*call
);
317 mhead
->m_pkthdr
.rcvif
= NULL
;
320 * Fill in the RPC header
322 call
= mtod(mhead
, struct rpc_call
*);
323 bzero((caddr_t
)call
, sizeof(*call
));
325 call
->rp_xid
= htonl(xid
);
326 /* call->rp_direction = 0; */
327 call
->rp_rpcvers
= htonl(2);
328 call
->rp_prog
= htonl(prog
);
329 call
->rp_vers
= htonl(vers
);
330 call
->rp_proc
= htonl(func
);
331 /* call->rp_auth = 0; */
332 /* call->rp_verf = 0; */
335 * Send it, repeatedly, until a reply is received,
336 * but delay each re-send by an increasing amount.
337 * If the delay hits the maximum, start complaining.
341 /* Send RPC request (or re-send). */
342 m
= m_copym(mhead
, 0, M_COPYALL
, M_WAIT
);
347 error
= sosend(so
, mtod(nam
, struct sockaddr
*), NULL
, m
, NULL
, 0);
349 printf("krpc_call: sosend: %d\n", error
);
354 /* Determine new timeout. */
355 if (timo
< MAX_RESEND_DELAY
)
358 printf("RPC timeout for server " IP_FORMAT
"\n",
359 IP_LIST(&(sin
->sin_addr
.s_addr
)));
362 * Wait for up to timo seconds for a reply.
363 * The socket receive timeout was set to 1 second.
367 if ((from_p
) && (*from_p
)){
368 FREE(*from_p
, M_SONAME
);
376 auio
.uio_resid
= len
= 1<<16;
379 error
= soreceive(so
, (struct sockaddr
**) from_p
, &auio
, &m
, NULL
, &rcvflg
);
381 if (error
== EWOULDBLOCK
) {
387 len
-= auio
.uio_resid
;
389 /* Does the reply contain at least a header? */
390 if (len
< MIN_REPLY_HDR
)
392 if (m
->m_len
< MIN_REPLY_HDR
)
394 reply
= mtod(m
, struct rpc_reply
*);
396 /* Is it the right reply? */
397 if (reply
->rp_direction
!= htonl(RPC_REPLY
))
400 if (reply
->rp_xid
!= htonl(xid
))
403 /* Was RPC accepted? (authorization OK) */
404 if (reply
->rp_astatus
!= 0) {
405 error
= ntohl(reply
->rp_u
.rpu_errno
);
406 printf("rpc denied, error=%d\n", error
);
407 /* convert rpc error to errno */
410 error
= ERPCMISMATCH
;
419 /* Did the call succeed? */
420 if ((error
= ntohl(reply
->rp_u
.rpu_ok
.rp_rstatus
)) != 0) {
421 printf("rpc status=%d\n", error
);
422 /* convert rpc error to errno */
424 case RPC_PROGUNAVAIL
:
425 error
= EPROGUNAVAIL
;
427 case RPC_PROGMISMATCH
:
428 error
= EPROGMISMATCH
;
430 case RPC_PROCUNAVAIL
:
431 error
= EPROCUNAVAIL
;
443 goto gotreply
; /* break two levels */
446 } /* forever send/receive */
454 * Pull as much as we can into first mbuf, to make
455 * result buffer contiguous. Note that if the entire
456 * result won't fit into one mbuf, you're out of luck.
457 * XXX - Should not rely on making the entire reply
458 * contiguous (fix callers instead). -gwr
461 if ((m
->m_flags
& M_PKTHDR
) == 0)
462 panic("krpc_call: received pkt w/o header?");
464 len
= m
->m_pkthdr
.len
;
465 if (m
->m_len
< len
) {
466 m
= m_pullup(m
, len
);
471 reply
= mtod(m
, struct rpc_reply
*);
477 len
= sizeof(*reply
);
478 if (reply
->rp_u
.rpu_ok
.rp_auth
.rp_atype
!= 0) {
479 len
+= ntohl(reply
->rp_u
.rpu_ok
.rp_auth
.rp_alen
);
480 len
= (len
+ 3) & ~3; /* XXX? */
487 if (nam
) m_freem(nam
);
488 if (mhead
) m_freem(mhead
);