diff options
Diffstat (limited to 'sys/nfsclient/nfs_diskless.c')
-rw-r--r-- | sys/nfsclient/nfs_diskless.c | 165 |
1 files changed, 120 insertions, 45 deletions
diff --git a/sys/nfsclient/nfs_diskless.c b/sys/nfsclient/nfs_diskless.c index 2f91b9d..aacecff 100644 --- a/sys/nfsclient/nfs_diskless.c +++ b/sys/nfsclient/nfs_diskless.c @@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$"); static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa); static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa); -static int decode_nfshandle(char *ev, u_char *fh); +static int decode_nfshandle(char *ev, u_char *fh, int maxfh); /* * Validate/sanity check a rsize/wsize parameter. @@ -143,20 +143,37 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd) * boot.nfsroot.server IP address of root filesystem server * boot.nfsroot.path path of the root filesystem on server * boot.nfsroot.nfshandle NFS handle for root filesystem on server + * boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only) * boot.nfsroot.options NFS options for the root filesystem */ void nfs_setup_diskless(void) { struct nfs_diskless *nd = &nfs_diskless; + struct nfsv3_diskless *nd3 = &nfsv3_diskless; struct ifnet *ifp; struct ifaddr *ifa; struct sockaddr_dl *sdl, ourdl; struct sockaddr_in myaddr, netmask; char *cp; + int cnt, fhlen, is_nfsv3; + uint32_t len; - if (nfs_diskless_valid) + if (nfs_diskless_valid != 0) return; + + /* get handle size. If this succeeds, it's an NFSv3 setup. */ + if ((cp = getenv("boot.nfsroot.nfshandlelen")) != NULL) { + cnt = sscanf(cp, "%d", &len); + freeenv(cp); + if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) { + printf("nfs_diskless: bad NFS handle len\n"); + return; + } + nd3->root_fhsize = len; + is_nfsv3 = 1; + } else + is_nfsv3 = 0; /* set up interface */ if (inaddr_to_sockaddr("boot.netif.ip", &myaddr)) return; @@ -164,11 +181,21 @@ nfs_setup_diskless(void) printf("nfs_diskless: 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 (is_nfsv3 != 0) { + bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr)); + bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr)); + ((struct sockaddr_in *) + &nd3->myif.ifra_broadaddr)->sin_addr.s_addr = + myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; + bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask)); + } else { + 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("nfs_diskless: no hardware address\n"); @@ -196,46 +223,94 @@ nfs_setup_diskless(void) return; /* no matching interface */ match_done: setenv("boot.netif.name", ifp->if_xname); - strlcpy(nd->myif.ifra_name, ifp->if_xname, sizeof(nd->myif.ifra_name)); + if (is_nfsv3 != 0) { + strlcpy(nd3->myif.ifra_name, ifp->if_xname, + sizeof(nd3->myif.ifra_name)); - /* set up gateway */ - inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); + /* set up gateway */ + inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway); - /* set up root mount */ - nd->root_args.rsize = 8192; /* XXX tunable? */ - nd->root_args.wsize = 8192; - nd->root_args.sotype = SOCK_STREAM; - nd->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); - if (inaddr_to_sockaddr("boot.nfsroot.server", &nd->root_saddr)) { - printf("nfs_diskless: no server\n"); - return; - } - nd->root_saddr.sin_port = htons(NFS_PORT); - if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) { - printf("nfs_diskless: no NFS handle\n"); - return; - } - if ((cp = getenv("boot.nfsroot.path")) != NULL) { - strncpy(nd->root_hostnam, cp, MNAMELEN - 1); - freeenv(cp); - } - if ((cp = getenv("boot.nfsroot.options")) != NULL) { - struct nfs_args args; + /* set up root mount */ + nd3->root_args.rsize = 32768; /* XXX tunable? */ + nd3->root_args.wsize = 32768; + nd3->root_args.sotype = SOCK_STREAM; + nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | + NFSMNT_RSIZE | NFSMNT_RESVPORT); + if (inaddr_to_sockaddr("boot.nfsroot.server", + &nd3->root_saddr)) { + printf("nfs_diskless: no server\n"); + return; + } + nd3->root_saddr.sin_port = htons(NFS_PORT); + fhlen = decode_nfshandle("boot.nfsroot.nfshandle", + &nd3->root_fh[0], NFSX_V3FHMAX); + if (fhlen == 0) { + printf("nfs_diskless: no NFS handle\n"); + return; + } + if (fhlen != nd3->root_fhsize) { + printf("nfs_diskless: bad NFS handle len=%d\n", fhlen); + return; + } + if ((cp = getenv("boot.nfsroot.path")) != NULL) { + strncpy(nd3->root_hostnam, cp, MNAMELEN - 1); + freeenv(cp); + } + if ((cp = getenv("boot.nfsroot.options")) != NULL) { + nfs_parse_options(cp, &nd3->root_args); + freeenv(cp); + } + + nfs_diskless_valid = 3; + } else { + strlcpy(nd->myif.ifra_name, ifp->if_xname, + sizeof(nd->myif.ifra_name)); + + /* set up gateway */ + inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); - /* XXX yech, convert between old and current arg format */ - args.flags = nd->root_args.flags; - args.sotype = nd->root_args.sotype; - args.rsize = nd->root_args.rsize; - args.wsize = nd->root_args.wsize; - nfs_parse_options(cp, &args); - nd->root_args.flags = args.flags; - nd->root_args.sotype = args.sotype; - nd->root_args.rsize = args.rsize; - nd->root_args.wsize = args.wsize; - freeenv(cp); + /* set up root mount */ + nd->root_args.rsize = 8192; /* XXX tunable? */ + nd->root_args.wsize = 8192; + nd->root_args.sotype = SOCK_STREAM; + nd->root_args.flags = (NFSMNT_WSIZE | + NFSMNT_RSIZE | NFSMNT_RESVPORT); + if (inaddr_to_sockaddr("boot.nfsroot.server", + &nd->root_saddr)) { + printf("nfs_diskless: no server\n"); + return; + } + nd->root_saddr.sin_port = htons(NFS_PORT); + if (decode_nfshandle("boot.nfsroot.nfshandle", + &nd->root_fh[0], NFSX_V2FH) == 0) { + printf("nfs_diskless: no NFS handle\n"); + return; + } + if ((cp = getenv("boot.nfsroot.path")) != NULL) { + strncpy(nd->root_hostnam, cp, MNAMELEN - 1); + freeenv(cp); + } + if ((cp = getenv("boot.nfsroot.options")) != NULL) { + struct nfs_args args; + + /* + * XXX yech, convert between old and current + * arg format + */ + args.flags = nd->root_args.flags; + args.sotype = nd->root_args.sotype; + args.rsize = nd->root_args.rsize; + args.wsize = nd->root_args.wsize; + nfs_parse_options(cp, &args); + nd->root_args.flags = args.flags; + nd->root_args.sotype = args.sotype; + nd->root_args.rsize = args.rsize; + nd->root_args.wsize = args.wsize; + freeenv(cp); + } + + nfs_diskless_valid = 1; } - - nfs_diskless_valid = 1; } static int @@ -289,7 +364,7 @@ hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa) } static int -decode_nfshandle(char *ev, u_char *fh) +decode_nfshandle(char *ev, u_char *fh, int maxfh) { u_char *cp, *ep; int len, val; @@ -315,7 +390,7 @@ decode_nfshandle(char *ev, u_char *fh) *(fh++) = val; len++; cp += 2; - if (len > NFSX_V2FH) { + if (len > maxfh) { freeenv(ep); return (0); } |