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