📄 main.c
字号:
/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Based on "src/main.c" in etherboot-5.0.5. *//**************************************************************************ETHERBOOT - BOOTP/TFTP Bootstrap ProgramAuthor: 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 GRUB 1#include <etherboot.h>#include <nic.h>/* #define DEBUG 1 */struct arptable_t arptable[MAX_ARP];/* Set if the user pushes Control-C. */int ip_abort = 0;/* Set if an ethernet card is probed and IP addresses are set. */int network_ready = 0;struct rom_info rom;static int vendorext_isvalid;static unsigned long netmask;static struct bootpd_t bootp_data;static unsigned long xid;static unsigned char *end_of_rfc1533 = NULL;#ifndef NO_DHCP_SUPPORT#endif /* NO_DHCP_SUPPORT *//* 銭th */static unsigned char vendorext_magic[] = {0xE4, 0x45, 0x74, 0x68};static const unsigned char broadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};#ifdef NO_DHCP_SUPPORTstatic unsigned char rfc1533_cookie[5] = {RFC1533_COOKIE, RFC1533_END};#else /* ! NO_DHCP_SUPPORT */static int dhcp_reply;static in_addr dhcp_server = {0L};static in_addr dhcp_addr = {0L};static unsigned char rfc1533_cookie[] = {RFC1533_COOKIE};static unsigned char rfc1533_end[] = {RFC1533_END};static const unsigned char dhcpdiscover[] ={ RFC2132_MSG_TYPE, 1, DHCPDISCOVER, RFC2132_MAX_SIZE,2, /* request as much as we can */ ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH};static const unsigned 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 */ ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, /* request parameters */ RFC2132_PARAM_LIST, /* 4 standard + 2 vendortags */ 4 + 2, /* Standard parameters */ RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, /* Etherboot vendortags */ RFC1533_VENDOR_MAGIC, RFC1533_VENDOR_CONFIGFILE,};#endif /* ! NO_DHCP_SUPPORT */static unsigned short ipchksum (unsigned short *ip, int len);static unsigned short udpchksum (struct iphdr *packet);voidprint_network_configuration (void){ if (! eth_probe ()) grub_printf ("No ethernet card found.\n"); else if (! network_ready) grub_printf ("Not initialized yet.\n"); else { etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr); etherboot_printf ("Netmask: %@\n", netmask); etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr); etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr); }}/**************************************************************************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));}/* ifconfig - configure network interface. */intifconfig (char *ip, char *sm, char *gw, char *svr){ in_addr tmp; if (sm) { if (! inet_aton (sm, &tmp)) return 0; netmask = tmp.s_addr; } if (ip) { if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr)) return 0; if (! netmask && ! sm) netmask = default_netmask (); } if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr)) return 0; /* Clear out the ARP entry. */ grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN); if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr)) return 0; /* Likewise. */ grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN); if (ip || sm) { if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr) || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr) || ! netmask) network_ready = 0; else network_ready = 1; } return 1;}/**************************************************************************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 *) ((unsigned 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; udp->chksum = htons (udpchksum (ip)); if (udp->chksum == 0) udp->chksum = 0xffff; 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) { etherboot_printf ("%@ is not in my arp table!\n", destip); return 0; } for (i = 0; i < ETH_ALEN; i++) if (arptable[arpentry].node[i]) break; if (i == ETH_ALEN) { /* Need to do arp request. */#ifdef DEBUG grub_printf ("arp request.\n");#endif arpreq.hwtype = htons (1); arpreq.protocol = htons (IP); arpreq.hwlen = ETH_ALEN; arpreq.protolen = 4; arpreq.opcode = htons (ARP_REQUEST); grub_memmove (arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); grub_memmove (arpreq.sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr, sizeof (in_addr)); grub_memset (arpreq.thwaddr, 0, ETH_ALEN); grub_memmove (arpreq.tipaddr, (char *) &destip, sizeof (in_addr)); for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { long timeout; eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout)) goto xmit; if (ip_abort) return 0; } return 0; } xmit: eth_transmit (arptable[arpentry].node, IP, len, buf); } return 1;}/**************************************************************************TFTP - Download extended BOOTP data, or kernel image**************************************************************************/static inttftp (const char *name, int (*fnc) (unsigned char *, int, int, int)){ int retry = 0; static unsigned short iport = 2000; unsigned short oport = 0; unsigned short len, block = 0, prevblock = 0; int bcounter = 0; struct tftp_t *tr; struct tftpreq_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 = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d", name, 0, 0, 0, TFTP_MAX_PACKET) + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; for (;;) { long timeout; #ifdef CONGESTED timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);#else timeout = rfc2131_sleep_interval (TIMEOUT, retry);#endif if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (! block && retry++ < MAX_TFTP_RETRIES) { /* Maybe initial request was lost. */ 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 grub_printf ("<REXMT>\n");#endif udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; }#endif /* Timeout. */ break; } tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_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; /* Shouldn't happen. */ if (prevblock) /* Ignore it. */ continue; len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -