123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119 |
- /**************************************************************************
- 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<MAX_ARP; arpentry++)
- if (arptable[arpentry].ipaddr.s_addr == destip) break;
- if (arpentry == MAX_ARP) {
- printf("%I is not in my arp table!\n", destip);
- return(0);
- }
- for (i = 0; i<ETHER_ADDR_SIZE; i++)
- if (arptable[arpentry].node[i]) break;
- if (i == ETHER_ADDR_SIZE) { /* Need to do arp request */
- arpreq.hwtype = htons(1);
- arpreq.protocol = htons(IP);
- arpreq.hwlen = ETHER_ADDR_SIZE;
- arpreq.protolen = 4;
- arpreq.opcode = htons(ARP_REQUEST);
- memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
- memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
- memset(arpreq.thwaddr, 0, ETHER_ADDR_SIZE);
- memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
- for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
- eth_transmit(broadcast, ARP, sizeof(arpreq),
- &arpreq);
- if (await_reply(AWAIT_ARP, arpentry,
- arpreq.tipaddr, TIMEOUT)) goto xmit;
- rfc951_sleep(retry);
- /* We have slept for a while - the packet may
- * have arrived by now. If not, we have at
- * least some room in the Rx buffer for the
- * next reply. */
- if (await_reply(AWAIT_ARP, arpentry,
- arpreq.tipaddr, 0)) goto xmit;
- }
- return(0);
- }
- xmit:
- eth_transmit(arptable[arpentry].node, IP, len, buf);
- }
- return(1);
- }
-
- /**************************************************************************
- DOWNLOADKERNEL - Try to load file
- **************************************************************************/
- int downloadkernel(data, block, len, eof)
- unsigned char *data;
- int block, len, eof;
- {
- #ifdef SIZEINDICATOR
- static int rlen = 0;
-
- if (!(block % 4) || eof) {
- int size;
- size = ((block-1) * rlen + len) / 1024;
-
- putchar('\b');
- putchar('\b');
- putchar('\b');
- putchar('\b');
-
- putchar('0' + (size/1000)%10);
- putchar('0' + (size/100)%10);
- putchar('0' + (size/10)%10);
- putchar('0' + (size/1)%10);
- }
- #endif
- if (block == 1)
- {
- #ifdef SIZEINDICATOR
- rlen=len;
- #endif
- if (!eof && (
- #ifdef TAGGED_IMAGE
- *((unsigned long *)data) == 0x1B031336L ||
- #endif
- #ifdef ELF_IMAGE
- *((unsigned long *)data) == 0x464C457FL ||
- #endif
- #ifdef AOUT_IMAGE
- *((unsigned short *)data) == 0x010BL ||
- #endif
- ((unsigned short *)data)[255] == 0xAA55))
- {
- ;
- }
- else if (eof)
- {
- memcpy(config_buffer, data, len);
- config_buffer[len] = 0;
- return (1); /* done */
- }
- else
- {
- printf("error: not a tagged image\n");
- return(0); /* error */
- }
- }
- if (len != 0) {
- if (!os_download(block, data, len))
- return(0); /* error */
- }
- if (eof) {
- os_download(block+1, data, 0); /* does not return */
- return(0); /* error */
- }
- return(-1); /* there is more data */
- }
-
- #ifdef DOWNLOAD_PROTO_TFTP
- /**************************************************************************
- TFTP - Download extended BOOTP data, or kernel image
- **************************************************************************/
- int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int))
- {
- int retry = 0;
- static unsigned short iport = 2000;
- unsigned short oport;
- unsigned short len, block = 0, prevblock = 0;
- int bcounter = 0;
- struct tftp_t *tr;
- struct tftp_t tp;
- int rc;
- int packetsize = TFTP_DEFAULTSIZE_PACKET;
-
- /* 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);
-
- tp.opcode = htons(TFTP_RRQ);
- len = (sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
- name, 0, 0, 0, TFTP_MAX_PACKET) - ((char *)&tp)) + 1;
- if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
- TFTP_PORT, len, &tp))
- return (0);
- for (;;)
- {
- #ifdef CONGESTED
- if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
- #else
- if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
- #endif
- {
- if (!block && retry++ < MAX_TFTP_RETRIES)
- { /* maybe initial request was lost */
- rfc951_sleep(retry);
- if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
- ++iport, TFTP_PORT, len, &tp))
- return (0);
- continue;
- }
- #ifdef CONGESTED
- if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
- { /* we resend our last ack */
- #ifdef MDEBUG
- printf("<REXMT>\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_IMG+RFC1533_VENDOR_NUMOFIMG){
- imagelist[c - RFC1533_VENDOR_IMG] = p;
- useimagemenu++;
- }
- #endif
- #ifdef MOTD
- else if (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<p+2+TAG_LEN(p);q++)
- printf("%x ",*q);
- putchar('\n');
- #endif
- }
- p += TAG_LEN(p) + 2;
- }
- extdata = extend = endp;
- if (block == 0 && extpath != NULL) {
- char fname[64];
- memcpy(fname, extpath+2, TAG_LEN(extpath));
- fname[(int)TAG_LEN(extpath)] = '\000';
- printf("Loading BOOTP-extension file: %s\n",fname);
- download(fname,decode_rfc1533);
- }
- }
- return(-1); /* proceed with next block */
- }
-
- /**************************************************************************
- IPCHKSUM - Checksum IP Header
- **************************************************************************/
- unsigned short ipchksum(ip, len)
- register unsigned short *ip;
- register int len;
- {
- unsigned long sum = 0;
- len >>= 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("<sleep>\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:
- */
|