xref: /dflybsd-src/sys/vfs/nfs/nfs_mountrpc.c (revision 086c1d7e3403a6c5a87926be7d71ac24d8ef7af4)
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 $
41*086c1d7eSSascha 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 extern struct nfsv3_diskless nfsv3_diskless;
900e8ff41aSMatthew Dillon 
910e8ff41aSMatthew Dillon static int getdec(char **ptr);
920e8ff41aSMatthew Dillon static char *substr(char *a,char *b);
930e8ff41aSMatthew Dillon static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
940e8ff41aSMatthew Dillon static int xdr_int_decode(struct mbuf **ptr, int *iptr);
950e8ff41aSMatthew Dillon 
960e8ff41aSMatthew Dillon void
970e8ff41aSMatthew Dillon mountopts(struct nfs_args *args, char *p)
980e8ff41aSMatthew Dillon {
990e8ff41aSMatthew Dillon 	char *tmp;
1000e8ff41aSMatthew Dillon 
1010e8ff41aSMatthew Dillon 	args->version = NFS_ARGSVERSION;
1020e8ff41aSMatthew Dillon 	args->rsize = 8192;
1030e8ff41aSMatthew Dillon 	args->wsize = 8192;
1040e8ff41aSMatthew Dillon 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
1050e8ff41aSMatthew Dillon 	args->sotype = SOCK_DGRAM;
1060e8ff41aSMatthew Dillon 	if (p == NULL)
1070e8ff41aSMatthew Dillon 		return;
1080e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "rsize=")))
1090e8ff41aSMatthew Dillon 		args->rsize = getdec(&tmp);
1100e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "wsize=")))
1110e8ff41aSMatthew Dillon 		args->wsize = getdec(&tmp);
1120e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "intr")))
1130e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_INT;
1140e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "soft")))
1150e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_SOFT;
1160e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "noconn")))
1170e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_NOCONN;
1180e8ff41aSMatthew Dillon 	if ((tmp = (char *)substr(p, "tcp")))
1190e8ff41aSMatthew Dillon 		args->sotype = SOCK_STREAM;
1200e8ff41aSMatthew Dillon }
1210e8ff41aSMatthew Dillon 
1220e8ff41aSMatthew Dillon /*
1230e8ff41aSMatthew Dillon  * RPC: mountd/mount
1240e8ff41aSMatthew Dillon  * Given a server pathname, get an NFS file handle.
1250e8ff41aSMatthew Dillon  * Also, sets sin->sin_port to the NFS service port.
1260e8ff41aSMatthew Dillon  */
1270e8ff41aSMatthew Dillon int
1280e8ff41aSMatthew Dillon md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
1290e8ff41aSMatthew Dillon 	 char *path,
1300e8ff41aSMatthew Dillon 	 u_char *fhp,
1310e8ff41aSMatthew Dillon 	 int *fhsizep,
1320e8ff41aSMatthew Dillon 	 struct nfs_args *args,
1330e8ff41aSMatthew Dillon 	 struct thread *td)
1340e8ff41aSMatthew Dillon {
1350e8ff41aSMatthew Dillon 	struct mbuf *m;
1360e8ff41aSMatthew Dillon 	int error;
1370e8ff41aSMatthew Dillon 	int authunixok;
1380e8ff41aSMatthew Dillon 	int authcount;
1390e8ff41aSMatthew Dillon 	int authver;
1400e8ff41aSMatthew Dillon 
1410e8ff41aSMatthew Dillon #ifdef BOOTP_NFSV3
1420e8ff41aSMatthew Dillon 	/* First try NFS v3 */
1430e8ff41aSMatthew Dillon 	/* Get port number for MOUNTD. */
1440e8ff41aSMatthew Dillon 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1450e8ff41aSMatthew Dillon 			     &mdsin->sin_port, td);
1460e8ff41aSMatthew Dillon 	if (error == 0) {
1470e8ff41aSMatthew Dillon 		m = xdr_string_encode(path, strlen(path));
1480e8ff41aSMatthew Dillon 
1490e8ff41aSMatthew Dillon 		/* Do RPC to mountd. */
1500e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1510e8ff41aSMatthew Dillon 				  RPCMNT_MOUNT, &m, NULL, td);
1520e8ff41aSMatthew Dillon 	}
1530e8ff41aSMatthew Dillon 	if (error == 0) {
1540e8ff41aSMatthew Dillon 		args->flags |= NFSMNT_NFSV3;
1550e8ff41aSMatthew Dillon 	} else {
1560e8ff41aSMatthew Dillon #endif
1570e8ff41aSMatthew Dillon 		/* Fallback to NFS v2 */
1580e8ff41aSMatthew Dillon 
1590e8ff41aSMatthew Dillon 		/* Get port number for MOUNTD. */
1600e8ff41aSMatthew Dillon 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1610e8ff41aSMatthew Dillon 				     &mdsin->sin_port, td);
1620e8ff41aSMatthew Dillon 		if (error != 0)
1630e8ff41aSMatthew Dillon 			return error;
1640e8ff41aSMatthew Dillon 
1650e8ff41aSMatthew Dillon 		m = xdr_string_encode(path, strlen(path));
1660e8ff41aSMatthew Dillon 
1670e8ff41aSMatthew Dillon 		/* Do RPC to mountd. */
1680e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1690e8ff41aSMatthew Dillon 				  RPCMNT_MOUNT, &m, NULL, td);
1700e8ff41aSMatthew Dillon 		if (error != 0)
1710e8ff41aSMatthew Dillon 			return error;	/* message already freed */
1720e8ff41aSMatthew Dillon 
1730e8ff41aSMatthew Dillon #ifdef BOOTP_NFSV3
1740e8ff41aSMatthew Dillon 	}
1750e8ff41aSMatthew Dillon #endif
1760e8ff41aSMatthew Dillon 
1770e8ff41aSMatthew Dillon 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
1780e8ff41aSMatthew Dillon 		goto bad;
1790e8ff41aSMatthew Dillon 
1800e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
1810e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, fhsizep) != 0 ||
1820e8ff41aSMatthew Dillon 		    *fhsizep > NFSX_V3FHMAX ||
1830e8ff41aSMatthew Dillon 		    *fhsizep <= 0)
1840e8ff41aSMatthew Dillon 			goto bad;
1850e8ff41aSMatthew Dillon 	} else
1860e8ff41aSMatthew Dillon 		*fhsizep = NFSX_V2FH;
1870e8ff41aSMatthew Dillon 
1880e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1890e8ff41aSMatthew Dillon 		goto bad;
1900e8ff41aSMatthew Dillon 
1910e8ff41aSMatthew Dillon 	if (args->flags & NFSMNT_NFSV3) {
1920e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, &authcount) != 0)
1930e8ff41aSMatthew Dillon 			goto bad;
1940e8ff41aSMatthew Dillon 		authunixok = 0;
1950e8ff41aSMatthew Dillon 		if (authcount < 0 || authcount > 100)
1960e8ff41aSMatthew Dillon 			goto bad;
1970e8ff41aSMatthew Dillon 		while (authcount > 0) {
1980e8ff41aSMatthew Dillon 			if (xdr_int_decode(&m, &authver) != 0)
1990e8ff41aSMatthew Dillon 				goto bad;
2000e8ff41aSMatthew Dillon 			if (authver == RPCAUTH_UNIX)
2010e8ff41aSMatthew Dillon 				authunixok = 1;
2020e8ff41aSMatthew Dillon 			authcount--;
2030e8ff41aSMatthew Dillon 		}
2040e8ff41aSMatthew Dillon 		if (authunixok == 0)
2050e8ff41aSMatthew Dillon 			goto bad;
2060e8ff41aSMatthew Dillon 	}
2070e8ff41aSMatthew Dillon 
2080e8ff41aSMatthew Dillon 	/* Set port number for NFS use. */
2090e8ff41aSMatthew Dillon 	error = krpc_portmap(mdsin, NFS_PROG,
2100e8ff41aSMatthew Dillon 			     (args->flags &
2110e8ff41aSMatthew Dillon 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
2120e8ff41aSMatthew Dillon 			     &mdsin->sin_port, td);
2130e8ff41aSMatthew Dillon 
2140e8ff41aSMatthew Dillon 	goto out;
2150e8ff41aSMatthew Dillon 
2160e8ff41aSMatthew Dillon bad:
2170e8ff41aSMatthew Dillon 	error = EBADRPC;
2180e8ff41aSMatthew Dillon 
2190e8ff41aSMatthew Dillon out:
2200e8ff41aSMatthew Dillon 	m_freem(m);
2210e8ff41aSMatthew Dillon 	return error;
2220e8ff41aSMatthew Dillon }
2230e8ff41aSMatthew Dillon 
2240e8ff41aSMatthew Dillon int
2250e8ff41aSMatthew Dillon md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
2260e8ff41aSMatthew Dillon 	       char *path,
2270e8ff41aSMatthew Dillon 	       u_char *fhp,
2280e8ff41aSMatthew Dillon 	       int *fhsizep,
2290e8ff41aSMatthew Dillon 	       struct nfs_args *args,
2300e8ff41aSMatthew Dillon 	       struct thread *td)
2310e8ff41aSMatthew Dillon {
2320e8ff41aSMatthew Dillon 	struct mbuf *m;
2330e8ff41aSMatthew Dillon 	int error;
2340e8ff41aSMatthew Dillon 	int size = -1;
2350e8ff41aSMatthew Dillon 	int attribs_present;
2360e8ff41aSMatthew Dillon 	int status;
2370e8ff41aSMatthew Dillon 	union {
2380e8ff41aSMatthew Dillon 		u_int32_t v2[17];
2390e8ff41aSMatthew Dillon 		u_int32_t v3[21];
2400e8ff41aSMatthew Dillon 	} fattribs;
2410e8ff41aSMatthew Dillon 
2420e8ff41aSMatthew Dillon 	m = m_get(MB_WAIT,MT_DATA);
2430e8ff41aSMatthew Dillon 	if (m == NULL)
2440e8ff41aSMatthew Dillon 	  	return ENOBUFS;
2450e8ff41aSMatthew Dillon 
2460e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2470e8ff41aSMatthew Dillon 		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
2480e8ff41aSMatthew Dillon 		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
2490e8ff41aSMatthew Dillon 		m->m_len = *fhsizep + sizeof(u_int32_t);
2500e8ff41aSMatthew Dillon 	} else {
2510e8ff41aSMatthew Dillon 		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
2520e8ff41aSMatthew Dillon 		m->m_len = NFSX_V2FH;
2530e8ff41aSMatthew Dillon 	}
2540e8ff41aSMatthew Dillon 
2550e8ff41aSMatthew Dillon 	m->m_next = xdr_string_encode(path, strlen(path));
2560e8ff41aSMatthew Dillon 	if (m->m_next == NULL) {
2570e8ff41aSMatthew Dillon 		error = ENOBUFS;
2580e8ff41aSMatthew Dillon 		goto out;
2590e8ff41aSMatthew Dillon 	}
2600e8ff41aSMatthew Dillon 
2610e8ff41aSMatthew Dillon 	/* Do RPC to nfsd. */
2620e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0)
2630e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
2640e8ff41aSMatthew Dillon 				  NFSPROC_LOOKUP, &m, NULL, td);
2650e8ff41aSMatthew Dillon 	else
2660e8ff41aSMatthew Dillon 		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
2670e8ff41aSMatthew Dillon 				  NFSV2PROC_LOOKUP, &m, NULL, td);
2680e8ff41aSMatthew Dillon 	if (error != 0)
2690e8ff41aSMatthew Dillon 		return error;	/* message already freed */
2700e8ff41aSMatthew Dillon 
2710e8ff41aSMatthew Dillon 	if (xdr_int_decode(&m, &status) != 0)
2720e8ff41aSMatthew Dillon 		goto bad;
2730e8ff41aSMatthew Dillon 	if (status != 0) {
2740e8ff41aSMatthew Dillon 		error = ENOENT;
2750e8ff41aSMatthew Dillon 		goto out;
2760e8ff41aSMatthew Dillon 	}
2770e8ff41aSMatthew Dillon 
2780e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2790e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, fhsizep) != 0 ||
2800e8ff41aSMatthew Dillon 		    *fhsizep > NFSX_V3FHMAX ||
2810e8ff41aSMatthew Dillon 		    *fhsizep <= 0)
2820e8ff41aSMatthew Dillon 			goto bad;
2830e8ff41aSMatthew Dillon 	} else
2840e8ff41aSMatthew Dillon 		*fhsizep = NFSX_V2FH;
2850e8ff41aSMatthew Dillon 
2860e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
2870e8ff41aSMatthew Dillon 		goto bad;
2880e8ff41aSMatthew Dillon 
2890e8ff41aSMatthew Dillon 	if ((args->flags & NFSMNT_NFSV3) != 0) {
2900e8ff41aSMatthew Dillon 		if (xdr_int_decode(&m, &attribs_present) != 0)
2910e8ff41aSMatthew Dillon 			goto bad;
2920e8ff41aSMatthew Dillon 		if (attribs_present != 0) {
2930e8ff41aSMatthew Dillon 			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
2940e8ff41aSMatthew Dillon 					      sizeof(u_int32_t) * 21) != 0)
2950e8ff41aSMatthew Dillon 				goto bad;
2960e8ff41aSMatthew Dillon 			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
2970e8ff41aSMatthew Dillon 		}
2980e8ff41aSMatthew Dillon 	} else {
2990e8ff41aSMatthew Dillon 		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
3000e8ff41aSMatthew Dillon 				      sizeof(u_int32_t) * 17) != 0)
3010e8ff41aSMatthew Dillon 			goto bad;
3020e8ff41aSMatthew Dillon 		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
3030e8ff41aSMatthew Dillon 	}
3040e8ff41aSMatthew Dillon 
3050e8ff41aSMatthew Dillon 	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
3060e8ff41aSMatthew Dillon 		nfsv3_diskless.swap_nblks = size / 1024;
307*086c1d7eSSascha Wildner 		kprintf("md_lookup_swap: Swap size is %d KB\n",
3080e8ff41aSMatthew Dillon 		       nfsv3_diskless.swap_nblks);
3090e8ff41aSMatthew Dillon 	}
3100e8ff41aSMatthew Dillon 
3110e8ff41aSMatthew Dillon 	goto out;
3120e8ff41aSMatthew Dillon 
3130e8ff41aSMatthew Dillon bad:
3140e8ff41aSMatthew Dillon 	error = EBADRPC;
3150e8ff41aSMatthew Dillon 
3160e8ff41aSMatthew Dillon out:
3170e8ff41aSMatthew Dillon 	m_freem(m);
3180e8ff41aSMatthew Dillon 	return error;
3190e8ff41aSMatthew Dillon }
3200e8ff41aSMatthew Dillon 
3210e8ff41aSMatthew Dillon int
3220e8ff41aSMatthew Dillon setfs(struct sockaddr_in *addr, char *path, char *p)
3230e8ff41aSMatthew Dillon {
3240e8ff41aSMatthew Dillon 	unsigned int ip;
3250e8ff41aSMatthew Dillon 	int val;
3260e8ff41aSMatthew Dillon 
3270e8ff41aSMatthew Dillon 	ip = 0;
3280e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3290e8ff41aSMatthew Dillon 		return 0;
3300e8ff41aSMatthew Dillon 	ip = val << 24;
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 << 16);
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 << 8);
3430e8ff41aSMatthew Dillon 	if (*p != '.')
3440e8ff41aSMatthew Dillon 		return 0;
3450e8ff41aSMatthew Dillon 	p++;
3460e8ff41aSMatthew Dillon 	if (((val = getdec(&p)) < 0) || (val > 255))
3470e8ff41aSMatthew Dillon 		return 0;
3480e8ff41aSMatthew Dillon 	ip |= val;
3490e8ff41aSMatthew Dillon 	if (*p != ':')
3500e8ff41aSMatthew Dillon 		return 0;
3510e8ff41aSMatthew Dillon 	p++;
3520e8ff41aSMatthew Dillon 
3530e8ff41aSMatthew Dillon 	addr->sin_addr.s_addr = htonl(ip);
3540e8ff41aSMatthew Dillon 	addr->sin_len = sizeof(struct sockaddr_in);
3550e8ff41aSMatthew Dillon 	addr->sin_family = AF_INET;
3560e8ff41aSMatthew Dillon 
3570e8ff41aSMatthew Dillon 	strncpy(path, p, MNAMELEN - 1);
3580e8ff41aSMatthew Dillon 	return 1;
3590e8ff41aSMatthew Dillon }
3600e8ff41aSMatthew Dillon 
3610e8ff41aSMatthew Dillon static int
3620e8ff41aSMatthew Dillon getdec(char **ptr)
3630e8ff41aSMatthew Dillon {
3640e8ff41aSMatthew Dillon 	char *p;
3650e8ff41aSMatthew Dillon 	int ret;
3660e8ff41aSMatthew Dillon 
3670e8ff41aSMatthew Dillon 	p = *ptr;
3680e8ff41aSMatthew Dillon 	ret = 0;
3690e8ff41aSMatthew Dillon 	if ((*p < '0') || (*p > '9'))
3700e8ff41aSMatthew Dillon 		return -1;
3710e8ff41aSMatthew Dillon 	while ((*p >= '0') && (*p <= '9')) {
3720e8ff41aSMatthew Dillon 		ret = ret * 10 + (*p - '0');
3730e8ff41aSMatthew Dillon 		p++;
3740e8ff41aSMatthew Dillon 	}
3750e8ff41aSMatthew Dillon 	*ptr = p;
3760e8ff41aSMatthew Dillon 	return ret;
3770e8ff41aSMatthew Dillon }
3780e8ff41aSMatthew Dillon 
3790e8ff41aSMatthew Dillon static char *
3800e8ff41aSMatthew Dillon substr(char *a, char *b)
3810e8ff41aSMatthew Dillon {
3820e8ff41aSMatthew Dillon 	char *loc1;
3830e8ff41aSMatthew Dillon 	char *loc2;
3840e8ff41aSMatthew Dillon 
3850e8ff41aSMatthew Dillon         while (*a != '\0') {
3860e8ff41aSMatthew Dillon                 loc1 = a;
3870e8ff41aSMatthew Dillon                 loc2 = b;
3880e8ff41aSMatthew Dillon                 while (*loc1 == *loc2++) {
3890e8ff41aSMatthew Dillon                         if (*loc1 == '\0')
3900e8ff41aSMatthew Dillon 				return 0;
3910e8ff41aSMatthew Dillon                         loc1++;
3920e8ff41aSMatthew Dillon                         if (*loc2 == '\0')
3930e8ff41aSMatthew Dillon 				return loc1;
3940e8ff41aSMatthew Dillon                 }
3950e8ff41aSMatthew Dillon 		a++;
3960e8ff41aSMatthew Dillon         }
3970e8ff41aSMatthew Dillon         return 0;
3980e8ff41aSMatthew Dillon }
3990e8ff41aSMatthew Dillon 
4000e8ff41aSMatthew Dillon static int
4010e8ff41aSMatthew Dillon xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
4020e8ff41aSMatthew Dillon {
4030e8ff41aSMatthew Dillon 	struct mbuf *m;
4040e8ff41aSMatthew Dillon 	int alignedlen;
4050e8ff41aSMatthew Dillon 
4060e8ff41aSMatthew Dillon 	m = *mptr;
4070e8ff41aSMatthew Dillon 	alignedlen = ( len + 3 ) & ~3;
4080e8ff41aSMatthew Dillon 
4090e8ff41aSMatthew Dillon 	if (m->m_len < alignedlen) {
4100e8ff41aSMatthew Dillon 		m = m_pullup(m, alignedlen);
4110e8ff41aSMatthew Dillon 		if (m == NULL) {
4120e8ff41aSMatthew Dillon 			*mptr = NULL;
4130e8ff41aSMatthew Dillon 			return EBADRPC;
4140e8ff41aSMatthew Dillon 		}
4150e8ff41aSMatthew Dillon 	}
4160e8ff41aSMatthew Dillon 	bcopy(mtod(m, u_char *), buf, len);
4170e8ff41aSMatthew Dillon 	m_adj(m, alignedlen);
4180e8ff41aSMatthew Dillon 	*mptr = m;
4190e8ff41aSMatthew Dillon 	return 0;
4200e8ff41aSMatthew Dillon }
4210e8ff41aSMatthew Dillon 
4220e8ff41aSMatthew Dillon static int
4230e8ff41aSMatthew Dillon xdr_int_decode(struct mbuf **mptr, int *iptr)
4240e8ff41aSMatthew Dillon {
4250e8ff41aSMatthew Dillon 	u_int32_t i;
4260e8ff41aSMatthew Dillon 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
4270e8ff41aSMatthew Dillon 		return EBADRPC;
4280e8ff41aSMatthew Dillon 	*iptr = fxdr_unsigned(u_int32_t, i);
4290e8ff41aSMatthew Dillon 	return 0;
4300e8ff41aSMatthew Dillon }
4310e8ff41aSMatthew Dillon 
4320e8ff41aSMatthew Dillon #endif	/* BOOTP && NFS_ROOT */
4330e8ff41aSMatthew Dillon 
434