xref: /titanic_44/usr/src/grub/grub-0.97/netboot/nic.c (revision 2506833e104b0230265b2060e907afe5b224df6c)
11b8adde7SWilliam Kucharski /**************************************************************************
21b8adde7SWilliam Kucharski Etherboot -  Network Bootstrap Program
31b8adde7SWilliam Kucharski 
41b8adde7SWilliam Kucharski Literature dealing with the network protocols:
51b8adde7SWilliam Kucharski 	ARP - RFC826
61b8adde7SWilliam Kucharski 	RARP - RFC903
71b8adde7SWilliam Kucharski         IP - RFC791
81b8adde7SWilliam Kucharski 	UDP - RFC768
91b8adde7SWilliam Kucharski 	BOOTP - RFC951, RFC2132 (vendor extensions)
101b8adde7SWilliam Kucharski 	DHCP - RFC2131, RFC2132 (options)
111b8adde7SWilliam Kucharski 	TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
121b8adde7SWilliam Kucharski 	RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
131b8adde7SWilliam Kucharski 	NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
141b8adde7SWilliam Kucharski 	IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
151b8adde7SWilliam Kucharski 
161b8adde7SWilliam Kucharski **************************************************************************/
171b8adde7SWilliam Kucharski #include "etherboot.h"
181b8adde7SWilliam Kucharski #include "grub.h"
191b8adde7SWilliam Kucharski #include "nic.h"
201b8adde7SWilliam Kucharski #include "elf.h" /* FOR EM_CURRENT */
211b8adde7SWilliam Kucharski #include "bootp.h"
221b8adde7SWilliam Kucharski #include "if_arp.h"
231b8adde7SWilliam Kucharski #include "tftp.h"
241b8adde7SWilliam Kucharski #include "timer.h"
251b8adde7SWilliam Kucharski #include "ip.h"
261b8adde7SWilliam Kucharski #include "udp.h"
271b8adde7SWilliam Kucharski 
281b8adde7SWilliam Kucharski /* Currently no other module uses rom, but it is available */
291b8adde7SWilliam Kucharski struct rom_info		rom;
301b8adde7SWilliam Kucharski struct arptable_t	arptable[MAX_ARP];
311b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
321b8adde7SWilliam Kucharski unsigned long last_igmpv1 = 0;
331b8adde7SWilliam Kucharski struct igmptable_t	igmptable[MAX_IGMP];
341b8adde7SWilliam Kucharski #endif
351b8adde7SWilliam Kucharski static unsigned long	netmask;
361b8adde7SWilliam Kucharski /* Used by nfs.c */
371b8adde7SWilliam Kucharski char *hostname = "";
381b8adde7SWilliam Kucharski int hostnamelen = 0;
391b8adde7SWilliam Kucharski /* Used by fsys_tftp.c */
401b8adde7SWilliam Kucharski int use_bios_pxe = 0;
411b8adde7SWilliam Kucharski static uint32_t xid;
421b8adde7SWilliam Kucharski static unsigned char *end_of_rfc1533 = NULL;
431b8adde7SWilliam Kucharski static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
441b8adde7SWilliam Kucharski static const in_addr zeroIP = { 0L };
451b8adde7SWilliam Kucharski static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
461b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
471b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
481b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
491b8adde7SWilliam Kucharski static int dhcp_reply;
501b8adde7SWilliam Kucharski static in_addr dhcp_server = { 0L };
511b8adde7SWilliam Kucharski static in_addr dhcp_addr = { 0L };
521b8adde7SWilliam Kucharski 
531b8adde7SWilliam Kucharski static const unsigned char dhcpdiscover[] = {
541b8adde7SWilliam Kucharski 	RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
551b8adde7SWilliam Kucharski 	RFC2132_MAX_SIZE, 2,	/* request as much as we can */
561b8adde7SWilliam Kucharski 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
571b8adde7SWilliam Kucharski 	/* Vendor class identifier */
581b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
591b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
601b8adde7SWilliam Kucharski 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
611b8adde7SWilliam Kucharski 	'0','0','2','0','0','1',
621b8adde7SWilliam Kucharski #else
631b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
641b8adde7SWilliam Kucharski #endif
651b8adde7SWilliam Kucharski 	RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
661b8adde7SWilliam Kucharski 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
671b8adde7SWilliam Kucharski };
681b8adde7SWilliam Kucharski static const unsigned char dhcprequest [] = {
691b8adde7SWilliam Kucharski 	RFC2132_MSG_TYPE,1,DHCPREQUEST,
701b8adde7SWilliam Kucharski 	RFC2132_SRV_ID,4,0,0,0,0,
711b8adde7SWilliam Kucharski 	RFC2132_REQ_ADDR,4,0,0,0,0,
721b8adde7SWilliam Kucharski 	RFC2132_MAX_SIZE,2,	/* request as much as we can */
731b8adde7SWilliam Kucharski 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
741b8adde7SWilliam Kucharski 	/* Vendor class identifier */
751b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
761b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
771b8adde7SWilliam Kucharski 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
781b8adde7SWilliam Kucharski 	'0','0','2','0','0','1',
791b8adde7SWilliam Kucharski #else
801b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
811b8adde7SWilliam Kucharski #endif
821b8adde7SWilliam Kucharski 	RFC2132_PARAM_LIST,
831b8adde7SWilliam Kucharski 	/* 4 standard + 2 vendortags */
841b8adde7SWilliam Kucharski 	4 + 2,
851b8adde7SWilliam Kucharski 	/* Standard parameters */
861b8adde7SWilliam Kucharski 	RFC1533_NETMASK, RFC1533_GATEWAY,
871b8adde7SWilliam Kucharski 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
881b8adde7SWilliam Kucharski 	/* Etherboot vendortags */
891b8adde7SWilliam Kucharski 	RFC1533_VENDOR_MAGIC,
901b8adde7SWilliam Kucharski 	RFC1533_VENDOR_CONFIGFILE,
911b8adde7SWilliam Kucharski 	RFC1533_END
921b8adde7SWilliam Kucharski };
931b8adde7SWilliam Kucharski 
941b8adde7SWilliam Kucharski /* See nic.h */
951b8adde7SWilliam Kucharski int user_abort = 0;
961b8adde7SWilliam Kucharski int network_ready = 0;
971b8adde7SWilliam Kucharski 
981b8adde7SWilliam Kucharski #ifdef	REQUIRE_VCI_ETHERBOOT
991b8adde7SWilliam Kucharski int	vci_etherboot;
1001b8adde7SWilliam Kucharski #endif
1011b8adde7SWilliam Kucharski 
102*2506833eSJan Setje-Eilers char *bootfile = NULL;
103*2506833eSJan Setje-Eilers configfile_origin_t configfile_origin = CFG_HARDCODED;
104*2506833eSJan Setje-Eilers char *vendor_configfile = NULL;
105*2506833eSJan Setje-Eilers char vendor_configfile_len;
106*2506833eSJan Setje-Eilers 
1071b8adde7SWilliam Kucharski static void update_network_configuration(void);
1081b8adde7SWilliam Kucharski 
dummy(void * unused __unused)1091b8adde7SWilliam Kucharski static int dummy(void *unused __unused)
1101b8adde7SWilliam Kucharski {
1111b8adde7SWilliam Kucharski 	return (0);
1121b8adde7SWilliam Kucharski }
1131b8adde7SWilliam Kucharski 
1141b8adde7SWilliam Kucharski /* Careful.  We need an aligned buffer to avoid problems on machines
1151b8adde7SWilliam Kucharski  * that care about alignment.  To trivally align the ethernet data
1161b8adde7SWilliam Kucharski  * (the ip hdr and arp requests) we offset the packet by 2 bytes.
1171b8adde7SWilliam Kucharski  * leaving the ethernet data 16 byte aligned.  Beyond this
1181b8adde7SWilliam Kucharski  * we use memmove but this makes the common cast simple and fast.
1191b8adde7SWilliam Kucharski  */
1201b8adde7SWilliam Kucharski static char	packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
1211b8adde7SWilliam Kucharski 
1221b8adde7SWilliam Kucharski struct nic	nic =
1231b8adde7SWilliam Kucharski {
1241b8adde7SWilliam Kucharski 	{
1251b8adde7SWilliam Kucharski 		0,				/* dev.disable */
1261b8adde7SWilliam Kucharski 		{
1271b8adde7SWilliam Kucharski 			0,
1281b8adde7SWilliam Kucharski 			0,
1291b8adde7SWilliam Kucharski 			PCI_BUS_TYPE,
1301b8adde7SWilliam Kucharski 		},				/* dev.devid */
1311b8adde7SWilliam Kucharski 		0,				/* index */
1321b8adde7SWilliam Kucharski 		0,				/* type */
1331b8adde7SWilliam Kucharski 		PROBE_FIRST,			/* how_pobe */
1341b8adde7SWilliam Kucharski 		PROBE_NONE,			/* to_probe */
1351b8adde7SWilliam Kucharski 		0,				/* failsafe */
1361b8adde7SWilliam Kucharski 		0,				/* type_index */
1371b8adde7SWilliam Kucharski 		{},				/* state */
1381b8adde7SWilliam Kucharski 	},
1391b8adde7SWilliam Kucharski 	(int (*)(struct nic *, int))dummy,      /* poll */
1401b8adde7SWilliam Kucharski 	(void (*)(struct nic *, const char *,
1411b8adde7SWilliam Kucharski 		unsigned int, unsigned int,
1421b8adde7SWilliam Kucharski 		const char *))dummy,		/* transmit */
1431b8adde7SWilliam Kucharski 	(void (*)(struct nic *, irq_action_t))dummy, /* irq */
1441b8adde7SWilliam Kucharski 	0,					/* flags */
1451b8adde7SWilliam Kucharski 	&rom,					/* rom_info */
1461b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].node,		/* node_addr */
1471b8adde7SWilliam Kucharski 	packet + ETH_DATA_ALIGN,		/* packet */
1481b8adde7SWilliam Kucharski 	0,					/* packetlen */
1491b8adde7SWilliam Kucharski 	0,			/* ioaddr */
1501b8adde7SWilliam Kucharski 	0,			/* irqno */
1511b8adde7SWilliam Kucharski 	NULL,					/* priv_data */
1521b8adde7SWilliam Kucharski };
1531b8adde7SWilliam Kucharski 
1541b8adde7SWilliam Kucharski 
1551b8adde7SWilliam Kucharski 
grub_eth_probe(void)1561b8adde7SWilliam Kucharski int grub_eth_probe(void)
1571b8adde7SWilliam Kucharski {
1581b8adde7SWilliam Kucharski 	static int probed = 0;
1591b8adde7SWilliam Kucharski 	struct dev *dev;
1601b8adde7SWilliam Kucharski 
1611b8adde7SWilliam Kucharski 	EnterFunction("grub_eth_probe");
1621b8adde7SWilliam Kucharski 
1631b8adde7SWilliam Kucharski 	if (probed)
1641b8adde7SWilliam Kucharski 		return 1;
1651b8adde7SWilliam Kucharski 
1661b8adde7SWilliam Kucharski 	network_ready = 0;
1671b8adde7SWilliam Kucharski 	grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
1681b8adde7SWilliam Kucharski 	dev = &nic.dev;
1691b8adde7SWilliam Kucharski 	dev->how_probe = -1;
1701b8adde7SWilliam Kucharski 	dev->type = NIC_DRIVER;
1711b8adde7SWilliam Kucharski 	dev->failsafe = 1;
1721b8adde7SWilliam Kucharski 	rom = *((struct rom_info *)ROM_INFO_LOCATION);
1731b8adde7SWilliam Kucharski 
1741b8adde7SWilliam Kucharski 	probed = (eth_probe(dev) == PROBE_WORKED);
1751b8adde7SWilliam Kucharski 
1761b8adde7SWilliam Kucharski 	LeaveFunction("grub_eth_probe");
1771b8adde7SWilliam Kucharski 	return probed;
1781b8adde7SWilliam Kucharski }
1791b8adde7SWilliam Kucharski 
eth_probe(struct dev * dev)1801b8adde7SWilliam Kucharski int eth_probe(struct dev *dev)
1811b8adde7SWilliam Kucharski {
1821b8adde7SWilliam Kucharski 	return probe(dev);
1831b8adde7SWilliam Kucharski }
1841b8adde7SWilliam Kucharski 
eth_poll(int retrieve)1851b8adde7SWilliam Kucharski int eth_poll(int retrieve)
1861b8adde7SWilliam Kucharski {
1871b8adde7SWilliam Kucharski 	return ((*nic.poll)(&nic, retrieve));
1881b8adde7SWilliam Kucharski }
1891b8adde7SWilliam Kucharski 
eth_transmit(const char * d,unsigned int t,unsigned int s,const void * p)1901b8adde7SWilliam Kucharski void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
1911b8adde7SWilliam Kucharski {
1921b8adde7SWilliam Kucharski 	(*nic.transmit)(&nic, d, t, s, p);
1931b8adde7SWilliam Kucharski 	if (t == IP) twiddle();
1941b8adde7SWilliam Kucharski }
1951b8adde7SWilliam Kucharski 
eth_disable(void)1961b8adde7SWilliam Kucharski void eth_disable(void)
1971b8adde7SWilliam Kucharski {
1981b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
1991b8adde7SWilliam Kucharski 	int i;
2001b8adde7SWilliam Kucharski 	for(i = 0; i < MAX_IGMP; i++) {
2011b8adde7SWilliam Kucharski 		leave_group(i);
2021b8adde7SWilliam Kucharski 	}
2031b8adde7SWilliam Kucharski #endif
2041b8adde7SWilliam Kucharski 	disable(&nic.dev);
2051b8adde7SWilliam Kucharski }
2061b8adde7SWilliam Kucharski 
eth_irq(irq_action_t action)2071b8adde7SWilliam Kucharski void eth_irq (irq_action_t action)
2081b8adde7SWilliam Kucharski {
2091b8adde7SWilliam Kucharski 	(*nic.irq)(&nic,action);
2101b8adde7SWilliam Kucharski }
2111b8adde7SWilliam Kucharski 
2121b8adde7SWilliam Kucharski /**************************************************************************
2131b8adde7SWilliam Kucharski IPCHKSUM - Checksum IP Header
2141b8adde7SWilliam Kucharski **************************************************************************/
ipchksum(const void * data,unsigned long length)2151b8adde7SWilliam Kucharski uint16_t ipchksum(const void *data, unsigned long length)
2161b8adde7SWilliam Kucharski {
2171b8adde7SWilliam Kucharski 	unsigned long sum;
2181b8adde7SWilliam Kucharski 	unsigned long i;
2191b8adde7SWilliam Kucharski 	const uint8_t *ptr;
2201b8adde7SWilliam Kucharski 
2211b8adde7SWilliam Kucharski 	/* In the most straight forward way possible,
2221b8adde7SWilliam Kucharski 	 * compute an ip style checksum.
2231b8adde7SWilliam Kucharski 	 */
2241b8adde7SWilliam Kucharski 	sum = 0;
2251b8adde7SWilliam Kucharski 	ptr = data;
2261b8adde7SWilliam Kucharski 	for(i = 0; i < length; i++) {
2271b8adde7SWilliam Kucharski 		unsigned long value;
2281b8adde7SWilliam Kucharski 		value = ptr[i];
2291b8adde7SWilliam Kucharski 		if (i & 1) {
2301b8adde7SWilliam Kucharski 			value <<= 8;
2311b8adde7SWilliam Kucharski 		}
2321b8adde7SWilliam Kucharski 		/* Add the new value */
2331b8adde7SWilliam Kucharski 		sum += value;
2341b8adde7SWilliam Kucharski 		/* Wrap around the carry */
2351b8adde7SWilliam Kucharski 		if (sum > 0xFFFF) {
2361b8adde7SWilliam Kucharski 			sum = (sum + (sum >> 16)) & 0xFFFF;
2371b8adde7SWilliam Kucharski 		}
2381b8adde7SWilliam Kucharski 	}
2391b8adde7SWilliam Kucharski 	return (~cpu_to_le16(sum)) & 0xFFFF;
2401b8adde7SWilliam Kucharski }
2411b8adde7SWilliam Kucharski 
add_ipchksums(unsigned long offset,uint16_t sum,uint16_t new)2421b8adde7SWilliam Kucharski uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
2431b8adde7SWilliam Kucharski {
2441b8adde7SWilliam Kucharski 	unsigned long checksum;
2451b8adde7SWilliam Kucharski 	sum = ~sum & 0xFFFF;
2461b8adde7SWilliam Kucharski 	new = ~new & 0xFFFF;
2471b8adde7SWilliam Kucharski 	if (offset & 1) {
2481b8adde7SWilliam Kucharski 		/* byte swap the sum if it came from an odd offset
2491b8adde7SWilliam Kucharski 		 * since the computation is endian independant this
2501b8adde7SWilliam Kucharski 		 * works.
2511b8adde7SWilliam Kucharski 		 */
2521b8adde7SWilliam Kucharski 		new = bswap_16(new);
2531b8adde7SWilliam Kucharski 	}
2541b8adde7SWilliam Kucharski 	checksum = sum + new;
2551b8adde7SWilliam Kucharski 	if (checksum > 0xFFFF) {
2561b8adde7SWilliam Kucharski 		checksum -= 0xFFFF;
2571b8adde7SWilliam Kucharski 	}
2581b8adde7SWilliam Kucharski 	return (~checksum) & 0xFFFF;
2591b8adde7SWilliam Kucharski }
2601b8adde7SWilliam Kucharski 
2611b8adde7SWilliam Kucharski /**************************************************************************
2621b8adde7SWilliam Kucharski DEFAULT_NETMASK - Return default netmask for IP address
2631b8adde7SWilliam Kucharski **************************************************************************/
default_netmask(void)2641b8adde7SWilliam Kucharski static inline unsigned long default_netmask(void)
2651b8adde7SWilliam Kucharski {
2661b8adde7SWilliam Kucharski 	int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
2671b8adde7SWilliam Kucharski 	if (net <= 127)
2681b8adde7SWilliam Kucharski 		return(htonl(0xff000000));
2691b8adde7SWilliam Kucharski 	else if (net < 192)
2701b8adde7SWilliam Kucharski 		return(htonl(0xffff0000));
2711b8adde7SWilliam Kucharski 	else
2721b8adde7SWilliam Kucharski 		return(htonl(0xffffff00));
2731b8adde7SWilliam Kucharski }
2741b8adde7SWilliam Kucharski 
2751b8adde7SWilliam Kucharski /**************************************************************************
2761b8adde7SWilliam Kucharski IP_TRANSMIT - Send an IP datagram
2771b8adde7SWilliam Kucharski **************************************************************************/
await_arp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip __unused,struct udphdr * udp __unused)2781b8adde7SWilliam Kucharski static int await_arp(int ival, void *ptr,
2791b8adde7SWilliam Kucharski 	unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
2801b8adde7SWilliam Kucharski {
2811b8adde7SWilliam Kucharski 	struct	arprequest *arpreply;
2821b8adde7SWilliam Kucharski 	if (ptype != ARP)
2831b8adde7SWilliam Kucharski 		return 0;
2841b8adde7SWilliam Kucharski 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
2851b8adde7SWilliam Kucharski 		return 0;
2861b8adde7SWilliam Kucharski 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
2871b8adde7SWilliam Kucharski 
2881b8adde7SWilliam Kucharski 	if (arpreply->opcode != htons(ARP_REPLY))
2891b8adde7SWilliam Kucharski 		return 0;
2901b8adde7SWilliam Kucharski 	if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
2911b8adde7SWilliam Kucharski 		return 0;
2921b8adde7SWilliam Kucharski 	memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
2931b8adde7SWilliam Kucharski 	return 1;
2941b8adde7SWilliam Kucharski }
2951b8adde7SWilliam Kucharski 
ip_transmit(int len,const void * buf)2961b8adde7SWilliam Kucharski int ip_transmit(int len, const void *buf)
2971b8adde7SWilliam Kucharski {
2981b8adde7SWilliam Kucharski 	unsigned long destip;
2991b8adde7SWilliam Kucharski 	struct iphdr *ip;
3001b8adde7SWilliam Kucharski 	struct arprequest arpreq;
3011b8adde7SWilliam Kucharski 	int arpentry, i;
3021b8adde7SWilliam Kucharski 	int retry;
3031b8adde7SWilliam Kucharski 
3041b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
3051b8adde7SWilliam Kucharski 	destip = ip->dest.s_addr;
3061b8adde7SWilliam Kucharski 	if (destip == IP_BROADCAST) {
3071b8adde7SWilliam Kucharski 		eth_transmit(broadcast, IP, len, buf);
3081b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL1
3091b8adde7SWilliam Kucharski 	} else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
3101b8adde7SWilliam Kucharski 		unsigned char multicast[6];
3111b8adde7SWilliam Kucharski 		unsigned long hdestip;
3121b8adde7SWilliam Kucharski 		hdestip = ntohl(destip);
3131b8adde7SWilliam Kucharski 		multicast[0] = 0x01;
3141b8adde7SWilliam Kucharski 		multicast[1] = 0x00;
3151b8adde7SWilliam Kucharski 		multicast[2] = 0x5e;
3161b8adde7SWilliam Kucharski 		multicast[3] = (hdestip >> 16) & 0x7;
3171b8adde7SWilliam Kucharski 		multicast[4] = (hdestip >> 8) & 0xff;
3181b8adde7SWilliam Kucharski 		multicast[5] = hdestip & 0xff;
3191b8adde7SWilliam Kucharski 		eth_transmit(multicast, IP, len, buf);
3201b8adde7SWilliam Kucharski #endif
3211b8adde7SWilliam Kucharski 	} else {
3221b8adde7SWilliam Kucharski 		if (((destip & netmask) !=
3231b8adde7SWilliam Kucharski 		     (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
3241b8adde7SWilliam Kucharski 		    arptable[ARP_GATEWAY].ipaddr.s_addr)
3251b8adde7SWilliam Kucharski 			destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
3261b8adde7SWilliam Kucharski 		for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
3271b8adde7SWilliam Kucharski 			if (arptable[arpentry].ipaddr.s_addr == destip) break;
3281b8adde7SWilliam Kucharski 		if (arpentry == MAX_ARP) {
3291b8adde7SWilliam Kucharski 			printf("%@ is not in my arp table!\n", destip);
3301b8adde7SWilliam Kucharski 			return(0);
3311b8adde7SWilliam Kucharski 		}
3321b8adde7SWilliam Kucharski 		for (i = 0; i < ETH_ALEN; i++)
3331b8adde7SWilliam Kucharski 			if (arptable[arpentry].node[i])
3341b8adde7SWilliam Kucharski 				break;
3351b8adde7SWilliam Kucharski 		if (i == ETH_ALEN) {	/* Need to do arp request */
3361b8adde7SWilliam Kucharski 			arpreq.hwtype = htons(1);
3371b8adde7SWilliam Kucharski 			arpreq.protocol = htons(IP);
3381b8adde7SWilliam Kucharski 			arpreq.hwlen = ETH_ALEN;
3391b8adde7SWilliam Kucharski 			arpreq.protolen = 4;
3401b8adde7SWilliam Kucharski 			arpreq.opcode = htons(ARP_REQUEST);
3411b8adde7SWilliam Kucharski 			memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
3421b8adde7SWilliam Kucharski 			memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
3431b8adde7SWilliam Kucharski 			memset(arpreq.thwaddr, 0, ETH_ALEN);
3441b8adde7SWilliam Kucharski 			memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
3451b8adde7SWilliam Kucharski 			for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
3461b8adde7SWilliam Kucharski 				long timeout;
3471b8adde7SWilliam Kucharski 				eth_transmit(broadcast, ARP, sizeof(arpreq),
3481b8adde7SWilliam Kucharski 					&arpreq);
3491b8adde7SWilliam Kucharski 				timeout = rfc2131_sleep_interval(TIMEOUT, retry);
3501b8adde7SWilliam Kucharski 				if (await_reply(await_arp, arpentry,
3511b8adde7SWilliam Kucharski 					arpreq.tipaddr, timeout)) goto xmit;
3521b8adde7SWilliam Kucharski 			}
3531b8adde7SWilliam Kucharski 			return(0);
3541b8adde7SWilliam Kucharski 		}
3551b8adde7SWilliam Kucharski xmit:
3561b8adde7SWilliam Kucharski 		eth_transmit(arptable[arpentry].node, IP, len, buf);
3571b8adde7SWilliam Kucharski 	}
3581b8adde7SWilliam Kucharski 	return 1;
3591b8adde7SWilliam Kucharski }
3601b8adde7SWilliam Kucharski 
build_ip_hdr(unsigned long destip,int ttl,int protocol,int option_len,int len,const void * buf)3611b8adde7SWilliam Kucharski void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
3621b8adde7SWilliam Kucharski 	int len, const void *buf)
3631b8adde7SWilliam Kucharski {
3641b8adde7SWilliam Kucharski 	struct iphdr *ip;
3651b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
3661b8adde7SWilliam Kucharski 	ip->verhdrlen = 0x45;
3671b8adde7SWilliam Kucharski 	ip->verhdrlen += (option_len/4);
3681b8adde7SWilliam Kucharski 	ip->service = 0;
3691b8adde7SWilliam Kucharski 	ip->len = htons(len);
3701b8adde7SWilliam Kucharski 	ip->ident = 0;
3711b8adde7SWilliam Kucharski 	ip->frags = 0; /* Should we set don't fragment? */
3721b8adde7SWilliam Kucharski 	ip->ttl = ttl;
3731b8adde7SWilliam Kucharski 	ip->protocol = protocol;
3741b8adde7SWilliam Kucharski 	ip->chksum = 0;
3751b8adde7SWilliam Kucharski 	ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
3761b8adde7SWilliam Kucharski 	ip->dest.s_addr = destip;
3771b8adde7SWilliam Kucharski 	ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
3781b8adde7SWilliam Kucharski }
3791b8adde7SWilliam Kucharski 
udpchksum(struct iphdr * ip,struct udphdr * udp)3801b8adde7SWilliam Kucharski static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
3811b8adde7SWilliam Kucharski {
3821b8adde7SWilliam Kucharski 	struct udp_pseudo_hdr pseudo;
3831b8adde7SWilliam Kucharski 	uint16_t checksum;
3841b8adde7SWilliam Kucharski 
3851b8adde7SWilliam Kucharski 	/* Compute the pseudo header */
3861b8adde7SWilliam Kucharski 	pseudo.src.s_addr  = ip->src.s_addr;
3871b8adde7SWilliam Kucharski 	pseudo.dest.s_addr = ip->dest.s_addr;
3881b8adde7SWilliam Kucharski 	pseudo.unused      = 0;
3891b8adde7SWilliam Kucharski 	pseudo.protocol    = IP_UDP;
3901b8adde7SWilliam Kucharski 	pseudo.len         = udp->len;
3911b8adde7SWilliam Kucharski 
3921b8adde7SWilliam Kucharski 	/* Sum the pseudo header */
3931b8adde7SWilliam Kucharski 	checksum = ipchksum(&pseudo, 12);
3941b8adde7SWilliam Kucharski 
3951b8adde7SWilliam Kucharski 	/* Sum the rest of the udp packet */
3961b8adde7SWilliam Kucharski 	checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
3971b8adde7SWilliam Kucharski 	return checksum;
3981b8adde7SWilliam Kucharski }
3991b8adde7SWilliam Kucharski 
4001b8adde7SWilliam Kucharski 
build_udp_hdr(unsigned long destip,unsigned int srcsock,unsigned int destsock,int ttl,int len,const void * buf)4011b8adde7SWilliam Kucharski void build_udp_hdr(unsigned long destip,
4021b8adde7SWilliam Kucharski 	unsigned int srcsock, unsigned int destsock, int ttl,
4031b8adde7SWilliam Kucharski 	int len, const void *buf)
4041b8adde7SWilliam Kucharski {
4051b8adde7SWilliam Kucharski 	struct iphdr *ip;
4061b8adde7SWilliam Kucharski 	struct udphdr *udp;
4071b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
4081b8adde7SWilliam Kucharski 	build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
4091b8adde7SWilliam Kucharski 	udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
4101b8adde7SWilliam Kucharski 	udp->src = htons(srcsock);
4111b8adde7SWilliam Kucharski 	udp->dest = htons(destsock);
4121b8adde7SWilliam Kucharski 	udp->len = htons(len - sizeof(struct iphdr));
4131b8adde7SWilliam Kucharski 	udp->chksum = 0;
4141b8adde7SWilliam Kucharski 	if ((udp->chksum = udpchksum(ip, udp)) == 0)
4151b8adde7SWilliam Kucharski 		udp->chksum = 0xffff;
4161b8adde7SWilliam Kucharski }
4171b8adde7SWilliam Kucharski 
4181b8adde7SWilliam Kucharski 
4191b8adde7SWilliam Kucharski /**************************************************************************
4201b8adde7SWilliam Kucharski UDP_TRANSMIT - Send an UDP datagram
4211b8adde7SWilliam Kucharski **************************************************************************/
udp_transmit(unsigned long destip,unsigned int srcsock,unsigned int destsock,int len,const void * buf)4221b8adde7SWilliam Kucharski int udp_transmit(unsigned long destip, unsigned int srcsock,
4231b8adde7SWilliam Kucharski 	unsigned int destsock, int len, const void *buf)
4241b8adde7SWilliam Kucharski {
4251b8adde7SWilliam Kucharski 	build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
4261b8adde7SWilliam Kucharski 	return ip_transmit(len, buf);
4271b8adde7SWilliam Kucharski }
4281b8adde7SWilliam Kucharski 
4291b8adde7SWilliam Kucharski /**************************************************************************
4301b8adde7SWilliam Kucharski QDRAIN - clear the nic's receive queue
4311b8adde7SWilliam Kucharski **************************************************************************/
await_qdrain(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp __unused)4321b8adde7SWilliam Kucharski static int await_qdrain(int ival __unused, void *ptr __unused,
4331b8adde7SWilliam Kucharski 	unsigned short ptype __unused,
4341b8adde7SWilliam Kucharski 	struct iphdr *ip __unused, struct udphdr *udp __unused)
4351b8adde7SWilliam Kucharski {
4361b8adde7SWilliam Kucharski 	return 0;
4371b8adde7SWilliam Kucharski }
4381b8adde7SWilliam Kucharski 
rx_qdrain(void)4391b8adde7SWilliam Kucharski void rx_qdrain(void)
4401b8adde7SWilliam Kucharski {
4411b8adde7SWilliam Kucharski 	/* Clear out the Rx queue first.  It contains nothing of interest,
4421b8adde7SWilliam Kucharski 	 * except possibly ARP requests from the DHCP/TFTP server.  We use
4431b8adde7SWilliam Kucharski 	 * polling throughout Etherboot, so some time may have passed since we
4441b8adde7SWilliam Kucharski 	 * last polled the receive queue, which may now be filled with
4451b8adde7SWilliam Kucharski 	 * broadcast packets.  This will cause the reply to the packets we are
4461b8adde7SWilliam Kucharski 	 * about to send to be lost immediately.  Not very clever.  */
4471b8adde7SWilliam Kucharski 	await_reply(await_qdrain, 0, NULL, 0);
4481b8adde7SWilliam Kucharski }
4491b8adde7SWilliam Kucharski 
4501b8adde7SWilliam Kucharski /**
4511b8adde7SWilliam Kucharski  * rarp
4521b8adde7SWilliam Kucharski  *
4531b8adde7SWilliam Kucharski  * Get IP address by rarp. Just copy from etherboot
4541b8adde7SWilliam Kucharski  **/
await_rarp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip,struct udphdr * udp)4551b8adde7SWilliam Kucharski static int await_rarp(int ival, void *ptr, unsigned short ptype,
4561b8adde7SWilliam Kucharski 		      struct iphdr *ip, struct udphdr *udp)
4571b8adde7SWilliam Kucharski {
4581b8adde7SWilliam Kucharski 	struct arprequest *arpreply;
4591b8adde7SWilliam Kucharski 	if (ptype != RARP)
4601b8adde7SWilliam Kucharski 		return 0;
4611b8adde7SWilliam Kucharski 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
4621b8adde7SWilliam Kucharski 		return 0;
4631b8adde7SWilliam Kucharski 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
4641b8adde7SWilliam Kucharski 	if (arpreply->opcode != htons(RARP_REPLY))
4651b8adde7SWilliam Kucharski 		return 0;
4661b8adde7SWilliam Kucharski 	if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
4671b8adde7SWilliam Kucharski 		memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
4681b8adde7SWilliam Kucharski 		memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
4691b8adde7SWilliam Kucharski 		memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
4701b8adde7SWilliam Kucharski 		memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
4711b8adde7SWilliam Kucharski 		return 1;
4721b8adde7SWilliam Kucharski 	}
4731b8adde7SWilliam Kucharski 	return 0;
4741b8adde7SWilliam Kucharski }
4751b8adde7SWilliam Kucharski 
rarp(void)4761b8adde7SWilliam Kucharski int rarp(void)
4771b8adde7SWilliam Kucharski {
4781b8adde7SWilliam Kucharski 	int retry;
4791b8adde7SWilliam Kucharski 
4801b8adde7SWilliam Kucharski 	/* arp and rarp requests share the same packet structure. */
4811b8adde7SWilliam Kucharski 	struct arprequest rarpreq;
4821b8adde7SWilliam Kucharski 
4831b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
4841b8adde7SWilliam Kucharski 		return 0;
4851b8adde7SWilliam Kucharski 	network_ready = 0;
4861b8adde7SWilliam Kucharski 
4871b8adde7SWilliam Kucharski 	memset(&rarpreq, 0, sizeof(rarpreq));
4881b8adde7SWilliam Kucharski 
4891b8adde7SWilliam Kucharski 	rarpreq.hwtype = htons(1);
4901b8adde7SWilliam Kucharski 	rarpreq.protocol = htons(IP);
4911b8adde7SWilliam Kucharski 	rarpreq.hwlen = ETH_ALEN;
4921b8adde7SWilliam Kucharski 	rarpreq.protolen = 4;
4931b8adde7SWilliam Kucharski 	rarpreq.opcode = htons(RARP_REQUEST);
4941b8adde7SWilliam Kucharski 	memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4951b8adde7SWilliam Kucharski 	/* sipaddr is already zeroed out */
4961b8adde7SWilliam Kucharski 	memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4971b8adde7SWilliam Kucharski 	/* tipaddr is already zeroed out */
4981b8adde7SWilliam Kucharski 
4991b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
5001b8adde7SWilliam Kucharski 		long timeout;
5011b8adde7SWilliam Kucharski 		eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
5021b8adde7SWilliam Kucharski 
5031b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry);
5041b8adde7SWilliam Kucharski 		if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
5051b8adde7SWilliam Kucharski 			break;
5061b8adde7SWilliam Kucharski 		if (user_abort)
5071b8adde7SWilliam Kucharski 			return 0;
5081b8adde7SWilliam Kucharski 	}
5091b8adde7SWilliam Kucharski 
5101b8adde7SWilliam Kucharski 	if (retry == MAX_ARP_RETRIES) {
5111b8adde7SWilliam Kucharski 		return (0);
5121b8adde7SWilliam Kucharski 	}
5131b8adde7SWilliam Kucharski 
5141b8adde7SWilliam Kucharski 	network_ready = 1;
5151b8adde7SWilliam Kucharski   	update_network_configuration();
5161b8adde7SWilliam Kucharski 	return (1);
5171b8adde7SWilliam Kucharski }
5181b8adde7SWilliam Kucharski 
5191b8adde7SWilliam Kucharski /**
5201b8adde7SWilliam Kucharski  * bootp
5211b8adde7SWilliam Kucharski  *
5221b8adde7SWilliam Kucharski  * Get IP address by bootp, segregate from bootp in etherboot.
5231b8adde7SWilliam Kucharski  **/
await_bootp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)5241b8adde7SWilliam Kucharski static int await_bootp(int ival __unused, void *ptr __unused,
5251b8adde7SWilliam Kucharski 	unsigned short ptype __unused, struct iphdr *ip __unused,
5261b8adde7SWilliam Kucharski 	struct udphdr *udp)
5271b8adde7SWilliam Kucharski {
5281b8adde7SWilliam Kucharski 	struct	bootp_t *bootpreply;
5291b8adde7SWilliam Kucharski 	int len;		/* Length of vendor */
5301b8adde7SWilliam Kucharski 
5311b8adde7SWilliam Kucharski 	if (!udp) {
5321b8adde7SWilliam Kucharski 		return 0;
5331b8adde7SWilliam Kucharski 	}
5341b8adde7SWilliam Kucharski 	bootpreply = (struct bootp_t *)
5351b8adde7SWilliam Kucharski 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
5361b8adde7SWilliam Kucharski 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
5371b8adde7SWilliam Kucharski 		sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
5381b8adde7SWilliam Kucharski 	if (len < 0) {
5391b8adde7SWilliam Kucharski 		return 0;
5401b8adde7SWilliam Kucharski 	}
5411b8adde7SWilliam Kucharski 	if (udp->dest != htons(BOOTP_CLIENT))
5421b8adde7SWilliam Kucharski 		return 0;
5431b8adde7SWilliam Kucharski 	if (bootpreply->bp_op != BOOTP_REPLY)
5441b8adde7SWilliam Kucharski 		return 0;
5451b8adde7SWilliam Kucharski 	if (bootpreply->bp_xid != xid)
5461b8adde7SWilliam Kucharski 		return 0;
5471b8adde7SWilliam Kucharski 	if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
5481b8adde7SWilliam Kucharski 		return 0;
5491b8adde7SWilliam Kucharski 	if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
5501b8adde7SWilliam Kucharski 	    (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
5511b8adde7SWilliam Kucharski 		return 0;
5521b8adde7SWilliam Kucharski 	}
5531b8adde7SWilliam Kucharski 
5541b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
5551b8adde7SWilliam Kucharski 	/* fill in netinfo */
5561b8adde7SWilliam Kucharski 	dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
5571b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
5581b8adde7SWilliam Kucharski #endif
5591b8adde7SWilliam Kucharski 
5601b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
5611b8adde7SWilliam Kucharski 	netmask = default_netmask();
5621b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
5631b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
5641b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
5651b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
566*2506833eSJan Setje-Eilers 	bootfile = bootpreply->bp_file;
5671b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
5681b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
5691b8adde7SWilliam Kucharski 	return(1);
5701b8adde7SWilliam Kucharski }
5711b8adde7SWilliam Kucharski 
bootp(void)5721b8adde7SWilliam Kucharski int bootp(void)
5731b8adde7SWilliam Kucharski {
5741b8adde7SWilliam Kucharski 	int retry;
5751b8adde7SWilliam Kucharski 	struct bootpip_t ip;
5761b8adde7SWilliam Kucharski 	unsigned long  starttime;
5771b8adde7SWilliam Kucharski 
5781b8adde7SWilliam Kucharski 	EnterFunction("bootp");
5791b8adde7SWilliam Kucharski 
5801b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
5811b8adde7SWilliam Kucharski 		return 0;
5821b8adde7SWilliam Kucharski 	network_ready = 0;
5831b8adde7SWilliam Kucharski 
5841b8adde7SWilliam Kucharski 	memset(&ip, 0, sizeof(struct bootpip_t));
5851b8adde7SWilliam Kucharski 	ip.bp.bp_op = BOOTP_REQUEST;
5861b8adde7SWilliam Kucharski 	ip.bp.bp_htype = 1;
5871b8adde7SWilliam Kucharski 	ip.bp.bp_hlen = ETH_ALEN;
5881b8adde7SWilliam Kucharski 	starttime = currticks();
5891b8adde7SWilliam Kucharski 	/* Use lower 32 bits of node address, more likely to be
5901b8adde7SWilliam Kucharski 	   distinct than the time since booting */
5911b8adde7SWilliam Kucharski 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
5921b8adde7SWilliam Kucharski 	ip.bp.bp_xid = xid += htonl(starttime);
5931b8adde7SWilliam Kucharski 	/* bp_secs defaults to zero */
5941b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
5951b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
5961b8adde7SWilliam Kucharski 
5971b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
5981b8adde7SWilliam Kucharski 		long timeout;
5991b8adde7SWilliam Kucharski 
6001b8adde7SWilliam Kucharski 		rx_qdrain();
6011b8adde7SWilliam Kucharski 
6021b8adde7SWilliam Kucharski 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
6031b8adde7SWilliam Kucharski 			sizeof(struct bootpip_t), &ip);
6041b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
6051b8adde7SWilliam Kucharski 		if (await_reply(await_bootp, 0, NULL, timeout)){
6061b8adde7SWilliam Kucharski 			network_ready = 1;
6071b8adde7SWilliam Kucharski 			return(1);
6081b8adde7SWilliam Kucharski 		}
6091b8adde7SWilliam Kucharski 		if (user_abort)
6101b8adde7SWilliam Kucharski 			return 0;
6111b8adde7SWilliam Kucharski 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
6121b8adde7SWilliam Kucharski 	}
6131b8adde7SWilliam Kucharski 	return(0);
6141b8adde7SWilliam Kucharski }
6151b8adde7SWilliam Kucharski 
6161b8adde7SWilliam Kucharski /**
6171b8adde7SWilliam Kucharski  * dhcp
6181b8adde7SWilliam Kucharski  *
6191b8adde7SWilliam Kucharski  * Get IP address by dhcp, segregate from bootp in etherboot.
6201b8adde7SWilliam Kucharski  **/
await_dhcp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)6211b8adde7SWilliam Kucharski static int await_dhcp(int ival __unused, void *ptr __unused,
6221b8adde7SWilliam Kucharski 	unsigned short ptype __unused, struct iphdr *ip __unused,
6231b8adde7SWilliam Kucharski 	struct udphdr *udp)
6241b8adde7SWilliam Kucharski {
6251b8adde7SWilliam Kucharski 	struct	dhcp_t *dhcpreply;
6261b8adde7SWilliam Kucharski 	int len;
6271b8adde7SWilliam Kucharski 
6281b8adde7SWilliam Kucharski 	if (!udp) {
6291b8adde7SWilliam Kucharski 		return 0;
6301b8adde7SWilliam Kucharski 	}
6311b8adde7SWilliam Kucharski 	dhcpreply = (struct dhcp_t *)
6321b8adde7SWilliam Kucharski 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
6331b8adde7SWilliam Kucharski 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
6341b8adde7SWilliam Kucharski 		sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
6351b8adde7SWilliam Kucharski 	if (len < 0){
6361b8adde7SWilliam Kucharski 		return 0;
6371b8adde7SWilliam Kucharski 	}
6381b8adde7SWilliam Kucharski 	if (udp->dest != htons(BOOTP_CLIENT))
6391b8adde7SWilliam Kucharski 		return 0;
6401b8adde7SWilliam Kucharski 	if (dhcpreply->bp_op != BOOTP_REPLY)
6411b8adde7SWilliam Kucharski 		return 0;
6421b8adde7SWilliam Kucharski 	if (dhcpreply->bp_xid != xid)
6431b8adde7SWilliam Kucharski 		return 0;
6441b8adde7SWilliam Kucharski 	if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
6451b8adde7SWilliam Kucharski 		return 0;
6461b8adde7SWilliam Kucharski 	if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
6471b8adde7SWilliam Kucharski 	    (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
6481b8adde7SWilliam Kucharski 		return 0;
6491b8adde7SWilliam Kucharski 	}
6501b8adde7SWilliam Kucharski 
6511b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
6521b8adde7SWilliam Kucharski 	/* fill in netinfo */
6531b8adde7SWilliam Kucharski 	dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
6541b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
6551b8adde7SWilliam Kucharski #endif
6561b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6571b8adde7SWilliam Kucharski 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6581b8adde7SWilliam Kucharski 	netmask = default_netmask();
6591b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
6601b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
6611b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
6621b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
663*2506833eSJan Setje-Eilers 	bootfile = dhcpreply->bp_file;
6641b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
6651b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
6661b8adde7SWilliam Kucharski 	return(1);
6671b8adde7SWilliam Kucharski }
6681b8adde7SWilliam Kucharski 
dhcp(void)6691b8adde7SWilliam Kucharski int dhcp(void)
6701b8adde7SWilliam Kucharski {
6711b8adde7SWilliam Kucharski 	int retry;
6721b8adde7SWilliam Kucharski 	int reqretry;
6731b8adde7SWilliam Kucharski 	struct dhcpip_t ip;
6741b8adde7SWilliam Kucharski 	unsigned long  starttime;
6751b8adde7SWilliam Kucharski 
6761b8adde7SWilliam Kucharski 	/* try bios pxe stack first */
6771b8adde7SWilliam Kucharski 	if (dhcp_undi())
6781b8adde7SWilliam Kucharski 		return 1;
6791b8adde7SWilliam Kucharski 
6801b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
6811b8adde7SWilliam Kucharski 		return 0;
6821b8adde7SWilliam Kucharski 
6831b8adde7SWilliam Kucharski 	network_ready = 0;
6841b8adde7SWilliam Kucharski 
6851b8adde7SWilliam Kucharski 	memset(&ip, 0, sizeof(ip));
6861b8adde7SWilliam Kucharski 	ip.bp.bp_op = BOOTP_REQUEST;
6871b8adde7SWilliam Kucharski 	ip.bp.bp_htype = 1;
6881b8adde7SWilliam Kucharski 	ip.bp.bp_hlen = ETH_ALEN;
6891b8adde7SWilliam Kucharski 	starttime = currticks();
6901b8adde7SWilliam Kucharski 	/* Use lower 32 bits of node address, more likely to be
6911b8adde7SWilliam Kucharski 	   distinct than the time since booting */
6921b8adde7SWilliam Kucharski 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
6931b8adde7SWilliam Kucharski 	ip.bp.bp_xid = xid += htonl(starttime);
6941b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
6951b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
6961b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
6971b8adde7SWilliam Kucharski 
6981b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
6991b8adde7SWilliam Kucharski 		long timeout;
7001b8adde7SWilliam Kucharski 
7011b8adde7SWilliam Kucharski 		rx_qdrain();
7021b8adde7SWilliam Kucharski 
7031b8adde7SWilliam Kucharski 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7041b8adde7SWilliam Kucharski 			     sizeof(ip), &ip);
7051b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
7061b8adde7SWilliam Kucharski 		if (await_reply(await_dhcp, 0, NULL, timeout)) {
7071b8adde7SWilliam Kucharski 			/* If not a DHCPOFFER then must be just a
7081b8adde7SWilliam Kucharski 			   BOOTP reply, be backward compatible with
7091b8adde7SWilliam Kucharski 			   BOOTP then. Jscott report a bug here, but I
7101b8adde7SWilliam Kucharski 			   don't know how it happened */
7111b8adde7SWilliam Kucharski 			if (dhcp_reply != DHCPOFFER){
7121b8adde7SWilliam Kucharski 				network_ready = 1;
7131b8adde7SWilliam Kucharski 				return(1);
7141b8adde7SWilliam Kucharski 			}
7151b8adde7SWilliam Kucharski 			dhcp_reply = 0;
7161b8adde7SWilliam Kucharski 			memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
7171b8adde7SWilliam Kucharski 			memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
7181b8adde7SWilliam Kucharski 			/* Beware: the magic numbers 9 and 15 depend on
7191b8adde7SWilliam Kucharski 			   the layout of dhcprequest */
7201b8adde7SWilliam Kucharski 			memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
7211b8adde7SWilliam Kucharski 			memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
7221b8adde7SWilliam Kucharski 			for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
7231b8adde7SWilliam Kucharski 				udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7241b8adde7SWilliam Kucharski 					     sizeof(ip), &ip);
7251b8adde7SWilliam Kucharski 				dhcp_reply=0;
7261b8adde7SWilliam Kucharski 				timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
7271b8adde7SWilliam Kucharski 				if (await_reply(await_dhcp, 0, NULL, timeout))
7281b8adde7SWilliam Kucharski 					if (dhcp_reply == DHCPACK){
7291b8adde7SWilliam Kucharski 						network_ready = 1;
7301b8adde7SWilliam Kucharski 						return(1);
7311b8adde7SWilliam Kucharski 					}
7321b8adde7SWilliam Kucharski 				if (user_abort)
7331b8adde7SWilliam Kucharski 					return 0;
7341b8adde7SWilliam Kucharski 			}
7351b8adde7SWilliam Kucharski 		}
7361b8adde7SWilliam Kucharski 		if (user_abort)
7371b8adde7SWilliam Kucharski 			return 0;
7381b8adde7SWilliam Kucharski 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
7391b8adde7SWilliam Kucharski 	}
7401b8adde7SWilliam Kucharski 	return(0);
7411b8adde7SWilliam Kucharski }
7421b8adde7SWilliam Kucharski 
7431b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
send_igmp_reports(unsigned long now)7441b8adde7SWilliam Kucharski static void send_igmp_reports(unsigned long now)
7451b8adde7SWilliam Kucharski {
7461b8adde7SWilliam Kucharski 	int i;
7471b8adde7SWilliam Kucharski 	for(i = 0; i < MAX_IGMP; i++) {
7481b8adde7SWilliam Kucharski 		if (igmptable[i].time && (now >= igmptable[i].time)) {
7491b8adde7SWilliam Kucharski 			struct igmp_ip_t igmp;
7501b8adde7SWilliam Kucharski 			igmp.router_alert[0] = 0x94;
7511b8adde7SWilliam Kucharski 			igmp.router_alert[1] = 0x04;
7521b8adde7SWilliam Kucharski 			igmp.router_alert[2] = 0;
7531b8adde7SWilliam Kucharski 			igmp.router_alert[3] = 0;
7541b8adde7SWilliam Kucharski 			build_ip_hdr(igmptable[i].group.s_addr,
7551b8adde7SWilliam Kucharski 				1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
7561b8adde7SWilliam Kucharski 			igmp.igmp.type = IGMPv2_REPORT;
7571b8adde7SWilliam Kucharski 			if (last_igmpv1 &&
7581b8adde7SWilliam Kucharski 				(now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
7591b8adde7SWilliam Kucharski 				igmp.igmp.type = IGMPv1_REPORT;
7601b8adde7SWilliam Kucharski 			}
7611b8adde7SWilliam Kucharski 			igmp.igmp.response_time = 0;
7621b8adde7SWilliam Kucharski 			igmp.igmp.chksum = 0;
7631b8adde7SWilliam Kucharski 			igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
7641b8adde7SWilliam Kucharski 			igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
7651b8adde7SWilliam Kucharski 			ip_transmit(sizeof(igmp), &igmp);
7661b8adde7SWilliam Kucharski #ifdef	MDEBUG
7671b8adde7SWilliam Kucharski 			printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
7681b8adde7SWilliam Kucharski #endif
7691b8adde7SWilliam Kucharski 			/* Don't send another igmp report until asked */
7701b8adde7SWilliam Kucharski 			igmptable[i].time = 0;
7711b8adde7SWilliam Kucharski 		}
7721b8adde7SWilliam Kucharski 	}
7731b8adde7SWilliam Kucharski }
7741b8adde7SWilliam Kucharski 
process_igmp(struct iphdr * ip,unsigned long now)7751b8adde7SWilliam Kucharski static void process_igmp(struct iphdr *ip, unsigned long now)
7761b8adde7SWilliam Kucharski {
7771b8adde7SWilliam Kucharski 	struct igmp *igmp;
7781b8adde7SWilliam Kucharski 	int i;
7791b8adde7SWilliam Kucharski 	unsigned iplen = 0;
7801b8adde7SWilliam Kucharski 	if (!ip || (ip->protocol == IP_IGMP) ||
7811b8adde7SWilliam Kucharski 		(nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
7821b8adde7SWilliam Kucharski 		return;
7831b8adde7SWilliam Kucharski 	}
7841b8adde7SWilliam Kucharski 	iplen = (ip->verhdrlen & 0xf)*4;
7851b8adde7SWilliam Kucharski 	igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
7861b8adde7SWilliam Kucharski 	if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
7871b8adde7SWilliam Kucharski 		return;
7881b8adde7SWilliam Kucharski 	if ((igmp->type == IGMP_QUERY) &&
7891b8adde7SWilliam Kucharski 		(ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
7901b8adde7SWilliam Kucharski 		unsigned long interval = IGMP_INTERVAL;
7911b8adde7SWilliam Kucharski 		if (igmp->response_time == 0) {
7921b8adde7SWilliam Kucharski 			last_igmpv1 = now;
7931b8adde7SWilliam Kucharski 		} else {
7941b8adde7SWilliam Kucharski 			interval = (igmp->response_time * TICKS_PER_SEC)/10;
7951b8adde7SWilliam Kucharski 		}
7961b8adde7SWilliam Kucharski 
7971b8adde7SWilliam Kucharski #ifdef	MDEBUG
7981b8adde7SWilliam Kucharski 		printf("Received IGMP query for: %@\n", igmp->group.s_addr);
7991b8adde7SWilliam Kucharski #endif
8001b8adde7SWilliam Kucharski 		for(i = 0; i < MAX_IGMP; i++) {
8011b8adde7SWilliam Kucharski 			uint32_t group = igmptable[i].group.s_addr;
8021b8adde7SWilliam Kucharski 			if ((group == 0) || (group == igmp->group.s_addr)) {
8031b8adde7SWilliam Kucharski 				unsigned long time;
8041b8adde7SWilliam Kucharski 				time = currticks() + rfc1112_sleep_interval(interval, 0);
8051b8adde7SWilliam Kucharski 				if (time < igmptable[i].time) {
8061b8adde7SWilliam Kucharski 					igmptable[i].time = time;
8071b8adde7SWilliam Kucharski 				}
8081b8adde7SWilliam Kucharski 			}
8091b8adde7SWilliam Kucharski 		}
8101b8adde7SWilliam Kucharski 	}
8111b8adde7SWilliam Kucharski 	if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
8121b8adde7SWilliam Kucharski 		(ip->dest.s_addr == igmp->group.s_addr)) {
8131b8adde7SWilliam Kucharski #ifdef	MDEBUG
8141b8adde7SWilliam Kucharski 		printf("Received IGMP report for: %@\n", igmp->group.s_addr);
8151b8adde7SWilliam Kucharski #endif
8161b8adde7SWilliam Kucharski 		for(i = 0; i < MAX_IGMP; i++) {
8171b8adde7SWilliam Kucharski 			if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
8181b8adde7SWilliam Kucharski 				igmptable[i].time != 0) {
8191b8adde7SWilliam Kucharski 				igmptable[i].time = 0;
8201b8adde7SWilliam Kucharski 			}
8211b8adde7SWilliam Kucharski 		}
8221b8adde7SWilliam Kucharski 	}
8231b8adde7SWilliam Kucharski }
8241b8adde7SWilliam Kucharski 
leave_group(int slot)8251b8adde7SWilliam Kucharski void leave_group(int slot)
8261b8adde7SWilliam Kucharski {
8271b8adde7SWilliam Kucharski 	/* Be very stupid and always send a leave group message if
8281b8adde7SWilliam Kucharski 	 * I have subscribed.  Imperfect but it is standards
8291b8adde7SWilliam Kucharski 	 * compliant, easy and reliable to implement.
8301b8adde7SWilliam Kucharski 	 *
8311b8adde7SWilliam Kucharski 	 * The optimal group leave method is to only send leave when,
8321b8adde7SWilliam Kucharski 	 * we were the last host to respond to a query on this group,
8331b8adde7SWilliam Kucharski 	 * and igmpv1 compatibility is not enabled.
8341b8adde7SWilliam Kucharski 	 */
8351b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr) {
8361b8adde7SWilliam Kucharski 		struct igmp_ip_t igmp;
8371b8adde7SWilliam Kucharski 		igmp.router_alert[0] = 0x94;
8381b8adde7SWilliam Kucharski 		igmp.router_alert[1] = 0x04;
8391b8adde7SWilliam Kucharski 		igmp.router_alert[2] = 0;
8401b8adde7SWilliam Kucharski 		igmp.router_alert[3] = 0;
8411b8adde7SWilliam Kucharski 		build_ip_hdr(htonl(GROUP_ALL_HOSTS),
8421b8adde7SWilliam Kucharski 			1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
8431b8adde7SWilliam Kucharski 		igmp.igmp.type = IGMP_LEAVE;
8441b8adde7SWilliam Kucharski 		igmp.igmp.response_time = 0;
8451b8adde7SWilliam Kucharski 		igmp.igmp.chksum = 0;
8461b8adde7SWilliam Kucharski 		igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
8471b8adde7SWilliam Kucharski 		igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
8481b8adde7SWilliam Kucharski 		ip_transmit(sizeof(igmp), &igmp);
8491b8adde7SWilliam Kucharski #ifdef	MDEBUG
8501b8adde7SWilliam Kucharski 		printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
8511b8adde7SWilliam Kucharski #endif
8521b8adde7SWilliam Kucharski 	}
8531b8adde7SWilliam Kucharski 	memset(&igmptable[slot], 0, sizeof(igmptable[0]));
8541b8adde7SWilliam Kucharski }
8551b8adde7SWilliam Kucharski 
join_group(int slot,unsigned long group)8561b8adde7SWilliam Kucharski void join_group(int slot, unsigned long group)
8571b8adde7SWilliam Kucharski {
8581b8adde7SWilliam Kucharski 	/* I have already joined */
8591b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr == group)
8601b8adde7SWilliam Kucharski 		return;
8611b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr) {
8621b8adde7SWilliam Kucharski 		leave_group(slot);
8631b8adde7SWilliam Kucharski 	}
8641b8adde7SWilliam Kucharski 	/* Only join a group if we are given a multicast ip, this way
8651b8adde7SWilliam Kucharski 	 * code can be given a non-multicast (broadcast or unicast ip)
8661b8adde7SWilliam Kucharski 	 * and still work...
8671b8adde7SWilliam Kucharski 	 */
8681b8adde7SWilliam Kucharski 	if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
8691b8adde7SWilliam Kucharski 		igmptable[slot].group.s_addr = group;
8701b8adde7SWilliam Kucharski 		igmptable[slot].time = currticks();
8711b8adde7SWilliam Kucharski 	}
8721b8adde7SWilliam Kucharski }
8731b8adde7SWilliam Kucharski #else
8741b8adde7SWilliam Kucharski #define send_igmp_reports(now);
8751b8adde7SWilliam Kucharski #define process_igmp(ip, now)
8761b8adde7SWilliam Kucharski #endif
8771b8adde7SWilliam Kucharski 
8781b8adde7SWilliam Kucharski /**************************************************************************
8791b8adde7SWilliam Kucharski AWAIT_REPLY - Wait until we get a response for our request
8801b8adde7SWilliam Kucharski ************f**************************************************************/
await_reply(reply_t reply,int ival,void * ptr,long timeout)8811b8adde7SWilliam Kucharski int await_reply(reply_t reply, int ival, void *ptr, long timeout)
8821b8adde7SWilliam Kucharski {
8831b8adde7SWilliam Kucharski 	unsigned long time, now;
8841b8adde7SWilliam Kucharski 	struct	iphdr *ip;
8851b8adde7SWilliam Kucharski 	unsigned iplen = 0;
8861b8adde7SWilliam Kucharski 	struct	udphdr *udp;
8871b8adde7SWilliam Kucharski 	unsigned short ptype;
8881b8adde7SWilliam Kucharski 	int result;
8891b8adde7SWilliam Kucharski 
8901b8adde7SWilliam Kucharski 	user_abort = 0;
8911b8adde7SWilliam Kucharski 
8921b8adde7SWilliam Kucharski 	time = timeout + currticks();
8931b8adde7SWilliam Kucharski 	/* The timeout check is done below.  The timeout is only checked if
8941b8adde7SWilliam Kucharski 	 * there is no packet in the Rx queue.  This assumes that eth_poll()
8951b8adde7SWilliam Kucharski 	 * needs a negligible amount of time.
8961b8adde7SWilliam Kucharski 	 */
8971b8adde7SWilliam Kucharski 	for (;;) {
8981b8adde7SWilliam Kucharski 		now = currticks();
8991b8adde7SWilliam Kucharski 		send_igmp_reports(now);
9001b8adde7SWilliam Kucharski 		result = eth_poll(1);
9011b8adde7SWilliam Kucharski 		if (result == 0) {
9021b8adde7SWilliam Kucharski 			/* We don't have anything */
9031b8adde7SWilliam Kucharski 
9041b8adde7SWilliam Kucharski 			/* Check for abort key only if the Rx queue is empty -
9051b8adde7SWilliam Kucharski 			 * as long as we have something to process, don't
9061b8adde7SWilliam Kucharski 			 * assume that something failed.  It is unlikely that
9071b8adde7SWilliam Kucharski 			 * we have no processing time left between packets.  */
9081b8adde7SWilliam Kucharski 			poll_interruptions();
9091b8adde7SWilliam Kucharski 			/* Do the timeout after at least a full queue walk.  */
9101b8adde7SWilliam Kucharski 			if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
9111b8adde7SWilliam Kucharski 				break;
9121b8adde7SWilliam Kucharski 			}
9131b8adde7SWilliam Kucharski 			continue;
9141b8adde7SWilliam Kucharski 		}
9151b8adde7SWilliam Kucharski 
9161b8adde7SWilliam Kucharski 		/* We have something! */
9171b8adde7SWilliam Kucharski 
9181b8adde7SWilliam Kucharski 		/* Find the Ethernet packet type */
9191b8adde7SWilliam Kucharski 		if (nic.packetlen >= ETH_HLEN) {
9201b8adde7SWilliam Kucharski 			ptype = ((unsigned short) nic.packet[12]) << 8
9211b8adde7SWilliam Kucharski 				| ((unsigned short) nic.packet[13]);
9221b8adde7SWilliam Kucharski 		} else continue; /* what else could we do with it? */
9231b8adde7SWilliam Kucharski 		/* Verify an IP header */
9241b8adde7SWilliam Kucharski 		ip = 0;
9251b8adde7SWilliam Kucharski 		if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
9261b8adde7SWilliam Kucharski 			unsigned ipoptlen;
9271b8adde7SWilliam Kucharski 			ip = (struct iphdr *)&nic.packet[ETH_HLEN];
9281b8adde7SWilliam Kucharski 			if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
9291b8adde7SWilliam Kucharski 				continue;
9301b8adde7SWilliam Kucharski 			iplen = (ip->verhdrlen & 0xf) * 4;
9311b8adde7SWilliam Kucharski 			if (ipchksum(ip, iplen) != 0)
9321b8adde7SWilliam Kucharski 				continue;
9331b8adde7SWilliam Kucharski 			if (ip->frags & htons(0x3FFF)) {
9341b8adde7SWilliam Kucharski 				static int warned_fragmentation = 0;
9351b8adde7SWilliam Kucharski 				if (!warned_fragmentation) {
9361b8adde7SWilliam Kucharski 					printf("ALERT: got a fragmented packet - reconfigure your server\n");
9371b8adde7SWilliam Kucharski 					warned_fragmentation = 1;
9381b8adde7SWilliam Kucharski 				}
9391b8adde7SWilliam Kucharski 				continue;
9401b8adde7SWilliam Kucharski 			}
9411b8adde7SWilliam Kucharski 			if (ntohs(ip->len) > ETH_MAX_MTU)
9421b8adde7SWilliam Kucharski 				continue;
9431b8adde7SWilliam Kucharski 
9441b8adde7SWilliam Kucharski 			ipoptlen = iplen - sizeof(struct iphdr);
9451b8adde7SWilliam Kucharski 			if (ipoptlen) {
9461b8adde7SWilliam Kucharski 				/* Delete the ip options, to guarantee
9471b8adde7SWilliam Kucharski 				 * good alignment, and make etherboot simpler.
9481b8adde7SWilliam Kucharski 				 */
9491b8adde7SWilliam Kucharski 				memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
9501b8adde7SWilliam Kucharski 					&nic.packet[ETH_HLEN + iplen],
9511b8adde7SWilliam Kucharski 					nic.packetlen - ipoptlen);
9521b8adde7SWilliam Kucharski 				nic.packetlen -= ipoptlen;
9531b8adde7SWilliam Kucharski 			}
9541b8adde7SWilliam Kucharski 		}
9551b8adde7SWilliam Kucharski 		udp = 0;
9561b8adde7SWilliam Kucharski 		if (ip && (ip->protocol == IP_UDP) &&
9571b8adde7SWilliam Kucharski 		    (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
9581b8adde7SWilliam Kucharski 			udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
9591b8adde7SWilliam Kucharski 
9601b8adde7SWilliam Kucharski 			/* Make certain we have a reasonable packet length */
9611b8adde7SWilliam Kucharski 			if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
9621b8adde7SWilliam Kucharski 				continue;
9631b8adde7SWilliam Kucharski 
9641b8adde7SWilliam Kucharski 			if (udp->chksum && udpchksum(ip, udp)) {
9651b8adde7SWilliam Kucharski 				printf("UDP checksum error\n");
9661b8adde7SWilliam Kucharski 				continue;
9671b8adde7SWilliam Kucharski 			}
9681b8adde7SWilliam Kucharski 		}
9691b8adde7SWilliam Kucharski 		result = reply(ival, ptr, ptype, ip, udp);
9701b8adde7SWilliam Kucharski 		if (result > 0) {
9711b8adde7SWilliam Kucharski 			return result;
9721b8adde7SWilliam Kucharski 		}
9731b8adde7SWilliam Kucharski 
9741b8adde7SWilliam Kucharski 		/* If it isn't a packet the upper layer wants see if there is a default
9751b8adde7SWilliam Kucharski 		 * action.  This allows us reply to arp and igmp queryies.
9761b8adde7SWilliam Kucharski 		 */
9771b8adde7SWilliam Kucharski 		if ((ptype == ARP) &&
9781b8adde7SWilliam Kucharski 		    (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
9791b8adde7SWilliam Kucharski 			struct	arprequest *arpreply;
9801b8adde7SWilliam Kucharski 			unsigned long tmp;
9811b8adde7SWilliam Kucharski 
9821b8adde7SWilliam Kucharski 			arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
9831b8adde7SWilliam Kucharski 			memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9841b8adde7SWilliam Kucharski 			if ((arpreply->opcode == htons(ARP_REQUEST)) &&
9851b8adde7SWilliam Kucharski 			    (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
9861b8adde7SWilliam Kucharski 				arpreply->opcode = htons(ARP_REPLY);
9871b8adde7SWilliam Kucharski 				memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
9881b8adde7SWilliam Kucharski 				memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
9891b8adde7SWilliam Kucharski 				memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
9901b8adde7SWilliam Kucharski 				memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
9911b8adde7SWilliam Kucharski 				eth_transmit(arpreply->thwaddr, ARP,
9921b8adde7SWilliam Kucharski 					     sizeof(struct  arprequest),
9931b8adde7SWilliam Kucharski 					     arpreply);
9941b8adde7SWilliam Kucharski #ifdef	MDEBUG
9951b8adde7SWilliam Kucharski 				memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9961b8adde7SWilliam Kucharski 				printf("Sent ARP reply to: %@\n",tmp);
9971b8adde7SWilliam Kucharski #endif	/* MDEBUG */
9981b8adde7SWilliam Kucharski 			}
9991b8adde7SWilliam Kucharski 		}
10001b8adde7SWilliam Kucharski 		process_igmp(ip, now);
10011b8adde7SWilliam Kucharski 	}
10021b8adde7SWilliam Kucharski 	return(0);
10031b8adde7SWilliam Kucharski }
10041b8adde7SWilliam Kucharski 
10051b8adde7SWilliam Kucharski #ifdef	REQUIRE_VCI_ETHERBOOT
10061b8adde7SWilliam Kucharski /**************************************************************************
10071b8adde7SWilliam Kucharski FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
10081b8adde7SWilliam Kucharski On entry p points to byte count of VCI options
10091b8adde7SWilliam Kucharski **************************************************************************/
find_vci_etherboot(unsigned char * p)10101b8adde7SWilliam Kucharski static int find_vci_etherboot(unsigned char *p)
10111b8adde7SWilliam Kucharski {
10121b8adde7SWilliam Kucharski 	unsigned char	*end = p + 1 + *p;
10131b8adde7SWilliam Kucharski 
10141b8adde7SWilliam Kucharski 	for (p++; p < end; ) {
10151b8adde7SWilliam Kucharski 		if (*p == RFC2132_VENDOR_CLASS_ID) {
10161b8adde7SWilliam Kucharski 			if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
10171b8adde7SWilliam Kucharski 				return (1);
10181b8adde7SWilliam Kucharski 		} else if (*p == RFC1533_END)
10191b8adde7SWilliam Kucharski 			return (0);
10201b8adde7SWilliam Kucharski 		p += TAG_LEN(p) + 2;
10211b8adde7SWilliam Kucharski 	}
10221b8adde7SWilliam Kucharski 	return (0);
10231b8adde7SWilliam Kucharski }
10241b8adde7SWilliam Kucharski #endif	/* REQUIRE_VCI_ETHERBOOT */
10251b8adde7SWilliam Kucharski 
10261b8adde7SWilliam Kucharski /**
10271b8adde7SWilliam Kucharski  * decode_rfc1533
10281b8adde7SWilliam Kucharski  *
10291b8adde7SWilliam Kucharski  * Decodes RFC1533 header
10301b8adde7SWilliam Kucharski  **/
decode_rfc1533(unsigned char * p,unsigned int block,unsigned int len,int eof)10311b8adde7SWilliam Kucharski int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
10321b8adde7SWilliam Kucharski {
10331b8adde7SWilliam Kucharski 	static unsigned char *extdata = NULL, *extend = NULL;
10341b8adde7SWilliam Kucharski 	unsigned char        *extpath = NULL;
10351b8adde7SWilliam Kucharski 	unsigned char        *endp;
10361b8adde7SWilliam Kucharski 
10371b8adde7SWilliam Kucharski 	if (block == 0) {
10381b8adde7SWilliam Kucharski 		end_of_rfc1533 = NULL;
10391b8adde7SWilliam Kucharski 		if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10401b8adde7SWilliam Kucharski 			return(0); /* no RFC 1533 header found */
10411b8adde7SWilliam Kucharski 		p += 4;
10421b8adde7SWilliam Kucharski 		endp = p + len;
10431b8adde7SWilliam Kucharski 	} else {
10441b8adde7SWilliam Kucharski 		if (block == 1) {
10451b8adde7SWilliam Kucharski 			if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10461b8adde7SWilliam Kucharski 				return(0); /* no RFC 1533 header found */
10471b8adde7SWilliam Kucharski 			p += 4;
10481b8adde7SWilliam Kucharski 			len -= 4; }
10491b8adde7SWilliam Kucharski 		if (extend + len <= (unsigned char *)
10501b8adde7SWilliam Kucharski 		    rfc1533_venddata + sizeof(rfc1533_venddata)) {
10511b8adde7SWilliam Kucharski 			memcpy(extend, p, len);
10521b8adde7SWilliam Kucharski 			extend += len;
10531b8adde7SWilliam Kucharski 		} else {
10541b8adde7SWilliam Kucharski 			printf("Overflow in vendor data buffer! Aborting...\n");
10551b8adde7SWilliam Kucharski 			*extdata = RFC1533_END;
10561b8adde7SWilliam Kucharski 			return(0);
10571b8adde7SWilliam Kucharski 		}
10581b8adde7SWilliam Kucharski 		p = extdata; endp = extend;
10591b8adde7SWilliam Kucharski 	}
10601b8adde7SWilliam Kucharski 	if (!eof)
10611b8adde7SWilliam Kucharski 		return 1;
10621b8adde7SWilliam Kucharski 	while (p < endp) {
10631b8adde7SWilliam Kucharski 		unsigned char c = *p;
10641b8adde7SWilliam Kucharski 		if (c == RFC1533_PAD) {
10651b8adde7SWilliam Kucharski 			p++;
10661b8adde7SWilliam Kucharski 			continue;
10671b8adde7SWilliam Kucharski 		}
10681b8adde7SWilliam Kucharski 		else if (c == RFC1533_END) {
10691b8adde7SWilliam Kucharski 			end_of_rfc1533 = endp = p;
10701b8adde7SWilliam Kucharski 			continue;
10711b8adde7SWilliam Kucharski 		}
10721b8adde7SWilliam Kucharski 		else if (c == RFC1533_NETMASK)
10731b8adde7SWilliam Kucharski 			memcpy(&netmask, p+2, sizeof(in_addr));
10741b8adde7SWilliam Kucharski 		else if (c == RFC1533_GATEWAY) {
10751b8adde7SWilliam Kucharski 			/* This is a little simplistic, but it will
10761b8adde7SWilliam Kucharski 			   usually be sufficient.
10771b8adde7SWilliam Kucharski 			   Take only the first entry */
10781b8adde7SWilliam Kucharski 			if (TAG_LEN(p) >= sizeof(in_addr))
10791b8adde7SWilliam Kucharski 				memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
10801b8adde7SWilliam Kucharski 		}
10811b8adde7SWilliam Kucharski 		else if (c == RFC1533_EXTENSIONPATH)
10821b8adde7SWilliam Kucharski 			extpath = p;
10831b8adde7SWilliam Kucharski 		else if (c == RFC2132_MSG_TYPE)
10841b8adde7SWilliam Kucharski 			dhcp_reply=*(p+2);
10851b8adde7SWilliam Kucharski 		else if (c == RFC2132_SRV_ID)
10861b8adde7SWilliam Kucharski 			memcpy(&dhcp_server, p+2, sizeof(in_addr));
10871b8adde7SWilliam Kucharski 		else if (c == RFC1533_HOSTNAME) {
10881b8adde7SWilliam Kucharski 			hostname = p + 2;
10891b8adde7SWilliam Kucharski 			hostnamelen = *(p + 1);
10901b8adde7SWilliam Kucharski 		}
10911b8adde7SWilliam Kucharski 		else if (c == RFC1533_VENDOR_CONFIGFILE){
10921b8adde7SWilliam Kucharski 			int l = TAG_LEN (p);
10931b8adde7SWilliam Kucharski 
10941b8adde7SWilliam Kucharski 			/* Eliminate the trailing NULs according to RFC 2132.  */
10951b8adde7SWilliam Kucharski 			while (*(p + 2 + l - 1) == '\000' && l > 0)
10961b8adde7SWilliam Kucharski 				l--;
10971b8adde7SWilliam Kucharski 
10981b8adde7SWilliam Kucharski 			/* XXX: Should check if LEN is less than the maximum length
10991b8adde7SWilliam Kucharski 			   of CONFIG_FILE. This kind of robustness will be a goal
11001b8adde7SWilliam Kucharski 			   in GRUB 1.0.  */
11011b8adde7SWilliam Kucharski 			memcpy (config_file, p + 2, l);
11021b8adde7SWilliam Kucharski 			config_file[l] = 0;
1103*2506833eSJan Setje-Eilers 			vendor_configfile = p + 2;
1104*2506833eSJan Setje-Eilers 			vendor_configfile_len = l;
1105*2506833eSJan Setje-Eilers 			configfile_origin = CFG_150;
11061b8adde7SWilliam Kucharski 		}
11071b8adde7SWilliam Kucharski 		else {
11081b8adde7SWilliam Kucharski 			;
11091b8adde7SWilliam Kucharski 		}
11101b8adde7SWilliam Kucharski 		p += TAG_LEN(p) + 2;
11111b8adde7SWilliam Kucharski 	}
11121b8adde7SWilliam Kucharski 	extdata = extend = endp;
11131b8adde7SWilliam Kucharski 	if (block <= 0 && extpath != NULL) {
11141b8adde7SWilliam Kucharski 		char fname[64];
11151b8adde7SWilliam Kucharski 		if (TAG_LEN(extpath) >= sizeof(fname)){
11161b8adde7SWilliam Kucharski 			printf("Overflow in vendor data buffer! Aborting...\n");
11171b8adde7SWilliam Kucharski 			*extdata = RFC1533_END;
11181b8adde7SWilliam Kucharski 			return(0);
11191b8adde7SWilliam Kucharski 		}
11201b8adde7SWilliam Kucharski 		memcpy(fname, extpath+2, TAG_LEN(extpath));
11211b8adde7SWilliam Kucharski 		fname[(int)TAG_LEN(extpath)] = '\0';
11221b8adde7SWilliam Kucharski 		printf("Loading BOOTP-extension file: %s\n",fname);
11231b8adde7SWilliam Kucharski 		tftp_file_read(fname, decode_rfc1533);
11241b8adde7SWilliam Kucharski 	}
11251b8adde7SWilliam Kucharski 	return 1;	/* proceed with next block */
11261b8adde7SWilliam Kucharski }
11271b8adde7SWilliam Kucharski 
11281b8adde7SWilliam Kucharski 
11291b8adde7SWilliam Kucharski /* FIXME double check TWO_SECOND_DIVISOR */
11301b8adde7SWilliam Kucharski #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
11311b8adde7SWilliam Kucharski /**************************************************************************
11321b8adde7SWilliam Kucharski RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
11331b8adde7SWilliam Kucharski **************************************************************************/
rfc2131_sleep_interval(long base,int exp)11341b8adde7SWilliam Kucharski long rfc2131_sleep_interval(long base, int exp)
11351b8adde7SWilliam Kucharski {
11361b8adde7SWilliam Kucharski 	unsigned long tmo;
11371b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
11381b8adde7SWilliam Kucharski 	if (exp > BACKOFF_LIMIT)
11391b8adde7SWilliam Kucharski 		exp = BACKOFF_LIMIT;
11401b8adde7SWilliam Kucharski #endif
11411b8adde7SWilliam Kucharski 	tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
11421b8adde7SWilliam Kucharski 	return tmo;
11431b8adde7SWilliam Kucharski }
11441b8adde7SWilliam Kucharski 
11451b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
11461b8adde7SWilliam Kucharski /**************************************************************************
11471b8adde7SWilliam Kucharski RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
11481b8adde7SWilliam Kucharski **************************************************************************/
rfc1112_sleep_interval(long base,int exp)11491b8adde7SWilliam Kucharski long rfc1112_sleep_interval(long base, int exp)
11501b8adde7SWilliam Kucharski {
11511b8adde7SWilliam Kucharski 	unsigned long divisor, tmo;
11521b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
11531b8adde7SWilliam Kucharski 	if (exp > BACKOFF_LIMIT)
11541b8adde7SWilliam Kucharski 		exp = BACKOFF_LIMIT;
11551b8adde7SWilliam Kucharski #endif
11561b8adde7SWilliam Kucharski 	divisor = RAND_MAX/(base << exp);
11571b8adde7SWilliam Kucharski 	tmo = random()/divisor;
11581b8adde7SWilliam Kucharski 	return tmo;
11591b8adde7SWilliam Kucharski }
11601b8adde7SWilliam Kucharski #endif /* MULTICAST_LEVEL_2 */
11611b8adde7SWilliam Kucharski /* ifconfig - configure network interface.  */
11621b8adde7SWilliam Kucharski int
ifconfig(char * ip,char * sm,char * gw,char * svr)11631b8adde7SWilliam Kucharski ifconfig (char *ip, char *sm, char *gw, char *svr)
11641b8adde7SWilliam Kucharski {
11651b8adde7SWilliam Kucharski   in_addr tmp;
11661b8adde7SWilliam Kucharski 
11671b8adde7SWilliam Kucharski   if (sm)
11681b8adde7SWilliam Kucharski     {
11691b8adde7SWilliam Kucharski       if (! inet_aton (sm, &tmp))
11701b8adde7SWilliam Kucharski 	return 0;
11711b8adde7SWilliam Kucharski 
11721b8adde7SWilliam Kucharski       netmask = tmp.s_addr;
11731b8adde7SWilliam Kucharski     }
11741b8adde7SWilliam Kucharski 
11751b8adde7SWilliam Kucharski   if (ip)
11761b8adde7SWilliam Kucharski     {
11771b8adde7SWilliam Kucharski       if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
11781b8adde7SWilliam Kucharski 	return 0;
11791b8adde7SWilliam Kucharski 
11801b8adde7SWilliam Kucharski       if (! netmask && ! sm)
11811b8adde7SWilliam Kucharski 	netmask = default_netmask ();
11821b8adde7SWilliam Kucharski     }
11831b8adde7SWilliam Kucharski 
11841b8adde7SWilliam Kucharski   if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
11851b8adde7SWilliam Kucharski     return 0;
11861b8adde7SWilliam Kucharski 
11871b8adde7SWilliam Kucharski   /* Clear out the ARP entry.  */
11881b8adde7SWilliam Kucharski   grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
11891b8adde7SWilliam Kucharski 
11901b8adde7SWilliam Kucharski   if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
11911b8adde7SWilliam Kucharski     return 0;
11921b8adde7SWilliam Kucharski 
11931b8adde7SWilliam Kucharski   /* Likewise.  */
11941b8adde7SWilliam Kucharski   grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
11951b8adde7SWilliam Kucharski 
11961b8adde7SWilliam Kucharski   if (ip || sm)
11971b8adde7SWilliam Kucharski     {
11981b8adde7SWilliam Kucharski       if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
11991b8adde7SWilliam Kucharski 	  || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
12001b8adde7SWilliam Kucharski 	  || ! netmask)
12011b8adde7SWilliam Kucharski 	network_ready = 0;
12021b8adde7SWilliam Kucharski       else
12031b8adde7SWilliam Kucharski 	network_ready = 1;
12041b8adde7SWilliam Kucharski     }
12051b8adde7SWilliam Kucharski 
12061b8adde7SWilliam Kucharski   update_network_configuration();
12071b8adde7SWilliam Kucharski   return 1;
12081b8adde7SWilliam Kucharski }
12091b8adde7SWilliam Kucharski 
12101b8adde7SWilliam Kucharski /*
12111b8adde7SWilliam Kucharski  * print_network_configuration
12121b8adde7SWilliam Kucharski  *
12131b8adde7SWilliam Kucharski  * Output the network configuration. It may broke the graphic console now.:-(
12141b8adde7SWilliam Kucharski  */
print_network_configuration(void)12151b8adde7SWilliam Kucharski void print_network_configuration (void)
12161b8adde7SWilliam Kucharski {
12171b8adde7SWilliam Kucharski 	EnterFunction("print_network_configuration");
12181b8adde7SWilliam Kucharski 	if (! network_ready)
12191b8adde7SWilliam Kucharski 		grub_printf ("Network interface not initialized yet.\n");
12201b8adde7SWilliam Kucharski 	else {
1221*2506833eSJan Setje-Eilers 		if (hostnamelen == 0)
1222*2506833eSJan Setje-Eilers 			etherboot_printf ("Hostname: not set\n");
1223*2506833eSJan Setje-Eilers 		else
1224*2506833eSJan Setje-Eilers 			etherboot_printf ("Hostname: %s\n", hostname);
1225*2506833eSJan Setje-Eilers 
12261b8adde7SWilliam Kucharski 		etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
12271b8adde7SWilliam Kucharski 		etherboot_printf ("Netmask: %@\n", netmask);
12281b8adde7SWilliam Kucharski 		etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
1229*2506833eSJan Setje-Eilers 		etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
1230*2506833eSJan Setje-Eilers 		if (vendor_configfile == NULL) {
1231*2506833eSJan Setje-Eilers 			etherboot_printf ("Site Option 150: not set\n");
1232*2506833eSJan Setje-Eilers 		} else {
1233*2506833eSJan Setje-Eilers 			/*
1234*2506833eSJan Setje-Eilers 			 * vendor_configfile points into the packet and
1235*2506833eSJan Setje-Eilers 			 * is not NULL terminated, so it needs to be
1236*2506833eSJan Setje-Eilers 			 * patched up before printing it out
1237*2506833eSJan Setje-Eilers 			 */
1238*2506833eSJan Setje-Eilers 			char c = vendor_configfile[vendor_configfile_len];
1239*2506833eSJan Setje-Eilers 			vendor_configfile[vendor_configfile_len] = '\0';
1240*2506833eSJan Setje-Eilers 			etherboot_printf ("Site Option 150: %s\n",
1241*2506833eSJan Setje-Eilers 			    vendor_configfile);
1242*2506833eSJan Setje-Eilers 			vendor_configfile[vendor_configfile_len] = c;
1243*2506833eSJan Setje-Eilers 		}
1244*2506833eSJan Setje-Eilers 
1245*2506833eSJan Setje-Eilers 		if (bootfile == NULL)
1246*2506833eSJan Setje-Eilers 			etherboot_printf ("BootFile: not set\n");
1247*2506833eSJan Setje-Eilers 		else
1248*2506833eSJan Setje-Eilers 			etherboot_printf ("BootFile: %s\n", bootfile);
1249*2506833eSJan Setje-Eilers 
1250*2506833eSJan Setje-Eilers 		etherboot_printf ("GRUB menu file: %s", config_file);
1251*2506833eSJan Setje-Eilers 		switch (configfile_origin) {
1252*2506833eSJan Setje-Eilers 		case CFG_HARDCODED:
1253*2506833eSJan Setje-Eilers 			etherboot_printf (" from hardcoded default\n");
1254*2506833eSJan Setje-Eilers 			break;
1255*2506833eSJan Setje-Eilers 		case CFG_150:
1256*2506833eSJan Setje-Eilers 			etherboot_printf (" from Site Option 150\n");
1257*2506833eSJan Setje-Eilers 			break;
1258*2506833eSJan Setje-Eilers 		case CFG_MAC:
1259*2506833eSJan Setje-Eilers 			etherboot_printf (" inferred from system MAC\n");
1260*2506833eSJan Setje-Eilers 			break;
1261*2506833eSJan Setje-Eilers 		case CFG_BOOTFILE:
1262*2506833eSJan Setje-Eilers 			etherboot_printf (" inferred from BootFile\n");
1263*2506833eSJan Setje-Eilers 			break;
1264*2506833eSJan Setje-Eilers 		default:
1265*2506833eSJan Setje-Eilers 			etherboot_printf ("\n");
1266*2506833eSJan Setje-Eilers 		}
12671b8adde7SWilliam Kucharski 	}
12681b8adde7SWilliam Kucharski 	LeaveFunction("print_network_configuration");
12691b8adde7SWilliam Kucharski }
12701b8adde7SWilliam Kucharski 
12711b8adde7SWilliam Kucharski /*
12721b8adde7SWilliam Kucharski  * update_network_configuration
12731b8adde7SWilliam Kucharski  *
12741b8adde7SWilliam Kucharski  * Update network configuration for diskless clients (Solaris only)
12751b8adde7SWilliam Kucharski  */
update_network_configuration(void)12761b8adde7SWilliam Kucharski static void update_network_configuration (void)
12771b8adde7SWilliam Kucharski {
12781b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
12791b8adde7SWilliam Kucharski   	struct sol_netinfo {
12801b8adde7SWilliam Kucharski 	  	uint8_t sn_infotype;
12811b8adde7SWilliam Kucharski 		uint8_t sn_mactype;
12821b8adde7SWilliam Kucharski 		uint8_t sn_maclen;
12831b8adde7SWilliam Kucharski 	  	uint8_t sn_padding;
12841b8adde7SWilliam Kucharski 		unsigned long sn_ciaddr;
12851b8adde7SWilliam Kucharski 		unsigned long sn_siaddr;
12861b8adde7SWilliam Kucharski 		unsigned long sn_giaddr;
12871b8adde7SWilliam Kucharski 		unsigned long sn_netmask;
12881b8adde7SWilliam Kucharski 		uint8_t sn_macaddr[1];
12891b8adde7SWilliam Kucharski 	} *sip;
12901b8adde7SWilliam Kucharski 
12911b8adde7SWilliam Kucharski 	if (! network_ready)
12921b8adde7SWilliam Kucharski 	  	return;
12931b8adde7SWilliam Kucharski 
12941b8adde7SWilliam Kucharski 	sip = (struct sol_netinfo *)dhcpack_buf;
12951b8adde7SWilliam Kucharski 	sip->sn_infotype = 0xf0;	/* something not BOOTP_REPLY */
12961b8adde7SWilliam Kucharski 	sip->sn_mactype = 4;		/* DL_ETHER */
12971b8adde7SWilliam Kucharski 	sip->sn_maclen = ETH_ALEN;
12981b8adde7SWilliam Kucharski 	sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
12991b8adde7SWilliam Kucharski 	sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
13001b8adde7SWilliam Kucharski 	sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
13011b8adde7SWilliam Kucharski 	sip->sn_netmask = netmask;
13021b8adde7SWilliam Kucharski 	memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
13031b8adde7SWilliam Kucharski 	dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
13041b8adde7SWilliam Kucharski #endif /* SOLARIS_NETBOOT */
13051b8adde7SWilliam Kucharski }
13061b8adde7SWilliam Kucharski 
13071b8adde7SWilliam Kucharski /**
13081b8adde7SWilliam Kucharski  * cleanup_net
13091b8adde7SWilliam Kucharski  *
13101b8adde7SWilliam Kucharski  * Mark network unusable, and disable NICs
13111b8adde7SWilliam Kucharski  */
cleanup_net(void)13121b8adde7SWilliam Kucharski void cleanup_net (void)
13131b8adde7SWilliam Kucharski {
13141b8adde7SWilliam Kucharski 	if (network_ready){
13151b8adde7SWilliam Kucharski 		/* Stop receiving packets.  */
13161b8adde7SWilliam Kucharski 		if (use_bios_pxe)
13171b8adde7SWilliam Kucharski 			undi_pxe_disable();
13181b8adde7SWilliam Kucharski 		else
13191b8adde7SWilliam Kucharski 			eth_disable ();
13201b8adde7SWilliam Kucharski 		network_ready = 0;
13211b8adde7SWilliam Kucharski 	}
13221b8adde7SWilliam Kucharski }
13231b8adde7SWilliam Kucharski 
13241b8adde7SWilliam Kucharski /*******************************************************************
13251b8adde7SWilliam Kucharski  * dhcp implementation reusing the BIOS pxe stack
13261b8adde7SWilliam Kucharski  */
13271b8adde7SWilliam Kucharski static void
dhcp_copy(struct dhcp_t * dhcpreply)13281b8adde7SWilliam Kucharski dhcp_copy(struct dhcp_t *dhcpreply)
13291b8adde7SWilliam Kucharski {
13301b8adde7SWilliam Kucharski 	unsigned long time;
13311b8adde7SWilliam Kucharski 	int ret, len = DHCP_OPT_LEN;
13321b8adde7SWilliam Kucharski 
13331b8adde7SWilliam Kucharski 	/* fill in netinfo */
13341b8adde7SWilliam Kucharski 	dhcpack_length = sizeof (struct dhcp_t);
13351b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
13361b8adde7SWilliam Kucharski 
13371b8adde7SWilliam Kucharski 	memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
13381b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13391b8adde7SWilliam Kucharski 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13401b8adde7SWilliam Kucharski 	netmask = default_netmask();
13411b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
13421b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
13431b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
13441b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
1345*2506833eSJan Setje-Eilers 	bootfile = dhcpreply->bp_file;
13461b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
13471b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
13481b8adde7SWilliam Kucharski }
13491b8adde7SWilliam Kucharski 
dhcp_undi(void)13501b8adde7SWilliam Kucharski int dhcp_undi(void)
13511b8adde7SWilliam Kucharski {
13521b8adde7SWilliam Kucharski 	struct dhcp_t *dhcpreply;
13531b8adde7SWilliam Kucharski 
13541b8adde7SWilliam Kucharski 	if (!undi_bios_pxe((void **)&dhcpreply))
13551b8adde7SWilliam Kucharski 		return 0;
13561b8adde7SWilliam Kucharski 
13571b8adde7SWilliam Kucharski 	dhcp_copy(dhcpreply);
13581b8adde7SWilliam Kucharski 	network_ready = 1;
13591b8adde7SWilliam Kucharski 	use_bios_pxe = 1;
13601b8adde7SWilliam Kucharski 	return (1);
13611b8adde7SWilliam Kucharski }
1362