void bootpc_init(void) { struct bootpc_ifcontext *ifctx, *nctx; /* Interface BOOTP contexts */ struct bootpc_globalcontext *gctx; /* Global BOOTP context */ struct ifnet *ifp; int error; #ifndef BOOTP_WIRED_TO int ifcnt; #endif struct nfsv3_diskless *nd; struct thread *td; nd = &nfsv3_diskless; td = curthread; /* * If already filled in, don't touch it here */ if (nfs_diskless_valid != 0) return; gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO); if (gctx == NULL) panic("Failed to allocate bootp global context structure"); gctx->xid = ~0xFFFF; gctx->starttime = time_second; /* * Find a network interface. */ CURVNET_SET(TD_TO_VNET(td)); #ifdef BOOTP_WIRED_TO printf("bootpc_init: wired to interface '%s'\n", __XSTRING(BOOTP_WIRED_TO)); allocifctx(gctx); #else /* * Preallocate interface context storage, if another interface * attaches and wins the race, it won't be eligible for bootp. */ IFNET_RLOCK(); for (ifp = TAILQ_FIRST(&V_ifnet), ifcnt = 0; ifp != NULL; ifp = TAILQ_NEXT(ifp, if_link)) { if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != IFF_BROADCAST) continue; ifcnt++; } IFNET_RUNLOCK(); if (ifcnt == 0) panic("bootpc_init: no eligible interfaces"); for (; ifcnt > 0; ifcnt--) allocifctx(gctx); #endif IFNET_RLOCK(); for (ifp = TAILQ_FIRST(&V_ifnet), ifctx = gctx->interfaces; ifp != NULL && ifctx != NULL; ifp = TAILQ_NEXT(ifp, if_link)) { strlcpy(ifctx->ireq.ifr_name, ifp->if_xname, sizeof(ifctx->ireq.ifr_name)); #ifdef BOOTP_WIRED_TO if (strcmp(ifctx->ireq.ifr_name, __XSTRING(BOOTP_WIRED_TO)) != 0) continue; #else if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != IFF_BROADCAST) continue; #endif ifctx->ifp = ifp; ifctx = ifctx->next; } IFNET_RUNLOCK(); CURVNET_RESTORE(); if (gctx->interfaces == NULL || gctx->interfaces->ifp == NULL) { #ifdef BOOTP_WIRED_TO panic("bootpc_init: Could not find interface specified " "by BOOTP_WIRED_TO: " __XSTRING(BOOTP_WIRED_TO)); #else panic("bootpc_init: no suitable interface"); #endif } for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) bootpc_fakeup_interface(ifctx, gctx, td); for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) bootpc_compose_query(ifctx, gctx, td); error = bootpc_call(gctx, td); if (error != 0) { #ifdef BOOTP_NFSROOT panic("BOOTP call failed"); #else printf("BOOTP call failed\n"); #endif } rootdevnames[0] = "nfs:"; #ifdef NFSCLIENT rootdevnames[1] = "oldnfs:"; #endif mountopts(&nd->root_args, NULL); for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) if (bootpc_ifctx_isresolved(ifctx) != 0) bootpc_decode_reply(nd, ifctx, gctx); #ifdef BOOTP_NFSROOT if (gctx->gotrootpath == 0) panic("bootpc: No root path offered"); #endif for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { bootpc_adjust_interface(ifctx, gctx, td); soclose(ifctx->so); } for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) if (ifctx->gotrootpath != 0) break; if (ifctx == NULL) { for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) if (bootpc_ifctx_isresolved(ifctx) != 0) break; } if (ifctx == NULL) goto out; if (gctx->gotrootpath != 0) { setenv("boot.netif.name", ifctx->ifp->if_xname); error = md_mount(&nd->root_saddr, nd->root_hostnam, nd->root_fh, &nd->root_fhsize, &nd->root_args, td); if (error != 0) panic("nfs_boot: mountd root, error=%d", error); nfs_diskless_valid = 3; } strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name); bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr)); bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr)); ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr | ~ ifctx->netmask.sin_addr.s_addr; bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask)); out: for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) { nctx = ifctx->next; free(ifctx, M_TEMP); } free(gctx, M_TEMP); }
/* * Get an initial NFS file handle using Sun RPC/mountd. * Separate function because we used to call it twice. * (once for root and once for swap) * * ndm output */ static int nfs_boot_getfh(struct nfs_dlmount *ndm, struct lwp *l) { struct nfs_args *args; struct sockaddr_in *sin; char *pathname; int error; u_int16_t port; args = &ndm->ndm_args; /* Initialize mount args. */ memset((void *) args, 0, sizeof(*args)); args->addr = &ndm->ndm_saddr; args->addrlen = args->addr->sa_len; #ifdef NFS_BOOT_TCP args->sotype = SOCK_STREAM; #else args->sotype = SOCK_DGRAM; #endif args->fh = ndm->ndm_fh; args->hostname = ndm->ndm_host; args->flags = NFSMNT_NOCONN | NFSMNT_RESVPORT; #ifndef NFS_V2_ONLY args->flags |= NFSMNT_NFSV3; #endif #ifdef NFS_BOOT_OPTIONS args->flags |= NFS_BOOT_OPTIONS; #endif #ifdef NFS_BOOT_RWSIZE /* * Reduce rsize,wsize for interfaces that consistently * drop fragments of long UDP messages. (i.e. wd8003). * You can always change these later via remount. */ args->flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; args->wsize = NFS_BOOT_RWSIZE; args->rsize = NFS_BOOT_RWSIZE; #endif /* * Find the pathname part of the "server:pathname" * string left in ndm->ndm_host by nfs_boot_init. */ pathname = strchr(ndm->ndm_host, ':'); if (pathname == 0) { printf("nfs_boot: getfh - no pathname\n"); return (EIO); } pathname++; /* * Get file handle using RPC to mountd/mount */ sin = (struct sockaddr_in *)&ndm->ndm_saddr; error = md_mount(sin, pathname, args, l); if (error) { printf("nfs_boot: mountd `%s', error=%d\n", ndm->ndm_host, error); return (error); } /* Set port number for NFS use. */ /* XXX: NFS port is always 2049, right? */ #ifdef NFS_BOOT_TCP retry: #endif error = krpc_portmap(sin, NFS_PROG, (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, (args->sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP, &port, l); if (port == htons(0)) error = EIO; if (error) { #ifdef NFS_BOOT_TCP if (args->sotype == SOCK_STREAM) { args->sotype = SOCK_DGRAM; goto retry; } #endif printf("nfs_boot: portmap NFS, error=%d\n", error); return (error); } sin->sin_port = port; return (0); }