|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1994 Adam Glass, Gordon Ross
28: * All rights reserved.
29: *
30: * The NEXTSTEP Software License Agreement specifies the terms
31: * and conditions for redistribution.
32: *
33: * History:
34: *
35: * 14-March-97 Dieter Siegmund ([email protected])
36: * Use BOOTP instead of RARP to get the IP address at boot time
37: *
38: * 23-May-97 Umesh Vaishampayan ([email protected])
39: * Added the ability to mount "/private" separately.
40: *
41: * 30-May-97 Dieter Siegmund ([email protected])
42: * - Clear out the ireq structure before using it to prevent
43: * our sending using a bogus source IP address, we should use
44: * an IP address of all zeroes
45: * - Right after BOOTP, get the correct netmask using AUTONETMASK
46: * 18-Jul-97 Dieter Siegmund ([email protected])
47: * - we can't restrict the netmask until we have a default route,
48: * removed AUTONETMASK call (ifdef'd out)
49: * 5-Aug-97 Dieter Siegmund ([email protected])
50: * - use the default route from the bpwhoami call, enabled autonetmask
51: * again
52: */
53:
54: #include <sys/param.h>
55: #include <sys/systm.h>
56: #include <sys/kernel.h>
57: #include <sys/conf.h>
58: #include <sys/ioctl.h>
59: #include <sys/proc.h>
60: #include <sys/mount.h>
61: #include <sys/mbuf.h>
62: #include <sys/socket.h>
63: #include <sys/reboot.h>
64:
65: #include <net/if.h>
66: #include <net/route.h>
67:
68: #include <netinet/in.h>
69: #include <netinet/if_ether.h>
70:
71: #include <nfs/rpcv2.h>
72: #include <nfs/nfsproto.h>
73: #include <nfs/nfs.h>
74: #include <nfs/nfsdiskless.h>
75: #include <nfs/krpc.h>
76:
77: #include "ether.h"
78:
79: #if NETHER == 0
80:
81: int nfs_boot_init(nd, procp)
82: struct nfs_diskless *nd;
83: struct proc *procp;
84: {
85: panic("nfs_boot_init: no ether");
86: }
87:
88: #else /* NETHER */
89:
90: /*
91: * Support for NFS diskless booting, specifically getting information
92: * about where to boot from, what pathnames, etc.
93: *
94: * This implememtation uses RARP and the bootparam RPC.
95: * We are forced to implement RPC anyway (to get file handles)
96: * so we might as well take advantage of it for bootparam too.
97: *
98: * The diskless boot sequence goes as follows:
99: * (1) Use RARP to get our interface address
100: * (2) Use RPC/bootparam/whoami to get our hostname,
101: * our IP address, and the server's IP address.
102: * (3) Use RPC/bootparam/getfile to get the root path
103: * (4) Use RPC/mountd to get the root file handle
104: * (5) Use RPC/bootparam/getfile to get the swap path
105: * (6) Use RPC/mountd to get the swap file handle
106: *
107: * (This happens to be the way Sun does it too.)
108: */
109:
110: /* bootparam RPC */
111: static int bp_whoami __P((struct sockaddr_in *bpsin,
112: struct in_addr *my_ip, struct in_addr *gw_ip));
113: static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
114: struct sockaddr_in *mdsin, char *servname, char *path));
115:
116: /* mountd RPC */
117: static int md_mount __P((struct sockaddr_in *mdsin, char *path,
118: u_char *fh));
119:
120: /* other helpers */
121: static void get_path_and_handle __P((struct sockaddr_in *bpsin,
122: char *key, struct nfs_dlmount *ndmntp));
123:
124: char *nfsbootdevname;
125:
126: /*
127: * Called with an empty nfs_diskless struct to be filled in.
128: */
129: int
130: nfs_boot_init(nd, procp)
131: struct nfs_diskless *nd;
132: struct proc *procp;
133: {
134: struct ifreq ireq;
135: struct in_addr my_ip, gw_ip;
136: struct sockaddr_in bp_sin;
137: struct sockaddr_in *sin;
138: struct ifnet *ifp;
139: struct socket *so;
140: int error;
141:
142: /* clear out the request structure */
143: bzero(&ireq, sizeof(ireq));
144:
145: /*
146: * Find an interface, rarp for its ip address, stuff it, the
147: * implied broadcast addr, and netmask into a nfs_diskless struct.
148: *
149: * This was moved here from nfs_vfsops.c because this procedure
150: * would be quite different if someone decides to write (i.e.) a
151: * BOOTP version of this file (might not use RARP, etc.)
152: */
153:
154: /*
155: * Find a network interface.
156: */
157: if (nfsbootdevname)
158: ifp = ifunit(nfsbootdevname);
159: else
160: for (ifp = ifnet; ifp; ifp = ifp->if_next)
161: if ((ifp->if_flags &
162: (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
163: break;
164: if (ifp == NULL)
165: panic("nfs_boot: no suitable interface");
166: sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
167: printf("nfs_boot: using network interface '%s'\n", ireq.ifr_name);
168:
169: /*
170: * Bring up the interface.
171: */
172: if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
173: panic("nfs_boot: socreate, error=%d", error);
174: ireq.ifr_flags = IFF_UP;
175: error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
176: if (error)
177: panic("nfs_boot: SIFFLAGS, error=%d", error);
178:
179: #if NeXT
180: /*
181: * Do BOOTP to get the interface address
182: */
183: {
184: int message = 0;
185:
186: ireq.ifr_addr.sa_family = AF_INET;
187: while ((error = ifioctl(so, SIOCAUTOADDR, (caddr_t)&ireq, procp))) {
188: if (error == ETIMEDOUT) {
189: if (!message) {
190: printf("nfs_boot: BOOTP timed out, still trying...\n");
191: message++;
192: }
193: }
194: else {
195: printf("nfs_boot: autoaddr failed, error = %d\n", error);
196: panic("nfs_boot: SIOCAUTOADDR failed");
197: }
198: }
199:
200: sin = (struct sockaddr_in *)&(ireq.ifr_addr);
201: my_ip = sin->sin_addr;
202: }
203: printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
204:
205: /*
206: * get the netmask
207: * XXX - if BOOTP returns a netmask, we should use that instead
208: * of icmp (DWS)
209: */
210: if ((error = ifioctl(so, SIOCAUTONETMASK, (caddr_t)&ireq, procp))) {
211: printf("nfs_boot: autonetmask failed, error = %d\n", error);
212: }
213:
214: #else NeXT
215: /*
216: * Do RARP for the interface address.
217: */
218: if ((error = revarpwhoami(&my_ip, ifp)) != 0)
219: panic("revarp failed, error=%d", error);
220: printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
221:
222: /*
223: * Do enough of ifconfig(8) so that the chosen interface
224: * can talk to the servers. (just set the address)
225: */
226: sin = (struct sockaddr_in *)&ireq.ifr_addr;
227: bzero((caddr_t)sin, sizeof(*sin));
228: sin->sin_len = sizeof(*sin);
229: sin->sin_family = AF_INET;
230: sin->sin_addr.s_addr = my_ip.s_addr;
231: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
232: if (error)
233: panic("nfs_boot: set if addr, error=%d", error);
234: #endif NeXT
235:
236: soclose(so);
237:
238: /*
239: * Get client name and gateway address.
240: * RPC: bootparam/whoami
241: * Use the old broadcast address for the WHOAMI
242: * call because we do not yet know our netmask.
243: * The server address returned by the WHOAMI call
244: * is used for all subsequent booptaram RPCs.
245: */
246: bzero((caddr_t)&bp_sin, sizeof(bp_sin));
247: bp_sin.sin_len = sizeof(bp_sin);
248: bp_sin.sin_family = AF_INET;
249: bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
250: hostnamelen = MAXHOSTNAMELEN;
251:
252: /* this returns gateway IP address */
253: error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
254: if (error) {
255: printf("nfs_boot: bootparam whoami, error=%d", error);
256: panic("nfs_boot: bootparam whoami\n");
257: }
258: printf("nfs_boot: server_addr=0x%x\n",
259: ntohl(bp_sin.sin_addr.s_addr));
260: printf("nfs_boot: hostname=%s\n", hostname);
261: #define NFS_BOOT_GATEWAY 1
262: #ifdef NFS_BOOT_GATEWAY
263: /*
264: * XXX - This code is conditionally compiled only because
265: * many bootparam servers (in particular, SunOS 4.1.3)
266: * always set the gateway address to their own address.
267: * The bootparam server is not necessarily the gateway.
268: * We could just believe the server, and at worst you would
269: * need to delete the incorrect default route before adding
270: * the correct one, but for simplicity, ignore the gateway.
271: * If your server is OK, you can turn on this option.
272: *
273: * If the gateway address is set, add a default route.
274: * (The mountd RPCs may go across a gateway.)
275: */
276: if (gw_ip.s_addr) {
277: struct sockaddr dst, gw, mask;
278: /* Destination: (default) */
279: bzero((caddr_t)&dst, sizeof(dst));
280: dst.sa_len = sizeof(dst);
281: dst.sa_family = AF_INET;
282: /* Gateway: */
283: bzero((caddr_t)&gw, sizeof(gw));
284: sin = (struct sockaddr_in *)&gw;
285: sin->sin_len = sizeof(gw);
286: sin->sin_family = AF_INET;
287: sin->sin_addr.s_addr = gw_ip.s_addr;
288: /* Mask: (zero length) */
289: bzero(&mask, sizeof(mask));
290:
291: printf("nfs_boot: gateway=0x%x\n", ntohl(gw_ip.s_addr));
292: /* add, dest, gw, mask, flags, 0 */
293: error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
294: &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
295: if (error)
296: printf("nfs_boot: add route, error=%d\n", error);
297: }
298: #endif
299:
300: get_path_and_handle(&bp_sin, "root", &nd->nd_root);
301: #if !defined(NO_MOUNT_PRIVATE)
302: get_path_and_handle(&bp_sin, "private", &nd->nd_private);
303: #endif /* NO_MOUNT_PRIVATE */
304:
305: return (0);
306: }
307:
308: static void
309: get_path_and_handle(bpsin, key, ndmntp)
310: struct sockaddr_in *bpsin; /* bootparam server */
311: char *key; /* root or swap */
312: struct nfs_dlmount *ndmntp; /* output */
313: {
314: char pathname[MAXPATHLEN];
315: char *sp, *dp, *endp;
316: int error;
317:
318: /*
319: * Get server:pathname for "key" (root or swap)
320: * using RPC to bootparam/getfile
321: */
322: error = bp_getfile(bpsin, key, &ndmntp->ndm_saddr,
323: ndmntp->ndm_host, pathname);
324: if (error) {
325: printf("nfs_boot: bootparam get %s: %d\n", key, error);
326: panic("nfs_boot: bootparam get %s: %d", key, error);
327: }
328: /*
329: * Get file handle for "key" (root or swap)
330: * using RPC to mountd/mount
331: */
332: error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh);
333: if (error)
334: panic("nfs_boot: mountd %s, error=%d", key, error);
335:
336: /* Construct remote path (for getmntinfo(3)) */
337: dp = ndmntp->ndm_host;
338: endp = dp + MNAMELEN - 1;
339: dp += strlen(dp);
340: *dp++ = ':';
341: for (sp = pathname; *sp && dp < endp;)
342: *dp++ = *sp++;
343: *dp = '\0';
344:
345: }
346:
347:
348: /*
349: * Get an mbuf with the given length, and
350: * initialize the pkthdr length field.
351: */
352: static struct mbuf *
353: m_get_len(int msg_len)
354: {
355: struct mbuf *m;
356: m = m_gethdr(M_WAIT, MT_DATA);
357: if (m == NULL)
358: return NULL;
359: if (msg_len > MHLEN) {
360: if (msg_len > MCLBYTES)
361: panic("nfs_boot: msg_len > MCLBYTES");
362: MCLGET(m, M_WAIT);
363: if (m == NULL)
364: return NULL;
365: }
366: m->m_len = msg_len;
367: m->m_pkthdr.len = m->m_len;
368: return (m);
369: }
370:
371:
372: /*
373: * String representation for RPC.
374: */
375: struct rpc_string {
376: u_long len; /* length without null or padding */
377: u_char data[4]; /* data (longer, of course) */
378: /* data is padded to a long-word boundary */
379: };
380: /* Compute space used given string length. */
381: #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
382:
383: /*
384: * Inet address in RPC messages
385: * (Note, really four longs, NOT chars. Blech.)
386: */
387: struct bp_inaddr {
388: u_long atype;
389: long addr[4];
390: };
391:
392:
393: /*
394: * RPC: bootparam/whoami
395: * Given client IP address, get:
396: * client name (hostname)
397: * domain name (domainname)
398: * gateway address
399: *
400: * The hostname and domainname are set here for convenience.
401: *
402: * Note - bpsin is initialized to the broadcast address,
403: * and will be replaced with the bootparam server address
404: * after this call is complete. Have to use PMAP_PROC_CALL
405: * to make sure we get responses only from a servers that
406: * know about us (don't want to broadcast a getport call).
407: */
408: static int
409: bp_whoami(bpsin, my_ip, gw_ip)
410: struct sockaddr_in *bpsin;
411: struct in_addr *my_ip;
412: struct in_addr *gw_ip;
413: {
414: /* RPC structures for PMAPPROC_CALLIT */
415: struct whoami_call {
416: u_long call_prog;
417: u_long call_vers;
418: u_long call_proc;
419: u_long call_arglen;
420: struct bp_inaddr call_ia;
421: } *call;
422:
423: struct rpc_string *str;
424: struct bp_inaddr *bia;
425: struct mbuf *m, *from;
426: struct sockaddr_in *sin;
427: int error, msg_len;
428: int cn_len, dn_len;
429: u_char *p;
430: long *lp;
431:
432: /*
433: * Get message buffer of sufficient size.
434: */
435: msg_len = sizeof(*call);
436: m = m_get_len(msg_len);
437: if (m == NULL)
438: return ENOBUFS;
439:
440: /*
441: * Build request message for PMAPPROC_CALLIT.
442: */
443: call = mtod(m, struct whoami_call *);
444: call->call_prog = htonl(BOOTPARAM_PROG);
445: call->call_vers = htonl(BOOTPARAM_VERS);
446: call->call_proc = htonl(BOOTPARAM_WHOAMI);
447: call->call_arglen = htonl(sizeof(struct bp_inaddr));
448:
449: /* client IP address */
450: call->call_ia.atype = htonl(1);
451: p = (u_char*)my_ip;
452: lp = call->call_ia.addr;
453: *lp++ = htonl(*p); p++;
454: *lp++ = htonl(*p); p++;
455: *lp++ = htonl(*p); p++;
456: *lp++ = htonl(*p); p++;
457:
458: /* RPC: portmap/callit */
459: bpsin->sin_port = htons(PMAPPORT);
460: from = NULL;
461: error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
462: PMAPPROC_CALLIT, &m, &from);
463: if (error)
464: return error;
465:
466: /*
467: * Parse result message.
468: */
469: msg_len = m->m_len;
470: lp = mtod(m, long *);
471:
472: /* bootparam server port (also grab from address). */
473: if (msg_len < sizeof(*lp))
474: goto bad;
475: msg_len -= sizeof(*lp);
476: bpsin->sin_port = htons((short)ntohl(*lp++));
477: sin = mtod(from, struct sockaddr_in *);
478: bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
479:
480: /* length of encapsulated results */
481: if (msg_len < (ntohl(*lp) + sizeof(*lp)))
482: goto bad;
483: msg_len = ntohl(*lp++);
484: p = (char*)lp;
485:
486: /* client name */
487: if (msg_len < sizeof(*str))
488: goto bad;
489: str = (struct rpc_string *)p;
490: cn_len = ntohl(str->len);
491: if (msg_len < cn_len)
492: goto bad;
493: if (cn_len >= MAXHOSTNAMELEN)
494: goto bad;
495: bcopy(str->data, hostname, cn_len);
496: hostname[cn_len] = '\0';
497: hostnamelen = cn_len;
498: p += RPC_STR_SIZE(cn_len);
499: msg_len -= RPC_STR_SIZE(cn_len);
500:
501: /* domain name */
502: if (msg_len < sizeof(*str))
503: goto bad;
504: str = (struct rpc_string *)p;
505: dn_len = ntohl(str->len);
506: if (msg_len < dn_len)
507: goto bad;
508: if (dn_len >= MAXHOSTNAMELEN)
509: goto bad;
510: bcopy(str->data, domainname, dn_len);
511: domainname[dn_len] = '\0';
512: domainnamelen = dn_len;
513: p += RPC_STR_SIZE(dn_len);
514: msg_len -= RPC_STR_SIZE(dn_len);
515:
516: /* gateway address */
517: if (msg_len < sizeof(*bia))
518: goto bad;
519: bia = (struct bp_inaddr *)p;
520: if (bia->atype != htonl(1))
521: goto bad;
522: p = (u_char*)gw_ip;
523: *p++ = ntohl(bia->addr[0]);
524: *p++ = ntohl(bia->addr[1]);
525: *p++ = ntohl(bia->addr[2]);
526: *p++ = ntohl(bia->addr[3]);
527: goto out;
528:
529: bad:
530: printf("nfs_boot: bootparam_whoami: bad reply\n");
531: error = EBADRPC;
532:
533: out:
534: if (from)
535: m_freem(from);
536: m_freem(m);
537: return(error);
538: }
539:
540:
541: /*
542: * RPC: bootparam/getfile
543: * Given client name and file "key", get:
544: * server name
545: * server IP address
546: * server pathname
547: */
548: static int
549: bp_getfile(bpsin, key, md_sin, serv_name, pathname)
550: struct sockaddr_in *bpsin;
551: char *key;
552: struct sockaddr_in *md_sin;
553: char *serv_name;
554: char *pathname;
555: {
556: struct rpc_string *str;
557: struct mbuf *m;
558: struct bp_inaddr *bia;
559: struct sockaddr_in *sin;
560: u_char *p, *q;
561: int error, msg_len;
562: int cn_len, key_len, sn_len, path_len;
563:
564: /*
565: * Get message buffer of sufficient size.
566: */
567: cn_len = hostnamelen;
568: key_len = strlen(key);
569: msg_len = 0;
570: msg_len += RPC_STR_SIZE(cn_len);
571: msg_len += RPC_STR_SIZE(key_len);
572: m = m_get_len(msg_len);
573: if (m == NULL)
574: return ENOBUFS;
575:
576: /*
577: * Build request message.
578: */
579: p = mtod(m, u_char *);
580: bzero(p, msg_len);
581: /* client name (hostname) */
582: str = (struct rpc_string *)p;
583: str->len = htonl(cn_len);
584: bcopy(hostname, str->data, cn_len);
585: p += RPC_STR_SIZE(cn_len);
586: /* key name (root or swap) */
587: str = (struct rpc_string *)p;
588: str->len = htonl(key_len);
589: bcopy(key, str->data, key_len);
590:
591: /* RPC: bootparam/getfile */
592: error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
593: BOOTPARAM_GETFILE, &m, NULL);
594: if (error)
595: return error;
596:
597: /*
598: * Parse result message.
599: */
600: p = mtod(m, u_char *);
601: msg_len = m->m_len;
602:
603: /* server name */
604: if (msg_len < sizeof(*str))
605: goto bad;
606: str = (struct rpc_string *)p;
607: sn_len = ntohl(str->len);
608: if (msg_len < sn_len)
609: goto bad;
610: if (sn_len >= MNAMELEN)
611: goto bad;
612: bcopy(str->data, serv_name, sn_len);
613: serv_name[sn_len] = '\0';
614: p += RPC_STR_SIZE(sn_len);
615: msg_len -= RPC_STR_SIZE(sn_len);
616:
617: /* server IP address (mountd) */
618: if (msg_len < sizeof(*bia))
619: goto bad;
620: bia = (struct bp_inaddr *)p;
621: if (bia->atype != htonl(1))
622: goto bad;
623: sin = md_sin;
624: bzero((caddr_t)sin, sizeof(*sin));
625: sin->sin_len = sizeof(*sin);
626: sin->sin_family = AF_INET;
627: q = (u_char*) &sin->sin_addr;
628: *q++ = ntohl(bia->addr[0]);
629: *q++ = ntohl(bia->addr[1]);
630: *q++ = ntohl(bia->addr[2]);
631: *q++ = ntohl(bia->addr[3]);
632: p += sizeof(*bia);
633: msg_len -= sizeof(*bia);
634:
635: /* server pathname */
636: if (msg_len < sizeof(*str))
637: goto bad;
638: str = (struct rpc_string *)p;
639: path_len = ntohl(str->len);
640: if (msg_len < path_len)
641: goto bad;
642: if (path_len >= MAXPATHLEN)
643: goto bad;
644: bcopy(str->data, pathname, path_len);
645: pathname[path_len] = '\0';
646: goto out;
647:
648: bad:
649: printf("nfs_boot: bootparam_getfile: bad reply\n");
650: error = EBADRPC;
651:
652: out:
653: m_freem(m);
654: return(0);
655: }
656:
657:
658: /*
659: * RPC: mountd/mount
660: * Given a server pathname, get an NFS file handle.
661: * Also, sets sin->sin_port to the NFS service port.
662: */
663: static int
664: md_mount(mdsin, path, fhp)
665: struct sockaddr_in *mdsin; /* mountd server address */
666: char *path;
667: u_char *fhp;
668: {
669: /* The RPC structures */
670: struct rpc_string *str;
671: struct rdata {
672: u_long errno;
673: u_char fh[NFSX_V2FH];
674: } *rdata;
675: struct mbuf *m;
676: int error, mlen, slen;
677:
678: /* Get port number for MOUNTD. */
679: error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
680: &mdsin->sin_port);
681: if (error) return error;
682:
683: slen = strlen(path);
684: mlen = RPC_STR_SIZE(slen);
685:
686: m = m_get_len(mlen);
687: if (m == NULL)
688: return ENOBUFS;
689: str = mtod(m, struct rpc_string *);
690: str->len = htonl(slen);
691: bcopy(path, str->data, slen);
692:
693: /* Do RPC to mountd. */
694: error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
695: RPCMNT_MOUNT, &m, NULL);
696: if (error)
697: return error; /* message already freed */
698:
699: mlen = m->m_len;
700: if (mlen < sizeof(*rdata))
701: goto bad;
702: rdata = mtod(m, struct rdata *);
703: error = ntohl(rdata->errno);
704: if (error)
705: goto bad;
706: bcopy(rdata->fh, fhp, NFSX_V2FH);
707:
708: /* Set port number for NFS use. */
709: error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2,
710: &mdsin->sin_port);
711: goto out;
712:
713: bad:
714: error = EBADRPC;
715:
716: out:
717: m_freem(m);
718: return error;
719: }
720:
721: #endif /* NETHER */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.