/* $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.8 2002/03/16 15:56:06 luigi Exp $ */ /* * Copyright (c) 1995 Gordon Ross, Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * based on: * nfs/krpc_subr.c * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ */ #include "opt_bootp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ETHER_ADDR_LEN 6 /* * extern int nfs_diskless_valid; * extern struct nfsv3_diskless nfsv3_diskless; * extern struct nfs_diskless nfs_diskless; */ struct nfsv3_diskless *nd3; struct nfs_diskless *nd = &nfs_diskless; static int get_file_handle(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, struct nfs_args *args, struct thread *td); static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); static int xdr_int_decode(struct mbuf **ptr, int *iptr); static void print_in_addr(struct in_addr addr); static void print_sin_addr(struct sockaddr_in *addr); static void nfs_convert_diskless __P((void)); static void nfs_convert_oargs __P((struct nfs_args *args, struct onfs_args *oargs)); static void clear_sinaddr(struct sockaddr_in *sin); static void setup_nfsdiskless(void); static void clear_sinaddr(struct sockaddr_in *sin) { bzero(sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */ sin->sin_port = 0; } static void nfs_convert_oargs(args, oargs) struct nfs_args *args; struct onfs_args *oargs; { args->version = NFS_ARGSVERSION; args->addr = oargs->addr; args->addrlen = oargs->addrlen; args->sotype = oargs->sotype; args->proto = oargs->proto; args->fh = oargs->fh; args->fhsize = oargs->fhsize; args->flags = oargs->flags; args->wsize = oargs->wsize; args->rsize = oargs->rsize; args->readdirsize = oargs->readdirsize; args->timeo = oargs->timeo; args->retrans = oargs->retrans; args->maxgrouplist = oargs->maxgrouplist; args->readahead = oargs->readahead; /* args->leaseterm = oargs->leaseterm; */ args->deadthresh = oargs->deadthresh; args->hostname = oargs->hostname; } static void nfs_convert_diskless() { bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, sizeof(struct ifaliasreq)); bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, sizeof(struct sockaddr_in)); nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args); nfsv3_diskless.swap_fhsize = NFSX_V2FH; bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH); bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr, sizeof(struct sockaddr_in)); bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam, MNAMELEN); nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks; bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred, sizeof(struct ucred)); nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); nfsv3_diskless.root_fhsize = NFSX_V2FH; bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH); bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, sizeof(struct sockaddr_in)); bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam, MNAMELEN); nfsv3_diskless.root_time = nfs_diskless.root_time; bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam, MAXHOSTNAMELEN); nfs_diskless_valid = 3; } static void print_sin_addr(struct sockaddr_in *sin) { print_in_addr(sin->sin_addr); } static void print_in_addr(struct in_addr addr) { unsigned int ip; ip = ntohl(addr.s_addr); printf("%d.%d.%d.%d\n", ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); } static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa) { char *cp; u_int32_t a[6]; bzero(sa, sizeof(*sa)); sa->sdl_len = sizeof(*sa); sa->sdl_family = AF_LINK; sa->sdl_type = IFT_ETHER; sa->sdl_alen = ETHER_ADDR_LEN; if ((cp = getenv(ev)) == NULL) return(1); if (sscanf(cp, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) != 6) return(1); sa->sdl_data[0] = a[0]; sa->sdl_data[1] = a[1]; sa->sdl_data[2] = a[2]; sa->sdl_data[3] = a[3]; sa->sdl_data[4] = a[4]; sa->sdl_data[5] = a[5]; return(0); } static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa) { u_int32_t a[4]; char *cp; struct sockaddr_in *sin; bzero(sa, sizeof(*sa)); sa->sin_len = sizeof(*sa); sa->sin_family = AF_INET; if ((cp = getenv(ev)) == NULL) return(1); if (sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]) != 4) return(1); /* XXX is this ordering correct? */ sa->sin_addr.s_addr = (a[3] << 24) + (a[2] << 16) + (a[1] << 8) + a[0]; sin = (struct sockaddr_in *) sa; print_sin_addr(sin); return(0); } static void setup_nfsdiskless(void) { struct nfs_diskless *nd = &nfs_diskless; struct ifnet *ifp; struct ifaddr *ifa; struct sockaddr_dl *sdl, ourdl; struct socket *so; char *cp; int error; struct thread *td; struct sockaddr_in mygw, myaddr, netmask; struct nfsv3_diskless *nd3 = &nfsv3_diskless; char *cp3; td = curthread; /* set up interface */ printf("me........:"); if (inaddr_to_sockaddr("boot.netif.ip", &myaddr)) { printf("FHP: no ip\n"); return; } printf("mask......:"); if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) { printf("FHP: no netmask\n"); return; } bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr)); bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr)); ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) { printf("FHP: guessing hardware address...\n"); ifa = NULL; ifp = TAILQ_FIRST(&ifnet); TAILQ_FOREACH(ifp, &ifnet, if_link) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if ((ifa->ifa_addr->sa_family == AF_LINK) && (sdl = ((struct sockaddr_dl *)ifa->ifa_addr))) { if ((sdl->sdl_type == ourdl.sdl_type) && (sdl->sdl_alen == ourdl.sdl_alen)) goto guess_done; } } } guess_done: sprintf(nd->myif.ifra_name, "%s%d", ifp->if_name, ifp->if_unit); } else { ifa = NULL; ifp = TAILQ_FIRST(&ifnet); TAILQ_FOREACH(ifp, &ifnet, if_link) { TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if ((ifa->ifa_addr->sa_family == AF_LINK) && (sdl = ((struct sockaddr_dl *)ifa->ifa_addr))) { if ((sdl->sdl_type == ourdl.sdl_type) && (sdl->sdl_alen == ourdl.sdl_alen) && !bcmp(sdl->sdl_data + sdl->sdl_nlen, ourdl.sdl_data + ourdl.sdl_nlen, sdl->sdl_alen)) goto match_done; } } } printf("FHP: no matching interface\n"); return; match_done: sprintf(nd->myif.ifra_name, "%s%d", ifp->if_name, ifp->if_unit); } /* set up root mount */ nd->root_args.rsize = 8192; /* XXX tunable? */ nd->root_args.wsize = 8192; nd->root_args.sotype = SOCK_DGRAM; nd->root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); printf("NFS svr...:"); if (inaddr_to_sockaddr("boot.nfsroot.server", &nd->root_saddr)) { printf("FHP: no NFS server\n"); return; } nd->root_saddr.sin_port = htons(NFS_PORT); if ((cp = getenv("boot.netif.hostname")) != NULL) { strncpy(nd->my_hostnam, cp, MAXHOSTNAMELEN - 1); printf("hostname..:%s\n", nd->my_hostnam); } if ((cp = getenv("boot.nfsroot.path")) != NULL) strncpy(nd->root_hostnam, cp, MNAMELEN - 1); /* * by Leal * 2003-17-03 * gateway... */ if ((cp = getenv("boot.netif.gateway")) != NULL) { /* set up gw */ printf("gw........:"); if (inaddr_to_sockaddr("boot.netif.gateway", &mygw)) { printf("FHP: no gateway\n"); return; } } nfs_convert_diskless(); /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ error = socreate(nd3->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, td->td_ucred, td); if (error) panic("FHP: socreate(%04x): %d", nd3->myif.ifra_addr.sa_family, error); error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd3->myif, td); if (error) panic("FHP: ifioctl error"); /* * 2003-17-03 * gateway... */ if (&mygw.sin_len != 0) { struct sockaddr_in dst, mask; clear_sinaddr(&dst); clear_sinaddr(&mask); error = rtrequest(RTM_ADD, (struct sockaddr *) &dst, (struct sockaddr *) &mygw, (struct sockaddr *) &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); if (error != 0) panic("FHP gateway: RTM_ADD: %d", error); } if ((cp3 = getenv("boot.nfsroot.path")) != NULL) { strncpy(nd3->root_hostnam, cp3, MNAMELEN - 1); } error = get_file_handle(&nd3->root_saddr, nd3->root_hostnam, nd3->root_fh, &nd3->root_fhsize, &nd3->root_args, td); if (error != 0 ) panic ("FHP: get_file_handle error"); } static int xdr_int_decode(struct mbuf **mptr, int *iptr) { u_int32_t i; if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) return EBADRPC; *iptr = fxdr_unsigned(u_int32_t, i); return 0; } static int xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) { struct mbuf *m; int alignedlen; m = *mptr; alignedlen = ( len + 3 ) & ~3; if (m->m_len < alignedlen) { m = m_pullup(m, alignedlen); if (m == NULL) { *mptr = NULL; return EBADRPC; } } bcopy(mtod(m, u_char *), buf, len); m_adj(m, alignedlen); *mptr = m; return 0; } /* obtain the "magic" file number... */ static int get_file_handle(struct sockaddr_in *mdsin, /* mountd server address */ char *path, u_char *fhp, int *fhsizep, struct nfs_args *args, struct thread *td) { struct mbuf *m; int error; int authunixok; int authcount; int authver; #ifdef BOOTP_NFSV3 /* First try NFS v3 */ /* Get port number for MOUNTD. */ error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, &mdsin->sin_port, td); if (error == 0) { m = xdr_string_encode(path, strlen(path)); /* Do RPC to mountd. */ error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, &m, NULL, td); } if (error == 0) { args->flags |= NFSMNT_NFSV3; } else { #endif /* Fallback to NFS v2 */ /* Get port number for MOUNTD. */ error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, &mdsin->sin_port, td); if (error != 0) return error; m = xdr_string_encode(path, strlen(path)); /* Do RPC to mountd. */ error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, &m, NULL, td); if (error != 0) return error; /* message already freed */ #ifdef BOOTP_NFSV3 } #endif if (xdr_int_decode(&m, &error) != 0 || error != 0) goto bad; if ((args->flags & NFSMNT_NFSV3) != 0) { if (xdr_int_decode(&m, fhsizep) != 0 || *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0) goto bad; } else *fhsizep = NFSX_V2FH; if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) goto bad; if (args->flags & NFSMNT_NFSV3) { if (xdr_int_decode(&m, &authcount) != 0) goto bad; authunixok = 0; if (authcount < 0 || authcount > 100) goto bad; while (authcount > 0) { if (xdr_int_decode(&m, &authver) != 0) goto bad; if (authver == RPCAUTH_UNIX) authunixok = 1; authcount--; } if (authunixok == 0) goto bad; } /* Set port number for NFS use. */ error = krpc_portmap(mdsin, NFS_PROG, (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, &mdsin->sin_port, td); goto out; bad: error = EBADRPC; out: m_freem(m); return error; } void bootpc_init(void) { /* If already filled in, don't touch it here */ if (nfs_diskless_valid != 0) return; /* The start... */ printf("---------------------------------FILE HANDLE PATCH\n"); printf("--------------------------------------------------\n"); setup_nfsdiskless(); printf("--------------------------------------------------\n"); }