Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Dec 2002 18:48:19 -0200 (BRST)
From:      Marcelo Leal <msl@procergs.rs.gov.br>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/46174: bootp_subr.c patch	
Message-ID:  <20021210204819.64EF3E97D457@lagos.procergs.com.br>

next in thread | raw e-mail | index | archive | help

>Number:         46174
>Category:       kern
>Synopsis:       bootp_subr.c patch
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Dec 10 12:50:11 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Marcelo leal
>Release:        FreeBSD 4.7-RELEASE i386
>Organization:
PROCERGS	
>Environment:
System: FreeBSD lagos.procergs.com.br 4.7-RELEASE FreeBSD 4.7-RELEASE #18: Tue Dec 10 12:51:17 BRST 2002 procergs@lagos.procergs.com.br:/usr/src/sys/compile/ROOT_NFS-CAM256-FHP i386

>Description:
 bootp_subr.c patch
 Today, hard drives is not so expansives, and "diskless" machines normaly have hard drives ( to hold swap device, /tmp, /dev/ and /spool directories).
 So, in my environment, my diskless machines have hard drives to do that job, and my important data are in a confiable storage equipament. Because the machines 
have hard drives, i have decided loads the diskless kernel from HD too. Then, i do not need bootp/dhcpd and tftp servers anymore... And i want configure my diskless kernel
with variables, set in loader.conf. But i can't, because FreeBSD do ip, network, root server and so configurations with bootp or pxe protocol... So i did some adaptations and 
patches in the bootp_subr.c code for fix this.
 Now i have a bootp_subr.c code that works fine! With the BOOTP and BOOTP_NFSROOT options in kernel config file, and replacing the default bootp_subr.c code for mine, The FreeBSD
kernel can configure itself for nfs root filesystem (get a file handle too), without dynamic protocols. This is one more feature for FreeBSD project.
 I would be honor if the FreeBSD project lets me put my contribution in kernel source code... 
 The variables in loader.conf:
 boot.netif.hostname=
 boot.netif.hwaddr=
 boot.netif.ip=
 boot.netif.netmask=
 boot.nfsroot.server=
 boot.nfsroot.path=
 vfs.root.mountfrom=
 
  In my home page have instructions and my bootp_subr.c code:
  http://oslo.procergs.com.br/tor/leal/FreeBSD/bootp_subr.c

>How-To-Repeat:
  This report is not for bug, is a patch report.
>Fix:

/* $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.8 2002/03/16 15:56:06 luigi Exp $        */

/*
 * Copyright (c) 2002 Marcelo Leal 
 * 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sockio.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsdiskless.h>
#include <nfs/krpc.h>
#include <nfs/xdr_subs.h>

#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 proc *procp);
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
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()
{      
        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 proc 		*procp;
        struct sockaddr_in      myaddr, netmask;
	struct nfsv3_diskless   *nd3 = &nfsv3_diskless;
	struct onfs_args 	oargs;
	char   			*cp3;

        procp = curproc;
        /* set up interface */
        printf("me........:", "%s");
        if (inaddr_to_sockaddr("boot.netif.ip", &myaddr)) {
                printf("FHP: no ip\n");
                return;
        }
        printf("mask......:", "%s");
        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: no hardware address\n");
                return;
        }

        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 interface\n");
        return; /* no matching interface */
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...:", "%s");
        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);

        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, procp);
        if (error)
           panic("FHP: socreate(%04x): %d", nd3->myif.ifra_addr.sa_family, error);
        error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd3->myif, procp);
        if (error)
           panic("FHP: ifioctl error", "%s"); 
        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, procp);
        if (error != 0 ) 
	    panic ("FHP: get_file_handle error", "%s");
}        

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 proc *procp)
{       
        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, procp);
        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, procp);
        }
        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, procp);
                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, procp);
                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, procp);
       
        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", "%s");
        printf("\033\[01\;34mCia de Processamento de Dados do Rio Grande do Sul\033\[0m\n", "%s");
        printf("--------------------------------------------------\n", "%s");
        setup_nfsdiskless();
        printf("--------------------------------------------------\n", "%s");
}


>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021210204819.64EF3E97D457>