xref: /dflybsd-src/sys/vfs/nfs/nfs_mountrpc.c (revision b9a7a2bd9ad2f9f23579d9721b65ab0daecd7486)
10e8ff41aSMatthew Dillon /*
20e8ff41aSMatthew Dillon  * Copyright (c) 1995 Gordon Ross, Adam Glass
30e8ff41aSMatthew Dillon  * Copyright (c) 1992 Regents of the University of California.
40e8ff41aSMatthew Dillon  * All rights reserved.
50e8ff41aSMatthew Dillon  *
60e8ff41aSMatthew Dillon  * This software was developed by the Computer Systems Engineering group
70e8ff41aSMatthew Dillon  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
80e8ff41aSMatthew Dillon  * contributed to Berkeley.
90e8ff41aSMatthew Dillon  *
100e8ff41aSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
110e8ff41aSMatthew Dillon  * modification, are permitted provided that the following conditions
120e8ff41aSMatthew Dillon  * are met:
130e8ff41aSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
140e8ff41aSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
150e8ff41aSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
160e8ff41aSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
170e8ff41aSMatthew Dillon  *    documentation and/or other materials provided with the distribution.
180e8ff41aSMatthew Dillon  * 3. All advertising materials mentioning features or use of this software
190e8ff41aSMatthew Dillon  *    must display the following acknowledgement:
200e8ff41aSMatthew Dillon  *	This product includes software developed by the University of
210e8ff41aSMatthew Dillon  *	California, Lawrence Berkeley Laboratory and its contributors.
220e8ff41aSMatthew Dillon  * 4. Neither the name of the University nor the names of its contributors
230e8ff41aSMatthew Dillon  *    may be used to endorse or promote products derived from this software
240e8ff41aSMatthew Dillon  *    without specific prior written permission.
250e8ff41aSMatthew Dillon  *
260e8ff41aSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
270e8ff41aSMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
280e8ff41aSMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
290e8ff41aSMatthew Dillon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
300e8ff41aSMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
310e8ff41aSMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
320e8ff41aSMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
330e8ff41aSMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
340e8ff41aSMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
350e8ff41aSMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
360e8ff41aSMatthew Dillon  * SUCH DAMAGE.
370e8ff41aSMatthew Dillon  *
380e8ff41aSMatthew Dillon  * nfs/krpc_subr.c
390e8ff41aSMatthew Dillon  * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
400e8ff41aSMatthew Dillon  * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $
41086c1d7eSSascha Wildner  * $DragonFly: src/sys/vfs/nfs/nfs_mountrpc.c,v 1.2 2006/12/23 00:41:29 swildner Exp $
420e8ff41aSMatthew Dillon  */
430e8ff41aSMatthew Dillon /*
440e8ff41aSMatthew Dillon  * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain
450e8ff41aSMatthew Dillon  * the nfs root file handle for a NFS-based root mount point.  This module
460e8ff41aSMatthew Dillon  * is not used by normal operating code because the 'mount' command has a
470e8ff41aSMatthew Dillon  * far more sophisticated implementation.
480e8ff41aSMatthew Dillon  */
490e8ff41aSMatthew Dillon #include "opt_bootp.h"
500e8ff41aSMatthew Dillon #include "opt_nfsroot.h"
510e8ff41aSMatthew Dillon 
520e8ff41aSMatthew Dillon #if defined(BOOTP) || defined(NFS_ROOT)
530e8ff41aSMatthew Dillon 
540e8ff41aSMatthew Dillon #include <sys/param.h>
550e8ff41aSMatthew Dillon #include <sys/systm.h>
560e8ff41aSMatthew Dillon #include <sys/kernel.h>
570e8ff41aSMatthew Dillon #include <sys/sockio.h>
580e8ff41aSMatthew Dillon #include <sys/proc.h>
590e8ff41aSMatthew Dillon #include <sys/malloc.h>
600e8ff41aSMatthew Dillon #include <sys/mount.h>
610e8ff41aSMatthew Dillon #include <sys/mbuf.h>
620e8ff41aSMatthew Dillon #include <sys/socket.h>
630e8ff41aSMatthew Dillon #include <sys/socketvar.h>
640e8ff41aSMatthew Dillon #include <sys/sysctl.h>
650e8ff41aSMatthew Dillon #include <sys/uio.h>
660e8ff41aSMatthew Dillon 
670e8ff41aSMatthew Dillon #include <net/if.h>
680e8ff41aSMatthew Dillon #include <net/route.h>
690e8ff41aSMatthew Dillon 
700e8ff41aSMatthew Dillon #include <netinet/in.h>
710e8ff41aSMatthew Dillon #include <net/if_types.h>
720e8ff41aSMatthew Dillon #include <net/if_dl.h>
730e8ff41aSMatthew Dillon 
740e8ff41aSMatthew Dillon #include "rpcv2.h"
750e8ff41aSMatthew Dillon #include "nfsproto.h"
760e8ff41aSMatthew Dillon #include "nfs.h"
770e8ff41aSMatthew Dillon #include "nfsdiskless.h"
780e8ff41aSMatthew Dillon #include "krpc.h"
790e8ff41aSMatthew Dillon #include "xdr_subs.h"
800e8ff41aSMatthew Dillon #include "nfsmountrpc.h"
810e8ff41aSMatthew Dillon 
820e8ff41aSMatthew Dillon /*
830e8ff41aSMatthew Dillon  * What is the longest we will wait before re-sending a request?
840e8ff41aSMatthew Dillon  * Note this is also the frequency of "RPC timeout" messages.
850e8ff41aSMatthew Dillon  * The re-send loop count sup linearly to this maximum, so the
860e8ff41aSMatthew Dillon  * first complaint will happen after (1+2+3+4+5)=15 seconds.
870e8ff41aSMatthew Dillon  */
880e8ff41aSMatthew Dillon 
890e8ff41aSMatthew Dillon static int getdec(char **ptr);
900e8ff41aSMatthew Dillon static char *substr(char *a,char *b);
910e8ff41aSMatthew Dillon static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
920e8ff41aSMatthew Dillon static int xdr_int_decode(struct mbuf **ptr, int *iptr);
930e8ff41aSMatthew Dillon 
940e8ff41aSMatthew Dillon void
95*b9a7a2bdSMatthew Dillon nfs_mountopts(struct nfs_args *args, char *p)
960e8ff41aSMatthew Dillon {
970e8ff41aSMatthew Dillon 	char *tmp;
980e8ff41aSMatthew Dillon 
990e8ff41aSMatthew Dillon 	args->version = NFS_ARGSVERSION;
1000e8ff41aSMatthew Dillon 	args->rsize = 8192;
1010e8ff41aSMatthew Dillon 	args->wsize = 8192;
1020e8ff41aSMatthew Dillon 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
103*b9a7a2bdSMatthew Dillon 	args->sotype = SOCK_STREAM;
1040e8ff41aSMatthew Dillon 	if (p == NULL)
1050e8ff41aSMatthew Dillon 		return;
1060e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "rsize=")))
1070e8ff41aSMatthew Dillon 		args->rsize = getdec(&tmp);
1080e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "wsize=")))
1090e8ff41aSMatthew Dillon 		args->wsize = getdec(&tmp);
1100e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "intr")))
1110e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_INT;
1120e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "soft")))
1130e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_SOFT;
1140e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "noconn")))
1150e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_NOCONN;
116*b9a7a2bdSMatthew Dillon 	if ((tmp = (char *)substr(p, "udp")))
117*b9a7a2bdSMatthew Dillon 		args->sotype = SOCK_DGRAM;
1180e8ff41aSMatthew Dillon }
1190e8ff41aSMatthew Dillon 
1200e8ff41aSMatthew Dillon /*
1210e8ff41aSMatthew Dillon  * RPC: mountd/mount
1220e8ff41aSMatthew Dillon  * Given a server pathname, get an NFS file handle.
1230e8ff41aSMatthew Dillon  * Also, sets sin->sin_port to the NFS service port.
1240e8ff41aSMatthew Dillon  */
1250e8ff41aSMatthew Dillon int
1260e8ff41aSMatthew Dillon md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
1270e8ff41aSMatthew Dillon 	 char *path,
1280e8ff41aSMatthew Dillon 	 u_char *fhp,
1290e8ff41aSMatthew Dillon 	 int *fhsizep,
1300e8ff41aSMatthew Dillon 	 struct nfs_args *args,
1310e8ff41aSMatthew Dillon 	 struct thread *td)
1320e8ff41aSMatthew Dillon {
1330e8ff41aSMatthew Dillon 	struct mbuf *m;
1340e8ff41aSMatthew Dillon 	int error;
1350e8ff41aSMatthew Dillon 	int authunixok;
1360e8ff41aSMatthew Dillon 	int authcount;
1370e8ff41aSMatthew Dillon 	int authver;
1380e8ff41aSMatthew Dillon 
1390e8ff41aSMatthew Dillon 	/* First try NFS v3 */
1400e8ff41aSMatthew Dillon 	/* Get port number for MOUNTD. */
1410e8ff41aSMatthew Dillon 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1420e8ff41aSMatthew Dillon 			     &mdsin->sin_port, td);
1430e8ff41aSMatthew Dillon 	if (error == 0) {
1440e8ff41aSMatthew Dillon 		m = xdr_string_encode(path, strlen(path));
1450e8ff41aSMatthew Dillon 
1460e8ff41aSMatthew Dillon 		/* Do RPC to mountd. */
1470e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1480e8ff41aSMatthew Dillon 				  RPCMNT_MOUNT, &m, NULL, td);
1490e8ff41aSMatthew Dillon 	}
1500e8ff41aSMatthew Dillon 	if (error == 0) {
1510e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_NFSV3;
1520e8ff41aSMatthew Dillon 	} else {
1530e8ff41aSMatthew Dillon 		/* Fallback to NFS v2 */
1540e8ff41aSMatthew Dillon 
1550e8ff41aSMatthew Dillon 		/* Get port number for MOUNTD. */
1560e8ff41aSMatthew Dillon 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1570e8ff41aSMatthew Dillon 				     &mdsin->sin_port, td);
1580e8ff41aSMatthew Dillon 		if (error != 0)
1590e8ff41aSMatthew Dillon 			return error;
1600e8ff41aSMatthew Dillon 
1610e8ff41aSMatthew Dillon 		m = xdr_string_encode(path, strlen(path));
1620e8ff41aSMatthew Dillon 
1630e8ff41aSMatthew Dillon 		/* Do RPC to mountd. */
1640e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1650e8ff41aSMatthew Dillon 				  RPCMNT_MOUNT, &m, NULL, td);
1660e8ff41aSMatthew Dillon 		if (error != 0)
1670e8ff41aSMatthew Dillon 			return error;	/* message already freed */
168*b9a7a2bdSMatthew Dillon 		args->flags &= ~NFSMNT_NFSV3;
1690e8ff41aSMatthew Dillon 	}
1700e8ff41aSMatthew Dillon 
1710e8ff41aSMatthew Dillon 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
1720e8ff41aSMatthew Dillon 		goto bad;
1730e8ff41aSMatthew Dillon 
1740e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1750e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, fhsizep) != 0 ||
1760e8ff41aSMatthew Dillon 		    *fhsizep > NFSX_V3FHMAX ||
1770e8ff41aSMatthew Dillon 		    *fhsizep <= 0)
1780e8ff41aSMatthew Dillon 			goto bad;
1790e8ff41aSMatthew Dillon 	} else
1800e8ff41aSMatthew Dillon 		*fhsizep = NFSX_V2FH;
1810e8ff41aSMatthew Dillon 
1820e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1830e8ff41aSMatthew Dillon 		goto bad;
1840e8ff41aSMatthew Dillon 
1850e8ff41aSMatthew Dillon 	if (args->flags & NFSMNT_NFSV3) {
1860e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, &authcount) != 0)
1870e8ff41aSMatthew Dillon 			goto bad;
1880e8ff41aSMatthew Dillon 		authunixok = 0;
1890e8ff41aSMatthew Dillon 		if (authcount < 0 || authcount > 100)
1900e8ff41aSMatthew Dillon 			goto bad;
1910e8ff41aSMatthew Dillon 		while (authcount > 0) {
1920e8ff41aSMatthew Dillon 			if (xdr_int_decode(&m, &authver) != 0)
1930e8ff41aSMatthew Dillon 				goto bad;
1940e8ff41aSMatthew Dillon 			if (authver == RPCAUTH_UNIX)
1950e8ff41aSMatthew Dillon 				authunixok = 1;
1960e8ff41aSMatthew Dillon 			authcount--;
1970e8ff41aSMatthew Dillon 		}
1980e8ff41aSMatthew Dillon 		if (authunixok == 0)
1990e8ff41aSMatthew Dillon 			goto bad;
2000e8ff41aSMatthew Dillon 	}
2010e8ff41aSMatthew Dillon 
2020e8ff41aSMatthew Dillon 	/* Set port number for NFS use. */
2030e8ff41aSMatthew Dillon 	error = krpc_portmap(mdsin, NFS_PROG,
2040e8ff41aSMatthew Dillon 			     (args->flags &
2050e8ff41aSMatthew Dillon 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
2060e8ff41aSMatthew Dillon 			     &mdsin->sin_port, td);
2070e8ff41aSMatthew Dillon 
2080e8ff41aSMatthew Dillon 	goto out;
2090e8ff41aSMatthew Dillon 
2100e8ff41aSMatthew Dillon bad:
2110e8ff41aSMatthew Dillon 	error = EBADRPC;
2120e8ff41aSMatthew Dillon 
2130e8ff41aSMatthew Dillon out:
2140e8ff41aSMatthew Dillon 	m_freem(m);
2150e8ff41aSMatthew Dillon 	return error;
2160e8ff41aSMatthew Dillon }
2170e8ff41aSMatthew Dillon 
2180e8ff41aSMatthew Dillon int
2190e8ff41aSMatthew Dillon md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
2200e8ff41aSMatthew Dillon 	       char *path,
2210e8ff41aSMatthew Dillon 	       u_char *fhp,
2220e8ff41aSMatthew Dillon 	       int *fhsizep,
2230e8ff41aSMatthew Dillon 	       struct nfs_args *args,
2240e8ff41aSMatthew Dillon 	       struct thread *td)
2250e8ff41aSMatthew Dillon {
2260e8ff41aSMatthew Dillon 	struct mbuf *m;
2270e8ff41aSMatthew Dillon 	int error;
2280e8ff41aSMatthew Dillon 	int size = -1;
2290e8ff41aSMatthew Dillon 	int attribs_present;
2300e8ff41aSMatthew Dillon 	int status;
2310e8ff41aSMatthew Dillon 	union {
2320e8ff41aSMatthew Dillon 		u_int32_t v2[17];
2330e8ff41aSMatthew Dillon 		u_int32_t v3[21];
2340e8ff41aSMatthew Dillon 	} fattribs;
2350e8ff41aSMatthew Dillon 
2360e8ff41aSMatthew Dillon 	m = m_get(MB_WAIT,MT_DATA);
2370e8ff41aSMatthew Dillon 	if (m == NULL)
2380e8ff41aSMatthew Dillon 	  	return ENOBUFS;
2390e8ff41aSMatthew Dillon 
2400e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2410e8ff41aSMatthew Dillon 		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
2420e8ff41aSMatthew Dillon 		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
2430e8ff41aSMatthew Dillon 		m->m_len = *fhsizep + sizeof(u_int32_t);
2440e8ff41aSMatthew Dillon 	} else {
2450e8ff41aSMatthew Dillon 		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
2460e8ff41aSMatthew Dillon 		m->m_len = NFSX_V2FH;
2470e8ff41aSMatthew Dillon 	}
2480e8ff41aSMatthew Dillon 
2490e8ff41aSMatthew Dillon 	m->m_next = xdr_string_encode(path, strlen(path));
2500e8ff41aSMatthew Dillon 	if (m->m_next == NULL) {
2510e8ff41aSMatthew Dillon 		error = ENOBUFS;
2520e8ff41aSMatthew Dillon 		goto out;
2530e8ff41aSMatthew Dillon 	}
2540e8ff41aSMatthew Dillon 
2550e8ff41aSMatthew Dillon 	/* Do RPC to nfsd. */
2560e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0)
2570e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
2580e8ff41aSMatthew Dillon 				  NFSPROC_LOOKUP, &m, NULL, td);
2590e8ff41aSMatthew Dillon 	else
2600e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
2610e8ff41aSMatthew Dillon 				  NFSV2PROC_LOOKUP, &m, NULL, td);
2620e8ff41aSMatthew Dillon 	if (error != 0)
2630e8ff41aSMatthew Dillon 		return error;	/* message already freed */
2640e8ff41aSMatthew Dillon 
2650e8ff41aSMatthew Dillon 	if (xdr_int_decode(&m, &status) != 0)
2660e8ff41aSMatthew Dillon 		goto bad;
2670e8ff41aSMatthew Dillon 	if (status != 0) {
2680e8ff41aSMatthew Dillon 		error = ENOENT;
2690e8ff41aSMatthew Dillon 		goto out;
2700e8ff41aSMatthew Dillon 	}
2710e8ff41aSMatthew Dillon 
2720e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2730e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, fhsizep) != 0 ||
2740e8ff41aSMatthew Dillon 		    *fhsizep > NFSX_V3FHMAX ||
2750e8ff41aSMatthew Dillon 		    *fhsizep <= 0)
2760e8ff41aSMatthew Dillon 			goto bad;
2770e8ff41aSMatthew Dillon 	} else
2780e8ff41aSMatthew Dillon 		*fhsizep = NFSX_V2FH;
2790e8ff41aSMatthew Dillon 
2800e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
2810e8ff41aSMatthew Dillon 		goto bad;
2820e8ff41aSMatthew Dillon 
2830e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2840e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, &attribs_present) != 0)
2850e8ff41aSMatthew Dillon 			goto bad;
2860e8ff41aSMatthew Dillon 		if (attribs_present != 0) {
2870e8ff41aSMatthew Dillon 			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
2880e8ff41aSMatthew Dillon 					      sizeof(u_int32_t) * 21) != 0)
2890e8ff41aSMatthew Dillon 				goto bad;
2900e8ff41aSMatthew Dillon 			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
2910e8ff41aSMatthew Dillon 		}
2920e8ff41aSMatthew Dillon 	} else {
2930e8ff41aSMatthew Dillon 		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
2940e8ff41aSMatthew Dillon 				      sizeof(u_int32_t) * 17) != 0)
2950e8ff41aSMatthew Dillon 			goto bad;
2960e8ff41aSMatthew Dillon 		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
2970e8ff41aSMatthew Dillon 	}
2980e8ff41aSMatthew Dillon 
2990e8ff41aSMatthew Dillon 	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
3000e8ff41aSMatthew Dillon 		nfsv3_diskless.swap_nblks = size / 1024;
301086c1d7eSSascha Wildner 		kprintf("md_lookup_swap: Swap size is %d KB\n",
3020e8ff41aSMatthew Dillon 		       nfsv3_diskless.swap_nblks);
3030e8ff41aSMatthew Dillon 	}
3040e8ff41aSMatthew Dillon 
3050e8ff41aSMatthew Dillon 	goto out;
3060e8ff41aSMatthew Dillon 
3070e8ff41aSMatthew Dillon bad:
3080e8ff41aSMatthew Dillon 	error = EBADRPC;
3090e8ff41aSMatthew Dillon 
3100e8ff41aSMatthew Dillon out:
3110e8ff41aSMatthew Dillon 	m_freem(m);
3120e8ff41aSMatthew Dillon 	return error;
3130e8ff41aSMatthew Dillon }
3140e8ff41aSMatthew Dillon 
3150e8ff41aSMatthew Dillon int
3160e8ff41aSMatthew Dillon setfs(struct sockaddr_in *addr, char *path, char *p)
3170e8ff41aSMatthew Dillon {
3180e8ff41aSMatthew Dillon 	unsigned int ip;
3190e8ff41aSMatthew Dillon 	int val;
3200e8ff41aSMatthew Dillon 
3210e8ff41aSMatthew Dillon 	ip = 0;
3220e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3230e8ff41aSMatthew Dillon 		return 0;
3240e8ff41aSMatthew Dillon 	ip = val << 24;
3250e8ff41aSMatthew Dillon 	if (*p != '.')
3260e8ff41aSMatthew Dillon 		return 0;
3270e8ff41aSMatthew Dillon 	p++;
3280e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3290e8ff41aSMatthew Dillon 		return 0;
3300e8ff41aSMatthew Dillon 	ip |= (val << 16);
3310e8ff41aSMatthew Dillon 	if (*p != '.')
3320e8ff41aSMatthew Dillon 		return 0;
3330e8ff41aSMatthew Dillon 	p++;
3340e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3350e8ff41aSMatthew Dillon 		return 0;
3360e8ff41aSMatthew Dillon 	ip |= (val << 8);
3370e8ff41aSMatthew Dillon 	if (*p != '.')
3380e8ff41aSMatthew Dillon 		return 0;
3390e8ff41aSMatthew Dillon 	p++;
3400e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3410e8ff41aSMatthew Dillon 		return 0;
3420e8ff41aSMatthew Dillon 	ip |= val;
3430e8ff41aSMatthew Dillon 	if (*p != ':')
3440e8ff41aSMatthew Dillon 		return 0;
3450e8ff41aSMatthew Dillon 	p++;
3460e8ff41aSMatthew Dillon 
3470e8ff41aSMatthew Dillon 	addr->sin_addr.s_addr = htonl(ip);
3480e8ff41aSMatthew Dillon 	addr->sin_len = sizeof(struct sockaddr_in);
3490e8ff41aSMatthew Dillon 	addr->sin_family = AF_INET;
3500e8ff41aSMatthew Dillon 
3510e8ff41aSMatthew Dillon 	strncpy(path, p, MNAMELEN - 1);
3520e8ff41aSMatthew Dillon 	return 1;
3530e8ff41aSMatthew Dillon }
3540e8ff41aSMatthew Dillon 
3550e8ff41aSMatthew Dillon static int
3560e8ff41aSMatthew Dillon getdec(char **ptr)
3570e8ff41aSMatthew Dillon {
3580e8ff41aSMatthew Dillon 	char *p;
3590e8ff41aSMatthew Dillon 	int ret;
3600e8ff41aSMatthew Dillon 
3610e8ff41aSMatthew Dillon 	p = *ptr;
3620e8ff41aSMatthew Dillon 	ret = 0;
3630e8ff41aSMatthew Dillon 	if ((*p < '0') || (*p > '9'))
3640e8ff41aSMatthew Dillon 		return -1;
3650e8ff41aSMatthew Dillon 	while ((*p >= '0') && (*p <= '9')) {
3660e8ff41aSMatthew Dillon 		ret = ret * 10 + (*p - '0');
3670e8ff41aSMatthew Dillon 		p++;
3680e8ff41aSMatthew Dillon 	}
3690e8ff41aSMatthew Dillon 	*ptr = p;
3700e8ff41aSMatthew Dillon 	return ret;
3710e8ff41aSMatthew Dillon }
3720e8ff41aSMatthew Dillon 
3730e8ff41aSMatthew Dillon static char *
3740e8ff41aSMatthew Dillon substr(char *a, char *b)
3750e8ff41aSMatthew Dillon {
3760e8ff41aSMatthew Dillon 	char *loc1;
3770e8ff41aSMatthew Dillon 	char *loc2;
3780e8ff41aSMatthew Dillon 
3790e8ff41aSMatthew Dillon         while (*a != '\0') {
3800e8ff41aSMatthew Dillon                 loc1 = a;
3810e8ff41aSMatthew Dillon                 loc2 = b;
3820e8ff41aSMatthew Dillon                 while (*loc1 == *loc2++) {
3830e8ff41aSMatthew Dillon                         if (*loc1 == '\0')
3840e8ff41aSMatthew Dillon 				return 0;
3850e8ff41aSMatthew Dillon                         loc1++;
3860e8ff41aSMatthew Dillon                         if (*loc2 == '\0')
3870e8ff41aSMatthew Dillon 				return loc1;
3880e8ff41aSMatthew Dillon                 }
3890e8ff41aSMatthew Dillon 		a++;
3900e8ff41aSMatthew Dillon         }
3910e8ff41aSMatthew Dillon         return 0;
3920e8ff41aSMatthew Dillon }
3930e8ff41aSMatthew Dillon 
3940e8ff41aSMatthew Dillon static int
3950e8ff41aSMatthew Dillon xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
3960e8ff41aSMatthew Dillon {
3970e8ff41aSMatthew Dillon 	struct mbuf *m;
3980e8ff41aSMatthew Dillon 	int alignedlen;
3990e8ff41aSMatthew Dillon 
4000e8ff41aSMatthew Dillon 	m = *mptr;
4010e8ff41aSMatthew Dillon 	alignedlen = ( len + 3 ) & ~3;
4020e8ff41aSMatthew Dillon 
4030e8ff41aSMatthew Dillon 	if (m->m_len < alignedlen) {
4040e8ff41aSMatthew Dillon 		m = m_pullup(m, alignedlen);
4050e8ff41aSMatthew Dillon 		if (m == NULL) {
4060e8ff41aSMatthew Dillon 			*mptr = NULL;
4070e8ff41aSMatthew Dillon 			return EBADRPC;
4080e8ff41aSMatthew Dillon 		}
4090e8ff41aSMatthew Dillon 	}
4100e8ff41aSMatthew Dillon 	bcopy(mtod(m, u_char *), buf, len);
4110e8ff41aSMatthew Dillon 	m_adj(m, alignedlen);
4120e8ff41aSMatthew Dillon 	*mptr = m;
4130e8ff41aSMatthew Dillon 	return 0;
4140e8ff41aSMatthew Dillon }
4150e8ff41aSMatthew Dillon 
4160e8ff41aSMatthew Dillon static int
4170e8ff41aSMatthew Dillon xdr_int_decode(struct mbuf **mptr, int *iptr)
4180e8ff41aSMatthew Dillon {
4190e8ff41aSMatthew Dillon 	u_int32_t i;
4200e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
4210e8ff41aSMatthew Dillon 		return EBADRPC;
4220e8ff41aSMatthew Dillon 	*iptr = fxdr_unsigned(u_int32_t, i);
4230e8ff41aSMatthew Dillon 	return 0;
4240e8ff41aSMatthew Dillon }
4250e8ff41aSMatthew Dillon 
4260e8ff41aSMatthew Dillon #endif	/* BOOTP && NFS_ROOT */
4270e8ff41aSMatthew Dillon 
428