Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub / netboot / main.c
blob82759b6cc86a9c16d14eaacb89da376d8f079b5a
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
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.
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.
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.
20 /* Based on "src/main.c" in etherboot-5.0.5. */
22 /**************************************************************************
23 ETHERBOOT - BOOTP/TFTP Bootstrap Program
25 Author: Martin Renters
26 Date: Dec/93
28 Literature 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)
38 **************************************************************************/
40 #define GRUB 1
41 #include <etherboot.h>
42 #include <nic.h>
44 /* #define DEBUG 1 */
46 struct arptable_t arptable[MAX_ARP];
48 /* Set if the user pushes Control-C. */
49 int ip_abort = 0;
50 /* Set if an ethernet card is probed and IP addresses are set. */
51 int network_ready = 0;
53 struct rom_info rom;
55 static int vendorext_isvalid;
56 static unsigned long netmask;
57 static struct bootpd_t bootp_data;
58 static unsigned long xid;
59 static unsigned char *end_of_rfc1533 = NULL;
61 #ifndef NO_DHCP_SUPPORT
62 #endif /* NO_DHCP_SUPPORT */
64 /* äEth */
65 static unsigned char vendorext_magic[] = {0xE4, 0x45, 0x74, 0x68};
66 static const unsigned char broadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
68 #ifdef NO_DHCP_SUPPORT
70 static unsigned char rfc1533_cookie[5] = {RFC1533_COOKIE, RFC1533_END};
72 #else /* ! NO_DHCP_SUPPORT */
74 static int dhcp_reply;
75 static in_addr dhcp_server = {0L};
76 static in_addr dhcp_addr = {0L};
77 static unsigned char rfc1533_cookie[] = {RFC1533_COOKIE};
78 static unsigned char rfc1533_end[] = {RFC1533_END};
80 static const unsigned char dhcpdiscover[] =
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
89 static const unsigned char dhcprequest[] =
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,
108 #endif /* ! NO_DHCP_SUPPORT */
110 static unsigned short ipchksum (unsigned short *ip, int len);
111 static unsigned short udpchksum (struct iphdr *packet);
113 void
114 print_network_configuration (void)
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
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);
130 /**************************************************************************
131 DEFAULT_NETMASK - Return default netmask for IP address
132 **************************************************************************/
133 static inline unsigned long
134 default_netmask (void)
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));
145 /* ifconfig - configure network interface. */
147 ifconfig (char *ip, char *sm, char *gw, char *svr)
149 in_addr tmp;
151 if (sm)
153 if (! inet_aton (sm, &tmp))
154 return 0;
156 netmask = tmp.s_addr;
159 if (ip)
161 if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
162 return 0;
164 if (! netmask && ! sm)
165 netmask = default_netmask ();
168 if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
169 return 0;
171 /* Clear out the ARP entry. */
172 grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
174 if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
175 return 0;
177 /* Likewise. */
178 grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
180 if (ip || sm)
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;
190 return 1;
194 /**************************************************************************
195 UDP_TRANSMIT - Send a UDP datagram
196 **************************************************************************/
197 int
198 udp_transmit (unsigned long destip, unsigned int srcsock,
199 unsigned int destsock, int len, const void *buf)
201 struct iphdr *ip;
202 struct udphdr *udp;
203 struct arprequest arpreq;
204 int arpentry, i;
205 int retry;
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));
226 if (udp->chksum == 0)
227 udp->chksum = 0xffff;
229 if (destip == IP_BROADCAST)
231 eth_transmit (broadcast, IP, len, buf);
233 else
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;
240 for (arpentry = 0; arpentry < MAX_ARP; arpentry++)
241 if (arptable[arpentry].ipaddr.s_addr == destip)
242 break;
244 if (arpentry == MAX_ARP)
246 etherboot_printf ("%@ is not in my arp table!\n", destip);
247 return 0;
250 for (i = 0; i < ETH_ALEN; i++)
251 if (arptable[arpentry].node[i])
252 break;
254 if (i == ETH_ALEN)
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));
272 for (retry = 1; retry <= MAX_ARP_RETRIES; retry++)
274 long timeout;
276 eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq);
277 timeout = rfc2131_sleep_interval (TIMEOUT, retry);
279 if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout))
280 goto xmit;
282 if (ip_abort)
283 return 0;
286 return 0;
289 xmit:
290 eth_transmit (arptable[arpentry].node, IP, len, buf);
293 return 1;
296 /**************************************************************************
297 TFTP - Download extended BOOTP data, or kernel image
298 **************************************************************************/
299 static int
300 tftp (const char *name, int (*fnc) (unsigned char *, int, int, int))
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;
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);
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;
328 for (;;)
330 long timeout;
332 #ifdef CONGESTED
333 timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
334 #else
335 timeout = rfc2131_sleep_interval (TIMEOUT, retry);
336 #endif
338 if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
340 if (! block && retry++ < MAX_TFTP_RETRIES)
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;
347 continue;
350 #ifdef CONGESTED
351 if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
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;
362 #endif
363 /* Timeout. */
364 break;
367 tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
368 if (tr->opcode == ntohs (TFTP_ERROR))
370 grub_printf ("TFTP error %d (%s)\n",
371 ntohs (tr->u.err.errcode),
372 tr->u.err.errmsg);
373 break;
376 if (tr->opcode == ntohs (TFTP_OACK))
378 char *p = tr->u.oack.data, *e;
380 /* Shouldn't happen. */
381 if (prevblock)
382 /* Ignore it. */
383 continue;
385 len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
386 if (len > TFTP_MAX_PACKET)
387 goto noak;
389 e = p + len;
390 while (*p != '\000' && p < e)
392 if (! grub_strcmp ("blksize", p))
394 p += 8;
395 if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
396 goto noak;
398 while (p < e && *p)
399 p++;
401 if (p < e)
402 p++;
404 else
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;
421 if (p > e)
422 goto noak;
424 /* This ensures that the packet does not get processed as data! */
425 block = tp.u.ack.block = 0;
427 else if (tr->opcode == ntohs (TFTP_DATA))
429 len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
430 /* Shouldn't happen. */
431 if (len > packetsize)
432 /* Ignore it. */
433 continue;
435 block = ntohs (tp.u.ack.block = tr->u.data.block);
437 else
438 /* Neither TFTP_OACK nor TFTP_DATA. */
439 break;
441 if ((block || bcounter) && (block != prevblock + 1))
442 /* Block order should be continuous */
443 tp.u.ack.block = htons (block = prevblock);
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);
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;
457 prevblock = block;
458 /* Is it the right place to zero the timer? */
459 retry = 0;
461 if ((rc = fnc (tr->u.data.download,
462 ++bcounter, len, len < packetsize)) >= 0)
463 return rc;
465 /* End of data. */
466 if (len < packetsize)
467 return 1;
470 return 0;
473 /**************************************************************************
474 RARP - Get my IP address and load information
475 **************************************************************************/
476 int
477 rarp (void)
479 int retry;
481 /* arp and rarp requests share the same packet structure. */
482 struct arprequest rarpreq;
484 /* Make sure that an ethernet is probed. */
485 if (! eth_probe ())
486 return 0;
488 /* Clear the ready flag. */
489 network_ready = 0;
491 grub_memset (&rarpreq, 0, sizeof (rarpreq));
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 */
505 for (retry = 0; retry < MAX_ARP_RETRIES; ++retry)
507 long timeout;
509 eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq);
511 timeout = rfc2131_sleep_interval (TIMEOUT, retry);
512 if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout))
513 break;
515 if (ip_abort)
516 return 0;
519 if (retry < MAX_ARP_RETRIES)
521 network_ready = 1;
522 return 1;
525 return 0;
528 /**************************************************************************
529 BOOTP - Get my IP address and load information
530 **************************************************************************/
531 int
532 bootp (void)
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;
541 /* Make sure that an ethernet is probed. */
542 if (! eth_probe ())
543 return 0;
545 /* Clear the ready flag. */
546 network_ready = 0;
548 #ifdef DEBUG
549 grub_printf ("network is ready.\n");
550 #endif
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
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 */
584 for (retry = 0; retry < MAX_BOOTP_RETRIES;)
586 long timeout;
588 #ifdef DEBUG
589 grub_printf ("retry = %d\n", retry);
590 #endif
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);
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))
607 network_ready = 1;
608 return 1;
610 #else /* ! NO_DHCP_SUPPORT */
611 if (await_reply (AWAIT_BOOTP, 0, NULL, timeout))
613 if (dhcp_reply != DHCPOFFER)
615 network_ready = 1;
616 return 1;
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;)
644 int ret;
645 #ifdef DEBUG
646 grub_printf ("reqretry = %d\n", reqretry);
647 #endif
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");
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)
659 network_ready = 1;
660 return 1;
663 #ifdef DEBUG
664 grub_printf ("dhcp_reply = %d\n", dhcp_reply);
665 #endif
667 if (ip_abort)
668 return 0;
671 #endif /* ! NO_DHCP_SUPPORT */
673 if (ip_abort)
674 return 0;
676 ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC);
679 /* Timeout. */
680 return 0;
683 /**************************************************************************
684 UDPCHKSUM - 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 **************************************************************************/
694 static inline void
695 dosum (unsigned short *start, unsigned int len, unsigned short *sum)
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"
710 /* UDP sum:
711 * proto, src_ip, dst_ip, udp_dport, udp_sport, 2*udp_len, payload
713 static unsigned short
714 udpchksum (struct iphdr *packet)
716 int len = ntohs (packet->len);
717 unsigned short rval;
719 /* add udplength + protocol number */
720 rval = (len - sizeof (struct iphdr)) + IP_UDP;
722 /* pad to an even number of bytes */
723 if (len % 2) {
724 ((char *) packet)[len++] = 0;
727 /* sum over src/dst ipaddr + udp packet */
728 len -= (char *) &packet->src - (char *) packet;
729 dosum ((unsigned short *) &packet->src, len >> 1, &rval);
731 /* take one's complement */
732 return ~rval;
735 /**************************************************************************
736 AWAIT_REPLY - Wait until we get a response for our request
737 **************************************************************************/
738 int
739 await_reply (int type, int ival, void *ptr, int timeout)
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));
750 /* Clear the abort flag. */
751 ip_abort = 0;
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 (;;)
759 if (eth_poll ())
761 /* We have something! */
763 /* Check for ARP - No IP hdr. */
764 if (nic.packetlen >= ETH_HLEN)
766 ptype = (((unsigned short) nic.packet[12]) << 8
767 | ((unsigned short) nic.packet[13]));
769 else
770 /* What else could we do with it? */
771 continue;
773 if (nic.packetlen >= ETH_HLEN + sizeof (struct arprequest)
774 && ptype == ARP)
776 unsigned long tmp;
778 arpreply = (struct arprequest *) &nic.packet[ETH_HLEN];
780 if (arpreply->opcode == htons (ARP_REPLY)
781 && ! grub_memcmp (arpreply->sipaddr, ptr, sizeof (in_addr))
782 && type == AWAIT_ARP)
784 grub_memmove ((char *) arptable[ival].node,
785 arpreply->shwaddr,
786 ETH_ALEN);
787 return 1;
790 grub_memmove ((char *) &tmp, arpreply->tipaddr,
791 sizeof (in_addr));
793 if (arpreply->opcode == htons (ARP_REQUEST)
794 && tmp == arptable[ARP_CLIENT].ipaddr.s_addr)
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 */
816 continue;
819 if (type == AWAIT_QDRAIN)
820 continue;
822 /* Check for RARP - No IP hdr. */
823 if (type == AWAIT_RARP
824 && nic.packetlen >= ETH_HLEN + sizeof (struct arprequest)
825 && ptype == RARP)
827 arpreply = (struct arprequest *) &nic.packet[ETH_HLEN];
829 if (arpreply->opcode == htons (RARP_REPLY)
830 && ! grub_memcmp (arpreply->thwaddr, ptr, ETH_ALEN))
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;
841 continue;
844 /* Anything else has IP header. */
845 if (nic.packetlen < protohdrlen || ptype != IP)
846 continue;
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;
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 :-(
862 /* If More Fragments bit and Fragment Offset field
863 are non-zero then packet is fragmented */
864 if (ip->frags & htons(0x3FFF))
866 grub_printf ("ALERT: got a fragmented packet - reconfigure your server\n");
867 continue;
870 udp = (struct udphdr *) &nic.packet[(ETH_HLEN
871 + sizeof (struct iphdr))];
872 if (udp->chksum && udpchksum (ip))
874 grub_printf ("UDP checksum error\n");
875 continue;
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)))
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);
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 */
928 return 1;
931 /* TFTP ? */
932 if (type == AWAIT_TFTP && ntohs (udp->dest) == ival)
933 return 1;
935 else
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)
943 ip_abort = 1;
944 return 0;
947 /* Do the timeout after at least a full queue walk. */
948 if ((timeout == 0) || (currticks() > time))
950 break;
955 return 0;
958 /**************************************************************************
959 DECODE_RFC1533 - Decodes RFC1533 header
960 **************************************************************************/
962 decode_rfc1533 (unsigned char *p, int block, int len, int eof)
964 static unsigned char *extdata = NULL, *extend = NULL;
965 unsigned char *extpath = NULL;
966 unsigned char *endp;
968 if (block == 0)
970 end_of_rfc1533 = NULL;
971 vendorext_isvalid = 0;
973 if (grub_memcmp (p, rfc1533_cookie, 4))
974 /* no RFC 1533 header found */
975 return 0;
977 p += 4;
978 endp = p + len;
980 else
982 if (block == 1)
984 if (grub_memcmp (p, rfc1533_cookie, 4))
985 /* no RFC 1533 header found */
986 return 0;
988 p += 4;
989 len -= 4;
992 if (extend + len
993 <= ((unsigned char *)
994 &(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])))
996 grub_memmove (extend, p, len);
997 extend += len;
999 else
1001 grub_printf ("Overflow in vendor data buffer! Aborting...\n");
1002 *extdata = RFC1533_END;
1003 return 0;
1006 p = extdata;
1007 endp = extend;
1010 if (! eof)
1011 return -1;
1013 while (p < endp)
1015 unsigned char c = *p;
1017 if (c == RFC1533_PAD)
1019 p++;
1020 continue;
1022 else if (c == RFC1533_END)
1024 end_of_rfc1533 = endp = p;
1025 continue;
1027 else if (c == RFC1533_NETMASK)
1029 grub_memmove ((char *) &netmask, p + 2, sizeof (in_addr));
1031 else if (c == RFC1533_GATEWAY)
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));
1040 else if (c == RFC1533_EXTENSIONPATH)
1041 extpath = p;
1042 #ifndef NO_DHCP_SUPPORT
1043 else if (c == RFC2132_MSG_TYPE)
1045 dhcp_reply = *(p + 2);
1047 else if (c == RFC2132_SRV_ID)
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
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)
1064 int l = TAG_LEN (p);
1066 /* Eliminate the trailing NULs according to RFC 2132. */
1067 while (*(p + 2 + l - 1) == '\000' && l > 0)
1068 l--;
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;
1077 p += TAG_LEN (p) + 2;
1080 extdata = extend = endp;
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)
1086 char fname[64];
1087 int fnamelen = TAG_LEN (extpath);
1089 while (*(extpath + 2 + fnamelen - 1) == '\000' && fnamelen > 0)
1090 fnamelen--;
1092 if (fnamelen + 1 > sizeof (fname))
1094 grub_printf ("Too long file name for Extensions Path\n");
1095 return 0;
1097 else if (! fnamelen)
1099 grub_printf ("Empty file name for Extensions Path\n");
1100 return 0;
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);
1109 /* Proceed with next block. */
1110 return -1;
1113 /**************************************************************************
1114 IPCHKSUM - Checksum IP Header
1115 **************************************************************************/
1116 static unsigned short
1117 ipchksum (unsigned short *ip, int len)
1119 unsigned long sum = 0;
1120 len >>= 1;
1121 while (len--)
1123 sum += *(ip++);
1124 if (sum > 0xFFFF)
1125 sum -= 0xFFFF;
1127 return (~sum) & 0x0000FFFF;
1130 #define TWO_SECOND_DIVISOR (2147483647l/TICKS_PER_SEC)
1132 /**************************************************************************
1133 RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times
1134 **************************************************************************/
1135 long
1136 rfc2131_sleep_interval (int base, int exp)
1138 static long seed = 0;
1139 long q;
1140 unsigned long tmo;
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;
1159 /**************************************************************************
1160 CLEANUP - shut down networking
1161 **************************************************************************/
1162 void
1163 cleanup_net (void)
1165 if (network_ready)
1167 /* Stop receiving packets. */
1168 eth_disable ();
1169 network_ready = 0;