1 1.2 pgoyette /* $NetBSD: nfs_diskless.c,v 1.2 2016/12/13 22:41:46 pgoyette Exp $ */ 2 1.1 dholland /*- 3 1.1 dholland * Copyright (c) 1990 The Regents of the University of California. 4 1.1 dholland * All rights reserved. 5 1.1 dholland * 6 1.1 dholland * This code is derived from software contributed to Berkeley by 7 1.1 dholland * William Jolitz. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 4. Neither the name of the University nor the names of its contributors 18 1.1 dholland * may be used to endorse or promote products derived from this software 19 1.1 dholland * without specific prior written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 dholland * SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 34 1.1 dholland */ 35 1.1 dholland 36 1.1 dholland #include <sys/cdefs.h> 37 1.2 pgoyette /* __FBSDID("FreeBSD: head/sys/nfs/nfs_diskless.c 297086 2016-03-20 21:48:26Z ian "); */ 38 1.2 pgoyette __RCSID("$NetBSD: nfs_diskless.c,v 1.2 2016/12/13 22:41:46 pgoyette Exp $"); 39 1.1 dholland 40 1.2 pgoyette #ifdef _KERNEL_OPT 41 1.2 pgoyette #include "opt_newnfs.h" 42 1.2 pgoyette #endif 43 1.1 dholland 44 1.1 dholland #include <sys/param.h> 45 1.1 dholland #include <sys/systm.h> 46 1.1 dholland #include <sys/jail.h> 47 1.1 dholland #include <sys/kernel.h> 48 1.1 dholland #include <sys/malloc.h> 49 1.1 dholland #include <sys/mount.h> 50 1.1 dholland #include <sys/socket.h> 51 1.1 dholland 52 1.1 dholland #include <net/if.h> 53 1.1 dholland #include <net/if_dl.h> 54 1.1 dholland #include <net/if_types.h> 55 1.2 pgoyette 56 1.1 dholland #include <net/if_var.h> 57 1.1 dholland #include <net/ethernet.h> 58 1.1 dholland #include <net/vnet.h> 59 1.1 dholland 60 1.1 dholland #include <netinet/in.h> 61 1.2 pgoyette 62 1.2 pgoyette #include <fs/nfs/common/nfsproto.h> 63 1.2 pgoyette #include <fs/nfs/client/nfs.h> 64 1.2 pgoyette #include <fs/nfs/common/nfsdiskless.h> 65 1.2 pgoyette 66 1.2 pgoyette #define NFS_IFACE_TIMEOUT_SECS 10 /* Timeout for interface to appear. */ 67 1.1 dholland 68 1.1 dholland static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa); 69 1.1 dholland static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa); 70 1.1 dholland static int decode_nfshandle(char *ev, u_char *fh, int maxfh); 71 1.1 dholland 72 1.1 dholland /* 73 1.1 dholland * This structure must be filled in by a primary bootstrap or bootstrap 74 1.1 dholland * server for a diskless/dataless machine. It is initialized below just 75 1.1 dholland * to ensure that it is allocated to initialized data (.data not .bss). 76 1.1 dholland */ 77 1.1 dholland struct nfs_diskless nfs_diskless = { { { 0 } } }; 78 1.1 dholland struct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 79 1.1 dholland int nfs_diskless_valid = 0; 80 1.1 dholland 81 1.1 dholland /* 82 1.1 dholland * Validate/sanity check a rsize/wsize parameter. 83 1.1 dholland */ 84 1.1 dholland static int 85 1.1 dholland checkrwsize(unsigned long v, const char *name) 86 1.1 dholland { 87 1.1 dholland /* 88 1.1 dholland * 32K is used as an upper bound because most servers 89 1.1 dholland * limit block size to satisfy IPv4's limit of 90 1.1 dholland * 64K/reassembled packet. The lower bound is pretty 91 1.1 dholland * much arbitrary. 92 1.1 dholland */ 93 1.1 dholland if (!(4 <= v && v <= 32*1024)) { 94 1.1 dholland printf("nfs_parse_options: invalid %s %lu ignored\n", name, v); 95 1.1 dholland return 0; 96 1.1 dholland } else 97 1.1 dholland return 1; 98 1.1 dholland } 99 1.1 dholland 100 1.1 dholland /* 101 1.1 dholland * Parse mount options and apply them to the supplied 102 1.1 dholland * nfs_diskless state. Used also by bootp/dhcp support. 103 1.1 dholland */ 104 1.1 dholland void 105 1.1 dholland nfs_parse_options(const char *envopts, struct nfs_args *nd) 106 1.1 dholland { 107 1.1 dholland char *opts, *o, *otmp; 108 1.1 dholland unsigned long v; 109 1.1 dholland 110 1.1 dholland opts = strdup(envopts, M_TEMP); 111 1.1 dholland otmp = opts; 112 1.1 dholland while ((o = strsep(&otmp, ":;, ")) != NULL) { 113 1.1 dholland if (*o == '\0') 114 1.1 dholland ; /* Skip empty options. */ 115 1.1 dholland else if (strcmp(o, "soft") == 0) 116 1.1 dholland nd->flags |= NFSMNT_SOFT; 117 1.1 dholland else if (strcmp(o, "intr") == 0) 118 1.1 dholland nd->flags |= NFSMNT_INT; 119 1.1 dholland else if (strcmp(o, "conn") == 0) 120 1.1 dholland nd->flags |= NFSMNT_NOCONN; 121 1.1 dholland else if (strcmp(o, "nolockd") == 0) 122 1.1 dholland nd->flags |= NFSMNT_NOLOCKD; 123 1.1 dholland else if (strcmp(o, "nocto") == 0) 124 1.1 dholland nd->flags |= NFSMNT_NOCTO; 125 1.1 dholland else if (strcmp(o, "nfsv2") == 0) 126 1.1 dholland nd->flags &= ~(NFSMNT_NFSV3 | NFSMNT_NFSV4); 127 1.1 dholland else if (strcmp(o, "nfsv3") == 0) { 128 1.1 dholland nd->flags &= ~NFSMNT_NFSV4; 129 1.1 dholland nd->flags |= NFSMNT_NFSV3; 130 1.1 dholland } else if (strcmp(o, "tcp") == 0) 131 1.1 dholland nd->sotype = SOCK_STREAM; 132 1.1 dholland else if (strcmp(o, "udp") == 0) 133 1.1 dholland nd->sotype = SOCK_DGRAM; 134 1.1 dholland else if (strncmp(o, "rsize=", 6) == 0) { 135 1.1 dholland v = strtoul(o+6, NULL, 10); 136 1.1 dholland if (checkrwsize(v, "rsize")) { 137 1.1 dholland nd->rsize = (int) v; 138 1.1 dholland nd->flags |= NFSMNT_RSIZE; 139 1.1 dholland } 140 1.1 dholland } else if (strncmp(o, "wsize=", 6) == 0) { 141 1.1 dholland v = strtoul(o+6, NULL, 10); 142 1.1 dholland if (checkrwsize(v, "wsize")) { 143 1.1 dholland nd->wsize = (int) v; 144 1.1 dholland nd->flags |= NFSMNT_WSIZE; 145 1.1 dholland } 146 1.1 dholland } else 147 1.1 dholland printf("%s: skipping unknown option \"%s\"\n", 148 1.1 dholland __func__, o); 149 1.1 dholland } 150 1.1 dholland free(opts, M_TEMP); 151 1.1 dholland } 152 1.1 dholland 153 1.1 dholland /* 154 1.1 dholland * Populate the essential fields in the nfsv3_diskless structure. 155 1.1 dholland * 156 1.1 dholland * The loader is expected to export the following environment variables: 157 1.1 dholland * 158 1.1 dholland * boot.netif.name name of boot interface 159 1.1 dholland * boot.netif.ip IP address on boot interface 160 1.1 dholland * boot.netif.netmask netmask on boot interface 161 1.1 dholland * boot.netif.gateway default gateway (optional) 162 1.1 dholland * boot.netif.hwaddr hardware address of boot interface 163 1.2 pgoyette * boot.netif.mtu interface mtu from bootp/dhcp (optional) 164 1.1 dholland * boot.nfsroot.server IP address of root filesystem server 165 1.1 dholland * boot.nfsroot.path path of the root filesystem on server 166 1.1 dholland * boot.nfsroot.nfshandle NFS handle for root filesystem on server 167 1.1 dholland * boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only) 168 1.1 dholland * boot.nfsroot.options NFS options for the root filesystem 169 1.1 dholland */ 170 1.1 dholland void 171 1.1 dholland nfs_setup_diskless(void) 172 1.1 dholland { 173 1.1 dholland struct nfs_diskless *nd = &nfs_diskless; 174 1.1 dholland struct nfsv3_diskless *nd3 = &nfsv3_diskless; 175 1.1 dholland struct ifnet *ifp; 176 1.1 dholland struct ifaddr *ifa; 177 1.1 dholland struct sockaddr_dl *sdl, ourdl; 178 1.1 dholland struct sockaddr_in myaddr, netmask; 179 1.1 dholland char *cp; 180 1.1 dholland int cnt, fhlen, is_nfsv3; 181 1.1 dholland uint32_t len; 182 1.2 pgoyette time_t timeout_at; 183 1.1 dholland 184 1.1 dholland if (nfs_diskless_valid != 0) 185 1.1 dholland return; 186 1.1 dholland 187 1.1 dholland /* get handle size. If this succeeds, it's an NFSv3 setup. */ 188 1.2 pgoyette if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) { 189 1.1 dholland cnt = sscanf(cp, "%d", &len); 190 1.1 dholland freeenv(cp); 191 1.1 dholland if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) { 192 1.1 dholland printf("nfs_diskless: bad NFS handle len\n"); 193 1.1 dholland return; 194 1.1 dholland } 195 1.1 dholland nd3->root_fhsize = len; 196 1.1 dholland is_nfsv3 = 1; 197 1.1 dholland } else 198 1.1 dholland is_nfsv3 = 0; 199 1.1 dholland /* set up interface */ 200 1.1 dholland if (inaddr_to_sockaddr("boot.netif.ip", &myaddr)) 201 1.1 dholland return; 202 1.1 dholland if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) { 203 1.1 dholland printf("nfs_diskless: no netmask\n"); 204 1.1 dholland return; 205 1.1 dholland } 206 1.1 dholland if (is_nfsv3 != 0) { 207 1.1 dholland bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr)); 208 1.1 dholland bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr)); 209 1.1 dholland ((struct sockaddr_in *) 210 1.1 dholland &nd3->myif.ifra_broadaddr)->sin_addr.s_addr = 211 1.1 dholland myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; 212 1.1 dholland bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask)); 213 1.1 dholland } else { 214 1.1 dholland bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr)); 215 1.1 dholland bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr)); 216 1.1 dholland ((struct sockaddr_in *) 217 1.1 dholland &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 218 1.1 dholland myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; 219 1.1 dholland bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); 220 1.1 dholland } 221 1.1 dholland 222 1.1 dholland if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) { 223 1.1 dholland printf("nfs_diskless: no hardware address\n"); 224 1.1 dholland return; 225 1.1 dholland } 226 1.1 dholland ifa = NULL; 227 1.2 pgoyette timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS; 228 1.2 pgoyette retry: 229 1.1 dholland CURVNET_SET(TD_TO_VNET(curthread)); 230 1.1 dholland IFNET_RLOCK(); 231 1.1 dholland TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 232 1.1 dholland TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 233 1.1 dholland if (ifa->ifa_addr->sa_family == AF_LINK) { 234 1.1 dholland sdl = (struct sockaddr_dl *)ifa->ifa_addr; 235 1.1 dholland if ((sdl->sdl_type == ourdl.sdl_type) && 236 1.1 dholland (sdl->sdl_alen == ourdl.sdl_alen) && 237 1.1 dholland !bcmp(LLADDR(sdl), 238 1.1 dholland LLADDR(&ourdl), 239 1.1 dholland sdl->sdl_alen)) { 240 1.1 dholland IFNET_RUNLOCK(); 241 1.1 dholland CURVNET_RESTORE(); 242 1.1 dholland goto match_done; 243 1.1 dholland } 244 1.1 dholland } 245 1.1 dholland } 246 1.1 dholland } 247 1.1 dholland IFNET_RUNLOCK(); 248 1.1 dholland CURVNET_RESTORE(); 249 1.2 pgoyette if (time_uptime < timeout_at) { 250 1.2 pgoyette pause("nfssdl", hz / 5); 251 1.2 pgoyette goto retry; 252 1.2 pgoyette } 253 1.1 dholland printf("nfs_diskless: no interface\n"); 254 1.1 dholland return; /* no matching interface */ 255 1.1 dholland match_done: 256 1.2 pgoyette kern_setenv("boot.netif.name", ifp->if_xname); 257 1.1 dholland if (is_nfsv3 != 0) { 258 1.1 dholland strlcpy(nd3->myif.ifra_name, ifp->if_xname, 259 1.1 dholland sizeof(nd3->myif.ifra_name)); 260 1.1 dholland 261 1.1 dholland /* set up gateway */ 262 1.1 dholland inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway); 263 1.1 dholland 264 1.1 dholland /* set up root mount */ 265 1.1 dholland nd3->root_args.rsize = 32768; /* XXX tunable? */ 266 1.1 dholland nd3->root_args.wsize = 32768; 267 1.1 dholland nd3->root_args.sotype = SOCK_STREAM; 268 1.1 dholland nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | 269 1.1 dholland NFSMNT_RSIZE | NFSMNT_RESVPORT); 270 1.1 dholland if (inaddr_to_sockaddr("boot.nfsroot.server", 271 1.1 dholland &nd3->root_saddr)) { 272 1.1 dholland printf("nfs_diskless: no server\n"); 273 1.1 dholland return; 274 1.1 dholland } 275 1.1 dholland nd3->root_saddr.sin_port = htons(NFS_PORT); 276 1.1 dholland fhlen = decode_nfshandle("boot.nfsroot.nfshandle", 277 1.1 dholland &nd3->root_fh[0], NFSX_V3FHMAX); 278 1.1 dholland if (fhlen == 0) { 279 1.1 dholland printf("nfs_diskless: no NFS handle\n"); 280 1.1 dholland return; 281 1.1 dholland } 282 1.1 dholland if (fhlen != nd3->root_fhsize) { 283 1.1 dholland printf("nfs_diskless: bad NFS handle len=%d\n", fhlen); 284 1.1 dholland return; 285 1.1 dholland } 286 1.2 pgoyette if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) { 287 1.1 dholland strncpy(nd3->root_hostnam, cp, MNAMELEN - 1); 288 1.1 dholland freeenv(cp); 289 1.1 dholland } 290 1.2 pgoyette if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { 291 1.1 dholland nfs_parse_options(cp, &nd3->root_args); 292 1.1 dholland freeenv(cp); 293 1.1 dholland } 294 1.1 dholland 295 1.1 dholland nfs_diskless_valid = 3; 296 1.1 dholland } else { 297 1.1 dholland strlcpy(nd->myif.ifra_name, ifp->if_xname, 298 1.1 dholland sizeof(nd->myif.ifra_name)); 299 1.1 dholland 300 1.1 dholland /* set up gateway */ 301 1.1 dholland inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); 302 1.1 dholland 303 1.1 dholland /* set up root mount */ 304 1.1 dholland nd->root_args.rsize = 8192; /* XXX tunable? */ 305 1.1 dholland nd->root_args.wsize = 8192; 306 1.1 dholland nd->root_args.sotype = SOCK_STREAM; 307 1.1 dholland nd->root_args.flags = (NFSMNT_WSIZE | 308 1.1 dholland NFSMNT_RSIZE | NFSMNT_RESVPORT); 309 1.1 dholland if (inaddr_to_sockaddr("boot.nfsroot.server", 310 1.1 dholland &nd->root_saddr)) { 311 1.1 dholland printf("nfs_diskless: no server\n"); 312 1.1 dholland return; 313 1.1 dholland } 314 1.1 dholland nd->root_saddr.sin_port = htons(NFS_PORT); 315 1.1 dholland if (decode_nfshandle("boot.nfsroot.nfshandle", 316 1.1 dholland &nd->root_fh[0], NFSX_V2FH) == 0) { 317 1.1 dholland printf("nfs_diskless: no NFS handle\n"); 318 1.1 dholland return; 319 1.1 dholland } 320 1.2 pgoyette if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) { 321 1.1 dholland strncpy(nd->root_hostnam, cp, MNAMELEN - 1); 322 1.1 dholland freeenv(cp); 323 1.1 dholland } 324 1.2 pgoyette if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { 325 1.1 dholland struct nfs_args args; 326 1.1 dholland 327 1.1 dholland /* 328 1.1 dholland * XXX yech, convert between old and current 329 1.1 dholland * arg format 330 1.1 dholland */ 331 1.1 dholland args.flags = nd->root_args.flags; 332 1.1 dholland args.sotype = nd->root_args.sotype; 333 1.1 dholland args.rsize = nd->root_args.rsize; 334 1.1 dholland args.wsize = nd->root_args.wsize; 335 1.1 dholland nfs_parse_options(cp, &args); 336 1.1 dholland nd->root_args.flags = args.flags; 337 1.1 dholland nd->root_args.sotype = args.sotype; 338 1.1 dholland nd->root_args.rsize = args.rsize; 339 1.1 dholland nd->root_args.wsize = args.wsize; 340 1.1 dholland freeenv(cp); 341 1.1 dholland } 342 1.1 dholland 343 1.1 dholland nfs_diskless_valid = 1; 344 1.1 dholland } 345 1.1 dholland } 346 1.1 dholland 347 1.1 dholland static int 348 1.1 dholland inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa) 349 1.1 dholland { 350 1.1 dholland u_int32_t a[4]; 351 1.1 dholland char *cp; 352 1.1 dholland int count; 353 1.1 dholland 354 1.1 dholland bzero(sa, sizeof(*sa)); 355 1.1 dholland sa->sin_len = sizeof(*sa); 356 1.1 dholland sa->sin_family = AF_INET; 357 1.1 dholland 358 1.2 pgoyette if ((cp = kern_getenv(ev)) == NULL) 359 1.1 dholland return (1); 360 1.1 dholland count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); 361 1.1 dholland freeenv(cp); 362 1.1 dholland if (count != 4) 363 1.1 dholland return (1); 364 1.1 dholland sa->sin_addr.s_addr = 365 1.1 dholland htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]); 366 1.1 dholland return (0); 367 1.1 dholland } 368 1.1 dholland 369 1.1 dholland static int 370 1.1 dholland hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa) 371 1.1 dholland { 372 1.1 dholland char *cp; 373 1.1 dholland u_int32_t a[6]; 374 1.1 dholland int count; 375 1.1 dholland 376 1.1 dholland bzero(sa, sizeof(*sa)); 377 1.1 dholland sa->sdl_len = sizeof(*sa); 378 1.1 dholland sa->sdl_family = AF_LINK; 379 1.1 dholland sa->sdl_type = IFT_ETHER; 380 1.1 dholland sa->sdl_alen = ETHER_ADDR_LEN; 381 1.2 pgoyette if ((cp = kern_getenv(ev)) == NULL) 382 1.1 dholland return (1); 383 1.1 dholland count = sscanf(cp, "%x:%x:%x:%x:%x:%x", 384 1.1 dholland &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); 385 1.1 dholland freeenv(cp); 386 1.1 dholland if (count != 6) 387 1.1 dholland return (1); 388 1.1 dholland sa->sdl_data[0] = a[0]; 389 1.1 dholland sa->sdl_data[1] = a[1]; 390 1.1 dholland sa->sdl_data[2] = a[2]; 391 1.1 dholland sa->sdl_data[3] = a[3]; 392 1.1 dholland sa->sdl_data[4] = a[4]; 393 1.1 dholland sa->sdl_data[5] = a[5]; 394 1.1 dholland return (0); 395 1.1 dholland } 396 1.1 dholland 397 1.1 dholland static int 398 1.1 dholland decode_nfshandle(char *ev, u_char *fh, int maxfh) 399 1.1 dholland { 400 1.1 dholland u_char *cp, *ep; 401 1.1 dholland int len, val; 402 1.1 dholland 403 1.2 pgoyette ep = cp = kern_getenv(ev); 404 1.1 dholland if (cp == NULL) 405 1.1 dholland return (0); 406 1.1 dholland if ((strlen(cp) < 2) || (*cp != 'X')) { 407 1.1 dholland freeenv(ep); 408 1.1 dholland return (0); 409 1.1 dholland } 410 1.1 dholland len = 0; 411 1.1 dholland cp++; 412 1.1 dholland for (;;) { 413 1.1 dholland if (*cp == 'X') { 414 1.1 dholland freeenv(ep); 415 1.1 dholland return (len); 416 1.1 dholland } 417 1.1 dholland if ((sscanf(cp, "%2x", &val) != 1) || (val > 0xff)) { 418 1.1 dholland freeenv(ep); 419 1.1 dholland return (0); 420 1.1 dholland } 421 1.1 dholland *(fh++) = val; 422 1.1 dholland len++; 423 1.1 dholland cp += 2; 424 1.1 dholland if (len > maxfh) { 425 1.1 dholland freeenv(ep); 426 1.1 dholland return (0); 427 1.1 dholland } 428 1.1 dholland } 429 1.1 dholland } 430 1.1 dholland 431 1.2 pgoyette #if !defined(NEW_NFS_BOOT_BOOTP) 432 1.1 dholland static void 433 1.1 dholland nfs_rootconf(void) 434 1.1 dholland { 435 1.1 dholland 436 1.1 dholland nfs_setup_diskless(); 437 1.1 dholland if (nfs_diskless_valid) 438 1.1 dholland rootdevnames[0] = "nfs:"; 439 1.1 dholland } 440 1.1 dholland 441 1.1 dholland SYSINIT(cpu_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, nfs_rootconf, NULL); 442 1.1 dholland #endif 443 1.1 dholland 444