]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_boot.c
232cdc1782869505488e979b3ca7cec38e4f9d39
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
25 * Copyright (c) 1994 Adam Glass, Gordon Ross
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
61 * 14-March-97 Dieter Siegmund (dieter@next.com)
62 * - Use BOOTP instead of RARP to get the IP address at boot time
64 * 23-May-97 Umesh Vaishampayan (umeshv@apple.com)
65 * - Added the ability to mount "/private" separately.
67 * 30-May-97 Dieter Siegmund (dieter@next.com)
68 * - Clear out the ireq structure before using it to prevent
69 * our sending using a bogus source IP address, we should use
70 * an IP address of all zeroes
71 * - Right after BOOTP, get the correct netmask using AUTONETMASK
72 * 18-Jul-97 Dieter Siegmund (dieter@apple.com)
73 * - we can't restrict the netmask until we have a default route,
74 * removed AUTONETMASK call (ifdef'd out)
75 * 5-Aug-97 Dieter Siegmund (dieter@apple.com)
76 * - use the default route from the bpwhoami call, enabled autonetmask
78 * 19-Feb-1999 Dieter Siegmund (dieter@apple.com)
79 * - use new BOOTP routine to get the subnet mask and router
80 * and stop using SIOCAUTOADDR
81 * - don't bother mounting private separately if it's not
82 * specified or not required because they are substrings of
83 * one another ie. root=host:/A and private=host:/A/private
84 * - allow the root path to be specified in the boot variable
85 * "rp" (AKA "rootpath")
86 * 19-Jul-1999 Dieter Siegmund (dieter@apple.com)
87 * - replaced big automatic arrays with MALLOC'd data
90 #include <sys/param.h>
91 #include <sys/systm.h>
92 #include <sys/kernel.h>
94 #include <sys/ioctl.h>
96 #include <sys/mount_internal.h>
97 #include <sys/kpi_mbuf.h>
99 #include <sys/malloc.h>
100 #include <sys/socket.h>
103 #include <net/if_dl.h>
104 #include <net/if_types.h>
105 #include <net/route.h>
107 #include <netinet/in.h>
108 #include <netinet/if_ether.h>
110 #include <nfs/rpcv2.h>
111 #include <nfs/nfsproto.h>
113 #include <nfs/nfsdiskless.h>
114 #include <nfs/krpc.h>
116 #include <pexpert/pexpert.h>
120 #include <libkern/libkern.h>
125 int nfs_boot_init(struct nfs_diskless
*nd
, proc_t procp
)
127 panic("nfs_boot_init: no ether");
130 int nfs_boot_getfh(struct nfs_diskless
*nd
, proc_t procp
, int v3
, int sotype
)
132 panic("nfs_boot_getfh: no ether");
138 * Support for NFS diskless booting, specifically getting information
139 * about where to boot from, what pathnames, etc.
141 * This implememtation uses RARP and the bootparam RPC.
142 * We are forced to implement RPC anyway (to get file handles)
143 * so we might as well take advantage of it for bootparam too.
145 * The diskless boot sequence goes as follows:
146 * (1) Use RARP to get our interface address
147 * (2) Use RPC/bootparam/whoami to get our hostname,
148 * our IP address, and the server's IP address.
149 * (3) Use RPC/bootparam/getfile to get the root path
150 * (4) Use RPC/mountd to get the root file handle
151 * (5) Use RPC/bootparam/getfile to get the swap path
152 * (6) Use RPC/mountd to get the swap file handle
154 * (This happens to be the way Sun does it too.)
158 static int bp_whoami(struct sockaddr_in
*bpsin
,
159 struct in_addr
*my_ip
, struct in_addr
*gw_ip
);
160 static int bp_getfile(struct sockaddr_in
*bpsin
, const char *key
,
161 struct sockaddr_in
*mdsin
, char *servname
, char *path
);
164 static int md_mount(struct sockaddr_in
*mdsin
, char *path
, int v3
, int sotype
,
165 u_char
*fhp
, u_long
*fhlenp
);
168 static int get_file_handle(struct nfs_dlmount
*ndmntp
);
171 #define IP_FORMAT "%d.%d.%d.%d"
172 #define IP_CH(ip) ((u_char *)ip)
173 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
176 netboot_iaddr(struct in_addr
* iaddr_p
);
179 netboot_rootpath(struct in_addr
* server_ip
,
180 char * name
, int name_len
,
181 char * path
, int path_len
);
184 * Called with an empty nfs_diskless struct to be filled in.
187 nfs_boot_init(struct nfs_diskless
*nd
, __unused proc_t procp
)
189 struct sockaddr_in bp_sin
;
190 boolean_t do_bpwhoami
= TRUE
;
191 boolean_t do_bpgetfile
= TRUE
;
193 struct in_addr my_ip
;
194 struct sockaddr_in
* sin_p
;
196 /* make sure mbuf constants are set up */
200 /* by this point, networking must already have been configured */
201 if (netboot_iaddr(&my_ip
) == FALSE
) {
202 printf("nfs_boot: networking is not initialized\n");
207 /* get the root path information */
208 MALLOC_ZONE(nd
->nd_root
.ndm_path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
209 if (!nd
->nd_root
.ndm_path
) {
210 printf("nfs_boot: can't allocate root path buffer\n");
214 sin_p
= &nd
->nd_root
.ndm_saddr
;
215 bzero((caddr_t
)sin_p
, sizeof(*sin_p
));
216 sin_p
->sin_len
= sizeof(*sin_p
);
217 sin_p
->sin_family
= AF_INET
;
218 if (netboot_rootpath(&sin_p
->sin_addr
, nd
->nd_root
.ndm_host
,
219 sizeof(nd
->nd_root
.ndm_host
),
220 nd
->nd_root
.ndm_path
, MAXPATHLEN
) == TRUE
) {
221 do_bpgetfile
= FALSE
;
224 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
227 struct in_addr router
;
229 * Get client name and gateway address.
230 * RPC: bootparam/whoami
231 * Use the old broadcast address for the WHOAMI
232 * call because we do not yet know our netmask.
233 * The server address returned by the WHOAMI call
234 * is used for all subsequent booptaram RPCs.
236 bzero((caddr_t
)&bp_sin
, sizeof(bp_sin
));
237 bp_sin
.sin_len
= sizeof(bp_sin
);
238 bp_sin
.sin_family
= AF_INET
;
239 bp_sin
.sin_addr
.s_addr
= INADDR_BROADCAST
;
240 hostnamelen
= MAXHOSTNAMELEN
;
242 error
= bp_whoami(&bp_sin
, &my_ip
, &router
);
244 printf("nfs_boot: bootparam whoami, error=%d", error
);
247 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT
"\n",
248 IP_LIST(&bp_sin
.sin_addr
));
249 printf("nfs_boot: hostname %s\n", hostname
);
252 error
= bp_getfile(&bp_sin
, "root", &nd
->nd_root
.ndm_saddr
,
253 nd
->nd_root
.ndm_host
, nd
->nd_root
.ndm_path
);
255 printf("nfs_boot: bootparam get root: %d\n", error
);
260 #if !defined(NO_MOUNT_PRIVATE)
261 if (do_bpgetfile
) { /* get private path */
262 MALLOC_ZONE(nd
->nd_private
.ndm_path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
263 if (!nd
->nd_private
.ndm_path
) {
264 printf("nfs_boot: can't allocate private path buffer\n");
268 error
= bp_getfile(&bp_sin
, "private",
269 &nd
->nd_private
.ndm_saddr
,
270 nd
->nd_private
.ndm_host
,
271 nd
->nd_private
.ndm_path
);
273 char * check_path
= NULL
;
275 MALLOC_ZONE(check_path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
277 printf("nfs_boot: can't allocate check_path buffer\n");
281 snprintf(check_path
, MAXPATHLEN
, "%s/private", nd
->nd_root
.ndm_path
);
282 if ((nd
->nd_root
.ndm_saddr
.sin_addr
.s_addr
283 == nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
)
284 && (strcmp(check_path
, nd
->nd_private
.ndm_path
) == 0)) {
285 /* private path is prefix of root path, don't mount */
286 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
288 FREE_ZONE(check_path
, MAXPATHLEN
, M_NAMEI
);
291 /* private key not defined, don't mount */
292 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
298 #endif /* NO_MOUNT_PRIVATE */
304 * Called with a partially initialized nfs_diskless struct
305 * with file handles to be filled in.
308 nfs_boot_getfh(struct nfs_diskless
*nd
, __unused proc_t procp
, int v3
, int sotype
)
312 nd
->nd_root
.ndm_nfsv3
= v3
;
313 nd
->nd_root
.ndm_sotype
= sotype
;
314 error
= get_file_handle(&nd
->nd_root
);
316 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n",
321 #if !defined(NO_MOUNT_PRIVATE)
322 if (nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
) {
323 /* get private file handle */
324 nd
->nd_private
.ndm_nfsv3
= v3
;
325 nd
->nd_private
.ndm_sotype
= sotype
;
326 error
= get_file_handle(&nd
->nd_private
);
328 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
333 #endif /* NO_MOUNT_PRIVATE */
339 get_file_handle(ndmntp
)
340 struct nfs_dlmount
*ndmntp
;
342 char *sp
, *dp
, *endp
;
346 * Get file handle for "key" (root or swap)
347 * using RPC to mountd/mount
349 error
= md_mount(&ndmntp
->ndm_saddr
, ndmntp
->ndm_path
, ndmntp
->ndm_nfsv3
,
350 ndmntp
->ndm_sotype
, ndmntp
->ndm_fh
, &ndmntp
->ndm_fhlen
);
354 /* Construct remote path (for getmntinfo(3)) */
355 dp
= ndmntp
->ndm_host
;
356 endp
= dp
+ MNAMELEN
- 1;
359 for (sp
= ndmntp
->ndm_path
; *sp
&& dp
< endp
;)
368 * Get an mbuf with the given length, and
369 * initialize the pkthdr length field.
372 mbuf_get_with_len(int msg_len
, mbuf_t
*m
)
375 error
= mbuf_gethdr(MBUF_WAITOK
, MBUF_TYPE_DATA
, m
);
378 if (msg_len
> mbuf_maxlen(*m
)) {
379 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, m
);
384 if (msg_len
> mbuf_maxlen(*m
))
385 panic("nfs_boot: msg_len > MCLBYTES");
387 mbuf_setlen(*m
, msg_len
);
388 mbuf_pkthdr_setlen(*m
, msg_len
);
394 * String representation for RPC.
397 u_long len
; /* length without null or padding */
398 u_char data
[4]; /* data (longer, of course) */
399 /* data is padded to a long-word boundary */
401 /* Compute space used given string length. */
402 #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
405 * Inet address in RPC messages
406 * (Note, really four longs, NOT chars. Blech.)
415 * RPC: bootparam/whoami
416 * Given client IP address, get:
417 * client name (hostname)
418 * domain name (domainname)
421 * The hostname and domainname are set here for convenience.
423 * Note - bpsin is initialized to the broadcast address,
424 * and will be replaced with the bootparam server address
425 * after this call is complete. Have to use PMAP_PROC_CALL
426 * to make sure we get responses only from a servers that
427 * know about us (don't want to broadcast a getport call).
430 bp_whoami(bpsin
, my_ip
, gw_ip
)
431 struct sockaddr_in
*bpsin
;
432 struct in_addr
*my_ip
;
433 struct in_addr
*gw_ip
;
435 /* RPC structures for PMAPPROC_CALLIT */
441 struct bp_inaddr call_ia
;
444 struct rpc_string
*str
;
445 struct bp_inaddr
*bia
;
447 struct sockaddr_in sin
;
454 * Get message buffer of sufficient size.
456 msg_len
= sizeof(*call
);
457 error
= mbuf_get_with_len(msg_len
, &m
);
462 * Build request message for PMAPPROC_CALLIT.
465 call
->call_prog
= htonl(BOOTPARAM_PROG
);
466 call
->call_vers
= htonl(BOOTPARAM_VERS
);
467 call
->call_proc
= htonl(BOOTPARAM_WHOAMI
);
468 call
->call_arglen
= htonl(sizeof(struct bp_inaddr
));
470 /* client IP address */
471 call
->call_ia
.atype
= htonl(1);
473 lp
= call
->call_ia
.addr
;
474 *lp
++ = htonl(*p
); p
++;
475 *lp
++ = htonl(*p
); p
++;
476 *lp
++ = htonl(*p
); p
++;
477 *lp
++ = htonl(*p
); p
++;
479 /* RPC: portmap/callit */
480 bpsin
->sin_port
= htons(PMAPPORT
);
482 error
= krpc_call(bpsin
, SOCK_DGRAM
, PMAPPROG
, PMAPVERS
, PMAPPROC_CALLIT
, &m
, &sin
);
487 * Parse result message.
489 msg_len
= mbuf_len(m
);
492 /* bootparam server port (also grab from address). */
493 if (msg_len
< (int)sizeof(*lp
))
495 msg_len
-= sizeof(*lp
);
496 bpsin
->sin_port
= htons((short)ntohl(*lp
++));
497 bpsin
->sin_addr
.s_addr
= sin
.sin_addr
.s_addr
;
499 /* length of encapsulated results */
500 if (msg_len
< (ntohl(*lp
) + (int)sizeof(*lp
)))
502 msg_len
= ntohl(*lp
++);
506 if (msg_len
< (int)sizeof(*str
))
508 str
= (struct rpc_string
*)p
;
509 cn_len
= ntohl(str
->len
);
510 if (msg_len
< cn_len
)
512 if (cn_len
>= MAXHOSTNAMELEN
)
514 bcopy(str
->data
, hostname
, cn_len
);
515 hostname
[cn_len
] = '\0';
516 hostnamelen
= cn_len
;
517 p
+= RPC_STR_SIZE(cn_len
);
518 msg_len
-= RPC_STR_SIZE(cn_len
);
521 if (msg_len
< (int)sizeof(*str
))
523 str
= (struct rpc_string
*)p
;
524 dn_len
= ntohl(str
->len
);
525 if (msg_len
< dn_len
)
527 if (dn_len
>= MAXHOSTNAMELEN
)
529 bcopy(str
->data
, domainname
, dn_len
);
530 domainname
[dn_len
] = '\0';
531 domainnamelen
= dn_len
;
532 p
+= RPC_STR_SIZE(dn_len
);
533 msg_len
-= RPC_STR_SIZE(dn_len
);
535 /* gateway address */
536 if (msg_len
< (int)sizeof(*bia
))
538 bia
= (struct bp_inaddr
*)p
;
539 if (bia
->atype
!= htonl(1))
542 *p
++ = ntohl(bia
->addr
[0]);
543 *p
++ = ntohl(bia
->addr
[1]);
544 *p
++ = ntohl(bia
->addr
[2]);
545 *p
++ = ntohl(bia
->addr
[3]);
549 printf("nfs_boot: bootparam_whoami: bad reply\n");
559 * RPC: bootparam/getfile
560 * Given client name and file "key", get:
566 bp_getfile(bpsin
, key
, md_sin
, serv_name
, pathname
)
567 struct sockaddr_in
*bpsin
;
569 struct sockaddr_in
*md_sin
;
573 struct rpc_string
*str
;
575 struct bp_inaddr
*bia
;
576 struct sockaddr_in
*sin
;
579 int cn_len
, key_len
, sn_len
, path_len
;
582 * Get message buffer of sufficient size.
584 cn_len
= hostnamelen
;
585 key_len
= strlen(key
);
587 msg_len
+= RPC_STR_SIZE(cn_len
);
588 msg_len
+= RPC_STR_SIZE(key_len
);
589 error
= mbuf_get_with_len(msg_len
, &m
);
594 * Build request message.
598 /* client name (hostname) */
599 str
= (struct rpc_string
*)p
;
600 str
->len
= htonl(cn_len
);
601 bcopy(hostname
, str
->data
, cn_len
);
602 p
+= RPC_STR_SIZE(cn_len
);
603 /* key name (root or swap) */
604 str
= (struct rpc_string
*)p
;
605 str
->len
= htonl(key_len
);
606 bcopy(key
, str
->data
, key_len
);
608 /* RPC: bootparam/getfile */
609 error
= krpc_call(bpsin
, SOCK_DGRAM
, BOOTPARAM_PROG
, BOOTPARAM_VERS
,
610 BOOTPARAM_GETFILE
, &m
, NULL
);
615 * Parse result message.
618 msg_len
= mbuf_len(m
);
621 if (msg_len
< (int)sizeof(*str
))
623 str
= (struct rpc_string
*)p
;
624 sn_len
= ntohl(str
->len
);
625 if (msg_len
< sn_len
)
627 if (sn_len
>= MNAMELEN
)
629 bcopy(str
->data
, serv_name
, sn_len
);
630 serv_name
[sn_len
] = '\0';
631 p
+= RPC_STR_SIZE(sn_len
);
632 msg_len
-= RPC_STR_SIZE(sn_len
);
634 /* server IP address (mountd) */
635 if (msg_len
< (int)sizeof(*bia
))
637 bia
= (struct bp_inaddr
*)p
;
638 if (bia
->atype
!= htonl(1))
641 bzero((caddr_t
)sin
, sizeof(*sin
));
642 sin
->sin_len
= sizeof(*sin
);
643 sin
->sin_family
= AF_INET
;
644 q
= (u_char
*) &sin
->sin_addr
;
645 *q
++ = ntohl(bia
->addr
[0]);
646 *q
++ = ntohl(bia
->addr
[1]);
647 *q
++ = ntohl(bia
->addr
[2]);
648 *q
++ = ntohl(bia
->addr
[3]);
650 msg_len
-= sizeof(*bia
);
652 /* server pathname */
653 if (msg_len
< (int)sizeof(*str
))
655 str
= (struct rpc_string
*)p
;
656 path_len
= ntohl(str
->len
);
657 if (msg_len
< path_len
)
659 if (path_len
>= MAXPATHLEN
)
661 bcopy(str
->data
, pathname
, path_len
);
662 pathname
[path_len
] = '\0';
666 printf("nfs_boot: bootparam_getfile: bad reply\n");
677 * Given a server pathname, get an NFS file handle.
678 * Also, sets sin->sin_port to the NFS service port.
681 md_mount(mdsin
, path
, v3
, sotype
, fhp
, fhlenp
)
682 struct sockaddr_in
*mdsin
; /* mountd server address */
689 /* The RPC structures */
690 struct rpc_string
*str
;
693 u_char data
[NFSX_V3FHMAX
+ sizeof(u_long
)];
696 int error
, mlen
, slen
;
697 int mntversion
= v3
? RPCMNT_VER3
: RPCMNT_VER1
;
698 int proto
= (sotype
== SOCK_STREAM
) ? IPPROTO_TCP
: IPPROTO_UDP
;
699 in_port_t mntport
, nfsport
;
701 /* Get port number for MOUNTD. */
702 error
= krpc_portmap(mdsin
, RPCPROG_MNT
, mntversion
, proto
, &mntport
);
706 /* Get port number for NFS use. */
707 /* (If NFS/proto unavailable, don't bother with the mount call) */
708 error
= krpc_portmap(mdsin
, NFS_PROG
, v3
? NFS_VER3
: NFS_VER2
, proto
, &nfsport
);
712 /* Set port number for MOUNTD */
713 mdsin
->sin_port
= mntport
;
716 mlen
= RPC_STR_SIZE(slen
);
718 error
= mbuf_get_with_len(mlen
, &m
);
722 str
->len
= htonl(slen
);
723 bcopy(path
, str
->data
, slen
);
725 /* Do RPC to mountd. */
726 error
= krpc_call(mdsin
, sotype
, RPCPROG_MNT
, mntversion
, RPCMNT_MOUNT
, &m
, NULL
);
728 return error
; /* message already freed */
731 * the reply must be long enough to hold the errno plus either of:
733 * + a v3 filehandle length + a v3 filehandle
736 if (mlen
< (int)sizeof(u_long
))
738 rdata
= mbuf_data(m
);
739 error
= ntohl(rdata
->errno
);
745 if (mlen
< (int)sizeof(u_long
)*2)
747 fhlen
= ntohl(*(u_long
*)rdata
->data
);
748 fh
= rdata
->data
+ sizeof(u_long
);
749 if (mlen
< (int)(sizeof(u_long
)*2 + fhlen
))
751 bcopy(fh
, fhp
, fhlen
);
754 if (mlen
< ((int)sizeof(u_long
) + NFSX_V2FH
))
756 bcopy(rdata
->data
, fhp
, NFSX_V2FH
);
760 /* Set port number for NFS use. */
761 mdsin
->sin_port
= nfsport
;