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