1*6dc9eaf1Sclaudio /* $OpenBSD: nfs_boot.c,v 1.42 2017/07/19 12:32:13 claudio Exp $ */ 209d901c0Sderaadt /* $NetBSD: nfs_boot.c,v 1.26 1996/05/07 02:51:25 thorpej Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1995 Adam Glass, Gordon Ross 6df930be7Sderaadt * All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 16df930be7Sderaadt * 3. The name of the authors may not be used to endorse or promote products 17df930be7Sderaadt * derived from this software without specific prior written permission. 18df930be7Sderaadt * 19df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 20df930be7Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21df930be7Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22df930be7Sderaadt * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23df930be7Sderaadt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24df930be7Sderaadt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25df930be7Sderaadt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26df930be7Sderaadt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27df930be7Sderaadt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28df930be7Sderaadt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29df930be7Sderaadt */ 30df930be7Sderaadt 31df930be7Sderaadt #include <sys/param.h> 32df930be7Sderaadt #include <sys/systm.h> 33df930be7Sderaadt #include <sys/kernel.h> 34df930be7Sderaadt #include <sys/conf.h> 35df930be7Sderaadt #include <sys/ioctl.h> 36df930be7Sderaadt #include <sys/mount.h> 37df930be7Sderaadt #include <sys/mbuf.h> 38df930be7Sderaadt #include <sys/reboot.h> 39df930be7Sderaadt #include <sys/socket.h> 40df930be7Sderaadt #include <sys/socketvar.h> 41d8c62b08Sblambert #include <sys/queue.h> 42df930be7Sderaadt 43df930be7Sderaadt #include <net/if.h> 440deb6685Smpi #include <net/if_var.h> 45df930be7Sderaadt 46df930be7Sderaadt #include <netinet/in.h> 474b69f2cbSmpi #include <netinet/in_var.h> 48df930be7Sderaadt #include <netinet/if_ether.h> 49df930be7Sderaadt 50df930be7Sderaadt #include <nfs/rpcv2.h> 5178530d46Smickey #include <nfs/nfsproto.h> 52df930be7Sderaadt #include <nfs/nfs.h> 53df930be7Sderaadt #include <nfs/nfsdiskless.h> 54df930be7Sderaadt #include <nfs/krpc.h> 55df930be7Sderaadt #include <nfs/xdr_subs.h> 56370decb4Sniklas #include <nfs/nfs_var.h> 57df930be7Sderaadt 58ddde6caeSderaadt #include "ether.h" 59df930be7Sderaadt 60ddde6caeSderaadt #if !defined(NFSCLIENT) || (NETHER == 0 && NFDDI == 0) 61ddde6caeSderaadt 62ddde6caeSderaadt int 63906a9d53Sjsg nfs_boot_init(struct nfs_diskless *nd, struct proc *procp) 64df930be7Sderaadt { 65a0bbd24dSbriggs panic("nfs_boot_init: NFSCLIENT not enabled in kernel"); 66df930be7Sderaadt } 67df930be7Sderaadt 68a28bd3cfSmickey int 69906a9d53Sjsg nfs_boot_getfh(struct sockaddr_in *bpsin, char *key, 70906a9d53Sjsg struct nfs_dlmount *ndmntp, int retries) 7178530d46Smickey { 7278530d46Smickey /* can not get here */ 73a28bd3cfSmickey return (EOPNOTSUPP); 7478530d46Smickey } 7578530d46Smickey 76ddde6caeSderaadt #else 77df930be7Sderaadt 78df930be7Sderaadt /* 79df930be7Sderaadt * Support for NFS diskless booting, specifically getting information 80df930be7Sderaadt * about where to boot from, what pathnames, etc. 81df930be7Sderaadt * 820eb08f42Spedro * This implementation uses RARP and the bootparam RPC. 83df930be7Sderaadt * We are forced to implement RPC anyway (to get file handles) 84df930be7Sderaadt * so we might as well take advantage of it for bootparam too. 85df930be7Sderaadt * 86df930be7Sderaadt * The diskless boot sequence goes as follows: 87df930be7Sderaadt * (1) Use RARP to get our interface address 88df930be7Sderaadt * (2) Use RPC/bootparam/whoami to get our hostname, 89df930be7Sderaadt * our IP address, and the server's IP address. 90df930be7Sderaadt * (3) Use RPC/bootparam/getfile to get the root path 91df930be7Sderaadt * (4) Use RPC/mountd to get the root file handle 92df930be7Sderaadt * (5) Use RPC/bootparam/getfile to get the swap path 93df930be7Sderaadt * (6) Use RPC/mountd to get the swap file handle 94df930be7Sderaadt * 95df930be7Sderaadt * (This happens to be the way Sun does it too.) 96df930be7Sderaadt */ 97df930be7Sderaadt 98df930be7Sderaadt /* bootparam RPC */ 99c4071fd1Smillert static int bp_whoami(struct sockaddr_in *bpsin, 100c4071fd1Smillert struct in_addr *my_ip, struct in_addr *gw_ip); 101c4071fd1Smillert static int bp_getfile(struct sockaddr_in *bpsin, char *key, 102c4071fd1Smillert struct sockaddr_in *mdsin, char *servname, char *path, int retries); 103df930be7Sderaadt 104df930be7Sderaadt /* mountd RPC */ 105c4071fd1Smillert static int md_mount(struct sockaddr_in *mdsin, char *path, 10649338274Sfgsch struct nfs_args *argp); 107df930be7Sderaadt 108df930be7Sderaadt char *nfsbootdevname; 109df930be7Sderaadt 110df930be7Sderaadt /* 111df930be7Sderaadt * Called with an empty nfs_diskless struct to be filled in. 112df930be7Sderaadt */ 113df930be7Sderaadt int 114906a9d53Sjsg nfs_boot_init(struct nfs_diskless *nd, struct proc *procp) 115df930be7Sderaadt { 116df930be7Sderaadt struct ifreq ireq; 1174b69f2cbSmpi struct in_aliasreq ifra; 118df930be7Sderaadt struct in_addr my_ip, gw_ip; 119df930be7Sderaadt struct sockaddr_in bp_sin; 120df930be7Sderaadt struct sockaddr_in *sin; 121df930be7Sderaadt struct ifnet *ifp; 122df930be7Sderaadt struct socket *so; 123c6e49a3dSmpi struct ifaddr *ifa; 124bbcf0337Smpi char addr[INET_ADDRSTRLEN]; 125906cf29eSmpi int s, error; 126df930be7Sderaadt 127df930be7Sderaadt /* 128df930be7Sderaadt * Find an interface, rarp for its ip address, stuff it, the 129df930be7Sderaadt * implied broadcast addr, and netmask into a nfs_diskless struct. 130df930be7Sderaadt * 131df930be7Sderaadt * This was moved here from nfs_vfsops.c because this procedure 132df930be7Sderaadt * would be quite different if someone decides to write (i.e.) a 133df930be7Sderaadt * BOOTP version of this file (might not use RARP, etc.) 134df930be7Sderaadt */ 135df930be7Sderaadt 136df930be7Sderaadt /* 137df930be7Sderaadt * Find a network interface. 138df930be7Sderaadt */ 139df930be7Sderaadt if (nfsbootdevname) 140df930be7Sderaadt ifp = ifunit(nfsbootdevname); 14104b702e4Sericj else { 142d8c62b08Sblambert TAILQ_FOREACH(ifp, &ifnet, if_list) { 143df930be7Sderaadt if ((ifp->if_flags & 144df930be7Sderaadt (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 145df930be7Sderaadt break; 14604b702e4Sericj } 14704b702e4Sericj } 148df930be7Sderaadt if (ifp == NULL) 149df930be7Sderaadt panic("nfs_boot: no suitable interface"); 15009d901c0Sderaadt bcopy(ifp->if_xname, ireq.ifr_name, IFNAMSIZ); 151f72c60a5Sderaadt printf("nfs_boot: using interface %s, with revarp & bootparams\n", 152f72c60a5Sderaadt ireq.ifr_name); 153df930be7Sderaadt 154df930be7Sderaadt /* 155df930be7Sderaadt * Bring up the interface. 156df930be7Sderaadt * 157df930be7Sderaadt * Get the old interface flags and or IFF_UP into them; if 158df930be7Sderaadt * IFF_UP set blindly, interface selection can be clobbered. 159df930be7Sderaadt */ 160df930be7Sderaadt if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) 161df930be7Sderaadt panic("nfs_boot: socreate, error=%d", error); 1622b4720fcSmpi NET_LOCK(s); 163df930be7Sderaadt error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp); 1642b4720fcSmpi NET_UNLOCK(s); 165df930be7Sderaadt if (error) 166df930be7Sderaadt panic("nfs_boot: GIFFLAGS, error=%d", error); 167df930be7Sderaadt ireq.ifr_flags |= IFF_UP; 1682b4720fcSmpi NET_LOCK(s); 169df930be7Sderaadt error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp); 1702b4720fcSmpi NET_UNLOCK(s); 171df930be7Sderaadt if (error) 172df930be7Sderaadt panic("nfs_boot: SIFFLAGS, error=%d", error); 173df930be7Sderaadt 174df930be7Sderaadt /* 175df930be7Sderaadt * Do RARP for the interface address. 176df930be7Sderaadt */ 177df930be7Sderaadt if ((error = revarpwhoami(&my_ip, ifp)) != 0) 17839529570Sderaadt panic("reverse arp not answered by rarpd(8) or dhcpd(8)"); 179bbcf0337Smpi inet_ntop(AF_INET, &my_ip, addr, sizeof(addr)); 180bbcf0337Smpi printf("nfs_boot: client_addr=%s\n", addr); 181df930be7Sderaadt 182df930be7Sderaadt /* 183df930be7Sderaadt * Do enough of ifconfig(8) so that the chosen interface 184df930be7Sderaadt * can talk to the servers. (just set the address) 185df930be7Sderaadt */ 186851e11faStedu memset(&ifra, 0, sizeof(ifra)); 1874b69f2cbSmpi bcopy(ifp->if_xname, ifra.ifra_name, sizeof(ifra.ifra_name)); 1884b69f2cbSmpi 1895dd46ca9Sbluhm sin = &ifra.ifra_addr; 190df930be7Sderaadt sin->sin_len = sizeof(*sin); 191df930be7Sderaadt sin->sin_family = AF_INET; 192df930be7Sderaadt sin->sin_addr.s_addr = my_ip.s_addr; 1932b4720fcSmpi NET_LOCK(s); 1944b69f2cbSmpi error = ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, procp); 1952b4720fcSmpi NET_UNLOCK(s); 196df930be7Sderaadt if (error) 197df930be7Sderaadt panic("nfs_boot: set if addr, error=%d", error); 198df930be7Sderaadt 199df930be7Sderaadt soclose(so); 200df930be7Sderaadt 201c6e49a3dSmpi TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 202c6e49a3dSmpi if (ifa->ifa_addr->sa_family == AF_INET) 203c6e49a3dSmpi break; 204c6e49a3dSmpi } 205c6e49a3dSmpi if (ifa == NULL) 206c6e49a3dSmpi panic("nfs_boot: address not configured on %s", ifp->if_xname); 207c6e49a3dSmpi 208df930be7Sderaadt /* 209df930be7Sderaadt * Get client name and gateway address. 210df930be7Sderaadt * RPC: bootparam/whoami 211df930be7Sderaadt * The server address returned by the WHOAMI call 21298b25bc4Sderaadt * is used for all subsequent bootparam RPCs. 213df930be7Sderaadt */ 214851e11faStedu memset(&bp_sin, 0, sizeof(bp_sin)); 215df930be7Sderaadt bp_sin.sin_len = sizeof(bp_sin); 216df930be7Sderaadt bp_sin.sin_family = AF_INET; 217c6e49a3dSmpi bp_sin.sin_addr.s_addr = ifatoia(ifa)->ia_broadaddr.sin_addr.s_addr; 218df930be7Sderaadt hostnamelen = MAXHOSTNAMELEN; 219df930be7Sderaadt 220df930be7Sderaadt /* this returns gateway IP address */ 221df930be7Sderaadt error = bp_whoami(&bp_sin, &my_ip, &gw_ip); 222df930be7Sderaadt if (error) 223df930be7Sderaadt panic("nfs_boot: bootparam whoami, error=%d", error); 224bbcf0337Smpi inet_ntop(AF_INET, &bp_sin.sin_addr, addr, sizeof(addr)); 225bbcf0337Smpi printf("nfs_boot: server_addr=%s hostname=%s\n", addr, hostname); 226df930be7Sderaadt 227370decb4Sniklas bcopy(&bp_sin, &nd->nd_boot, sizeof(bp_sin)); 228df930be7Sderaadt 229df930be7Sderaadt return (0); 230df930be7Sderaadt } 231df930be7Sderaadt 232906a9d53Sjsg /* 233906a9d53Sjsg * bpsin: bootparam server 234906a9d53Sjsg * key: root or swap 235906a9d53Sjsg * ndmntp: output 236906a9d53Sjsg */ 237a28bd3cfSmickey int 238906a9d53Sjsg nfs_boot_getfh(struct sockaddr_in *bpsin, char *key, 239906a9d53Sjsg struct nfs_dlmount *ndmntp, int retries) 240df930be7Sderaadt { 24149338274Sfgsch struct nfs_args *args; 242df930be7Sderaadt char pathname[MAXPATHLEN]; 243df930be7Sderaadt char *sp, *dp, *endp; 244370decb4Sniklas struct sockaddr_in *sin; 245df930be7Sderaadt int error; 246df930be7Sderaadt 24749338274Sfgsch args = &ndmntp->ndm_args; 24849338274Sfgsch 24949338274Sfgsch /* Initialize mount args. */ 250851e11faStedu memset(args, 0, sizeof(*args)); 2513e303383Sbluhm args->addr = sintosa(&ndmntp->ndm_saddr); 25249338274Sfgsch args->addrlen = args->addr->sa_len; 25349338274Sfgsch args->sotype = SOCK_DGRAM; 25449338274Sfgsch args->fh = ndmntp->ndm_fh; 25549338274Sfgsch args->hostname = ndmntp->ndm_host; 25649338274Sfgsch args->flags = NFSMNT_NFSV3; 25749338274Sfgsch #ifdef NFS_BOOT_OPTIONS 25849338274Sfgsch args->flags |= NFS_BOOT_OPTIONS; 25949338274Sfgsch #endif 26049338274Sfgsch #ifdef NFS_BOOT_RWSIZE 26149338274Sfgsch /* 26249338274Sfgsch * Reduce rsize,wsize for interfaces that consistently 26349338274Sfgsch * drop fragments of long UDP messages. (i.e. wd8003). 26449338274Sfgsch * You can always change these later via remount. 26549338274Sfgsch */ 26649338274Sfgsch args->flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; 26749338274Sfgsch args->wsize = NFS_BOOT_RWSIZE; 26849338274Sfgsch args->rsize = NFS_BOOT_RWSIZE; 26949338274Sfgsch #endif 27049338274Sfgsch 271370decb4Sniklas sin = &ndmntp->ndm_saddr; 272370decb4Sniklas 273df930be7Sderaadt /* 274df930be7Sderaadt * Get server:pathname for "key" (root or swap) 275df930be7Sderaadt * using RPC to bootparam/getfile 276df930be7Sderaadt */ 277a28bd3cfSmickey error = bp_getfile(bpsin, key, sin, ndmntp->ndm_host, pathname, 278a28bd3cfSmickey retries); 279a28bd3cfSmickey if (error) { 280a28bd3cfSmickey printf("nfs_boot: bootparam get %s: %d\n", key, error); 281a28bd3cfSmickey return (error); 282a28bd3cfSmickey } 283df930be7Sderaadt 284df930be7Sderaadt /* 285df930be7Sderaadt * Get file handle for "key" (root or swap) 286df930be7Sderaadt * using RPC to mountd/mount 287df930be7Sderaadt */ 28849338274Sfgsch error = md_mount(sin, pathname, args); 289a28bd3cfSmickey if (error) { 290a28bd3cfSmickey printf("nfs_boot: mountd %s, error=%d\n", key, error); 291a28bd3cfSmickey return (error); 292a28bd3cfSmickey } 293df930be7Sderaadt 294370decb4Sniklas /* Set port number for NFS use. */ 295370decb4Sniklas /* XXX: NFS port is always 2049, right? */ 29649338274Sfgsch error = krpc_portmap(sin, NFS_PROG, 29749338274Sfgsch (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, 29849338274Sfgsch &sin->sin_port); 299a28bd3cfSmickey if (error) { 30049338274Sfgsch printf("nfs_boot: portmap NFS, error=%d\n", error); 301a28bd3cfSmickey return (error); 302a28bd3cfSmickey } 303370decb4Sniklas 304df930be7Sderaadt /* Construct remote path (for getmntinfo(3)) */ 305df930be7Sderaadt dp = ndmntp->ndm_host; 306df930be7Sderaadt endp = dp + MNAMELEN - 1; 307df930be7Sderaadt dp += strlen(dp); 308df930be7Sderaadt *dp++ = ':'; 309df930be7Sderaadt for (sp = pathname; *sp && dp < endp;) 310df930be7Sderaadt *dp++ = *sp++; 311df930be7Sderaadt *dp = '\0'; 312df930be7Sderaadt 313a28bd3cfSmickey return (0); 314df930be7Sderaadt } 315df930be7Sderaadt 316df930be7Sderaadt 317df930be7Sderaadt /* 318df930be7Sderaadt * RPC: bootparam/whoami 319df930be7Sderaadt * Given client IP address, get: 320df930be7Sderaadt * client name (hostname) 321df930be7Sderaadt * domain name (domainname) 322df930be7Sderaadt * gateway address 323df930be7Sderaadt * 324df930be7Sderaadt * The hostname and domainname are set here for convenience. 325df930be7Sderaadt * 326df930be7Sderaadt * Note - bpsin is initialized to the broadcast address, 327df930be7Sderaadt * and will be replaced with the bootparam server address 328df930be7Sderaadt * after this call is complete. Have to use PMAP_PROC_CALL 329df930be7Sderaadt * to make sure we get responses only from a servers that 330df930be7Sderaadt * know about us (don't want to broadcast a getport call). 331df930be7Sderaadt */ 332df930be7Sderaadt static int 333906a9d53Sjsg bp_whoami(struct sockaddr_in *bpsin, struct in_addr *my_ip, 334906a9d53Sjsg struct in_addr *gw_ip) 335df930be7Sderaadt { 336df930be7Sderaadt /* RPC structures for PMAPPROC_CALLIT */ 337df930be7Sderaadt struct whoami_call { 338df930be7Sderaadt u_int32_t call_prog; 339df930be7Sderaadt u_int32_t call_vers; 340df930be7Sderaadt u_int32_t call_proc; 341df930be7Sderaadt u_int32_t call_arglen; 342df930be7Sderaadt } *call; 343df930be7Sderaadt struct callit_reply { 344df930be7Sderaadt u_int32_t port; 345df930be7Sderaadt u_int32_t encap_len; 346df930be7Sderaadt /* encapsulated data here */ 347df930be7Sderaadt } *reply; 348df930be7Sderaadt 349df930be7Sderaadt struct mbuf *m, *from; 350df930be7Sderaadt struct sockaddr_in *sin; 351df930be7Sderaadt int error, msg_len; 352df930be7Sderaadt int16_t port; 353df930be7Sderaadt 354df930be7Sderaadt /* 355df930be7Sderaadt * Build request message for PMAPPROC_CALLIT. 356df930be7Sderaadt */ 357df930be7Sderaadt m = m_get(M_WAIT, MT_DATA); 358df930be7Sderaadt call = mtod(m, struct whoami_call *); 359df930be7Sderaadt m->m_len = sizeof(*call); 360df930be7Sderaadt call->call_prog = txdr_unsigned(BOOTPARAM_PROG); 361df930be7Sderaadt call->call_vers = txdr_unsigned(BOOTPARAM_VERS); 362df930be7Sderaadt call->call_proc = txdr_unsigned(BOOTPARAM_WHOAMI); 363df930be7Sderaadt 364df930be7Sderaadt /* 365df930be7Sderaadt * append encapsulated data (client IP address) 366df930be7Sderaadt */ 367df930be7Sderaadt m->m_next = xdr_inaddr_encode(my_ip); 368df930be7Sderaadt call->call_arglen = txdr_unsigned(m->m_next->m_len); 369df930be7Sderaadt 370df930be7Sderaadt /* RPC: portmap/callit */ 371df930be7Sderaadt bpsin->sin_port = htons(PMAPPORT); 372df930be7Sderaadt from = NULL; 373df930be7Sderaadt error = krpc_call(bpsin, PMAPPROG, PMAPVERS, 374a28bd3cfSmickey PMAPPROC_CALLIT, &m, &from, -1); 375df930be7Sderaadt if (error) 376df930be7Sderaadt return error; 377df930be7Sderaadt 378df930be7Sderaadt /* 379df930be7Sderaadt * Parse result message. 380df930be7Sderaadt */ 381df930be7Sderaadt if (m->m_len < sizeof(*reply)) { 382df930be7Sderaadt m = m_pullup(m, sizeof(*reply)); 383df930be7Sderaadt if (m == NULL) 384df930be7Sderaadt goto bad; 385df930be7Sderaadt } 386df930be7Sderaadt reply = mtod(m, struct callit_reply *); 387df930be7Sderaadt port = fxdr_unsigned(u_int32_t, reply->port); 388df930be7Sderaadt msg_len = fxdr_unsigned(u_int32_t, reply->encap_len); 389df930be7Sderaadt m_adj(m, sizeof(*reply)); 390df930be7Sderaadt 391df930be7Sderaadt /* 392df930be7Sderaadt * Save bootparam server address 393df930be7Sderaadt */ 394df930be7Sderaadt sin = mtod(from, struct sockaddr_in *); 395df930be7Sderaadt bpsin->sin_port = htons(port); 396df930be7Sderaadt bpsin->sin_addr.s_addr = sin->sin_addr.s_addr; 397df930be7Sderaadt 398df930be7Sderaadt /* client name */ 399df930be7Sderaadt hostnamelen = MAXHOSTNAMELEN-1; 400df930be7Sderaadt m = xdr_string_decode(m, hostname, &hostnamelen); 401df930be7Sderaadt if (m == NULL) 402df930be7Sderaadt goto bad; 403df930be7Sderaadt 404df930be7Sderaadt /* domain name */ 405df930be7Sderaadt domainnamelen = MAXHOSTNAMELEN-1; 406df930be7Sderaadt m = xdr_string_decode(m, domainname, &domainnamelen); 407df930be7Sderaadt if (m == NULL) 408df930be7Sderaadt goto bad; 409df930be7Sderaadt 410df930be7Sderaadt /* gateway address */ 411df930be7Sderaadt m = xdr_inaddr_decode(m, gw_ip); 412df930be7Sderaadt if (m == NULL) 413df930be7Sderaadt goto bad; 414df930be7Sderaadt 415df930be7Sderaadt /* success */ 416df930be7Sderaadt goto out; 417df930be7Sderaadt 418df930be7Sderaadt bad: 419df930be7Sderaadt printf("nfs_boot: bootparam_whoami: bad reply\n"); 420df930be7Sderaadt error = EBADRPC; 421df930be7Sderaadt 422df930be7Sderaadt out: 423df930be7Sderaadt m_freem(from); 424df930be7Sderaadt m_freem(m); 425df930be7Sderaadt return(error); 426df930be7Sderaadt } 427df930be7Sderaadt 428df930be7Sderaadt 429df930be7Sderaadt /* 430df930be7Sderaadt * RPC: bootparam/getfile 431df930be7Sderaadt * Given client name and file "key", get: 432df930be7Sderaadt * server name 433df930be7Sderaadt * server IP address 434df930be7Sderaadt * server pathname 435df930be7Sderaadt */ 436df930be7Sderaadt static int 437906a9d53Sjsg bp_getfile(struct sockaddr_in *bpsin, char *key, struct sockaddr_in *md_sin, 438906a9d53Sjsg char *serv_name, char *pathname, int retries) 439df930be7Sderaadt { 440df930be7Sderaadt struct mbuf *m; 441df930be7Sderaadt struct sockaddr_in *sin; 442df930be7Sderaadt struct in_addr inaddr; 443df930be7Sderaadt int error, sn_len, path_len; 444df930be7Sderaadt 445df930be7Sderaadt /* 446df930be7Sderaadt * Build request message. 447df930be7Sderaadt */ 448df930be7Sderaadt 449df930be7Sderaadt /* client name (hostname) */ 450df930be7Sderaadt m = xdr_string_encode(hostname, hostnamelen); 451370decb4Sniklas if (m == NULL) 452370decb4Sniklas return (ENOMEM); 453df930be7Sderaadt 454df930be7Sderaadt /* key name (root or swap) */ 455df930be7Sderaadt m->m_next = xdr_string_encode(key, strlen(key)); 456*6dc9eaf1Sclaudio if (m->m_next == NULL) { 457*6dc9eaf1Sclaudio m_freem(m); 458370decb4Sniklas return (ENOMEM); 459*6dc9eaf1Sclaudio } 460df930be7Sderaadt 461df930be7Sderaadt /* RPC: bootparam/getfile */ 462df930be7Sderaadt error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS, 463a28bd3cfSmickey BOOTPARAM_GETFILE, &m, NULL, retries); 464df930be7Sderaadt if (error) 465df930be7Sderaadt return error; 466df930be7Sderaadt 467df930be7Sderaadt /* 468df930be7Sderaadt * Parse result message. 469df930be7Sderaadt */ 470df930be7Sderaadt 471df930be7Sderaadt /* server name */ 472df930be7Sderaadt sn_len = MNAMELEN-1; 473df930be7Sderaadt m = xdr_string_decode(m, serv_name, &sn_len); 474df930be7Sderaadt if (m == NULL) 475df930be7Sderaadt goto bad; 476df930be7Sderaadt 477df930be7Sderaadt /* server IP address (mountd/NFS) */ 478df930be7Sderaadt m = xdr_inaddr_decode(m, &inaddr); 479df930be7Sderaadt if (m == NULL) 480df930be7Sderaadt goto bad; 481df930be7Sderaadt 482df930be7Sderaadt /* server pathname */ 483df930be7Sderaadt path_len = MAXPATHLEN-1; 484df930be7Sderaadt m = xdr_string_decode(m, pathname, &path_len); 485df930be7Sderaadt if (m == NULL) 486df930be7Sderaadt goto bad; 487df930be7Sderaadt 488df930be7Sderaadt /* setup server socket address */ 489df930be7Sderaadt sin = md_sin; 490851e11faStedu memset(sin, 0, sizeof(*sin)); 491df930be7Sderaadt sin->sin_len = sizeof(*sin); 492df930be7Sderaadt sin->sin_family = AF_INET; 493df930be7Sderaadt sin->sin_addr = inaddr; 494df930be7Sderaadt 495df930be7Sderaadt /* success */ 496df930be7Sderaadt goto out; 497df930be7Sderaadt 498df930be7Sderaadt bad: 499df930be7Sderaadt printf("nfs_boot: bootparam_getfile: bad reply\n"); 500df930be7Sderaadt error = EBADRPC; 501df930be7Sderaadt 502df930be7Sderaadt out: 503df930be7Sderaadt m_freem(m); 504838ec05fSkrw return(error); 505df930be7Sderaadt } 506df930be7Sderaadt 507df930be7Sderaadt 508df930be7Sderaadt /* 509df930be7Sderaadt * RPC: mountd/mount 510df930be7Sderaadt * Given a server pathname, get an NFS file handle. 511df930be7Sderaadt * Also, sets sin->sin_port to the NFS service port. 512906a9d53Sjsg * mdsin: mountd server address 513df930be7Sderaadt */ 514df930be7Sderaadt static int 51549338274Sfgsch md_mount(struct sockaddr_in *mdsin, char *path, struct nfs_args *argp) 516df930be7Sderaadt { 517df930be7Sderaadt /* The RPC structures */ 518df930be7Sderaadt struct rdata { 519df930be7Sderaadt u_int32_t errno; 52049338274Sfgsch union { 52149338274Sfgsch u_int8_t v2fh[NFSX_V2FH]; 52249338274Sfgsch struct { 52349338274Sfgsch u_int32_t fhlen; 52449338274Sfgsch u_int8_t fh[1]; 52549338274Sfgsch } v3fh; 52649338274Sfgsch } fh; 527df930be7Sderaadt } *rdata; 528df930be7Sderaadt struct mbuf *m; 52949338274Sfgsch u_int8_t *fh; 53049338274Sfgsch int minlen, error; 53149338274Sfgsch int mntver; 532df930be7Sderaadt 53349338274Sfgsch mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2; 53449338274Sfgsch do { 53549338274Sfgsch error = krpc_portmap(mdsin, RPCPROG_MNT, mntver, 536df930be7Sderaadt &mdsin->sin_port); 53749338274Sfgsch if (error) 53849338274Sfgsch continue; 539df930be7Sderaadt 540df930be7Sderaadt m = xdr_string_encode(path, strlen(path)); 541370decb4Sniklas if (m == NULL) 54278530d46Smickey return ENOMEM; 543df930be7Sderaadt 544df930be7Sderaadt /* Do RPC to mountd. */ 54549338274Sfgsch error = krpc_call(mdsin, RPCPROG_MNT, mntver, 546a28bd3cfSmickey RPCMNT_MOUNT, &m, NULL, -1); 54749338274Sfgsch 54849338274Sfgsch if (error != EPROGMISMATCH) 54949338274Sfgsch break; 55049338274Sfgsch /* Try lower version of mountd. */ 55149338274Sfgsch } while (--mntver >= 1); 552df930be7Sderaadt if (error) 553df930be7Sderaadt return error; /* message already freed */ 554df930be7Sderaadt 55549338274Sfgsch if (mntver != 3) 55649338274Sfgsch argp->flags &= ~NFSMNT_NFSV3; 55749338274Sfgsch 558370decb4Sniklas /* The reply might have only the errno. */ 559370decb4Sniklas if (m->m_len < 4) 560370decb4Sniklas goto bad; 561370decb4Sniklas /* Have at least errno, so check that. */ 562370decb4Sniklas rdata = mtod(m, struct rdata *); 563370decb4Sniklas error = fxdr_unsigned(u_int32_t, rdata->errno); 564370decb4Sniklas if (error) 565370decb4Sniklas goto out; 566370decb4Sniklas 567370decb4Sniklas /* Have errno==0, so the fh must be there. */ 56849338274Sfgsch if (mntver == 3) { 56949338274Sfgsch argp->fhsize = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen); 57049338274Sfgsch if (argp->fhsize > NFSX_V3FHMAX) 571df930be7Sderaadt goto bad; 57249338274Sfgsch minlen = 2 * sizeof(u_int32_t) + argp->fhsize; 57349338274Sfgsch } else { 57449338274Sfgsch argp->fhsize = NFSX_V2FH; 57549338274Sfgsch minlen = sizeof(u_int32_t) + argp->fhsize; 57649338274Sfgsch } 57749338274Sfgsch 57849338274Sfgsch if (m->m_len < minlen) { 57949338274Sfgsch m = m_pullup(m, minlen); 58049338274Sfgsch if (m == NULL) 58149338274Sfgsch return (EBADRPC); 582df930be7Sderaadt rdata = mtod(m, struct rdata *); 583370decb4Sniklas } 58449338274Sfgsch 58549338274Sfgsch fh = (mntver == 3) ? rdata->fh.v3fh.fh : rdata->fh.v2fh; 58649338274Sfgsch bcopy(fh, argp->fh, argp->fhsize); 58749338274Sfgsch 588df930be7Sderaadt goto out; 589df930be7Sderaadt 590df930be7Sderaadt bad: 591df930be7Sderaadt error = EBADRPC; 592df930be7Sderaadt 593df930be7Sderaadt out: 594df930be7Sderaadt m_freem(m); 595df930be7Sderaadt return error; 596df930be7Sderaadt } 597df930be7Sderaadt 598f3f6cb75Sbriggs #endif /* ifdef NFSCLIENT */ 599