1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/* Based on "src/main.c" in etherboot-5.0.5.  */
21
22/**************************************************************************
23ETHERBOOT -  BOOTP/TFTP Bootstrap Program
24
25Author: Martin Renters
26  Date: Dec/93
27
28Literature dealing with the network protocols:
29       ARP - RFC826
30       RARP - RFC903
31       UDP - RFC768
32       BOOTP - RFC951, RFC2132 (vendor extensions)
33       DHCP - RFC2131, RFC2132 (options)
34       TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
35       RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
36       NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
37
38**************************************************************************/
39
40#define GRUB	1
41#include <etherboot.h>
42#include <nic.h>
43
44/* #define DEBUG	1 */
45
46struct arptable_t arptable[MAX_ARP];
47
48/* Set if the user pushes Control-C.  */
49int ip_abort = 0;
50/* Set if an ethernet card is probed and IP addresses are set.  */
51int network_ready = 0;
52
53struct rom_info rom;
54
55static int vendorext_isvalid;
56static unsigned long netmask;
57static struct bootpd_t bootp_data;
58static unsigned long xid;
59static unsigned char *end_of_rfc1533 = NULL;
60
61#ifndef	NO_DHCP_SUPPORT
62#endif /* NO_DHCP_SUPPORT */
63
64/* äEth */
65static unsigned char vendorext_magic[] = {0xE4, 0x45, 0x74, 0x68};
66static const unsigned char broadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
67
68#ifdef	NO_DHCP_SUPPORT
69
70static unsigned char rfc1533_cookie[5] = {RFC1533_COOKIE, RFC1533_END};
71
72#else /* ! NO_DHCP_SUPPORT */
73
74static int dhcp_reply;
75static in_addr dhcp_server = {0L};
76static in_addr dhcp_addr = {0L};
77static unsigned char rfc1533_cookie[] = {RFC1533_COOKIE};
78static unsigned char rfc1533_end[] = {RFC1533_END};
79
80static const unsigned char dhcpdiscover[] =
81{
82  RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
83  RFC2132_MAX_SIZE,2,	/* request as much as we can */
84  ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
85  RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
86  RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH
87};
88
89static const unsigned char dhcprequest[] =
90{
91  RFC2132_MSG_TYPE, 1, DHCPREQUEST,
92  RFC2132_SRV_ID, 4, 0, 0, 0, 0,
93  RFC2132_REQ_ADDR, 4, 0, 0, 0, 0,
94  RFC2132_MAX_SIZE, 2,	/* request as much as we can */
95  ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
96  /* request parameters */
97  RFC2132_PARAM_LIST,
98  /* 4 standard + 2 vendortags */
99  4 + 2,
100  /* Standard parameters */
101  RFC1533_NETMASK, RFC1533_GATEWAY,
102  RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
103  /* Etherboot vendortags */
104  RFC1533_VENDOR_MAGIC,
105  RFC1533_VENDOR_CONFIGFILE,
106};
107
108#endif /* ! NO_DHCP_SUPPORT */
109
110static unsigned short ipchksum (unsigned short *ip, int len);
111static unsigned short udpchksum (struct iphdr *packet);
112
113void
114print_network_configuration (void)
115{
116  if (! eth_probe ())
117    grub_printf ("No ethernet card found.\n");
118  else if (! network_ready)
119    grub_printf ("Not initialized yet.\n");
120  else
121    {
122      etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
123      etherboot_printf ("Netmask: %@\n", netmask);
124      etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
125      etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
126    }
127}
128
129
130/**************************************************************************
131DEFAULT_NETMASK - Return default netmask for IP address
132**************************************************************************/
133static inline unsigned long
134default_netmask (void)
135{
136  int net = ntohl (arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
137  if (net <= 127)
138    return (htonl (0xff000000));
139  else if (net < 192)
140    return (htonl (0xffff0000));
141  else
142    return (htonl (0xffffff00));
143}
144
145/* ifconfig - configure network interface.  */
146int
147ifconfig (char *ip, char *sm, char *gw, char *svr)
148{
149  in_addr tmp;
150
151  if (sm)
152    {
153      if (! inet_aton (sm, &tmp))
154	return 0;
155
156      netmask = tmp.s_addr;
157    }
158
159  if (ip)
160    {
161      if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
162	return 0;
163
164      if (! netmask && ! sm)
165	netmask = default_netmask ();
166    }
167
168  if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
169    return 0;
170
171  /* Clear out the ARP entry.  */
172  grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
173
174  if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
175    return 0;
176
177  /* Likewise.  */
178  grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
179
180  if (ip || sm)
181    {
182      if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
183	  || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
184	  || ! netmask)
185	network_ready = 0;
186      else
187	network_ready = 1;
188    }
189
190  return 1;
191}
192
193
194/**************************************************************************
195UDP_TRANSMIT - Send a UDP datagram
196**************************************************************************/
197int
198udp_transmit (unsigned long destip, unsigned int srcsock,
199	      unsigned int destsock, int len, const void *buf)
200{
201  struct iphdr *ip;
202  struct udphdr *udp;
203  struct arprequest arpreq;
204  int arpentry, i;
205  int retry;
206
207  ip = (struct iphdr *) buf;
208  udp = (struct udphdr *) ((unsigned long) buf + sizeof (struct iphdr));
209  ip->verhdrlen = 0x45;
210  ip->service = 0;
211  ip->len = htons (len);
212  ip->ident = 0;
213  ip->frags = 0;
214  ip->ttl = 60;
215  ip->protocol = IP_UDP;
216  ip->chksum = 0;
217  ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
218  ip->dest.s_addr = destip;
219  ip->chksum = ipchksum ((unsigned short *) buf, sizeof (struct iphdr));
220  udp->src = htons (srcsock);
221  udp->dest = htons (destsock);
222  udp->len = htons (len - sizeof (struct iphdr));
223  udp->chksum = 0;
224  udp->chksum = htons (udpchksum (ip));
225
226  if (udp->chksum == 0)
227    udp->chksum = 0xffff;
228
229  if (destip == IP_BROADCAST)
230    {
231      eth_transmit (broadcast, IP, len, buf);
232    }
233  else
234    {
235      if (((destip & netmask)
236	   != (arptable[ARP_CLIENT].ipaddr.s_addr & netmask))
237	  && arptable[ARP_GATEWAY].ipaddr.s_addr)
238	destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
239
240      for (arpentry = 0; arpentry < MAX_ARP; arpentry++)
241	if (arptable[arpentry].ipaddr.s_addr == destip)
242	  break;
243
244      if (arpentry == MAX_ARP)
245	{
246	  etherboot_printf ("%@ is not in my arp table!\n", destip);
247	  return 0;
248	}
249
250      for (i = 0; i < ETH_ALEN; i++)
251	if (arptable[arpentry].node[i])
252	  break;
253
254      if (i == ETH_ALEN)
255	{
256	  /* Need to do arp request.  */
257#ifdef DEBUG
258	  grub_printf ("arp request.\n");
259#endif
260	  arpreq.hwtype = htons (1);
261	  arpreq.protocol = htons (IP);
262	  arpreq.hwlen = ETH_ALEN;
263	  arpreq.protolen = 4;
264	  arpreq.opcode = htons (ARP_REQUEST);
265	  grub_memmove (arpreq.shwaddr, arptable[ARP_CLIENT].node,
266			ETH_ALEN);
267	  grub_memmove (arpreq.sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr,
268			sizeof (in_addr));
269	  grub_memset (arpreq.thwaddr, 0, ETH_ALEN);
270	  grub_memmove (arpreq.tipaddr, (char *) &destip, sizeof (in_addr));
271
272	  for (retry = 1; retry <= MAX_ARP_RETRIES; retry++)
273	    {
274	      long timeout;
275
276	      eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq);
277	      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
278
279	      if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout))
280		goto xmit;
281
282	      if (ip_abort)
283		return 0;
284	    }
285
286	  return 0;
287	}
288
289    xmit:
290      eth_transmit (arptable[arpentry].node, IP, len, buf);
291    }
292
293  return 1;
294}
295
296/**************************************************************************
297TFTP - Download extended BOOTP data, or kernel image
298**************************************************************************/
299static int
300tftp (const char *name, int (*fnc) (unsigned char *, int, int, int))
301{
302  int retry = 0;
303  static unsigned short iport = 2000;
304  unsigned short oport = 0;
305  unsigned short len, block = 0, prevblock = 0;
306  int bcounter = 0;
307  struct tftp_t *tr;
308  struct tftpreq_t tp;
309  int rc;
310  int packetsize = TFTP_DEFAULTSIZE_PACKET;
311
312  /* Clear out the Rx queue first.  It contains nothing of interest,
313   * except possibly ARP requests from the DHCP/TFTP server.  We use
314   * polling throughout Etherboot, so some time may have passed since we
315   * last polled the receive queue, which may now be filled with
316   * broadcast packets.  This will cause the reply to the packets we are
317   * about to send to be lost immediately.  Not very clever.  */
318  await_reply (AWAIT_QDRAIN, 0, NULL, 0);
319
320  tp.opcode = htons (TFTP_RRQ);
321  len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d",
322		       name, 0, 0, 0, TFTP_MAX_PACKET)
323	 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
324  if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
325		      TFTP_PORT, len, &tp))
326    return 0;
327
328  for (;;)
329    {
330      long timeout;
331
332#ifdef CONGESTED
333      timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
334#else
335      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
336#endif
337
338      if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
339	{
340	  if (! block && retry++ < MAX_TFTP_RETRIES)
341	    {
342	      /* Maybe initial request was lost.  */
343	      if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
344				  ++iport, TFTP_PORT, len, &tp))
345		return 0;
346
347	      continue;
348	    }
349
350#ifdef CONGESTED
351	  if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
352	    {
353	      /* We resend our last ack.  */
354#ifdef MDEBUG
355	      grub_printf ("<REXMT>\n");
356#endif
357	      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
358			    iport, oport,
359			    TFTP_MIN_PACKET, &tp);
360	      continue;
361	    }
362#endif
363	  /* Timeout.  */
364	  break;
365	}
366
367      tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
368      if (tr->opcode == ntohs (TFTP_ERROR))
369	{
370	  grub_printf ("TFTP error %d (%s)\n",
371		       ntohs (tr->u.err.errcode),
372		       tr->u.err.errmsg);
373	  break;
374	}
375
376      if (tr->opcode == ntohs (TFTP_OACK))
377	{
378	  char *p = tr->u.oack.data, *e;
379
380	  /* Shouldn't happen.  */
381	  if (prevblock)
382	    /* Ignore it.  */
383	    continue;
384
385	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
386	  if (len > TFTP_MAX_PACKET)
387	    goto noak;
388
389	  e = p + len;
390	  while (*p != '\000' && p < e)
391	    {
392	      if (! grub_strcmp ("blksize", p))
393		{
394		  p += 8;
395		  if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
396		    goto noak;
397
398		  while (p < e && *p)
399		    p++;
400
401		  if (p < e)
402		    p++;
403		}
404	      else
405		{
406		noak:
407		  tp.opcode = htons (TFTP_ERROR);
408		  tp.u.err.errcode = 8;
409		  len = (grub_sprintf ((char *) tp.u.err.errmsg,
410				       "RFC1782 error")
411			 + sizeof (tp.ip) + sizeof (tp.udp)
412			 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
413			 + 1);
414		  udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
415				iport, ntohs (tr->udp.src),
416				len, &tp);
417		  return 0;
418		}
419	    }
420
421	  if (p > e)
422	    goto noak;
423
424	  /* This ensures that the packet does not get processed as data!  */
425	  block = tp.u.ack.block = 0;
426	}
427      else if (tr->opcode == ntohs (TFTP_DATA))
428	{
429	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
430	  /* Shouldn't happen.  */
431	  if (len > packetsize)
432	    /* Ignore it.  */
433	    continue;
434
435	  block = ntohs (tp.u.ack.block = tr->u.data.block);
436	}
437      else
438	/* Neither TFTP_OACK nor TFTP_DATA.  */
439	break;
440
441      if ((block || bcounter) && (block != prevblock + 1))
442	/* Block order should be continuous */
443	tp.u.ack.block = htons (block = prevblock);
444
445      /* Should be continuous.  */
446      tp.opcode = htons (TFTP_ACK);
447      oport = ntohs (tr->udp.src);
448      /* Ack.  */
449      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
450		    oport, TFTP_MIN_PACKET, &tp);
451
452      if ((unsigned short) (block - prevblock) != 1)
453	/* Retransmission or OACK, don't process via callback
454	 * and don't change the value of prevblock.  */
455	continue;
456
457      prevblock = block;
458      /* Is it the right place to zero the timer?  */
459      retry = 0;
460
461      if ((rc = fnc (tr->u.data.download,
462		     ++bcounter, len, len < packetsize)) >= 0)
463	return rc;
464
465      /* End of data.  */
466      if (len < packetsize)
467	return 1;
468    }
469
470  return 0;
471}
472
473/**************************************************************************
474RARP - Get my IP address and load information
475**************************************************************************/
476int
477rarp (void)
478{
479  int retry;
480
481  /* arp and rarp requests share the same packet structure.  */
482  struct arprequest rarpreq;
483
484  /* Make sure that an ethernet is probed.  */
485  if (! eth_probe ())
486    return 0;
487
488  /* Clear the ready flag.  */
489  network_ready = 0;
490
491  grub_memset (&rarpreq, 0, sizeof (rarpreq));
492
493  rarpreq.hwtype = htons (1);
494  rarpreq.protocol = htons (IP);
495  rarpreq.hwlen = ETH_ALEN;
496  rarpreq.protolen = 4;
497  rarpreq.opcode = htons (RARP_REQUEST);
498  grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node,
499		ETH_ALEN);
500  /* sipaddr is already zeroed out */
501  grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node,
502		ETH_ALEN);
503  /* tipaddr is already zeroed out */
504
505  for (retry = 0; retry < MAX_ARP_RETRIES; ++retry)
506    {
507      long timeout;
508
509      eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq);
510
511      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
512      if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout))
513	break;
514
515      if (ip_abort)
516	return 0;
517    }
518
519  if (retry < MAX_ARP_RETRIES)
520    {
521      network_ready = 1;
522      return 1;
523    }
524
525  return 0;
526}
527
528/**************************************************************************
529BOOTP - Get my IP address and load information
530**************************************************************************/
531int
532bootp (void)
533{
534  int retry;
535#ifndef	NO_DHCP_SUPPORT
536  int reqretry;
537#endif /* ! NO_DHCP_SUPPORT */
538  struct bootpip_t ip;
539  unsigned long starttime;
540
541  /* Make sure that an ethernet is probed.  */
542  if (! eth_probe ())
543    return 0;
544
545  /* Clear the ready flag.  */
546  network_ready = 0;
547
548#ifdef DEBUG
549  grub_printf ("network is ready.\n");
550#endif
551
552  grub_memset (&ip, 0, sizeof (struct bootpip_t));
553  ip.bp.bp_op = BOOTP_REQUEST;
554  ip.bp.bp_htype = 1;
555  ip.bp.bp_hlen = ETH_ALEN;
556  starttime = currticks ();
557  /* Use lower 32 bits of node address, more likely to be
558     distinct than the time since booting */
559  grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
560  ip.bp.bp_xid = xid += htonl (starttime);
561  grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
562#ifdef DEBUG
563  etherboot_printf ("bp_op = %d\n", ip.bp.bp_op);
564  etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype);
565  etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen);
566  etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid);
567  etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr);
568  etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops);
569  etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr);
570#endif
571
572#ifdef	NO_DHCP_SUPPORT
573  /* Request RFC-style options.  */
574  grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5);
575#else
576  /* Request RFC-style options.  */
577  grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
578  grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover,
579		sizeof dhcpdiscover);
580  grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover,
581		rfc1533_end, sizeof rfc1533_end);
582#endif /* ! NO_DHCP_SUPPORT */
583
584  for (retry = 0; retry < MAX_BOOTP_RETRIES;)
585    {
586      long timeout;
587
588#ifdef DEBUG
589      grub_printf ("retry = %d\n", retry);
590#endif
591
592      /* Clear out the Rx queue first.  It contains nothing of
593       * interest, except possibly ARP requests from the DHCP/TFTP
594       * server.  We use polling throughout Etherboot, so some time
595       * may have passed since we last polled the receive queue,
596       * which may now be filled with broadcast packets.  This will
597       * cause the reply to the packets we are about to send to be
598       * lost immediately.  Not very clever.  */
599      await_reply (AWAIT_QDRAIN, 0, NULL, 0);
600
601      udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
602		    sizeof (struct bootpip_t), &ip);
603      timeout = rfc2131_sleep_interval (TIMEOUT, retry++);
604#ifdef NO_DHCP_SUPPORT
605      if (await_reply (AWAIT_BOOTP, 0, NULL, timeout))
606	{
607	  network_ready = 1;
608	  return 1;
609	}
610#else /* ! NO_DHCP_SUPPORT */
611      if (await_reply (AWAIT_BOOTP, 0, NULL, timeout))
612	{
613	  if (dhcp_reply != DHCPOFFER)
614	    {
615	      network_ready = 1;
616	      return 1;
617	    }
618
619	  dhcp_reply = 0;
620#ifdef DEBUG
621  etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op);
622  etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype);
623  etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen);
624  etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid);
625  etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr);
626  etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops);
627  etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr);
628#endif
629	  grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
630	  grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie,
631			dhcprequest, sizeof dhcprequest);
632	  grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie
633			+ sizeof dhcprequest,
634			rfc1533_end, sizeof rfc1533_end);
635	  grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server,
636			sizeof (in_addr));
637	  grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr,
638			sizeof (in_addr));
639#ifdef DEBUG
640	  grub_printf ("errnum = %d\n", errnum);
641#endif
642	  for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;)
643	    {
644	      int ret;
645#ifdef DEBUG
646	      grub_printf ("reqretry = %d\n", reqretry);
647#endif
648
649	      ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
650				  sizeof (struct bootpip_t), &ip);
651	      if (! ret)
652		grub_printf ("udp_transmit failed.\n");
653
654	      dhcp_reply = 0;
655	      timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++);
656	      if (await_reply (AWAIT_BOOTP, 0, NULL, timeout))
657		if (dhcp_reply == DHCPACK)
658		  {
659		    network_ready = 1;
660		    return 1;
661		  }
662
663#ifdef DEBUG
664	      grub_printf ("dhcp_reply = %d\n", dhcp_reply);
665#endif
666
667	      if (ip_abort)
668		return 0;
669	    }
670	}
671#endif /* ! NO_DHCP_SUPPORT */
672
673      if (ip_abort)
674	return 0;
675
676      ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC);
677    }
678
679  /* Timeout.  */
680  return 0;
681}
682
683/**************************************************************************
684UDPCHKSUM - Checksum UDP Packet (one of the rare cases when assembly is
685            actually simpler...)
686 RETURNS: checksum, 0 on checksum error. This
687          allows for using the same routine for RX and TX summing:
688          RX  if (packet->udp.chksum && udpchksum(packet))
689                  error("checksum error");
690          TX  packet->udp.chksum=0;
691              if (0==(packet->udp.chksum=udpchksum(packet)))
692                  packet->upd.chksum=0xffff;
693**************************************************************************/
694static inline void
695dosum (unsigned short *start, unsigned int len, unsigned short *sum)
696{
697  __asm__ __volatile__
698    ("clc\n"
699     "1:\tlodsw\n\t"
700     "xchg %%al,%%ah\n\t"	/* convert to host byte order */
701     "adcw %%ax,%0\n\t"		/* add carry of previous iteration */
702     "loop 1b\n\t"
703     "adcw $0,%0"		/* add carry of last iteration */
704     : "=b" (*sum), "=S"(start), "=c"(len)
705     : "0"(*sum), "1"(start), "2"(len)
706     : "ax", "cc"
707     );
708}
709
710/* UDP sum:
711 * proto, src_ip, dst_ip, udp_dport, udp_sport, 2*udp_len, payload
712 */
713static unsigned short
714udpchksum (struct iphdr *packet)
715{
716  int len = ntohs (packet->len);
717  unsigned short rval;
718
719  /* add udplength + protocol number */
720  rval = (len - sizeof (struct iphdr)) + IP_UDP;
721
722  /* pad to an even number of bytes */
723  if (len % 2) {
724    ((char *) packet)[len++] = 0;
725  }
726
727  /* sum over src/dst ipaddr + udp packet */
728  len -= (char *) &packet->src - (char *) packet;
729  dosum ((unsigned short *) &packet->src, len >> 1, &rval);
730
731  /* take one's complement */
732  return ~rval;
733}
734
735/**************************************************************************
736AWAIT_REPLY - Wait until we get a response for our request
737**************************************************************************/
738int
739await_reply (int type, int ival, void *ptr, int timeout)
740{
741  unsigned long time;
742  struct iphdr *ip;
743  struct udphdr *udp;
744  struct arprequest *arpreply;
745  struct bootp_t *bootpreply;
746  unsigned short ptype;
747  unsigned int protohdrlen = (ETH_HLEN + sizeof (struct iphdr)
748			      + sizeof (struct udphdr));
749
750  /* Clear the abort flag.  */
751  ip_abort = 0;
752
753  time = timeout + currticks ();
754  /* The timeout check is done below.  The timeout is only checked if
755   * there is no packet in the Rx queue.  This assumes that eth_poll()
756   * needs a negligible amount of time.  */
757  for (;;)
758    {
759      if (eth_poll ())
760	{
761	  /* We have something!  */
762
763	  /* Check for ARP - No IP hdr.  */
764	  if (nic.packetlen >= ETH_HLEN)
765	    {
766	      ptype = (((unsigned short) nic.packet[12]) << 8
767		       | ((unsigned short) nic.packet[13]));
768	    }
769	  else
770	    /* What else could we do with it?  */
771	    continue;
772
773	  if (nic.packetlen >= ETH_HLEN + sizeof (struct arprequest)
774	      && ptype == ARP)
775	    {
776	      unsigned long tmp;
777
778	      arpreply = (struct arprequest *) &nic.packet[ETH_HLEN];
779
780	      if (arpreply->opcode == htons (ARP_REPLY)
781		  && ! grub_memcmp (arpreply->sipaddr, ptr, sizeof (in_addr))
782		  && type == AWAIT_ARP)
783		{
784		  grub_memmove ((char *) arptable[ival].node,
785				arpreply->shwaddr,
786				ETH_ALEN);
787		  return 1;
788		}
789
790	      grub_memmove ((char *) &tmp, arpreply->tipaddr,
791			    sizeof (in_addr));
792
793	      if (arpreply->opcode == htons (ARP_REQUEST)
794		  && tmp == arptable[ARP_CLIENT].ipaddr.s_addr)
795		{
796		  arpreply->opcode = htons (ARP_REPLY);
797		  grub_memmove (arpreply->tipaddr, arpreply->sipaddr,
798				sizeof (in_addr));
799		  grub_memmove (arpreply->thwaddr, (char *) arpreply->shwaddr,
800				ETH_ALEN);
801		  grub_memmove (arpreply->sipaddr,
802				(char *) &arptable[ARP_CLIENT].ipaddr,
803				sizeof (in_addr));
804		  grub_memmove (arpreply->shwaddr,
805				arptable[ARP_CLIENT].node,
806				ETH_ALEN);
807		  eth_transmit (arpreply->thwaddr, ARP,
808				sizeof (struct arprequest),
809				arpreply);
810#ifdef MDEBUG
811		  grub_memmove (&tmp, arpreply->tipaddr, sizeof (in_addr));
812		  etherboot_printf ("Sent ARP reply to: %@\n", tmp);
813#endif	/* MDEBUG */
814		}
815
816	      continue;
817	    }
818
819	  if (type == AWAIT_QDRAIN)
820	    continue;
821
822	  /* Check for RARP - No IP hdr.  */
823	  if (type == AWAIT_RARP
824	      && nic.packetlen >= ETH_HLEN + sizeof (struct arprequest)
825	      && ptype == RARP)
826	    {
827	      arpreply = (struct arprequest *) &nic.packet[ETH_HLEN];
828
829	      if (arpreply->opcode == htons (RARP_REPLY)
830		  && ! grub_memcmp (arpreply->thwaddr, ptr, ETH_ALEN))
831		{
832		  grub_memmove ((char *) arptable[ARP_SERVER].node,
833				arpreply->shwaddr, ETH_ALEN);
834		  grub_memmove ((char *) &arptable[ARP_SERVER].ipaddr,
835				arpreply->sipaddr, sizeof (in_addr));
836		  grub_memmove ((char *) &arptable[ARP_CLIENT].ipaddr,
837				arpreply->tipaddr, sizeof (in_addr));
838		  return 1;
839		}
840
841	      continue;
842	    }
843
844	  /* Anything else has IP header.  */
845	  if (nic.packetlen < protohdrlen || ptype != IP)
846	    continue;
847
848	  ip = (struct iphdr *) &nic.packet[ETH_HLEN];
849	  if (ip->verhdrlen != 0x45
850	      || ipchksum ((unsigned short *) ip, sizeof (struct iphdr))
851	      || ip->protocol != IP_UDP)
852	    continue;
853
854	  /*
855	    - Till Straumann <Till.Straumann@TU-Berlin.de>
856	    added udp checksum (safer on a wireless link)
857	    added fragmentation check: I had a corrupted image
858	    in memory due to fragmented TFTP packets - took me
859	    3 days to find the cause for this :-(
860	  */
861
862	  /* If More Fragments bit and Fragment Offset field
863	     are non-zero then packet is fragmented */
864	  if (ip->frags & htons(0x3FFF))
865	    {
866	      grub_printf ("ALERT: got a fragmented packet - reconfigure your server\n");
867	      continue;
868	    }
869
870	  udp = (struct udphdr *) &nic.packet[(ETH_HLEN
871					       + sizeof (struct iphdr))];
872	  if (udp->chksum && udpchksum (ip))
873	    {
874	      grub_printf ("UDP checksum error\n");
875	      continue;
876	    }
877
878	  /* BOOTP ?  */
879	  bootpreply = (struct bootp_t *)
880	    &nic.packet[(ETH_HLEN + sizeof (struct iphdr)
881			 + sizeof (struct udphdr))];
882	  if (type == AWAIT_BOOTP
883#ifdef NO_DHCP_SUPPORT
884	      && (nic.packetlen
885		  >= (ETH_HLEN + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN))
886#else
887	      && (nic.packetlen
888		  >= (ETH_HLEN + sizeof (struct bootp_t) - DHCP_OPT_LEN))
889#endif /* ! NO_DHCP_SUPPORT */
890	      && udp->dest == htons (BOOTP_CLIENT)
891	      && bootpreply->bp_op == BOOTP_REPLY
892	      && bootpreply->bp_xid == xid
893	      && (! grub_memcmp (broadcast, bootpreply->bp_hwaddr, ETH_ALEN)
894		  || ! grub_memcmp (arptable[ARP_CLIENT].node,
895				    bootpreply->bp_hwaddr, ETH_ALEN)))
896	    {
897#ifdef DEBUG
898	      grub_printf ("BOOTP packet was received.\n");
899#endif
900	      arptable[ARP_CLIENT].ipaddr.s_addr
901		= bootpreply->bp_yiaddr.s_addr;
902#ifndef	NO_DHCP_SUPPORT
903	      dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
904#ifdef DEBUG
905	      etherboot_printf ("dhcp_addr = %@\n", dhcp_addr.s_addr);
906#endif
907#endif /* ! NO_DHCP_SUPPORT */
908	      netmask = default_netmask ();
909	      arptable[ARP_SERVER].ipaddr.s_addr
910		= bootpreply->bp_siaddr.s_addr;
911	      /* Kill arp.  */
912	      grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
913	      arptable[ARP_GATEWAY].ipaddr.s_addr
914		= bootpreply->bp_giaddr.s_addr;
915	      /* Kill arp.  */
916	      grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
917
918	      grub_memmove ((char *) BOOTP_DATA_ADDR, (char *) bootpreply,
919			    sizeof (struct bootpd_t));
920#ifdef NO_DHCP_SUPPORT
921	      decode_rfc1533 (BOOTP_DATA_ADDR->bootp_reply.bp_vend,
922			      0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1);
923#else
924	      decode_rfc1533 (BOOTP_DATA_ADDR->bootp_reply.bp_vend,
925			      0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1);
926#endif /* ! NO_DHCP_SUPPORT */
927
928	      return 1;
929	    }
930
931	  /* TFTP ? */
932	  if (type == AWAIT_TFTP && ntohs (udp->dest) == ival)
933	    return 1;
934	}
935      else
936	{
937	  /* Check for abort key only if the Rx queue is empty -
938	   * as long as we have something to process, don't
939	   * assume that something failed.  It is unlikely that
940	   * we have no processing time left between packets.  */
941	  if (checkkey () != -1 && ASCII_CHAR (getkey ()) == CTRL_C)
942	    {
943	      ip_abort = 1;
944	      return 0;
945	    }
946
947	  /* Do the timeout after at least a full queue walk.  */
948	  if ((timeout == 0) || (currticks() > time))
949	    {
950	      break;
951	    }
952	}
953    }
954
955  return 0;
956}
957
958/**************************************************************************
959DECODE_RFC1533 - Decodes RFC1533 header
960**************************************************************************/
961int
962decode_rfc1533 (unsigned char *p, int block, int len, int eof)
963{
964  static unsigned char *extdata = NULL, *extend = NULL;
965  unsigned char *extpath = NULL;
966  unsigned char *endp;
967
968  if (block == 0)
969    {
970      end_of_rfc1533 = NULL;
971      vendorext_isvalid = 0;
972
973      if (grub_memcmp (p, rfc1533_cookie, 4))
974	/* no RFC 1533 header found */
975	return 0;
976
977      p += 4;
978      endp = p + len;
979    }
980  else
981    {
982      if (block == 1)
983	{
984	  if (grub_memcmp (p, rfc1533_cookie, 4))
985	    /* no RFC 1533 header found */
986	    return 0;
987
988	  p += 4;
989	  len -= 4;
990	}
991
992      if (extend + len
993	  <= ((unsigned char *)
994	      &(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])))
995	{
996	  grub_memmove (extend, p, len);
997	  extend += len;
998	}
999      else
1000	{
1001	  grub_printf ("Overflow in vendor data buffer! Aborting...\n");
1002	  *extdata = RFC1533_END;
1003	  return 0;
1004	}
1005
1006      p = extdata;
1007      endp = extend;
1008    }
1009
1010  if (! eof)
1011    return -1;
1012
1013  while (p < endp)
1014    {
1015      unsigned char c = *p;
1016
1017      if (c == RFC1533_PAD)
1018	{
1019	  p++;
1020	  continue;
1021	}
1022      else if (c == RFC1533_END)
1023	{
1024	  end_of_rfc1533 = endp = p;
1025	  continue;
1026	}
1027      else if (c == RFC1533_NETMASK)
1028	{
1029	  grub_memmove ((char *) &netmask, p + 2, sizeof (in_addr));
1030	}
1031      else if (c == RFC1533_GATEWAY)
1032	{
1033	  /* This is a little simplistic, but it will
1034	     usually be sufficient.
1035	     Take only the first entry.  */
1036	  if (TAG_LEN (p) >= sizeof (in_addr))
1037	    grub_memmove ((char *) &arptable[ARP_GATEWAY].ipaddr, p + 2,
1038			  sizeof (in_addr));
1039	}
1040      else if (c == RFC1533_EXTENSIONPATH)
1041	extpath = p;
1042#ifndef	NO_DHCP_SUPPORT
1043      else if (c == RFC2132_MSG_TYPE)
1044	{
1045	  dhcp_reply = *(p + 2);
1046	}
1047      else if (c == RFC2132_SRV_ID)
1048	{
1049	  grub_memmove ((char *) &dhcp_server, p + 2, sizeof (in_addr));
1050#ifdef DEBUG
1051	  etherboot_printf ("dhcp_server = %@\n", dhcp_server.s_addr);
1052#endif
1053	}
1054#endif /* ! NO_DHCP_SUPPORT */
1055      else if (c == RFC1533_VENDOR_MAGIC
1056	       && TAG_LEN(p) >= 6
1057	       && ! grub_memcmp (p + 2, vendorext_magic, 4)
1058	       && p[6] == RFC1533_VENDOR_MAJOR)
1059	vendorext_isvalid++;
1060      /* GRUB now handles its own tag. Get the name of a configuration
1061	 file from the network. Cool...  */
1062      else if (c == RFC1533_VENDOR_CONFIGFILE)
1063	{
1064	  int l = TAG_LEN (p);
1065
1066	  /* Eliminate the trailing NULs according to RFC 2132.  */
1067	  while (*(p + 2 + l - 1) == '\000' && l > 0)
1068	    l--;
1069
1070	  /* XXX: Should check if LEN is less than the maximum length
1071	     of CONFIG_FILE. This kind of robustness will be a goal
1072	     in GRUB 1.0.  */
1073	  grub_memmove (config_file, p + 2, l);
1074	  config_file[l] = 0;
1075	}
1076
1077      p += TAG_LEN (p) + 2;
1078    }
1079
1080  extdata = extend = endp;
1081
1082  /* Perhaps we can eliminate this because we doesn't require so
1083     much information, but I leave this alone.  */
1084  if (block == 0 && extpath != NULL)
1085    {
1086      char fname[64];
1087      int fnamelen = TAG_LEN (extpath);
1088
1089      while (*(extpath + 2 + fnamelen - 1) == '\000' && fnamelen > 0)
1090	fnamelen--;
1091
1092      if (fnamelen + 1 > sizeof (fname))
1093	{
1094	  grub_printf ("Too long file name for Extensions Path\n");
1095	  return 0;
1096	}
1097      else if (! fnamelen)
1098	{
1099	  grub_printf ("Empty file name for Extensions Path\n");
1100	  return 0;
1101	}
1102
1103      grub_memmove (fname, extpath + 2, fnamelen);
1104      fname[fnamelen] = '\000';
1105      grub_printf ("Loading BOOTP-extension file: %s\n", fname);
1106      tftp (fname, decode_rfc1533);
1107    }
1108
1109  /* Proceed with next block.  */
1110  return -1;
1111}
1112
1113/**************************************************************************
1114IPCHKSUM - Checksum IP Header
1115**************************************************************************/
1116static unsigned short
1117ipchksum (unsigned short *ip, int len)
1118{
1119  unsigned long sum = 0;
1120  len >>= 1;
1121  while (len--)
1122    {
1123      sum += *(ip++);
1124      if (sum > 0xFFFF)
1125	sum -= 0xFFFF;
1126    }
1127  return (~sum) & 0x0000FFFF;
1128}
1129
1130#define TWO_SECOND_DIVISOR (2147483647l/TICKS_PER_SEC)
1131
1132/**************************************************************************
1133RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times
1134**************************************************************************/
1135long
1136rfc2131_sleep_interval (int base, int exp)
1137{
1138  static long seed = 0;
1139  long q;
1140  unsigned long tmo;
1141
1142#ifdef BACKOFF_LIMIT
1143  if (exp > BACKOFF_LIMIT)
1144    exp = BACKOFF_LIMIT;
1145#endif
1146  if (!seed)
1147    /* Initialize linear congruential generator */
1148    seed = (currticks () + *((long *) &arptable[ARP_CLIENT].node)
1149	    + ((short *) arptable[ARP_CLIENT].node)[2]);
1150  /* simplified version of the LCG given in Bruce Schneier's
1151     "Applied Cryptography" */
1152  q = seed / 53668;
1153  if ((seed = 40014 * (seed - 53668 * q) - 12211 *q ) < 0)
1154    seed += 2147483563L;
1155  tmo = (base << exp) + (TICKS_PER_SEC - (seed / TWO_SECOND_DIVISOR));
1156  return tmo;
1157}
1158
1159/**************************************************************************
1160CLEANUP - shut down networking
1161**************************************************************************/
1162void
1163cleanup_net (void)
1164{
1165  if (network_ready)
1166    {
1167      /* Stop receiving packets.  */
1168      eth_disable ();
1169      network_ready = 0;
1170    }
1171}
1172