Home | History | Annotate | Line # | Download | only in nfs
nfs_boot.c revision 1.29.2.1
      1  1.29.2.1   thorpej /*	$NetBSD: nfs_boot.c,v 1.29.2.1 1997/01/14 21:27:15 thorpej Exp $	*/
      2       1.5       cgd 
      3       1.1     glass /*
      4      1.16       gwr  * Copyright (c) 1995 Adam Glass, Gordon Ross
      5       1.1     glass  * All rights reserved.
      6       1.1     glass  *
      7       1.1     glass  * Redistribution and use in source and binary forms, with or without
      8       1.1     glass  * modification, are permitted provided that the following conditions
      9       1.1     glass  * are met:
     10       1.1     glass  * 1. Redistributions of source code must retain the above copyright
     11       1.1     glass  *    notice, this list of conditions and the following disclaimer.
     12       1.1     glass  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1     glass  *    notice, this list of conditions and the following disclaimer in the
     14       1.1     glass  *    documentation and/or other materials provided with the distribution.
     15       1.3       gwr  * 3. The name of the authors may not be used to endorse or promote products
     16       1.1     glass  *    derived from this software without specific prior written permission.
     17       1.1     glass  *
     18       1.3       gwr  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
     19       1.3       gwr  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20       1.3       gwr  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21       1.3       gwr  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     22       1.3       gwr  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23       1.3       gwr  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24       1.3       gwr  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25       1.3       gwr  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26       1.3       gwr  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27       1.3       gwr  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28       1.1     glass  */
     29       1.1     glass 
     30       1.2       cgd #include <sys/param.h>
     31       1.1     glass #include <sys/systm.h>
     32       1.1     glass #include <sys/kernel.h>
     33       1.1     glass #include <sys/conf.h>
     34  1.29.2.1   thorpej #include <sys/device.h>
     35       1.1     glass #include <sys/ioctl.h>
     36       1.1     glass #include <sys/proc.h>
     37       1.1     glass #include <sys/mount.h>
     38       1.1     glass #include <sys/mbuf.h>
     39      1.16       gwr #include <sys/reboot.h>
     40       1.1     glass #include <sys/socket.h>
     41      1.16       gwr #include <sys/socketvar.h>
     42       1.1     glass 
     43       1.1     glass #include <net/if.h>
     44       1.3       gwr #include <net/route.h>
     45       1.3       gwr 
     46       1.1     glass #include <netinet/in.h>
     47       1.3       gwr #include <netinet/if_ether.h>
     48       1.1     glass 
     49       1.1     glass #include <nfs/rpcv2.h>
     50      1.25      fvdl #include <nfs/nfsproto.h>
     51       1.1     glass #include <nfs/nfs.h>
     52       1.1     glass #include <nfs/nfsdiskless.h>
     53      1.11       gwr #include <nfs/krpc.h>
     54      1.17   mycroft #include <nfs/xdr_subs.h>
     55      1.21  christos #include <nfs/nfs_var.h>
     56       1.1     glass 
     57       1.7    paulus #include "ether.h"
     58      1.11       gwr #if NETHER == 0
     59      1.11       gwr 
     60      1.11       gwr int nfs_boot_init(nd, procp)
     61      1.11       gwr 	struct nfs_diskless *nd;
     62      1.11       gwr 	struct proc *procp;
     63      1.11       gwr {
     64      1.11       gwr 	panic("nfs_boot_init: no ether");
     65      1.24       gwr }
     66      1.24       gwr 
     67      1.24       gwr void
     68      1.24       gwr nfs_boot_getfh(bpsin, key, ndmntp)
     69      1.24       gwr 	struct sockaddr_in *bpsin;
     70      1.24       gwr 	char *key;
     71      1.24       gwr 	struct nfs_dlmount *ndmntp;
     72      1.24       gwr {
     73      1.24       gwr 	/* can not get here */
     74      1.11       gwr }
     75      1.11       gwr 
     76      1.11       gwr #else /* NETHER */
     77       1.7    paulus 
     78       1.1     glass /*
     79       1.1     glass  * Support for NFS diskless booting, specifically getting information
     80       1.1     glass  * about where to boot from, what pathnames, etc.
     81       1.1     glass  *
     82       1.3       gwr  * This implememtation uses RARP and the bootparam RPC.
     83       1.3       gwr  * We are forced to implement RPC anyway (to get file handles)
     84       1.3       gwr  * so we might as well take advantage of it for bootparam too.
     85       1.1     glass  *
     86       1.3       gwr  * The diskless boot sequence goes as follows:
     87      1.15       gwr  * (1) Use RARP to get our interface address
     88      1.15       gwr  * (2) Use RPC/bootparam/whoami to get our hostname,
     89      1.15       gwr  *     our IP address, and the server's IP address.
     90      1.15       gwr  * (3) Use RPC/bootparam/getfile to get the root path
     91      1.15       gwr  * (4) Use RPC/mountd to get the root file handle
     92      1.15       gwr  * (5) Use RPC/bootparam/getfile to get the swap path
     93      1.15       gwr  * (6) Use RPC/mountd to get the swap file handle
     94       1.1     glass  *
     95       1.3       gwr  * (This happens to be the way Sun does it too.)
     96       1.1     glass  */
     97       1.1     glass 
     98       1.3       gwr /* bootparam RPC */
     99       1.6   deraadt static int bp_whoami __P((struct sockaddr_in *bpsin,
    100       1.6   deraadt 	struct in_addr *my_ip, struct in_addr *gw_ip));
    101       1.6   deraadt static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
    102       1.6   deraadt 	struct sockaddr_in *mdsin, char *servname, char *path));
    103       1.3       gwr 
    104       1.3       gwr /* mountd RPC */
    105       1.6   deraadt static int md_mount __P((struct sockaddr_in *mdsin, char *path,
    106      1.29      fvdl 	struct nfs_args *argp));
    107       1.3       gwr 
    108       1.1     glass /*
    109       1.3       gwr  * Called with an empty nfs_diskless struct to be filled in.
    110       1.1     glass  */
    111       1.6   deraadt int
    112       1.6   deraadt nfs_boot_init(nd, procp)
    113       1.3       gwr 	struct nfs_diskless *nd;
    114       1.3       gwr 	struct proc *procp;
    115       1.1     glass {
    116       1.3       gwr 	struct ifreq ireq;
    117      1.11       gwr 	struct in_addr my_ip, gw_ip;
    118       1.3       gwr 	struct sockaddr_in bp_sin;
    119       1.1     glass 	struct sockaddr_in *sin;
    120       1.3       gwr 	struct ifnet *ifp;
    121       1.3       gwr 	struct socket *so;
    122      1.16       gwr 	int error;
    123       1.3       gwr 
    124       1.3       gwr 	/*
    125       1.3       gwr 	 * Find an interface, rarp for its ip address, stuff it, the
    126       1.3       gwr 	 * implied broadcast addr, and netmask into a nfs_diskless struct.
    127       1.3       gwr 	 *
    128       1.3       gwr 	 * This was moved here from nfs_vfsops.c because this procedure
    129       1.3       gwr 	 * would be quite different if someone decides to write (i.e.) a
    130      1.15       gwr 	 * BOOTP version of this file (might not use RARP, etc.)
    131       1.3       gwr 	 */
    132       1.3       gwr 
    133       1.3       gwr 	/*
    134       1.3       gwr 	 * Find a network interface.
    135       1.3       gwr 	 */
    136  1.29.2.1   thorpej 	ifp = ifunit(root_device->dv_xname);
    137  1.29.2.1   thorpej 	if (ifp == NULL) {
    138  1.29.2.1   thorpej 		printf("nfs_boot: no suitable interface");
    139  1.29.2.1   thorpej 		return (ENXIO);
    140  1.29.2.1   thorpej 	}
    141      1.26   thorpej 	bcopy(ifp->if_xname, ireq.ifr_name, IFNAMSIZ);
    142      1.28  christos 	printf("nfs_boot: using network interface '%s'\n",
    143       1.6   deraadt 	    ireq.ifr_name);
    144       1.3       gwr 
    145       1.3       gwr 	/*
    146       1.3       gwr 	 * Bring up the interface.
    147      1.18       cgd 	 *
    148      1.18       cgd 	 * Get the old interface flags and or IFF_UP into them; if
    149      1.18       cgd 	 * IFF_UP set blindly, interface selection can be clobbered.
    150       1.3       gwr 	 */
    151       1.3       gwr 	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
    152       1.3       gwr 		panic("nfs_boot: socreate, error=%d", error);
    153      1.18       cgd 	error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
    154      1.18       cgd 	if (error)
    155      1.18       cgd 		panic("nfs_boot: GIFFLAGS, error=%d", error);
    156      1.18       cgd 	ireq.ifr_flags |= IFF_UP;
    157       1.3       gwr 	error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
    158       1.6   deraadt 	if (error)
    159       1.6   deraadt 		panic("nfs_boot: SIFFLAGS, error=%d", error);
    160       1.3       gwr 
    161       1.3       gwr 	/*
    162      1.15       gwr 	 * Do RARP for the interface address.
    163       1.3       gwr 	 */
    164  1.29.2.1   thorpej 	if ((error = revarpwhoami(&my_ip, ifp)) != 0) {
    165  1.29.2.1   thorpej 		printf("revarp failed, error=%d", error);
    166  1.29.2.1   thorpej 		return (EIO);
    167  1.29.2.1   thorpej 	}
    168      1.28  christos 	printf("nfs_boot: client_addr=0x%x\n", (u_int32_t)ntohl(my_ip.s_addr));
    169       1.3       gwr 
    170       1.3       gwr 	/*
    171      1.15       gwr 	 * Do enough of ifconfig(8) so that the chosen interface
    172      1.15       gwr 	 * can talk to the servers.  (just set the address)
    173       1.3       gwr 	 */
    174       1.3       gwr 	sin = (struct sockaddr_in *)&ireq.ifr_addr;
    175      1.10   mycroft 	bzero((caddr_t)sin, sizeof(*sin));
    176       1.3       gwr 	sin->sin_len = sizeof(*sin);
    177       1.3       gwr 	sin->sin_family = AF_INET;
    178       1.3       gwr 	sin->sin_addr.s_addr = my_ip.s_addr;
    179       1.3       gwr 	error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
    180       1.6   deraadt 	if (error)
    181       1.6   deraadt 		panic("nfs_boot: set if addr, error=%d", error);
    182       1.3       gwr 
    183       1.3       gwr 	soclose(so);
    184       1.3       gwr 
    185       1.3       gwr 	/*
    186       1.3       gwr 	 * Get client name and gateway address.
    187       1.3       gwr 	 * RPC: bootparam/whoami
    188      1.15       gwr 	 * Use the old broadcast address for the WHOAMI
    189      1.15       gwr 	 * call because we do not yet know our netmask.
    190      1.15       gwr 	 * The server address returned by the WHOAMI call
    191      1.15       gwr 	 * is used for all subsequent booptaram RPCs.
    192       1.3       gwr 	 */
    193      1.10   mycroft 	bzero((caddr_t)&bp_sin, sizeof(bp_sin));
    194       1.3       gwr 	bp_sin.sin_len = sizeof(bp_sin);
    195       1.3       gwr 	bp_sin.sin_family = AF_INET;
    196      1.15       gwr 	bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
    197       1.3       gwr 	hostnamelen = MAXHOSTNAMELEN;
    198       1.6   deraadt 
    199       1.6   deraadt 	/* this returns gateway IP address */
    200       1.6   deraadt 	error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
    201  1.29.2.1   thorpej 	if (error) {
    202  1.29.2.1   thorpej 		printf("nfs_boot: bootparam whoami, error=%d", error);
    203  1.29.2.1   thorpej 		return (error);
    204  1.29.2.1   thorpej 	}
    205      1.28  christos 	printf("nfs_boot: server_addr=0x%x\n",
    206      1.25      fvdl 		   (u_int32_t)ntohl(bp_sin.sin_addr.s_addr));
    207      1.28  christos 	printf("nfs_boot: hostname=%s\n", hostname);
    208       1.1     glass 
    209       1.3       gwr #ifdef	NFS_BOOT_GATEWAY
    210       1.1     glass 	/*
    211       1.8       gwr 	 * XXX - This code is conditionally compiled only because
    212       1.8       gwr 	 * many bootparam servers (in particular, SunOS 4.1.3)
    213       1.8       gwr 	 * always set the gateway address to their own address.
    214       1.8       gwr 	 * The bootparam server is not necessarily the gateway.
    215       1.8       gwr 	 * We could just believe the server, and at worst you would
    216       1.8       gwr 	 * need to delete the incorrect default route before adding
    217       1.8       gwr 	 * the correct one, but for simplicity, ignore the gateway.
    218       1.3       gwr 	 * If your server is OK, you can turn on this option.
    219       1.3       gwr 	 *
    220       1.3       gwr 	 * If the gateway address is set, add a default route.
    221       1.3       gwr 	 * (The mountd RPCs may go across a gateway.)
    222       1.1     glass 	 */
    223       1.3       gwr 	if (gw_ip.s_addr) {
    224       1.8       gwr 		struct sockaddr dst, gw, mask;
    225       1.3       gwr 		/* Destination: (default) */
    226      1.10   mycroft 		bzero((caddr_t)&dst, sizeof(dst));
    227       1.8       gwr 		dst.sa_len = sizeof(dst);
    228       1.8       gwr 		dst.sa_family = AF_INET;
    229       1.3       gwr 		/* Gateway: */
    230      1.10   mycroft 		bzero((caddr_t)&gw, sizeof(gw));
    231       1.8       gwr 		sin = (struct sockaddr_in *)&gw;
    232       1.8       gwr 		sin->sin_len = sizeof(gw);
    233       1.8       gwr 		sin->sin_family = AF_INET;
    234       1.8       gwr 		sin->sin_addr.s_addr = gw_ip.s_addr;
    235       1.8       gwr 		/* Mask: (zero length) */
    236       1.8       gwr 		bzero(&mask, sizeof(mask));
    237       1.6   deraadt 
    238      1.28  christos 		printf("nfs_boot: gateway=0x%x\n", ntohl(gw_ip.s_addr));
    239       1.3       gwr 		/* add, dest, gw, mask, flags, 0 */
    240       1.8       gwr 		error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
    241       1.8       gwr 		    &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
    242       1.3       gwr 		if (error)
    243      1.28  christos 			printf("nfs_boot: add route, error=%d\n", error);
    244       1.3       gwr 	}
    245       1.3       gwr #endif
    246       1.3       gwr 
    247      1.23       gwr 	bcopy(&bp_sin, &nd->nd_boot, sizeof(bp_sin));
    248       1.1     glass 
    249       1.3       gwr 	return (0);
    250       1.3       gwr }
    251       1.1     glass 
    252      1.23       gwr void
    253      1.23       gwr nfs_boot_getfh(bpsin, key, ndmntp)
    254       1.3       gwr 	struct sockaddr_in *bpsin;	/* bootparam server */
    255       1.6   deraadt 	char *key;			/* root or swap */
    256       1.6   deraadt 	struct nfs_dlmount *ndmntp;	/* output */
    257       1.3       gwr {
    258      1.29      fvdl 	struct nfs_args *args;
    259       1.3       gwr 	char pathname[MAXPATHLEN];
    260       1.4        pk 	char *sp, *dp, *endp;
    261      1.23       gwr 	struct sockaddr_in *sin;
    262       1.3       gwr 	int error;
    263       1.1     glass 
    264      1.29      fvdl 	args = &ndmntp->ndm_args;
    265      1.29      fvdl 
    266      1.29      fvdl 	/* Initialize mount args. */
    267      1.29      fvdl 	bzero((caddr_t) args, sizeof(*args));
    268      1.29      fvdl 	args->addr     = &ndmntp->ndm_saddr;
    269      1.29      fvdl 	args->addrlen  = args->addr->sa_len;
    270      1.29      fvdl #ifdef NFS_BOOT_TCP
    271      1.29      fvdl 	args->sotype   = SOCK_STREAM;
    272      1.29      fvdl #else
    273      1.29      fvdl 	args->sotype   = SOCK_DGRAM;
    274      1.29      fvdl #endif
    275      1.29      fvdl 	args->fh       = ndmntp->ndm_fh;
    276      1.29      fvdl 	args->hostname = ndmntp->ndm_host;
    277      1.29      fvdl 	args->flags    = NFSMNT_RESVPORT | NFSMNT_NFSV3;
    278      1.29      fvdl 
    279      1.29      fvdl #ifdef	NFS_BOOT_OPTIONS
    280      1.29      fvdl 	args->flags    |= NFS_BOOT_OPTIONS;
    281      1.29      fvdl #endif
    282      1.29      fvdl #ifdef	NFS_BOOT_RWSIZE
    283      1.29      fvdl 	/*
    284      1.29      fvdl 	 * Reduce rsize,wsize for interfaces that consistently
    285      1.29      fvdl 	 * drop fragments of long UDP messages.  (i.e. wd8003).
    286      1.29      fvdl 	 * You can always change these later via remount.
    287      1.29      fvdl 	 */
    288      1.29      fvdl 	args->flags   |= NFSMNT_WSIZE | NFSMNT_RSIZE;
    289      1.29      fvdl 	args->wsize    = NFS_BOOT_RWSIZE;
    290      1.29      fvdl 	args->rsize    = NFS_BOOT_RWSIZE;
    291      1.29      fvdl #endif
    292      1.29      fvdl 
    293      1.29      fvdl 	sin = (void*)&ndmntp->ndm_saddr;
    294      1.23       gwr 
    295       1.3       gwr 	/*
    296       1.3       gwr 	 * Get server:pathname for "key" (root or swap)
    297       1.3       gwr 	 * using RPC to bootparam/getfile
    298       1.3       gwr 	 */
    299      1.25      fvdl 	error = bp_getfile(bpsin, key, sin, ndmntp->ndm_host, pathname);
    300       1.3       gwr 	if (error)
    301       1.3       gwr 		panic("nfs_boot: bootparam get %s: %d", key, error);
    302       1.1     glass 
    303       1.3       gwr 	/*
    304       1.3       gwr 	 * Get file handle for "key" (root or swap)
    305       1.3       gwr 	 * using RPC to mountd/mount
    306       1.3       gwr 	 */
    307      1.29      fvdl 	error = md_mount(sin, pathname, args);
    308       1.3       gwr 	if (error)
    309       1.3       gwr 		panic("nfs_boot: mountd %s, error=%d", key, error);
    310       1.4        pk 
    311      1.23       gwr 	/* Set port number for NFS use. */
    312      1.23       gwr 	/* XXX: NFS port is always 2049, right? */
    313      1.29      fvdl #ifdef NFS_BOOT_TCP
    314      1.29      fvdl retry:
    315      1.29      fvdl #endif
    316      1.29      fvdl 	error = krpc_portmap(sin, NFS_PROG,
    317      1.29      fvdl 		    (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
    318      1.29      fvdl 		    (args->sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP,
    319      1.29      fvdl 		    &sin->sin_port);
    320      1.29      fvdl 
    321      1.29      fvdl 	if (error || (sin->sin_port == htons(0))) {
    322      1.29      fvdl #ifdef NFS_BOOT_TCP
    323      1.29      fvdl 		if (args->sotype == SOCK_STREAM) {
    324      1.29      fvdl 			args->sotype = SOCK_DGRAM;
    325      1.29      fvdl 			goto retry;
    326      1.29      fvdl 		}
    327      1.29      fvdl #endif
    328      1.29      fvdl 		panic("nfs_boot: portmap NFS, error=%d", error);
    329      1.29      fvdl 	}
    330      1.23       gwr 
    331       1.4        pk 	/* Construct remote path (for getmntinfo(3)) */
    332       1.4        pk 	dp = ndmntp->ndm_host;
    333       1.4        pk 	endp = dp + MNAMELEN - 1;
    334       1.4        pk 	dp += strlen(dp);
    335       1.4        pk 	*dp++ = ':';
    336       1.4        pk 	for (sp = pathname; *sp && dp < endp;)
    337       1.4        pk 		*dp++ = *sp++;
    338       1.4        pk 	*dp = '\0';
    339       1.6   deraadt 
    340       1.1     glass }
    341       1.1     glass 
    342       1.3       gwr 
    343       1.1     glass /*
    344       1.3       gwr  * RPC: bootparam/whoami
    345       1.3       gwr  * Given client IP address, get:
    346       1.3       gwr  *	client name	(hostname)
    347       1.3       gwr  *	domain name (domainname)
    348       1.3       gwr  *	gateway address
    349       1.3       gwr  *
    350      1.15       gwr  * The hostname and domainname are set here for convenience.
    351      1.11       gwr  *
    352      1.11       gwr  * Note - bpsin is initialized to the broadcast address,
    353      1.11       gwr  * and will be replaced with the bootparam server address
    354      1.11       gwr  * after this call is complete.  Have to use PMAP_PROC_CALL
    355      1.11       gwr  * to make sure we get responses only from a servers that
    356      1.11       gwr  * know about us (don't want to broadcast a getport call).
    357       1.3       gwr  */
    358       1.3       gwr static int
    359       1.6   deraadt bp_whoami(bpsin, my_ip, gw_ip)
    360       1.6   deraadt 	struct sockaddr_in *bpsin;
    361       1.6   deraadt 	struct in_addr *my_ip;
    362       1.6   deraadt 	struct in_addr *gw_ip;
    363       1.1     glass {
    364      1.11       gwr 	/* RPC structures for PMAPPROC_CALLIT */
    365      1.11       gwr 	struct whoami_call {
    366      1.16       gwr 		u_int32_t call_prog;
    367      1.16       gwr 		u_int32_t call_vers;
    368      1.16       gwr 		u_int32_t call_proc;
    369      1.16       gwr 		u_int32_t call_arglen;
    370      1.11       gwr 	} *call;
    371      1.16       gwr 	struct callit_reply {
    372      1.16       gwr 		u_int32_t port;
    373      1.16       gwr 		u_int32_t encap_len;
    374      1.16       gwr 		/* encapsulated data here */
    375      1.16       gwr 	} *reply;
    376      1.11       gwr 
    377      1.11       gwr 	struct mbuf *m, *from;
    378       1.3       gwr 	struct sockaddr_in *sin;
    379       1.3       gwr 	int error, msg_len;
    380      1.16       gwr 	int16_t port;
    381       1.1     glass 
    382       1.3       gwr 	/*
    383      1.11       gwr 	 * Build request message for PMAPPROC_CALLIT.
    384       1.3       gwr 	 */
    385      1.16       gwr 	m = m_get(M_WAIT, MT_DATA);
    386      1.11       gwr 	call = mtod(m, struct whoami_call *);
    387      1.16       gwr 	m->m_len = sizeof(*call);
    388      1.17   mycroft 	call->call_prog = txdr_unsigned(BOOTPARAM_PROG);
    389      1.17   mycroft 	call->call_vers = txdr_unsigned(BOOTPARAM_VERS);
    390      1.17   mycroft 	call->call_proc = txdr_unsigned(BOOTPARAM_WHOAMI);
    391      1.11       gwr 
    392      1.16       gwr 	/*
    393      1.16       gwr 	 * append encapsulated data (client IP address)
    394      1.16       gwr 	 */
    395      1.16       gwr 	m->m_next = xdr_inaddr_encode(my_ip);
    396      1.17   mycroft 	call->call_arglen = txdr_unsigned(m->m_next->m_len);
    397      1.11       gwr 
    398      1.11       gwr 	/* RPC: portmap/callit */
    399      1.11       gwr 	bpsin->sin_port = htons(PMAPPORT);
    400      1.11       gwr 	from = NULL;
    401      1.11       gwr 	error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
    402      1.11       gwr 			PMAPPROC_CALLIT, &m, &from);
    403       1.1     glass 	if (error)
    404       1.1     glass 		return error;
    405       1.3       gwr 
    406       1.3       gwr 	/*
    407       1.3       gwr 	 * Parse result message.
    408       1.3       gwr 	 */
    409      1.16       gwr 	if (m->m_len < sizeof(*reply)) {
    410      1.16       gwr 		m = m_pullup(m, sizeof(*reply));
    411      1.16       gwr 		if (m == NULL)
    412      1.16       gwr 			goto bad;
    413      1.16       gwr 	}
    414      1.16       gwr 	reply = mtod(m, struct callit_reply *);
    415      1.17   mycroft 	port = fxdr_unsigned(u_int32_t, reply->port);
    416      1.17   mycroft 	msg_len = fxdr_unsigned(u_int32_t, reply->encap_len);
    417      1.16       gwr 	m_adj(m, sizeof(*reply));
    418      1.11       gwr 
    419      1.16       gwr 	/*
    420      1.16       gwr 	 * Save bootparam server address
    421      1.16       gwr 	 */
    422      1.11       gwr 	sin = mtod(from, struct sockaddr_in *);
    423      1.16       gwr 	bpsin->sin_port = htons(port);
    424      1.11       gwr 	bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
    425      1.11       gwr 
    426       1.3       gwr 	/* client name */
    427      1.16       gwr 	hostnamelen = MAXHOSTNAMELEN-1;
    428      1.16       gwr 	m = xdr_string_decode(m, hostname, &hostnamelen);
    429      1.16       gwr 	if (m == NULL)
    430       1.3       gwr 		goto bad;
    431       1.3       gwr 
    432       1.3       gwr 	/* domain name */
    433      1.16       gwr 	domainnamelen = MAXHOSTNAMELEN-1;
    434      1.16       gwr 	m = xdr_string_decode(m, domainname, &domainnamelen);
    435      1.16       gwr 	if (m == NULL)
    436       1.3       gwr 		goto bad;
    437       1.3       gwr 
    438       1.3       gwr 	/* gateway address */
    439      1.16       gwr 	m = xdr_inaddr_decode(m, gw_ip);
    440      1.16       gwr 	if (m == NULL)
    441       1.3       gwr 		goto bad;
    442      1.16       gwr 
    443      1.16       gwr 	/* success */
    444       1.3       gwr 	goto out;
    445       1.3       gwr 
    446       1.6   deraadt bad:
    447      1.28  christos 	printf("nfs_boot: bootparam_whoami: bad reply\n");
    448       1.3       gwr 	error = EBADRPC;
    449       1.3       gwr 
    450       1.6   deraadt out:
    451      1.11       gwr 	if (from)
    452      1.11       gwr 		m_freem(from);
    453      1.16       gwr 	if (m)
    454      1.16       gwr 		m_freem(m);
    455       1.3       gwr 	return(error);
    456       1.1     glass }
    457       1.1     glass 
    458       1.3       gwr 
    459       1.1     glass /*
    460       1.3       gwr  * RPC: bootparam/getfile
    461       1.3       gwr  * Given client name and file "key", get:
    462       1.3       gwr  *	server name
    463       1.3       gwr  *	server IP address
    464       1.3       gwr  *	server pathname
    465       1.1     glass  */
    466       1.3       gwr static int
    467       1.6   deraadt bp_getfile(bpsin, key, md_sin, serv_name, pathname)
    468       1.6   deraadt 	struct sockaddr_in *bpsin;
    469       1.6   deraadt 	char *key;
    470       1.6   deraadt 	struct sockaddr_in *md_sin;
    471       1.6   deraadt 	char *serv_name;
    472       1.6   deraadt 	char *pathname;
    473       1.1     glass {
    474       1.3       gwr 	struct mbuf *m;
    475       1.1     glass 	struct sockaddr_in *sin;
    476      1.16       gwr 	struct in_addr inaddr;
    477      1.16       gwr 	int error, sn_len, path_len;
    478       1.1     glass 
    479       1.3       gwr 	/*
    480      1.16       gwr 	 * Build request message.
    481       1.3       gwr 	 */
    482       1.1     glass 
    483       1.3       gwr 	/* client name (hostname) */
    484      1.16       gwr 	m  = xdr_string_encode(hostname, hostnamelen);
    485      1.22        pk 	if (m == NULL)
    486      1.22        pk 		return (ENOMEM);
    487      1.16       gwr 
    488       1.3       gwr 	/* key name (root or swap) */
    489      1.16       gwr 	m->m_next = xdr_string_encode(key, strlen(key));
    490      1.22        pk 	if (m->m_next == NULL)
    491      1.22        pk 		return (ENOMEM);
    492       1.3       gwr 
    493       1.3       gwr 	/* RPC: bootparam/getfile */
    494      1.11       gwr 	error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
    495      1.11       gwr 			BOOTPARAM_GETFILE, &m, NULL);
    496       1.3       gwr 	if (error)
    497       1.1     glass 		return error;
    498       1.3       gwr 
    499       1.3       gwr 	/*
    500       1.3       gwr 	 * Parse result message.
    501       1.3       gwr 	 */
    502       1.3       gwr 
    503       1.3       gwr 	/* server name */
    504      1.16       gwr 	sn_len = MNAMELEN-1;
    505      1.16       gwr 	m = xdr_string_decode(m, serv_name, &sn_len);
    506      1.16       gwr 	if (m == NULL)
    507       1.3       gwr 		goto bad;
    508      1.16       gwr 
    509      1.16       gwr 	/* server IP address (mountd/NFS) */
    510      1.16       gwr 	m = xdr_inaddr_decode(m, &inaddr);
    511      1.16       gwr 	if (m == NULL)
    512       1.3       gwr 		goto bad;
    513      1.16       gwr 
    514      1.16       gwr 	/* server pathname */
    515      1.16       gwr 	path_len = MAXPATHLEN-1;
    516      1.16       gwr 	m = xdr_string_decode(m, pathname, &path_len);
    517      1.16       gwr 	if (m == NULL)
    518       1.3       gwr 		goto bad;
    519       1.3       gwr 
    520      1.16       gwr 	/* setup server socket address */
    521       1.3       gwr 	sin = md_sin;
    522      1.10   mycroft 	bzero((caddr_t)sin, sizeof(*sin));
    523       1.3       gwr 	sin->sin_len = sizeof(*sin);
    524       1.1     glass 	sin->sin_family = AF_INET;
    525      1.16       gwr 	sin->sin_addr = inaddr;
    526       1.3       gwr 
    527      1.16       gwr 	/* success */
    528       1.3       gwr 	goto out;
    529       1.3       gwr 
    530       1.6   deraadt bad:
    531      1.28  christos 	printf("nfs_boot: bootparam_getfile: bad reply\n");
    532       1.3       gwr 	error = EBADRPC;
    533       1.1     glass 
    534       1.6   deraadt out:
    535       1.3       gwr 	m_freem(m);
    536       1.3       gwr 	return(0);
    537       1.3       gwr }
    538       1.1     glass 
    539       1.1     glass 
    540       1.1     glass /*
    541       1.3       gwr  * RPC: mountd/mount
    542       1.3       gwr  * Given a server pathname, get an NFS file handle.
    543       1.3       gwr  * Also, sets sin->sin_port to the NFS service port.
    544       1.1     glass  */
    545       1.3       gwr static int
    546      1.29      fvdl md_mount(mdsin, path, argp)
    547       1.3       gwr 	struct sockaddr_in *mdsin;		/* mountd server address */
    548       1.3       gwr 	char *path;
    549      1.29      fvdl 	struct nfs_args *argp;
    550       1.1     glass {
    551       1.3       gwr 	/* The RPC structures */
    552       1.3       gwr 	struct rdata {
    553      1.20       cgd 		u_int32_t errno;
    554      1.29      fvdl 		union {
    555      1.29      fvdl 			u_int8_t  v2fh[NFSX_V2FH];
    556      1.29      fvdl 			struct {
    557      1.29      fvdl 				u_int32_t fhlen;
    558      1.29      fvdl 				u_int8_t  fh[1];
    559      1.29      fvdl 			} v3fh;
    560      1.29      fvdl 		} fh;
    561       1.3       gwr 	} *rdata;
    562       1.3       gwr 	struct mbuf *m;
    563      1.29      fvdl 	u_int8_t *fh;
    564      1.29      fvdl 	int minlen, error;
    565       1.3       gwr 
    566      1.29      fvdl retry:
    567      1.11       gwr 	/* Get port number for MOUNTD. */
    568      1.29      fvdl 	error = krpc_portmap(mdsin, RPCPROG_MNT,
    569      1.29      fvdl 		     (argp->flags & NFSMNT_NFSV3) ? RPCMNT_VER3 : RPCMNT_VER1,
    570      1.29      fvdl 		     IPPROTO_UDP, &mdsin->sin_port);
    571      1.29      fvdl 	if (error)
    572      1.29      fvdl 		return error;
    573      1.11       gwr 
    574      1.16       gwr 	m = xdr_string_encode(path, strlen(path));
    575      1.22        pk 	if (m == NULL)
    576      1.25      fvdl 		return ENOMEM;
    577       1.3       gwr 
    578       1.3       gwr 	/* Do RPC to mountd. */
    579      1.29      fvdl 	error = krpc_call(mdsin, RPCPROG_MNT, (argp->flags & NFSMNT_NFSV3) ?
    580      1.29      fvdl 			  RPCMNT_VER3 : RPCMNT_VER1, RPCMNT_MOUNT, &m, NULL);
    581      1.29      fvdl 	if (error) {
    582      1.29      fvdl 		if ((error==RPC_PROGMISMATCH) && (argp->flags & NFSMNT_NFSV3)) {
    583      1.29      fvdl 			argp->flags &= ~NFSMNT_NFSV3;
    584      1.29      fvdl 			goto retry;
    585      1.29      fvdl 		}
    586       1.3       gwr 		return error;	/* message already freed */
    587      1.29      fvdl 	}
    588       1.1     glass 
    589      1.23       gwr 	/* The reply might have only the errno. */
    590      1.23       gwr 	if (m->m_len < 4)
    591      1.23       gwr 		goto bad;
    592      1.23       gwr 	/* Have at least errno, so check that. */
    593      1.23       gwr 	rdata = mtod(m, struct rdata *);
    594      1.23       gwr 	error = fxdr_unsigned(u_int32_t, rdata->errno);
    595      1.23       gwr 	if (error)
    596      1.23       gwr 		goto out;
    597      1.23       gwr 
    598      1.25      fvdl 	 /* Have errno==0, so the fh must be there. */
    599      1.29      fvdl 	if (argp->flags & NFSMNT_NFSV3){
    600      1.29      fvdl 		argp->fhsize   = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen);
    601      1.29      fvdl 		if (argp->fhsize > NFSX_V3FHMAX)
    602      1.29      fvdl 			goto bad;
    603      1.29      fvdl 		minlen = 2 * sizeof(u_int32_t) + argp->fhsize;
    604      1.29      fvdl 	} else {
    605      1.29      fvdl 		argp->fhsize   = NFSX_V2FH;
    606      1.29      fvdl 		minlen = sizeof(u_int32_t) + argp->fhsize;
    607      1.29      fvdl 	}
    608      1.29      fvdl 
    609      1.29      fvdl 	if (m->m_len < minlen) {
    610      1.29      fvdl 		m = m_pullup(m, minlen);
    611      1.16       gwr 		if (m == NULL)
    612      1.29      fvdl 			return(EBADRPC);
    613      1.23       gwr 		rdata = mtod(m, struct rdata *);
    614      1.16       gwr 	}
    615      1.29      fvdl 
    616      1.29      fvdl 	fh = (argp->flags & NFSMNT_NFSV3) ? rdata->fh.v3fh.fh : rdata->fh.v2fh;
    617      1.29      fvdl 	bcopy(fh, argp->fh, argp->fhsize);
    618      1.29      fvdl 
    619       1.3       gwr 	goto out;
    620       1.1     glass 
    621       1.6   deraadt bad:
    622       1.3       gwr 	error = EBADRPC;
    623       1.1     glass 
    624       1.6   deraadt out:
    625       1.3       gwr 	m_freem(m);
    626       1.3       gwr 	return error;
    627       1.7    paulus }
    628       1.7    paulus 
    629       1.7    paulus #endif /* NETHER */
    630