]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/krpc_subr.c
   2  * Copyright (c) 2000-2004 Apple Computer, 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 <sys/param.h> 
  70 #include <sys/ioctl.h> 
  72 #include <sys/mount.h> 
  73 #include <sys/kpi_mbuf.h> 
  74 #include <sys/malloc.h> 
  75 #include <sys/socket.h> 
  76 #include <sys/socketvar.h> 
  77 #include <sys/systm.h> 
  78 #include <sys/reboot.h> 
  79 #include <sys/uio_internal.h> 
  82 #include <netinet/in.h> 
  84 #include <nfs/rpcv2.h> 
  88  * Kernel support for Sun RPC 
  90  * Used currently for bootstrapping in nfs diskless configurations. 
  92  * Note: will not work on variable-sized rpc args/results. 
  93  *       implicit size-limit of an mbuf. 
 101         u_int32_t       rp_atype
;       /* auth type */ 
 102         u_int32_t       rp_alen
;        /* auth length */ 
 106         u_int32_t       rp_xid
;         /* request transaction id */ 
 107         int32_t         rp_direction
;   /* call direction (0) */ 
 108         u_int32_t       rp_rpcvers
;     /* rpc version (2) */ 
 109         u_int32_t       rp_prog
;        /* program */ 
 110         u_int32_t       rp_vers
;        /* version */ 
 111         u_int32_t       rp_proc
;        /* procedure */ 
 112         struct  auth_info rp_auth
; 
 113         struct  auth_info rp_verf
; 
 117         u_int32_t rp_xid
;               /* request transaction id */ 
 118         int32_t  rp_direction
;          /* call direction (1) */ 
 119         int32_t  rp_astatus
;            /* accept status (0: accepted) */ 
 123                         struct auth_info rp_auth
; 
 124                         u_int32_t       rp_rstatus
; 
 129 #define MIN_REPLY_HDR 16        /* xid, dir, astat, errno */ 
 132  * What is the longest we will wait before re-sending a request? 
 133  * Note this is also the frequency of "RPC timeout" messages. 
 134  * The re-send loop count sup linearly to this maximum, so the 
 135  * first complaint will happen after (1+2+3+4+5)=15 seconds. 
 137 #define MAX_RESEND_DELAY 5      /* seconds */ 
 139 /* copied over from nfs_boot.c for printf format. could put in .h file... */ 
 140 #define IP_FORMAT       "%d.%d.%d.%d" 
 141 #define IP_CH(ip)       ((u_char *)ip) 
 142 #define IP_LIST(ip)     IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] 
 146  * Call portmap to lookup a port number for a particular rpc program 
 147  * Returns non-zero error on failure. 
 150 krpc_portmap(sin
, prog
, vers
, proto
, portp
) 
 151         struct sockaddr_in 
*sin
;        /* server address */ 
 152         u_int prog
, vers
, proto
;        /* host order */ 
 153         u_int16_t 
*portp
;               /* network order */ 
 156                 u_int32_t prog
;         /* call program */ 
 157                 u_int32_t vers
;         /* call version */ 
 158                 u_int32_t proto
;        /* call protocol */ 
 159                 u_int32_t port
;         /* call port (unused) */ 
 168         /* The portmapper port is fixed. */ 
 169         if (prog 
== PMAPPROG
) { 
 170                 *portp 
= htons(PMAPPORT
); 
 174         error 
= mbuf_gethdr(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
); 
 177         mbuf_setlen(m
, sizeof(*sdata
)); 
 178         mbuf_pkthdr_setlen(m
, sizeof(*sdata
)); 
 179         sdata 
= mbuf_data(m
); 
 181         /* Do the RPC to get it. */ 
 182         sdata
->prog 
= htonl(prog
); 
 183         sdata
->vers 
= htonl(vers
); 
 184         sdata
->proto 
= htonl(proto
); 
 187         sin
->sin_port 
= htons(PMAPPORT
); 
 188         error 
= krpc_call(sin
, SOCK_DGRAM
, PMAPPROG
, PMAPVERS
, PMAPPROC_GETPORT
, &m
, NULL
); 
 192         rdata 
= mbuf_data(m
); 
 193         *portp 
= rdata
->port
; 
 196                 error 
= EPROGUNAVAIL
; 
 203  * Do a remote procedure call (RPC) and wait for its reply. 
 204  * If from_p is non-null, then we are doing broadcast, and 
 205  * the address from whence the response came is saved there. 
 208 krpc_call(sa
, sotype
, prog
, vers
, func
, data
, from_p
) 
 209         struct sockaddr_in 
*sa
; 
 210         u_int sotype
, prog
, vers
, func
; 
 211         mbuf_t 
*data
;                   /* input/output */ 
 212         struct sockaddr_in 
*from_p
;     /* output */ 
 215         struct sockaddr_in 
*sin
; 
 216         mbuf_t m
, nam
, mhead
; 
 217         struct rpc_call 
*call
; 
 218         struct rpc_reply 
*reply
; 
 219         int error
, timo
, secs
, len
; 
 220         static u_int32_t xid 
= ~0xFF; 
 222         int maxpacket 
= 1<<16; 
 225          * Validate address family. 
 226          * Sorry, this is INET specific... 
 228         if (sa
->sin_family 
!= AF_INET
) 
 229                 return (EAFNOSUPPORT
); 
 231         /* Free at end if not null. */ 
 235          * Create socket and set its recieve timeout. 
 237         if ((error 
= sock_socket(AF_INET
, sotype
, 0, 0, 0, &so
))) 
 246                 if ((error 
= sock_setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)))) 
 252          * Enable broadcast if necessary. 
 255         if (from_p 
&& (sotype 
== SOCK_DGRAM
)) { 
 257                 if ((error 
= sock_setsockopt(so
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)))) 
 262          * Bind the local endpoint to a reserved port, 
 263          * because some NFS servers refuse requests from 
 264          * non-reserved (non-privileged) ports. 
 266         if ((error 
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &m
))) 
 269         bzero(sin
, sizeof(*sin
)); 
 270         mbuf_setlen(m
, sizeof(*sin
)); 
 271         sin
->sin_len 
= sizeof(*sin
); 
 272         sin
->sin_family 
= AF_INET
; 
 273         sin
->sin_addr
.s_addr 
= INADDR_ANY
; 
 274         tport 
= IPPORT_RESERVED
; 
 277                 sin
->sin_port 
= htons(tport
); 
 278                 error 
= sock_bind(so
, (struct sockaddr
*)sin
); 
 279         } while (error 
== EADDRINUSE 
&& 
 280                          tport 
> IPPORT_RESERVED 
/ 2); 
 284                 printf("bind failed\n"); 
 289          * Setup socket address for the server. 
 291         if ((error 
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_SONAME
, &nam
))) 
 293         sin 
= mbuf_data(nam
); 
 294         mbuf_setlen(nam
, sa
->sin_len
); 
 295         bcopy((caddr_t
)sa
, (caddr_t
)sin
, sa
->sin_len
); 
 297         if (sotype 
== SOCK_STREAM
) { 
 301                 error 
= sock_connect(so
, mbuf_data(nam
), MSG_DONTWAIT
); 
 302                 if (error 
&& (error 
!= EINPROGRESS
)) 
 304                 error 
= sock_connectwait(so
, &tv
); 
 306                         if (error 
== EINPROGRESS
) 
 308                         printf("krpc_call: error waiting for TCP socket connect: %d\n", error
); 
 314          * Prepend RPC message header. 
 319         if ((mbuf_flags(m
) & MBUF_PKTHDR
) == 0) 
 320                 panic("krpc_call: send data w/o pkthdr"); 
 321         if (mbuf_pkthdr_len(m
) < mbuf_len(m
)) 
 322                 panic("krpc_call: pkthdr.len not set"); 
 325         if (sotype 
== SOCK_STREAM
) 
 326                 len 
+= 4;  /* account for RPC record marker */ 
 328         if ((error 
= mbuf_prepend(&mhead
, len
, MBUF_WAITOK
))) 
 330         if ((error 
= mbuf_pkthdr_setrcvif(mhead
, NULL
))) 
 334          * Fill in the RPC header 
 336         if (sotype 
== SOCK_STREAM
) { 
 337                 /* first, fill in RPC record marker */ 
 338                 u_long 
*recmark 
= mbuf_data(mhead
); 
 339                 *recmark 
= htonl(0x80000000 | (mbuf_pkthdr_len(mhead
) - 4)); 
 340                 call 
= (struct rpc_call 
*)(recmark 
+ 1); 
 342                 call 
= mbuf_data(mhead
); 
 344         bzero((caddr_t
)call
, sizeof(*call
)); 
 346         call
->rp_xid 
= htonl(xid
); 
 347         /* call->rp_direction = 0; */ 
 348         call
->rp_rpcvers 
= htonl(2); 
 349         call
->rp_prog 
= htonl(prog
); 
 350         call
->rp_vers 
= htonl(vers
); 
 351         call
->rp_proc 
= htonl(func
); 
 352         /* call->rp_auth = 0; */ 
 353         /* call->rp_verf = 0; */ 
 356          * Send it, repeatedly, until a reply is received, 
 357          * but delay each re-send by an increasing amount. 
 358          * If the delay hits the maximum, start complaining. 
 364                 /* Send RPC request (or re-send). */ 
 365                 if ((error 
= mbuf_copym(mhead
, 0, MBUF_COPYALL
, MBUF_WAITOK
, &m
))) 
 367                 bzero(&msg
, sizeof(msg
)); 
 368                 if (sotype 
== SOCK_STREAM
) { 
 372                         msg
.msg_name 
= mbuf_data(nam
); 
 373                         msg
.msg_namelen 
= mbuf_len(nam
); 
 375                 error 
= sock_sendmbuf(so
, &msg
, m
, 0, 0); 
 377                         printf("krpc_call: sosend: %d\n", error
); 
 382                 /* Determine new timeout. */ 
 383                 if (timo 
< MAX_RESEND_DELAY
) 
 386                         printf("RPC timeout for server " IP_FORMAT 
"\n", 
 387                                 IP_LIST(&(sin
->sin_addr
.s_addr
))); 
 390                  * Wait for up to timo seconds for a reply. 
 391                  * The socket receive timeout was set to 1 second. 
 401                         if (sotype 
== SOCK_STREAM
) { 
 404                                 aio
.iov_base 
= (uintptr_t) &len
; 
 405                                 aio
.iov_len 
= sizeof(u_long
); 
 406                                 bzero(&msg
, sizeof(msg
)); 
 407                                 msg
.msg_iov 
= (struct iovec 
*) &aio
; 
 410                                    error 
= sock_receive(so
, &msg
, MSG_WAITALL
, &readlen
); 
 411                                    if ((error 
== EWOULDBLOCK
) && (--maxretries 
<= 0)) 
 413                                 } while (error 
== EWOULDBLOCK
); 
 414                                 if (!error 
&& readlen 
< aio
.iov_len
) { 
 415                                     /* only log a message if we got a partial word */ 
 417                                             printf("short receive (%d/%d) from server " IP_FORMAT 
"\n", 
 418                                                  readlen
, sizeof(u_long
), IP_LIST(&(sin
->sin_addr
.s_addr
))); 
 423                                 len 
= ntohl(len
) & ~0x80000000; 
 425                                  * This is SERIOUS! We are out of sync with the sender 
 426                                  * and forcing a disconnect/reconnect is all I can do. 
 428                                 if (len 
> maxpacket
) { 
 429                                     printf("impossible packet length (%d) from server %s\n", 
 430                                         len
, IP_LIST(&(sin
->sin_addr
.s_addr
))); 
 437                                     error 
= sock_receivembuf(so
, NULL
, &m
, MSG_WAITALL
, &readlen
); 
 438                                 } while (error 
== EWOULDBLOCK
); 
 440                                 if (!error 
&& (len 
> (int)readlen
)) { 
 441                                     printf("short receive (%d/%d) from server %s\n", 
 442                                         readlen
, len
, IP_LIST(&(sin
->sin_addr
.s_addr
))); 
 448                                 bzero(&msg
, sizeof(msg
)); 
 449                                 msg
.msg_name 
= from_p
; 
 450                                 msg
.msg_namelen 
= (from_p 
== NULL
) ? 0 : sizeof(*from_p
); 
 451                                 error 
= sock_receivembuf(so
, &msg
, &m
, 0, &readlen
); 
 454                         if (error 
== EWOULDBLOCK
) { 
 462                         /* Does the reply contain at least a header? */ 
 463                         if (len 
< MIN_REPLY_HDR
) 
 465                         if (mbuf_len(m
) < MIN_REPLY_HDR
) 
 467                         reply 
= mbuf_data(m
); 
 469                         /* Is it the right reply? */ 
 470                         if (reply
->rp_direction 
!= htonl(RPC_REPLY
)) 
 473                         if (reply
->rp_xid 
!= htonl(xid
)) 
 476                         /* Was RPC accepted? (authorization OK) */ 
 477                         if (reply
->rp_astatus 
!= 0) { 
 478                                 error 
= ntohl(reply
->rp_u
.rpu_errno
); 
 479                                 printf("rpc denied, error=%d\n", error
); 
 480                                 /* convert rpc error to errno */ 
 483                                         error 
= ERPCMISMATCH
; 
 492                         /* Did the call succeed? */ 
 493                         if ((error 
= ntohl(reply
->rp_u
.rpu_ok
.rp_rstatus
)) != 0) { 
 494                                 printf("rpc status=%d\n", error
); 
 495                                 /* convert rpc error to errno */ 
 497                                 case RPC_PROGUNAVAIL
: 
 498                                         error 
= EPROGUNAVAIL
; 
 500                                 case RPC_PROGMISMATCH
: 
 501                                         error 
= EPROGMISMATCH
; 
 503                                 case RPC_PROCUNAVAIL
: 
 504                                         error 
= EPROCUNAVAIL
; 
 516                         goto gotreply
;  /* break two levels */ 
 519         } /* forever send/receive */ 
 527          * Pull as much as we can into first mbuf, to make 
 528          * result buffer contiguous.  Note that if the entire 
 529          * result won't fit into one mbuf, you're out of luck. 
 530          * XXX - Should not rely on making the entire reply 
 531          * contiguous (fix callers instead). -gwr 
 534         if ((mbuf_flags(m
) & MBUF_PKTHDR
) == 0) 
 535                 panic("krpc_call: received pkt w/o header?"); 
 537         len 
= mbuf_pkthdr_len(m
); 
 538         if (sotype 
== SOCK_STREAM
) 
 539                 len 
-= 4;  /* the RPC record marker was read separately */ 
 540         if (mbuf_len(m
) < len
) { 
 541                 if ((error 
= mbuf_pullup(&m
, len
))) 
 543                 reply 
= mbuf_data(m
); 
 549         len 
= sizeof(*reply
); 
 550         if (reply
->rp_u
.rpu_ok
.rp_auth
.rp_atype 
!= 0) { 
 551                 len 
+= ntohl(reply
->rp_u
.rpu_ok
.rp_auth
.rp_alen
); 
 552                 len 
= (len 
+ 3) & ~3; /* XXX? */ 
 559         if (nam
) mbuf_freem(nam
); 
 560         if (mhead
) mbuf_freem(mhead
);