int tftp_open(char *path, struct open_file *f) { struct tftp_handle *tftpfile; struct iodesc *io; int res; tftpfile = (struct tftp_handle *) alloc(sizeof(*tftpfile)); if (tftpfile == NULL) return ENOMEM; tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); io->destip = servip; tftpfile->off = 0; tftpfile->path = path; /* XXXXXXX we hope it's static */ res = tftp_makereq(tftpfile); if (res) { free(tftpfile, sizeof(*tftpfile)); return res; } f->f_fsdata = (void *) tftpfile; return 0; }
/* * nfs_mount - mount this nfs filesystem to a host * On error, return non-zero and set errno. */ int nfs_mount(int sock, struct in_addr ip, char *path) { struct iodesc *desc; struct nfsv2_fattrs *fa; if (!(desc = socktodesc(sock))) { errno = EINVAL; return(-1); } /* Bind to a reserved port. */ desc->myport = htons(--rpc_port); desc->destip = ip; if (nfs_getrootfh(desc, path, nfs_root_node.fh)) return (-1); nfs_root_node.iodesc = desc; /* Fake up attributes for the root dir. */ fa = &nfs_root_node.fa; fa->fa_type = htonl(NFDIR); fa->fa_mode = htonl(0755); fa->fa_nlink = htonl(2); #ifdef NFS_DEBUG if (debug) printf("nfs_mount: got fh for %s\n", path); #endif return(0); }
int net_open(struct open_file *f, ...) { char *fname; char **file; struct iodesc *s; va_list ap; va_start(ap, f); fname = va_arg(ap, char *); file = va_arg(ap, char **); va_end(ap); f->f_devdata = &netdev_sock; netdev_sock = netif_open(NULL); bootfile[0] = '\0'; if (bootopts.b_flags & B_F_USE_BOOTP) { s = socktodesc(netdev_sock); bootp(netdev_sock); if (fname[0] != '\0') strlcpy(bootfile, fname, sizeof bootfile); } else { s = socktodesc(netdev_sock); servip = s->destip = bootopts.b_remote_ip; myip = s->myip = bootopts.b_local_ip; netmask = bootopts.b_netmask; gateip = bootopts.b_gate_ip; if (fname[0] == '\0') { printf("no boot filename\n"); netif_close(netdev_sock); return EIO; } strlcpy(bootfile, fname, sizeof bootfile); } *file = bootfile; return 0; }
/* Fetch required bootp information */ void bootp(int sock) { struct iodesc *d; struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[HEADER_SIZE]; struct bootp rbootp; } rbuf; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%x\n", (u_int)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = HTYPE_ETHERNET; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); bzero(bp->bp_file, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); d->myip = myip; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); (void)sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)); /* Bump xid so next request will be unique. */ ++d->xid; }
static int tftp_open(const char *path, struct open_file *f) { struct tftp_handle *tftpfile; struct iodesc *io; int res; if (strcmp(f->f_dev->dv_name, "net") != 0) { #ifdef __i386__ if (strcmp(f->f_dev->dv_name, "pxe") != 0) return (EINVAL); #else return (EINVAL); #endif } if (is_open) return (EBUSY); tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile)); if (!tftpfile) return (ENOMEM); memset(tftpfile, 0, sizeof(*tftpfile)); tftpfile->tftp_blksize = TFTP_REQUESTED_BLKSIZE; tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); if (io == NULL) return (EINVAL); io->destip = servip; tftpfile->off = 0; tftpfile->path = strdup(path); if (tftpfile->path == NULL) { free(tftpfile); return(ENOMEM); } res = tftp_makereq(tftpfile); if (res) { free(tftpfile->path); free(tftpfile); return (res); } f->f_fsdata = (void *) tftpfile; is_open = 1; return (0); }
static int tftp_open(const char *path, struct open_file *f) { struct tftp_handle *tftpfile; struct iodesc *io; int res; /* Avoid trying out tftp_open for disk devices in the EFI loader */ #ifndef __i386__ if (strcmp(f->f_dev->dv_name, "net") != 0) return (EINVAL); #endif tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile)); if (!tftpfile) return (ENOMEM); tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata)); if (io == NULL) { free(tftpfile); return (EINVAL); } io->destip = servip; tftpfile->off = 0; tftpfile->path = strdup(path); if (tftpfile->path == NULL) { free(tftpfile); return(ENOMEM); } res = tftp_makereq(tftpfile); if (res) { free(tftpfile->path); free(tftpfile); return (res); } f->f_fsdata = (void *) tftpfile; return (0); }
/* * Called by devopen after it sets f->f_dev to our devsw entry. * This opens the low-level device and sets f->f_devdata. * This is declared with variable arguments... */ static int net_open(struct open_file *f, ...) { char temp[FNAME_SIZE]; struct iodesc *d; va_list args; char *devname; /* Device part of file name (or NULL). */ int error = 0; va_start(args, f); devname = va_arg(args, char*); va_end(args); #ifdef NETIF_OPEN_CLOSE_ONCE /* Before opening another interface, close the previous one first. */ if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) net_cleanup(); #endif /* On first open, do netif open, mount, etc. */ if (netdev_opens == 0) { /* Find network interface. */ if (netdev_sock < 0) { netdev_sock = netif_open(devname); if (netdev_sock < 0) { printf("net_open: netif_open() failed\n"); return (ENXIO); } netdev_name = strdup(devname); #ifdef NETIF_DEBUG if (debug) printf("net_open: netif_open() succeeded\n"); #endif } /* * If network params were not set by netif_open(), try to get * them via bootp, rarp, etc. */ if (rootip.s_addr == 0) { /* Get root IP address, and path, etc. */ error = net_getparams(netdev_sock); if (error) { /* getparams makes its own noise */ free(netdev_name); netif_close(netdev_sock); netdev_sock = -1; return (error); } } /* * Set the variables required by the kernel's nfs_diskless * mechanism. This is the minimum set of variables required to * mount a root filesystem without needing to obtain additional * info from bootp or other sources. */ d = socktodesc(netdev_sock); sprintf(temp, "%6D", d->myea, ":"); setenv("boot.netif.hwaddr", temp, 1); setenv("boot.netif.ip", inet_ntoa(myip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); } netdev_opens++; f->f_devdata = &netdev_sock; return (error); }
int netmountroot(struct open_file *f, char *devname) { int error; struct iodesc *d; #ifdef DEBUG printf("netmountroot: %s\n", devname); #endif if (netio_ask) { get_my_ip: printf("My IP address? "); bzero(input_line, sizeof(input_line)); gets(input_line); if ((myip.s_addr = inet_addr(input_line)) == htonl(INADDR_NONE)) { printf("invalid IP address: %s\n", input_line); goto get_my_ip; } get_my_netmask: printf("My netmask? "); bzero(input_line, sizeof(input_line)); gets(input_line); if ((netmask = inet_addr(input_line)) == htonl(INADDR_NONE)) { printf("invalid netmask: %s\n", input_line); goto get_my_netmask; } get_my_gateway: printf("My gateway? "); bzero(input_line, sizeof(input_line)); gets(input_line); if ((gateip.s_addr = inet_addr(input_line)) == htonl(INADDR_NONE)) { printf("invalid IP address: %s\n", input_line); goto get_my_gateway; } get_server_ip: printf("Server IP address? "); bzero(input_line, sizeof(input_line)); gets(input_line); if ((rootip.s_addr = inet_addr(input_line)) == htonl(INADDR_NONE)) { printf("invalid IP address: %s\n", input_line); goto get_server_ip; } get_server_path: printf("Server path? "); bzero(rootpath, sizeof(rootpath)); gets(rootpath); if (rootpath[0] == '\0' || rootpath[0] == '\n') goto get_server_path; if ((d = socktodesc(netdev_sock)) == NULL) return (EMFILE); d->myip = myip; goto do_nfs_mount; } /* * Get info for NFS boot: our IP address, our hostname, * server IP address, and our root path on the server. * There are two ways to do this: The old, Sun way, * and the more modern, BOOTP way. (RFC951, RFC1048) */ #ifdef SUN_BOOTPARAMS /* Get boot info using RARP and Sun bootparams. */ /* Get our IP address. (rarp.c) */ if (rarp_getipaddress(netdev_sock) == -1) return (errno); printf("boot: client IP address: %s\n", inet_ntoa(myip)); /* Get our hostname, server IP address. */ if (bp_whoami(netdev_sock)) return (errno); printf("boot: client name: %s\n", hostname); /* Get the root pathname. */ if (bp_getfile(netdev_sock, "root", &rootip, rootpath)) return (errno); #else /* Get boot info using BOOTP way. (RFC951, RFC1048) */ bootp(netdev_sock); printf("Using IP address: %s\n", inet_ntoa(myip)); printf("myip: %s (%s)", hostname, inet_ntoa(myip)); if (gateip) printf(", gateip: %s", inet_ntoa(gateip)); if (mask) printf(", mask: %s", intoa(netmask)); printf("\n"); #endif /* SUN_BOOTPARAMS */ printf("root addr=%s path=%s\n", inet_ntoa(rootip), rootpath); do_nfs_mount: /* Get the NFS file handle (mount). */ error = nfs_mount(netdev_sock, rootip, rootpath); return (error); }
/* Fetch required bootp infomation */ void bootp(int sock, int flag) { struct iodesc *d; struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[HEADER_SIZE]; struct bootp rbootp; } rbuf; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); #ifdef SUPPORT_DHCP bp->bp_vend[4] = TAG_DHCP_MSGTYPE; bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPDISCOVER; /* * If we are booting from PXE, we want to send the string * 'PXEClient' to the DHCP server so you have the option of * only responding to PXE aware dhcp requests. */ if (flag & BOOTP_PXE) { bp->bp_vend[7] = TAG_CLASSID; bp->bp_vend[8] = 9; bcopy("PXEClient", &bp->bp_vend[9], 9); bp->bp_vend[18] = TAG_PARAM_REQ; bp->bp_vend[19] = 7; bp->bp_vend[20] = TAG_ROOTPATH; bp->bp_vend[21] = TAG_HOSTNAME; bp->bp_vend[22] = TAG_SWAPSERVER; bp->bp_vend[23] = TAG_GATEWAY; bp->bp_vend[24] = TAG_SUBNET_MASK; bp->bp_vend[25] = TAG_INTF_MTU; bp->bp_vend[26] = TAG_SERVERID; bp->bp_vend[27] = TAG_END; } else bp->bp_vend[7] = TAG_END; #else bp->bp_vend[4] = TAG_END; #endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if(dhcp_ok) { u_int32_t leasetime; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4); bp->bp_vend[13] = TAG_SERVERID; bp->bp_vend[14] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bp->bp_vend[19] = TAG_LEASETIME; bp->bp_vend[20] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[21], 4); if (flag & BOOTP_PXE) { bp->bp_vend[25] = TAG_CLASSID; bp->bp_vend[26] = 9; bcopy("PXEClient", &bp->bp_vend[27], 9); bp->bp_vend[36] = TAG_END; } else bp->bp_vend[25] = TAG_END; expected_dhcpmsgtype = DHCPACK; if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbuf.rbootp.bp_yiaddr; servip = rbuf.rbootp.bp_siaddr; if(rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if (!netmask) { if (IN_CLASSA(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSB_NET); else netmask = htonl(IN_CLASSC_NET); #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(netmask)); #endif } #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; }
/* * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). */ int rarp_getipaddress(int sock) { struct iodesc *d; struct ether_arp *ap; struct { u_char header[ETHER_SIZE]; struct { struct ether_arp arp; u_char pad[18]; /* 60 - sizeof(arp) */ } data; } wbuf; struct { u_char header[ETHER_SIZE]; struct { struct ether_arp arp; u_char pad[24]; /* extra space */ } data; } rbuf; #ifdef RARP_DEBUG if (debug) printf("rarp: socket=%d\n", sock); #endif if (!(d = socktodesc(sock))) { printf("rarp: bad socket. %d\n", sock); return (-1); } #ifdef RARP_DEBUG if (debug) printf("rarp: d=%x\n", (u_int)d); #endif bzero((char*)&wbuf.data, sizeof(wbuf.data)); ap = &wbuf.data.arp; ap->arp_hrd = htons(ARPHRD_ETHER); ap->arp_pro = htons(ETHERTYPE_IP); ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ ap->arp_op = htons(ARPOP_REVREQUEST); bcopy(d->myea, ap->arp_sha, 6); bcopy(d->myea, ap->arp_tha, 6); if (sendrecv(d, rarpsend, &wbuf.data, sizeof(wbuf.data), rarprecv, &rbuf.data, sizeof(rbuf.data)) < 0) { printf("No response for RARP request\n"); return (-1); } ap = &rbuf.data.arp; bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); #if 0 /* XXX - Can NOT assume this is our root server! */ bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); #endif /* Compute our "natural" netmask. */ if (IN_CLASSA(myip.s_addr)) netmask = IN_CLASSA_NET; else if (IN_CLASSB(myip.s_addr)) netmask = IN_CLASSB_NET; else netmask = IN_CLASSC_NET; d->myip = myip; return (0); }
/* Fetch required bootp information */ void bootp(int sock) { struct iodesc *d; struct bootp *bp; struct { u_char header[UDP_TOTAL_HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[UDP_TOTAL_HEADER_SIZE]; struct bootp rbootp; } rbuf; unsigned int index; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; (void)memset(bp, 0, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); (void)strncpy((char *)bp->bp_file, bootfile, sizeof(bp->bp_file)); (void)memcpy(bp->bp_vend, vm_rfc1048, sizeof(vm_rfc1048)); index = 4; #ifdef SUPPORT_DHCP bp->bp_vend[index++] = TAG_DHCP_MSGTYPE; bp->bp_vend[index++] = 1; bp->bp_vend[index++] = DHCPDISCOVER; #endif bootp_addvend(&bp->bp_vend[index]); d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if (sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if (dhcp_ok) { u_int32_t leasetime; index = 6; bp->bp_vend[index++] = DHCPREQUEST; bp->bp_vend[index++] = TAG_REQ_ADDR; bp->bp_vend[index++] = 4; (void)memcpy(&bp->bp_vend[9], &rbuf.rbootp.bp_yiaddr, 4); index += 4; bp->bp_vend[index++] = TAG_SERVERID; bp->bp_vend[index++] = 4; (void)memcpy(&bp->bp_vend[index], &dhcp_serverip.s_addr, 4); index += 4; bp->bp_vend[index++] = TAG_LEASETIME; bp->bp_vend[index++] = 4; leasetime = htonl(300); (void)memcpy(&bp->bp_vend[index], &leasetime, 4); index += 4; bootp_addvend(&bp->bp_vend[index]); expected_dhcpmsgtype = DHCPACK; if (sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbuf.rbootp.bp_yiaddr; servip = rbuf.rbootp.bp_siaddr; if (rootip.s_addr == INADDR_ANY) rootip = servip; (void)memcpy(bootfile, rbuf.rbootp.bp_file, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if (IN_CLASSA(myip.s_addr)) nmask = IN_CLASSA_NET; else if (IN_CLASSB(myip.s_addr)) nmask = IN_CLASSB_NET; else nmask = IN_CLASSC_NET; #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(nmask)); #endif /* Get subnet (or natural net) mask */ netmask = nmask; if (smask) netmask = smask; #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } #ifdef BOOTP_DEBUG if (debug) { printf("client addr: %s\n", inet_ntoa(myip)); if (smask) printf("subnet mask: %s\n", intoa(smask)); if (gateip.s_addr != 0) printf("net gateway: %s\n", inet_ntoa(gateip)); printf("server addr: %s\n", inet_ntoa(rootip)); if (rootpath[0] != '\0') printf("server path: %s\n", rootpath); if (bootfile[0] != '\0') printf("file name: %s\n", bootfile); } #endif /* Bump xid so next request will be unique. */ ++d->xid; }
/* Fetch required bootp infomation */ void bootp(int sock) { void *pkt; struct iodesc *d; struct bootp *bp; struct { uchar_t header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct bootp *rbootp; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof (*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof (bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)); #ifdef SUPPORT_DHCP bp->bp_vend[4] = TAG_DHCP_MSGTYPE; bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPDISCOVER; bootp_fill_request(&bp->bp_vend[7]); #else bp->bp_vend[4] = TAG_END; #endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if (sendrecv(d, bootpsend, bp, sizeof (*bp), bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if (dhcp_ok) { uint32_t leasetime; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); bp->bp_vend[13] = TAG_SERVERID; bp->bp_vend[14] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bp->bp_vend[19] = TAG_LEASETIME; bp->bp_vend[20] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[21], 4); bootp_fill_request(&bp->bp_vend[25]); expected_dhcpmsgtype = DHCPACK; free(pkt); if (sendrecv(d, bootpsend, bp, sizeof (*bp), bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbootp->bp_yiaddr; servip = rbootp->bp_siaddr; if (rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbootp->bp_file, bootfile, sizeof (bootfile)); bootfile[sizeof (bootfile) - 1] = '\0'; if (!netmask) { if (IN_CLASSA(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSB_NET); else netmask = htonl(IN_CLASSC_NET); #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(netmask)); #endif } #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; free(pkt); }
static int net_getparams(int sock) { char buf[MAXHOSTNAMELEN]; char temp[FNAME_SIZE]; struct iodesc *d; int i; n_long smask; #ifdef SUPPORT_BOOTP /* * Try to get boot info using BOOTP. If we succeed, then * the server IP address, gateway, and root path will all * be initialized. If any remain uninitialized, we will * use RARP and RPC/bootparam (the Sun way) to get them. */ if (try_bootp) bootp(sock, BOOTP_NONE); if (myip.s_addr != 0) goto exit; if (debug) printf("net_open: BOOTP failed, trying RARP/RPC...\n"); #endif /* * Use RARP to get our IP address. This also sets our * netmask to the "natural" default for our address. */ if (rarp_getipaddress(sock)) { printf("net_open: RARP failed\n"); return (EIO); } printf("net_open: client addr: %s\n", inet_ntoa(myip)); /* Get our hostname, server IP address, gateway. */ if (bp_whoami(sock)) { printf("net_open: bootparam/whoami RPC failed\n"); return (EIO); } printf("net_open: client name: %s\n", hostname); /* * Ignore the gateway from whoami (unreliable). * Use the "gateway" parameter instead. */ smask = 0; gateip.s_addr = 0; if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { /* Got it! Parse the netmask. */ smask = ip_convertaddr(buf); } if (smask) { netmask = smask; printf("net_open: subnet mask: %s\n", intoa(netmask)); } if (gateip.s_addr) printf("net_open: net gateway: %s\n", inet_ntoa(gateip)); /* Get the root server and pathname. */ if (bp_getfile(sock, "root", &rootip, rootpath)) { printf("net_open: bootparam/getfile RPC failed\n"); return (EIO); } exit: /* * If present, strip the server's address off of the rootpath * before passing it along. This allows us to be compatible with * the kernel's diskless (BOOTP_NFSROOT) booting conventions */ for (i = 0; i < FNAME_SIZE && rootpath[i] != '\0'; i++) if (rootpath[i] == ':') break; if (i && i != FNAME_SIZE && rootpath[i] == ':') { rootpath[i++] = '\0'; if (inet_addr(&rootpath[0]) != INADDR_NONE) rootip.s_addr = inet_addr(&rootpath[0]); memcpy(&temp[0], &rootpath[i], strlen(&rootpath[i])+1); memcpy(&rootpath[0], &temp[0], strlen(&rootpath[i])+1); } printf("net_open: server addr: %s\n", inet_ntoa(rootip)); printf("net_open: server path: %s\n", rootpath); d = socktodesc(sock); snprintf(temp, sizeof(temp), "%6D", d->myea, ":"); setenv("boot.netif.ip", inet_ntoa(myip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); setenv("boot.netif.hwaddr", temp, 1); setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); return (0); }
/* * Open a file. * return zero or error number */ int nfs_open(const char *upath, struct open_file *f) { struct iodesc *desc; struct nfs_iodesc *currfd; char buf[2 * NFS_FHSIZE + 3]; u_char *fh; char *cp; int i; #ifndef NFS_NOSYMLINK struct nfs_iodesc *newfd; struct nfsv2_fattrs *fa; char *ncp; int c; char namebuf[NFS_MAXPATHLEN + 1]; char linkbuf[NFS_MAXPATHLEN + 1]; int nlinks = 0; #endif int error; char *path; #ifdef NFS_DEBUG if (debug) printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); #endif if (!rootpath[0]) { printf("no rootpath, no nfs\n"); return (ENXIO); } /* * This is silly - we should look at dv_type but that value is * arch dependant and we can't use it here. */ #ifndef __i386__ if (strcmp(f->f_dev->dv_name, "net") != 0) return(EINVAL); #else if (strcmp(f->f_dev->dv_name, "pxe") != 0) return(EINVAL); #endif if (!(desc = socktodesc(*(int *)(f->f_devdata)))) return(EINVAL); /* Bind to a reserved port. */ desc->myport = htons(--rpc_port); desc->destip = rootip; if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) return (error); nfs_root_node.fa.fa_type = htonl(NFDIR); nfs_root_node.fa.fa_mode = htonl(0755); nfs_root_node.fa.fa_nlink = htonl(2); nfs_root_node.iodesc = desc; fh = &nfs_root_node.fh[0]; buf[0] = 'X'; cp = &buf[1]; for (i = 0; i < NFS_FHSIZE; i++, cp += 2) sprintf(cp, "%02x", fh[i]); sprintf(cp, "X"); setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); setenv("boot.nfsroot.nfshandle", buf, 1); /* Allocate file system specific data structure */ currfd = malloc(sizeof(*newfd)); if (currfd == NULL) { error = ENOMEM; goto out; } #ifndef NFS_NOSYMLINK bcopy(&nfs_root_node, currfd, sizeof(*currfd)); newfd = 0; cp = path = strdup(upath); if (path == NULL) { error = ENOMEM; goto out; } while (*cp) { /* * Remove extra separators */ while (*cp == '/') cp++; if (*cp == '\0') break; /* * Check that current node is a directory. */ if (currfd->fa.fa_type != htonl(NFDIR)) { error = ENOTDIR; goto out; } /* allocate file system specific data structure */ newfd = malloc(sizeof(*newfd)); newfd->iodesc = currfd->iodesc; /* * Get next component of path name. */ { int len = 0; ncp = cp; while ((c = *cp) != '\0' && c != '/') { if (++len > NFS_MAXNAMLEN) { error = ENOENT; goto out; } cp++; } *cp = '\0'; } /* lookup a file handle */ error = nfs_lookupfh(currfd, ncp, newfd); *cp = c; if (error) goto out; /* * Check for symbolic link */ if (newfd->fa.fa_type == htonl(NFLNK)) { int link_len, len; error = nfs_readlink(newfd, linkbuf); if (error) goto out; link_len = strlen(linkbuf); len = strlen(cp); if (link_len + len > MAXPATHLEN || ++nlinks > MAXSYMLINKS) { error = ENOENT; goto out; } bcopy(cp, &namebuf[link_len], len + 1); bcopy(linkbuf, namebuf, link_len); /* * If absolute pathname, restart at root. * If relative pathname, restart at parent directory. */ cp = namebuf; if (*cp == '/') bcopy(&nfs_root_node, currfd, sizeof(*currfd)); free(newfd); newfd = 0; continue; } free(currfd); currfd = newfd; newfd = 0; } error = 0; out: free(newfd); free(path); #else currfd->iodesc = desc; error = nfs_lookupfh(&nfs_root_node, upath, currfd); #endif if (!error) { currfd->off = 0; f->f_fsdata = (void *)currfd; return (0); } #ifdef NFS_DEBUG if (debug) printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(error)); #endif free(currfd); return (error); }
/* * RPC: bootparam/getfile * Given client name and file "key", get: * server name * server IP address * server pathname */ int bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) { struct { n_long h[RPC_HEADER_WORDS]; n_long d[64]; } sdata; struct { n_long h[RPC_HEADER_WORDS]; n_long d[128]; } rdata; char serv_name[FNAME_SIZE]; char *send_tail, *recv_head; /* misc... */ struct iodesc *d; int sn_len, path_len, rlen; if (!(d = socktodesc(sockfd))) { RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); return (-1); } send_tail = (char *)sdata.d; recv_head = (char *)rdata.d; /* * Build request message. */ /* client name (hostname) */ if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { RPC_PRINTF(("bp_getfile: bad client\n")); return (-1); } /* key name (root or swap) */ if (xdr_string_encode(&send_tail, key, strlen(key))) { RPC_PRINTF(("bp_getfile: bad key\n")); return (-1); } /* RPC: bootparam/getfile */ d->myport = htons(--rpc_port); d->destip = bp_server_addr; /* rpc_call will set d->destport */ rlen = rpc_call(d, BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, sdata.d, send_tail - (char *)sdata.d, rdata.d, sizeof(rdata.d)); if (rlen < 4) { RPC_PRINTF(("bp_getfile: short reply\n")); errno = EBADRPC; return (-1); } recv_head = (char *)rdata.d; /* * Parse result message. */ /* server name */ sn_len = FNAME_SIZE-1; if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { RPC_PRINTF(("bp_getfile: bad server name\n")); return (-1); } /* server IP address (mountd/NFS) */ if (xdr_inaddr_decode(&recv_head, serv_addr)) { RPC_PRINTF(("bp_getfile: bad server addr\n")); return (-1); } /* server pathname */ path_len = MAXPATHLEN-1; if (xdr_string_decode(&recv_head, pathname, &path_len)) { RPC_PRINTF(("bp_getfile: bad server path\n")); return (-1); } /* success */ return(0); }
/* * RPC: bootparam/whoami * Given client IP address, get: * client name (hostname) * domain name (domainname) * gateway address * * The hostname and domainname are set here for convenience. * * Note - bpsin is initialized to the broadcast address, * and will be replaced with the bootparam server address * after this call is complete. Have to use PMAP_PROC_CALL * to make sure we get responses only from a servers that * know about us (don't want to broadcast a getport call). */ int bp_whoami(int sockfd) { /* RPC structures for PMAPPROC_CALLIT */ struct args { u_int32_t prog; u_int32_t vers; u_int32_t proc; u_int32_t arglen; struct xdr_inaddr xina; } *args; struct repl { u_int16_t _pad; u_int16_t port; u_int32_t encap_len; /* encapsulated data here */ n_long capsule[64]; } *repl; struct { n_long h[RPC_HEADER_WORDS]; struct args d; } sdata; struct { n_long h[RPC_HEADER_WORDS]; struct repl d; } rdata; char *send_tail, *recv_head; struct iodesc *d; int len, x; RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); if (!(d = socktodesc(sockfd))) { RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); return (-1); } args = &sdata.d; repl = &rdata.d; /* * Build request args for PMAPPROC_CALLIT. */ args->prog = htonl(BOOTPARAM_PROG); args->vers = htonl(BOOTPARAM_VERS); args->proc = htonl(BOOTPARAM_WHOAMI); args->arglen = htonl(sizeof(struct xdr_inaddr)); send_tail = (char *)&args->xina; /* * append encapsulated data (client IP address) */ if (xdr_inaddr_encode(&send_tail, myip)) return (-1); /* RPC: portmap/callit */ d->myport = htons(--rpc_port); d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ /* rpc_call will set d->destport */ len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, args, send_tail - (char *)args, repl, sizeof(*repl)); if (len < 8) { printf("bootparamd: 'whoami' call failed\n"); return (-1); } /* Save bootparam server address (from IP header). */ rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); /* * Note that bp_server_port is now 111 due to the * indirect call (using PMAPPROC_CALLIT), so get the * actual port number from the reply data. */ bp_server_port = repl->port; RPC_PRINTF(("bp_whoami: server at %s:%d\n", inet_ntoa(bp_server_addr), ntohs(bp_server_port))); /* We have just done a portmap call, so cache the portnum. */ rpc_pmap_putcache(bp_server_addr, BOOTPARAM_PROG, BOOTPARAM_VERS, (int)ntohs(bp_server_port)); /* * Parse the encapsulated results from bootparam/whoami */ x = ntohl(repl->encap_len); if (len < x) { printf("bp_whoami: short reply, %d < %d\n", len, x); return (-1); } recv_head = (char *)repl->capsule; /* client name */ hostnamelen = MAXHOSTNAMELEN-1; if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { RPC_PRINTF(("bp_whoami: bad hostname\n")); return (-1); } /* domain name */ domainnamelen = MAXHOSTNAMELEN-1; if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { RPC_PRINTF(("bp_whoami: bad domainname\n")); return (-1); } /* gateway address */ if (xdr_inaddr_decode(&recv_head, &gateip)) { RPC_PRINTF(("bp_whoami: bad gateway\n")); return (-1); } /* success */ return(0); }