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