]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/krpc_subr.c
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1994 Gordon Ross, Adam Glass
31 * Copyright (c) 1992 Regents of the University of California.
32 * All rights reserved.
34 * This software was developed by the Computer Systems Engineering group
35 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
36 * contributed to Berkeley.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Lawrence Berkeley Laboratory and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 #include <nfs/nfs_conf.h>
71 #include <sys/param.h>
73 #include <sys/ioctl.h>
75 #include <sys/mount.h>
76 #include <sys/kpi_mbuf.h>
77 #include <sys/malloc.h>
78 #include <sys/socket.h>
79 #include <sys/socketvar.h>
80 #include <sys/systm.h>
81 #include <sys/reboot.h>
84 #include <netinet/in.h>
86 #include <nfs/rpcv2.h>
90 * Kernel support for Sun RPC
92 * Used currently for bootstrapping in nfs diskless configurations.
94 * Note: will not work on variable-sized rpc args/results.
95 * implicit size-limit of an mbuf.
103 u_int32_t rp_atype
; /* auth type */
104 u_int32_t rp_alen
; /* auth length */
108 u_int32_t rp_xid
; /* request transaction id */
109 int32_t rp_direction
; /* call direction (0) */
110 u_int32_t rp_rpcvers
; /* rpc version (2) */
111 u_int32_t rp_prog
; /* program */
112 u_int32_t rp_vers
; /* version */
113 u_int32_t rp_proc
; /* procedure */
114 struct auth_info rp_auth
;
115 struct auth_info rp_verf
;
119 u_int32_t rp_xid
; /* request transaction id */
120 int32_t rp_direction
; /* call direction (1) */
121 int32_t rp_astatus
; /* accept status (0: accepted) */
125 struct auth_info rp_auth
;
126 u_int32_t rp_rstatus
;
131 #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
132 #define REPLY_SIZE 24 /* xid, dir, astat, rpu_ok */
135 * What is the longest we will wait before re-sending a request?
136 * Note this is also the frequency of "RPC timeout" messages.
137 * The re-send loop count sup linearly to this maximum, so the
138 * first complaint will happen after (1+2+3+4+5)=15 seconds.
140 #define MAX_RESEND_DELAY 5 /* seconds */
142 /* copied over from nfs_boot.c for printf format. could put in .h file... */
143 #define IP_FORMAT "%d.%d.%d.%d"
144 #define IP_CH(ip) ((u_char *)ip)
145 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
149 * Call portmap to lookup a port number for a particular rpc program
150 * Returns non-zero error on failure.
154 struct sockaddr_in
*sin
, /* server address */
155 u_int prog
, u_int vers
, u_int proto
, /* host order */
156 u_int16_t
*portp
) /* network order */
159 u_int32_t prog
; /* call program */
160 u_int32_t vers
; /* call version */
161 u_int32_t proto
; /* call protocol */
162 u_int32_t port
; /* call port (unused) */
171 /* The portmapper port is fixed. */
172 if (prog
== PMAPPROG
) {
173 *portp
= htons(PMAPPORT
);
177 error
= mbuf_gethdr(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
);
181 mbuf_setlen(m
, sizeof(*sdata
));
182 mbuf_pkthdr_setlen(m
, sizeof(*sdata
));
183 sdata
= mbuf_data(m
);
185 /* Do the RPC to get it. */
186 sdata
->prog
= htonl(prog
);
187 sdata
->vers
= htonl(vers
);
188 sdata
->proto
= htonl(proto
);
191 sin
->sin_port
= htons(PMAPPORT
);
192 error
= krpc_call(sin
, SOCK_DGRAM
, PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
, &m
, NULL
);
197 rdata
= mbuf_data(m
);
199 if (mbuf_len(m
) >= sizeof(*rdata
)) {
200 *portp
= rdata
->port
;
203 if (mbuf_len(m
) < sizeof(*rdata
) || !rdata
->port
) {
204 error
= EPROGUNAVAIL
;
212 * Do a remote procedure call (RPC) and wait for its reply.
213 * If from_p is non-null, then we are doing broadcast, and
214 * the address from whence the response came is saved there.
218 struct sockaddr_in
*sa
,
219 u_int sotype
, u_int prog
, u_int vers
, u_int func
,
220 mbuf_t
*data
, /* input/output */
221 struct sockaddr_in
*from_p
) /* output */
224 struct sockaddr_in
*sin
;
225 mbuf_t m
, nam
, mhead
;
226 struct rpc_call
*call
;
227 struct rpc_reply
*reply
;
228 int error
, timo
, secs
;
230 static u_int32_t xid
= ~0xFF;
232 size_t maxpacket
= 1 << 16;
235 * Validate address family.
236 * Sorry, this is INET specific...
238 if (sa
->sin_family
!= AF_INET
) {
242 /* Free at end if not null. */
246 * Create socket and set its recieve timeout.
248 if ((error
= sock_socket(AF_INET
, sotype
, 0, 0, 0, &so
))) {
258 if ((error
= sock_setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)))) {
264 * Enable broadcast if necessary.
267 if (from_p
&& (sotype
== SOCK_DGRAM
)) {
269 if ((error
= sock_setsockopt(so
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)))) {
275 * Bind the local endpoint to a reserved port,
276 * because some NFS servers refuse requests from
277 * non-reserved (non-privileged) ports.
279 if ((error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &m
))) {
283 bzero(sin
, sizeof(*sin
));
284 mbuf_setlen(m
, sizeof(*sin
));
285 sin
->sin_len
= sizeof(*sin
);
286 sin
->sin_family
= AF_INET
;
287 sin
->sin_addr
.s_addr
= INADDR_ANY
;
288 tport
= IPPORT_RESERVED
;
291 sin
->sin_port
= htons(tport
);
292 error
= sock_bind(so
, (struct sockaddr
*)sin
);
293 } while (error
== EADDRINUSE
&&
294 tport
> IPPORT_RESERVED
/ 2);
298 printf("bind failed\n");
303 * Setup socket address for the server.
305 if ((error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &nam
))) {
308 sin
= mbuf_data(nam
);
309 mbuf_setlen(nam
, sa
->sin_len
);
310 bcopy((caddr_t
)sa
, (caddr_t
)sin
, sa
->sin_len
);
312 if (sotype
== SOCK_STREAM
) {
316 error
= sock_connect(so
, mbuf_data(nam
), MSG_DONTWAIT
);
317 if (error
&& (error
!= EINPROGRESS
)) {
320 error
= sock_connectwait(so
, &tv
);
322 if (error
== EINPROGRESS
) {
325 printf("krpc_call: error waiting for TCP socket connect: %d\n", error
);
331 * Prepend RPC message header.
336 if ((mbuf_flags(m
) & MBUF_PKTHDR
) == 0) {
337 panic("krpc_call: send data w/o pkthdr");
339 if (mbuf_pkthdr_len(m
) < mbuf_len(m
)) {
340 panic("krpc_call: pkthdr.len not set");
344 if (sotype
== SOCK_STREAM
) {
345 len
+= 4; /* account for RPC record marker */
348 if ((error
= mbuf_prepend(&mhead
, len
, MBUF_WAITOK
))) {
351 if ((error
= mbuf_pkthdr_setrcvif(mhead
, NULL
))) {
356 * Fill in the RPC header
358 if (sotype
== SOCK_STREAM
) {
359 /* first, fill in RPC record marker */
360 u_int32_t
*recmark
= mbuf_data(mhead
);
361 size_t pkthdr_len
= mbuf_pkthdr_len(mhead
);
362 assert(pkthdr_len
<= UINT32_MAX
);
363 *recmark
= htonl(0x80000000 | (uint32_t)(pkthdr_len
- 4));
364 call
= (struct rpc_call
*)(recmark
+ 1);
366 call
= mbuf_data(mhead
);
368 bzero((caddr_t
)call
, sizeof(*call
));
370 call
->rp_xid
= htonl(xid
);
371 /* call->rp_direction = 0; */
372 call
->rp_rpcvers
= htonl(2);
373 call
->rp_prog
= htonl(prog
);
374 call
->rp_vers
= htonl(vers
);
375 call
->rp_proc
= htonl(func
);
376 /* call->rp_auth = 0; */
377 /* call->rp_verf = 0; */
380 * Send it, repeatedly, until a reply is received,
381 * but delay each re-send by an increasing amount.
382 * If the delay hits the maximum, start complaining.
388 /* Send RPC request (or re-send). */
389 if ((error
= mbuf_copym(mhead
, 0, MBUF_COPYALL
, MBUF_WAITOK
, &m
))) {
392 bzero(&msg
, sizeof(msg
));
393 if (sotype
== SOCK_STREAM
) {
397 msg
.msg_name
= mbuf_data(nam
);
398 if (mbuf_len(nam
) > UINT_MAX
) {
399 printf("krpc_call: mbuf_len is too long: EINVAL\n");
403 msg
.msg_namelen
= (uint32_t)mbuf_len(nam
);
405 error
= sock_sendmbuf(so
, &msg
, m
, 0, 0);
407 printf("krpc_call: sosend: %d\n", error
);
412 /* Determine new timeout. */
413 if (timo
< MAX_RESEND_DELAY
) {
416 printf("RPC timeout for server " IP_FORMAT
"\n",
417 IP_LIST(&(sin
->sin_addr
.s_addr
)));
421 * Wait for up to timo seconds for a reply.
422 * The socket receive timeout was set to 1 second.
432 if (sotype
== SOCK_STREAM
) {
436 aio
.iov_len
= sizeof(u_int32_t
);
437 bzero(&msg
, sizeof(msg
));
441 error
= sock_receive(so
, &msg
, MSG_WAITALL
, &readlen
);
442 if ((error
== EWOULDBLOCK
) && (--maxretries
<= 0)) {
445 } while (error
== EWOULDBLOCK
);
446 if (!error
&& readlen
< aio
.iov_len
) {
447 /* only log a message if we got a partial word */
449 printf("short receive (%ld/%ld) from server " IP_FORMAT
"\n",
450 readlen
, sizeof(u_int32_t
), IP_LIST(&(sin
->sin_addr
.s_addr
)));
457 len
= ntohll(len
) & ~0x80000000;
459 * This is SERIOUS! We are out of sync with the sender
460 * and forcing a disconnect/reconnect is all I can do.
462 if (len
> maxpacket
) {
463 printf("impossible packet length (%ld) from server " IP_FORMAT
"\n",
464 len
, IP_LIST(&(sin
->sin_addr
.s_addr
)));
471 error
= sock_receivembuf(so
, NULL
, &m
, MSG_WAITALL
, &readlen
);
472 } while (error
== EWOULDBLOCK
);
474 if (!error
&& (len
> readlen
)) {
475 printf("short receive (%ld/%ld) from server " IP_FORMAT
"\n",
476 readlen
, len
, IP_LIST(&(sin
->sin_addr
.s_addr
)));
482 bzero(&msg
, sizeof(msg
));
483 msg
.msg_name
= from_p
;
484 msg
.msg_namelen
= (from_p
== NULL
) ? 0 : sizeof(*from_p
);
485 error
= sock_receivembuf(so
, &msg
, &m
, 0, &readlen
);
488 if (error
== EWOULDBLOCK
) {
497 /* Does the reply contain at least a header? */
498 if (len
< MIN_REPLY_HDR
) {
501 if (mbuf_len(m
) < MIN_REPLY_HDR
) {
504 reply
= mbuf_data(m
);
506 /* Is it the right reply? */
507 if (reply
->rp_direction
!= htonl(RPC_REPLY
)) {
511 if (reply
->rp_xid
!= htonl(xid
)) {
515 /* Was RPC accepted? (authorization OK) */
516 if (reply
->rp_astatus
!= 0) {
517 error
= ntohl(reply
->rp_u
.rpu_errno
);
518 printf("rpc denied, error=%d\n", error
);
519 /* convert rpc error to errno */
522 error
= ERPCMISMATCH
;
532 if (mbuf_len(m
) < REPLY_SIZE
) {
533 error
= RPC_SYSTEM_ERR
;
535 error
= ntohl(reply
->rp_u
.rpu_ok
.rp_rstatus
);
538 /* Did the call succeed? */
540 printf("rpc status=%d\n", error
);
541 /* convert rpc error to errno */
543 case RPC_PROGUNAVAIL
:
544 error
= EPROGUNAVAIL
;
546 case RPC_PROGMISMATCH
:
547 error
= EPROGMISMATCH
;
549 case RPC_PROCUNAVAIL
:
550 error
= EPROCUNAVAIL
;
562 goto gotreply
; /* break two levels */
564 } /* forever send/receive */
572 * Pull as much as we can into first mbuf, to make
573 * result buffer contiguous. Note that if the entire
574 * result won't fit into one mbuf, you're out of luck.
575 * XXX - Should not rely on making the entire reply
576 * contiguous (fix callers instead). -gwr
579 if ((mbuf_flags(m
) & MBUF_PKTHDR
) == 0) {
580 panic("krpc_call: received pkt w/o header?");
583 len
= mbuf_pkthdr_len(m
);
584 if (sotype
== SOCK_STREAM
) {
585 len
-= 4; /* the RPC record marker was read separately */
587 if (mbuf_len(m
) < len
) {
588 if ((error
= mbuf_pullup(&m
, len
))) {
591 reply
= mbuf_data(m
);
597 len
= sizeof(*reply
);
598 if (reply
->rp_u
.rpu_ok
.rp_auth
.rp_atype
!= 0) {
599 len
+= ntohl(reply
->rp_u
.rpu_ok
.rp_auth
.rp_alen
);
600 len
= (len
+ 3) & ~3; /* XXX? */
608 mbuf_adj(m
, (int)len
);
624 #endif /* CONFIG_NFS_CLIENT */