summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/nfsclient/nfs_diskless.c165
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);
}
OpenPOWER on IntegriCloud