/************************************************************************** ETHERBOOT - BOOTP/TFTP Bootstrap Program Author: Martin Renters Date: Dec/93 Literature dealing with the network protocols: ARP - RFC826 RARP - RFC903 UDP - RFC768 BOOTP - RFC951, RFC2132 (vendor extensions) DHCP - RFC2131, RFC2132 (options) TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize) RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper) NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented) **************************************************************************/ /* #define MDEBUG */ #include "etherboot.h" #include "nic.h" int jmp_bootmenu[10]; struct arptable_t arptable[MAX_ARP]; const char *kernel; char kernel_buf[128]; struct rom_info rom; #ifdef IMAGE_MENU static char *imagelist[RFC1533_VENDOR_NUMOFIMG]; static int useimagemenu; int menutmo,menudefault; unsigned char *defparams = NULL; int defparams_max = 0; #endif #ifdef MOTD char *motd[RFC1533_VENDOR_NUMOFMOTD]; #endif #ifdef IMAGE_FREEBSD int freebsd_howto = 0; #endif int vendorext_isvalid; char config_buffer[TFTP_MAX_PACKET+1]; /* +1 for null byte */ unsigned long netmask; char *hostname = ""; int hostnamelen = 0; #if defined(ETHERBOOT16) || defined(INTERNAL_BOOTP_DATA) struct bootpd_t bootp_data; #endif unsigned long xid; unsigned char *end_of_rfc1533 = NULL; #ifndef NO_DHCP_SUPPORT int dhcp_reply; in_addr dhcp_server = { 0L }; in_addr dhcp_addr = { 0L }; #endif /* NO_DHCP_SUPPORT */ unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */ #ifdef NO_DHCP_SUPPORT char rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END }; #else char rfc1533_cookie[] = { RFC1533_COOKIE}; char rfc1533_end[]={RFC1533_END }; static const char dhcpdiscover[]={ RFC2132_MSG_TYPE,1,DHCPDISCOVER, RFC2132_MAX_SIZE,2, /* request as much as we can */ sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY, RFC1533_HOSTNAME }; static const char dhcprequest []={ RFC2132_MSG_TYPE,1,DHCPREQUEST, RFC2132_SRV_ID,4,0,0,0,0, RFC2132_REQ_ADDR,4,0,0,0,0, RFC2132_MAX_SIZE,2, /* request as much as we can */ sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, /* request parameters */ RFC2132_PARAM_LIST, #ifdef IMAGE_FREEBSD /* 4 standard + 6 vendortags + 8 motd + 16 menu items */ 4 + 6 + 8 + 16, #else /* 4 standard + 5 vendortags + 8 motd + 16 menu items */ 4 + 5 + 8 + 16, #endif /* Standard parameters */ RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME, RFC1533_ROOTPATH, /* only passed to the booted image */ /* Etherboot vendortags */ RFC1533_VENDOR_MAGIC, RFC1533_VENDOR_ADDPARM, RFC1533_VENDOR_ETHDEV, #ifdef IMAGE_FREEBSD RFC1533_VENDOR_HOWTO, #endif RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, /* 8 MOTD entries */ RFC1533_VENDOR_MOTD, RFC1533_VENDOR_MOTD+1, RFC1533_VENDOR_MOTD+2, RFC1533_VENDOR_MOTD+3, RFC1533_VENDOR_MOTD+4, RFC1533_VENDOR_MOTD+5, RFC1533_VENDOR_MOTD+6, RFC1533_VENDOR_MOTD+7, /* 16 image entries */ RFC1533_VENDOR_IMG, RFC1533_VENDOR_IMG+1, RFC1533_VENDOR_IMG+2, RFC1533_VENDOR_IMG+3, RFC1533_VENDOR_IMG+4, RFC1533_VENDOR_IMG+5, RFC1533_VENDOR_IMG+6, RFC1533_VENDOR_IMG+7, RFC1533_VENDOR_IMG+8, RFC1533_VENDOR_IMG+9, RFC1533_VENDOR_IMG+10, RFC1533_VENDOR_IMG+11, RFC1533_VENDOR_IMG+12, RFC1533_VENDOR_IMG+13, RFC1533_VENDOR_IMG+14, RFC1533_VENDOR_IMG+15, }; #endif /* NO_DHCP_SUPPORT */ static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /************************************************************************** MAIN - Kick off routine **************************************************************************/ int main(void) { char *p; static int card_retries = 0; int i; for (p=_edata; p<_end; p++) *p = 0; /* Zero BSS */ #ifdef CONSOLE_SERIAL (void)serial_init(); #endif #ifdef DELIMITERLINES for (i=0; i<80; i++) putchar('='); #endif #ifdef ETHERBOOT32 rom = *(struct rom_info *)ROM_INFO_LOCATION; printf("ROM segment %#x length %#x reloc %#x\n", rom.rom_segment, rom.rom_length << 1, ((unsigned long)_start) >> 4); #endif #ifdef ETHERBOOT16 fmemcpy(&rom, (Address)ROM_INFO_LOCATION, sizeof(rom)); printf("ROM segment %#x length %#x\n", rom.rom_segment, rom.rom_length << 1); #endif #ifdef ASK_BOOT while (1) { int c; unsigned long time; printf(ASK_PROMPT); #if ASK_BOOT > 0 for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); ) if (currticks() > time) { c = ANS_DEFAULT; goto done; } #endif c = getchar(); if ((c >= 'a') && (c <= 'z')) c &= 0x5F; if (c == '\n') c = ANS_DEFAULT; done: if ((c >= ' ') && (c <= '~')) putchar(c); putchar('\n'); if (c == ANS_LOCAL) exit(0); if (c == ANS_NETWORK) break; } #endif #if (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY) disk_init(); printf("Trying floppy"); for (i = TRY_FLOPPY_FIRST; i-- > 0; ) { putchar('.'); if (disk_read(0, 0, 0, 0, ((char *) FLOPPY_BOOT_LOCATION)) != 0x8000) { printf("using floppy\n"); exit(0); } } printf("no floppy\n"); #endif /* TRY_FLOPPY_FIRST && FLOPPY */ print_config(); gateA20_set(); #ifdef EMERGENCYDISKBOOT if (!eth_probe()) { printf("No adapter found\n"); exit(0); } #else while (!eth_probe()) { printf("No adapter found"); if (!setjmp(jmp_bootmenu)) rfc951_sleep(++card_retries); } #endif kernel = DEFAULT_BOOTFILE; while (1) { if ((i = setjmp(jmp_bootmenu)) != 0) { #if defined(ANSIESC) && defined(CONSOLE_CRT) ansi_reset(); #endif bootmenu(--i); } else { load(); } #if defined(ANSIESC) && defined(CONSOLE_CRT) ansi_reset(); #endif } } /************************************************************************** LOADKERNEL - Try to load kernel image **************************************************************************/ #ifndef FLOPPY #define loadkernel(s) download((s),downloadkernel) #else static int loadkernel(const char *fname) { if (!memcmp(fname,"/dev/",5) && fname[6] == 'd') { int dev, part = 0; if (fname[5] == 'f') { if ((dev = fname[7] - '0') < 0 || dev > 3) goto nodisk; } else if (fname[5] == 'h' || fname[5] == 's') { if ((dev = 0x80 + fname[7] - 'a') < 0x80 || dev > 0x83) goto nodisk; if (fname[8]) { part = fname[8] - '0'; if (fname[9]) part = 10*part + fname[9] - '0'; } /* bootdisk cannot cope with more than eight partitions */ if (part < 0 || part > 8) goto nodisk; } else goto nodisk; return(bootdisk(dev,part)); } nodisk: return download(fname, downloadkernel); } #endif /************************************************************************** LOAD - Try to get booted **************************************************************************/ void load() { static int bootp_completed = 0; /* Find a server to get BOOTP reply from */ if (!bootp_completed || !arptable[ARP_CLIENT].ipaddr.s_addr || !arptable[ARP_SERVER].ipaddr.s_addr) { retry: bootp_completed = 0; #ifdef RARP_NOT_BOOTP printf("Searching for server (RARP)...\n"); #else #ifndef NO_DHCP_SUPPORT printf("Searching for server (DHCP)...\n"); #else printf("Searching for server (BOOTP)...\n"); #endif #endif #ifdef RARP_NOT_BOOTP if (!rarp()) { #else if (!bootp()) { #endif printf("No Server found\n"); #ifdef EMERGENCYDISKBOOT exit(0); #else goto retry; #endif } bootp_completed++; } printf("Me: %I, Server: %I", arptable[ARP_CLIENT].ipaddr.s_addr, arptable[ARP_SERVER].ipaddr.s_addr); if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr) printf(", Relay: %I", BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr); if (arptable[ARP_GATEWAY].ipaddr.s_addr) printf(", Gateway %I", arptable[ARP_GATEWAY].ipaddr.s_addr); putchar('\n'); #ifdef MDEBUG printf("\n=>>"); getchar(); #endif #ifdef MOTD if (vendorext_isvalid) show_motd(); #endif /* Now use TFTP to load file */ #ifdef IMAGE_MENU if (vendorext_isvalid && useimagemenu) { selectImage(imagelist); bootp_completed = 0; } #endif #ifdef DOWNLOAD_PROTO_NFS rpc_init(); #endif for (;;) { printf("Loading %s ",kernel); while (!loadkernel(kernel)) { printf("Unable to load file.\n"); sleep(2); /* lay off server for a while */ } } } /************************************************************************** DEFAULT_NETMASK - Return default netmask for IP address **************************************************************************/ static inline unsigned long default_netmask(void) { int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24; if (net <= 127) return(htonl(0xff000000)); else if (net < 192) return(htonl(0xffff0000)); else return(htonl(0xffffff00)); } /************************************************************************** UDP_TRANSMIT - Send a UDP datagram **************************************************************************/ int udp_transmit(unsigned long destip, unsigned int srcsock, unsigned int destsock, int len, const void *buf) { struct iphdr *ip; struct udphdr *udp; struct arprequest arpreq; int arpentry, i; int retry; ip = (struct iphdr *)buf; udp = (struct udphdr *)((long)buf + sizeof(struct iphdr)); ip->verhdrlen = 0x45; ip->service = 0; ip->len = htons(len); ip->ident = 0; ip->frags = 0; ip->ttl = 60; ip->protocol = IP_UDP; ip->chksum = 0; ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; ip->dest.s_addr = destip; ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr)); udp->src = htons(srcsock); udp->dest = htons(destsock); udp->len = htons(len - sizeof(struct iphdr)); udp->chksum = 0; if (destip == IP_BROADCAST) { eth_transmit(broadcast, IP, len, buf); } else { if (((destip & netmask) != (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) && arptable[ARP_GATEWAY].ipaddr.s_addr) destip = arptable[ARP_GATEWAY].ipaddr.s_addr; for(arpentry = 0; arpentry\n"); #endif udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; } #endif break; /* timeout */ } tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE]; if (tr->opcode == ntohs(TFTP_ERROR)) { printf("TFTP error %d (%s)\n", ntohs(tr->u.err.errcode), tr->u.err.errmsg); break; } if (tr->opcode == ntohs(TFTP_OACK)) { char *p = tr->u.oack.data, *e; if (prevblock) /* shouldn't happen */ continue; /* ignore it */ len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) { if (!strcasecmp("blksize", p)) { p += 8; if ((packetsize = getdec(&p)) < TFTP_DEFAULTSIZE_PACKET) goto noak; while (p < e && *p) p++; if (p < e) p++; } else { noak: tp.opcode = htons(TFTP_ERROR); tp.u.err.errcode = 8; len = (sprintf((char *)tp.u.err.errmsg, "RFC1782 error") - ((char *)&tp)) + 1; udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs(tr->udp.src), len, &tp); return (0); } } if (p > e) goto noak; block = tp.u.ack.block = 0; /* this ensures, that */ /* the packet does not get */ /* processed as data! */ } else if (tr->opcode == ntohs(TFTP_DATA)) { len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; if (len > packetsize) /* shouldn't happen */ continue; /* ignore it */ block = ntohs(tp.u.ack.block = tr->u.data.block); } else /* neither TFTP_OACK nor TFTP_DATA */ break; if ((block || bcounter) && (block != prevblock+1)) { /* Block order should be continuous */ tp.u.ack.block = htons(block = prevblock); } tp.opcode = htons(TFTP_ACK); oport = ntohs(tr->udp.src); udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); /* ack */ if ((unsigned short)(block-prevblock) != 1) { /* Retransmission or OACK, don't process via callback * and don't change the value of prevblock. */ continue; } prevblock = block; retry = 0; /* It's the right place to zero the timer? */ if ((rc = fnc(tr->u.data.download, ++bcounter, len, len < packetsize)) >= 0) return(rc); if (len < packetsize) /* End of data */ return (1); } return (0); } #endif /* DOWNLOAD_PROTO_TFTP */ #ifdef RARP_NOT_BOOTP /************************************************************************** RARP - Get my IP address and load information **************************************************************************/ int rarp() { int retry; /* arp and rarp requests share the same packet structure. */ struct arprequest rarpreq; memset(&rarpreq, 0, sizeof(rarpreq)); rarpreq.hwtype = htons(1); rarpreq.protocol = htons(IP); rarpreq.hwlen = ETHER_ADDR_SIZE; rarpreq.protolen = 4; rarpreq.opcode = htons(RARP_REQUEST); memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); /* sipaddr is already zeroed out */ memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); /* tipaddr is already zeroed out */ for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) { eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq); if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT)) break; } if (retry < MAX_ARP_RETRIES) { sprintf(kernel = kernel_buf, "/tftpboot/kernel.%I", arptable[ARP_CLIENT].ipaddr); return (1); } return (0); } #else /************************************************************************** BOOTP - Get my IP address and load information **************************************************************************/ int bootp() { int retry; #ifndef NO_DHCP_SUPPORT int retry1; #endif /* NO_DHCP_SUPPORT */ struct bootp_t bp; unsigned long starttime; #ifdef T509HACK int flag; flag = 1; #endif memset(&bp, 0, sizeof(struct bootp_t)); bp.bp_op = BOOTP_REQUEST; bp.bp_htype = 1; bp.bp_hlen = ETHER_ADDR_SIZE; bp.bp_xid = xid = starttime = currticks(); memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); #ifdef NO_DHCP_SUPPORT memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */ #else memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */ memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif /* NO_DHCP_SUPPORT */ for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { /* Clear out the Rx queue first. It contains nothing of * interest, except possibly ARP requests from the DHCP/TFTP * server. We use polling throughout Etherboot, so some time * may have passed since we last polled the receive queue, * which may now be filled with broadcast packets. This will * cause the reply to the packets we are about to send to be * lost immediately. Not very clever. */ await_reply(AWAIT_QDRAIN, 0, NULL, 0); udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof(struct bootp_t), &bp); #ifdef T509HACK if (flag) { flag--; } else { if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) return(1); rfc951_sleep(++retry); } #else #ifdef NO_DHCP_SUPPORT if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) #else if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){ if (dhcp_reply==DHCPOFFER){ dhcp_reply=0; memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr)); memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr)); for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) { udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof(struct bootp_t), &bp); dhcp_reply=0; if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)) if (dhcp_reply==DHCPACK) return(1); rfc951_sleep(++retry1); } } else #endif /* NO_DHCP_SUPPORT */ return(1); #ifndef NO_DHCP_SUPPORT } rfc951_sleep(++retry); #endif /* NO_DHCP_SUPPORT */ #endif bp.bp_secs = htons((currticks()-starttime)/20); } return(0); } #endif /* RARP_NOT_BOOTP */ /************************************************************************** AWAIT_REPLY - Wait until we get a response for our request **************************************************************************/ int await_reply(int type, int ival, void *ptr, int timeout) { unsigned long time; struct iphdr *ip; struct udphdr *udp; struct arprequest *arpreply; struct bootp_t *bootpreply; struct rpc_t *rpc; unsigned short ptype; unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) + sizeof(struct udphdr); time = timeout + currticks(); /* The timeout check is done below. The timeout is only checked if * there is no packet in the Rx queue. This assumes that eth_poll() * needs a negligible amount of time. */ for (;;) { if (eth_poll()) { /* We have something! */ /* Check for ARP - No IP hdr */ if (nic.packetlen >= ETHER_HDR_SIZE) { ptype = ((unsigned short) nic.packet[12]) << 8 | ((unsigned short) nic.packet[13]); } else continue; /* what else could we do with it? */ if ((nic.packetlen >= ETHER_HDR_SIZE + sizeof(struct arprequest)) && (ptype == ARP) ) { unsigned long tmp; arpreply = (struct arprequest *) &nic.packet[ETHER_HDR_SIZE]; if ((arpreply->opcode == ntohs(ARP_REPLY)) && !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) && (type == AWAIT_ARP)) { memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE); return(1); } memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); if ((arpreply->opcode == ntohs(ARP_REQUEST)) && (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) { arpreply->opcode = htons(ARP_REPLY); memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr)); memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE); memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); eth_transmit(arpreply->thwaddr, ARP, sizeof(struct arprequest), arpreply); #ifdef MDEBUG memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); printf("Sent ARP reply to: %I\n",tmp); #endif MDEBUG } continue; } if (type == AWAIT_QDRAIN) { continue; } /* Check for RARP - No IP hdr */ if ((type == AWAIT_RARP) && (nic.packetlen >= ETHER_HDR_SIZE + sizeof(struct arprequest)) && (ptype == RARP)) { arpreply = (struct arprequest *) &nic.packet[ETHER_HDR_SIZE]; if ((arpreply->opcode == ntohs(RARP_REPLY)) && !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) { memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE); memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr)); memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr)); return(1); } continue; } /* Anything else has IP header */ if ((nic.packetlen < protohdrlen) || (ptype != IP) ) continue; ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE]; if ((ip->verhdrlen != 0x45) || ipchksum((unsigned short *)ip, sizeof(struct iphdr)) || (ip->protocol != IP_UDP)) continue; udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE + sizeof(struct iphdr)]; /* BOOTP ? */ bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE]; if ((type == AWAIT_BOOTP) && (nic.packetlen >= (ETHER_HDR_SIZE + #ifdef NO_DHCP_SUPPORT sizeof(struct bootp_t))) && #else sizeof(struct bootp_t))-DHCP_OPT_LEN) && #endif /* NO_DHCP_SUPPORT */ (ntohs(udp->dest) == BOOTP_CLIENT) && (bootpreply->bp_op == BOOTP_REPLY) && (bootpreply->bp_xid == xid)) { arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr; #ifndef NO_DHCP_SUPPORT dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr; #endif /* NO_DHCP_SUPPORT */ netmask = default_netmask(); arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr; memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr; memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE); /* Kill arp */ if (bootpreply->bp_file[0]) { memcpy(kernel_buf, bootpreply->bp_file, 128); kernel = kernel_buf; } memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t)); decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, #ifdef NO_DHCP_SUPPORT 0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1); #else 0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1); #endif /* NO_DHCP_SUPPORT */ return(1); } #ifdef DOWNLOAD_PROTO_TFTP /* TFTP ? */ if ((type == AWAIT_TFTP) && (ntohs(udp->dest) == ival)) return(1); #endif /* DOWNLOAD_PROTO_TFTP */ #ifdef DOWNLOAD_PROTO_NFS /* RPC ? */ rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE]; if ((type == AWAIT_RPC) && (ntohs(udp->dest) == ival) && (*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) && (ntohl(rpc->u.reply.type) == MSG_REPLY)) { return (1); } #endif /* DOWNLOAD_PROTO_NFS */ } else { /* Check for abort key only if the Rx queue is empty - * as long as we have something to process, don't * assume that something failed. It is unlikely that * we have no processing time left between packets. */ if (iskey() && (getchar() == ESC)) #ifdef EMERGENCYDISKBOOT exit(0); #else longjmp(jmp_bootmenu,1); #endif /* Do the timeout after at least a full queue walk. */ if ((timeout == 0) || (currticks() > time)) { break; } } } return(0); } /************************************************************************** DECODE_RFC1533 - Decodes RFC1533 header **************************************************************************/ int decode_rfc1533(p, block, len, eof) register unsigned char *p; int block, len, eof; { static unsigned char *extdata = NULL, *extend = NULL; unsigned char *extpath = NULL; unsigned char *endp; if (block == 0) { #ifdef IMAGE_MENU memset(imagelist, 0, sizeof(imagelist)); menudefault = useimagemenu = 0; menutmo = -1; #endif #ifdef MOTD memset(motd, 0, sizeof(motd)); #endif end_of_rfc1533 = NULL; vendorext_isvalid = 0; if (memcmp(p, rfc1533_cookie, 4)) return(0); /* no RFC 1533 header found */ p += 4; endp = p + len; } else { if (block == 1) { if (memcmp(p, rfc1533_cookie, 4)) return(0); /* no RFC 1533 header found */ p += 4; len -= 4; } if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) { memcpy(extend, p, len); extend += len; } else { printf("Overflow in vendor data buffer! Aborting...\n"); *extdata = RFC1533_END; return(0); } p = extdata; endp = extend; } if (eof) { while(p < endp) { unsigned char c = *p; if (c == RFC1533_PAD) {p++; continue;} else if (c == RFC1533_END) { end_of_rfc1533 = endp = p; continue; } else if (c == RFC1533_NETMASK) {memcpy(&netmask, p+2, sizeof(in_addr));} else if (c == RFC1533_GATEWAY) { /* This is a little simplistic, but it will usually be sufficient. Take only the first entry */ if (TAG_LEN(p) >= sizeof(in_addr)) memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr)); } else if (c == RFC1533_EXTENSIONPATH) extpath = p; #ifndef NO_DHCP_SUPPORT else if (c == RFC2132_MSG_TYPE) { dhcp_reply=*(p+2); } else if (c == RFC2132_SRV_ID) { memcpy(&dhcp_server, p+2, sizeof(in_addr)); } #endif /* NO_DHCP_SUPPORT */ else if (c == RFC1533_HOSTNAME) { hostname = p + 2; hostnamelen = *(p + 1); } else if (c == RFC1533_VENDOR_MAGIC #ifndef IMAGE_FREEBSD /* since FreeBSD uses tag 128 for swap definition */ && TAG_LEN(p) >= 6 && !memcmp(p+2,vendorext_magic,4) && p[6] == RFC1533_VENDOR_MAJOR #endif ) vendorext_isvalid++; #ifdef IMAGE_FREEBSD else if (c == RFC1533_VENDOR_HOWTO) { freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5]; } #endif #ifdef IMAGE_MENU else if (c == RFC1533_VENDOR_MNUOPTS) { parse_menuopts(p+2, TAG_LEN(p)); } else if (c >= RFC1533_VENDOR_IMG && c= RFC1533_VENDOR_MOTD && c < RFC1533_VENDOR_MOTD + RFC1533_VENDOR_NUMOFMOTD) motd[c - RFC1533_VENDOR_MOTD] = p; #endif else { #if 0 unsigned char *q; printf("Unknown RFC1533-tag "); for(q=p;q>= 1; while (len--) { sum += *(ip++); if (sum > 0xFFFF) sum -= 0xFFFF; } return((~sum) & 0x0000FFFF); } /************************************************************************** RFC951_SLEEP - sleep for expotentially longer times **************************************************************************/ void rfc951_sleep(exp) int exp; { static long seed = 0; long q; unsigned long tmo; #ifdef BACKOFF_LIMIT if (exp > BACKOFF_LIMIT) exp = BACKOFF_LIMIT; #endif if (!seed) /* Initialize linear congruential generator */ seed = currticks() + *(long *)&arptable[ARP_CLIENT].node + ((short *)arptable[ARP_CLIENT].node)[2]; /* simplified version of the LCG given in Bruce Scheier's "Applied Cryptography" */ q = seed/53668; if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l; /* compute mask */ for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1); /* sleep */ printf("\n"); for (tmo = (tmo&seed)+currticks(); currticks() < tmo; ) if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1); return; } /************************************************************************** CLEANUP_NET - shut down networking **************************************************************************/ void cleanup_net(void) { #ifdef DOWNLOAD_PROTO_NFS nfs_umountall(ARP_SERVER); #endif eth_disable(); eth_reset(); } /************************************************************************** CLEANUP - shut down etherboot so that the OS may be called right away **************************************************************************/ void cleanup(void) { #if defined(ANSIESC) && defined(CONSOLE_CRT) ansi_reset(); #endif } /* * Local variables: * c-basic-offset: 8 * End: */