17c478bd9Sstevel@tonic-gate /**************************************************************************
27c478bd9Sstevel@tonic-gate Etherboot -  Network Bootstrap Program
37c478bd9Sstevel@tonic-gate 
47c478bd9Sstevel@tonic-gate Literature dealing with the network protocols:
57c478bd9Sstevel@tonic-gate 	ARP - RFC826
67c478bd9Sstevel@tonic-gate 	RARP - RFC903
77c478bd9Sstevel@tonic-gate         IP - RFC791
87c478bd9Sstevel@tonic-gate 	UDP - RFC768
97c478bd9Sstevel@tonic-gate 	BOOTP - RFC951, RFC2132 (vendor extensions)
107c478bd9Sstevel@tonic-gate 	DHCP - RFC2131, RFC2132 (options)
117c478bd9Sstevel@tonic-gate 	TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
127c478bd9Sstevel@tonic-gate 	RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
137c478bd9Sstevel@tonic-gate 	NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
147c478bd9Sstevel@tonic-gate 	IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate **************************************************************************/
177c478bd9Sstevel@tonic-gate #include "etherboot.h"
187c478bd9Sstevel@tonic-gate #include "grub.h"
197c478bd9Sstevel@tonic-gate #include "nic.h"
207c478bd9Sstevel@tonic-gate #include "elf.h" /* FOR EM_CURRENT */
217c478bd9Sstevel@tonic-gate #include "bootp.h"
227c478bd9Sstevel@tonic-gate #include "if_arp.h"
237c478bd9Sstevel@tonic-gate #include "tftp.h"
247c478bd9Sstevel@tonic-gate #include "timer.h"
257c478bd9Sstevel@tonic-gate #include "ip.h"
267c478bd9Sstevel@tonic-gate #include "udp.h"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /* Currently no other module uses rom, but it is available */
297c478bd9Sstevel@tonic-gate struct rom_info		rom;
307c478bd9Sstevel@tonic-gate struct arptable_t	arptable[MAX_ARP];
317c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
327c478bd9Sstevel@tonic-gate unsigned long last_igmpv1 = 0;
337c478bd9Sstevel@tonic-gate struct igmptable_t	igmptable[MAX_IGMP];
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate static unsigned long	netmask;
367c478bd9Sstevel@tonic-gate /* Used by nfs.c */
377c478bd9Sstevel@tonic-gate char *hostname = "";
387c478bd9Sstevel@tonic-gate int hostnamelen = 0;
3999ed6083Sszhou /* Used by fsys_tftp.c */
4099ed6083Sszhou int use_bios_pxe = 0;
417c478bd9Sstevel@tonic-gate static uint32_t xid;
427c478bd9Sstevel@tonic-gate static unsigned char *end_of_rfc1533 = NULL;
437c478bd9Sstevel@tonic-gate static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
447c478bd9Sstevel@tonic-gate static const in_addr zeroIP = { 0L };
457c478bd9Sstevel@tonic-gate static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
467c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
477c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
487c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
497c478bd9Sstevel@tonic-gate static int dhcp_reply;
507c478bd9Sstevel@tonic-gate static in_addr dhcp_server = { 0L };
517c478bd9Sstevel@tonic-gate static in_addr dhcp_addr = { 0L };
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static const unsigned char dhcpdiscover[] = {
547c478bd9Sstevel@tonic-gate 	RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
557c478bd9Sstevel@tonic-gate 	RFC2132_MAX_SIZE, 2,	/* request as much as we can */
567c478bd9Sstevel@tonic-gate 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
577c478bd9Sstevel@tonic-gate 	/* Vendor class identifier */
587c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
597c478bd9Sstevel@tonic-gate 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
607c478bd9Sstevel@tonic-gate 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
617c478bd9Sstevel@tonic-gate 	'0','0','2','0','0','1',
627c478bd9Sstevel@tonic-gate #else
637c478bd9Sstevel@tonic-gate 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
647c478bd9Sstevel@tonic-gate #endif
657c478bd9Sstevel@tonic-gate 	RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
667c478bd9Sstevel@tonic-gate 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
677c478bd9Sstevel@tonic-gate };
687c478bd9Sstevel@tonic-gate static const unsigned char dhcprequest [] = {
697c478bd9Sstevel@tonic-gate 	RFC2132_MSG_TYPE,1,DHCPREQUEST,
707c478bd9Sstevel@tonic-gate 	RFC2132_SRV_ID,4,0,0,0,0,
717c478bd9Sstevel@tonic-gate 	RFC2132_REQ_ADDR,4,0,0,0,0,
727c478bd9Sstevel@tonic-gate 	RFC2132_MAX_SIZE,2,	/* request as much as we can */
737c478bd9Sstevel@tonic-gate 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
747c478bd9Sstevel@tonic-gate 	/* Vendor class identifier */
757c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
767c478bd9Sstevel@tonic-gate 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
777c478bd9Sstevel@tonic-gate 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
787c478bd9Sstevel@tonic-gate 	'0','0','2','0','0','1',
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate 	RFC2132_PARAM_LIST,
837c478bd9Sstevel@tonic-gate 	/* 4 standard + 2 vendortags */
847c478bd9Sstevel@tonic-gate 	4 + 2,
857c478bd9Sstevel@tonic-gate 	/* Standard parameters */
867c478bd9Sstevel@tonic-gate 	RFC1533_NETMASK, RFC1533_GATEWAY,
877c478bd9Sstevel@tonic-gate 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
887c478bd9Sstevel@tonic-gate 	/* Etherboot vendortags */
897c478bd9Sstevel@tonic-gate 	RFC1533_VENDOR_MAGIC,
907c478bd9Sstevel@tonic-gate 	RFC1533_VENDOR_CONFIGFILE,
917c478bd9Sstevel@tonic-gate 	RFC1533_END
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /* See nic.h */
957c478bd9Sstevel@tonic-gate int user_abort = 0;
967c478bd9Sstevel@tonic-gate int network_ready = 0;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #ifdef	REQUIRE_VCI_ETHERBOOT
997c478bd9Sstevel@tonic-gate int	vci_etherboot;
1007c478bd9Sstevel@tonic-gate #endif
1017c478bd9Sstevel@tonic-gate 
1022506833eSJan Setje-Eilers char *bootfile = NULL;
1032506833eSJan Setje-Eilers configfile_origin_t configfile_origin = CFG_HARDCODED;
1042506833eSJan Setje-Eilers char *vendor_configfile = NULL;
1052506833eSJan Setje-Eilers char vendor_configfile_len;
1062506833eSJan Setje-Eilers 
1077c478bd9Sstevel@tonic-gate static void update_network_configuration(void);
1087c478bd9Sstevel@tonic-gate 
dummy(void * unused __unused)1097c478bd9Sstevel@tonic-gate static int dummy(void *unused __unused)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	return (0);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Careful.  We need an aligned buffer to avoid problems on machines
1157c478bd9Sstevel@tonic-gate  * that care about alignment.  To trivally align the ethernet data
1167c478bd9Sstevel@tonic-gate  * (the ip hdr and arp requests) we offset the packet by 2 bytes.
1177c478bd9Sstevel@tonic-gate  * leaving the ethernet data 16 byte aligned.  Beyond this
1187c478bd9Sstevel@tonic-gate  * we use memmove but this makes the common cast simple and fast.
1197c478bd9Sstevel@tonic-gate  */
120*5f82aa32SToomas Soome static char	packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned(16);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate struct nic	nic =
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	{
1257c478bd9Sstevel@tonic-gate 		0,				/* dev.disable */
1267c478bd9Sstevel@tonic-gate 		{
1277c478bd9Sstevel@tonic-gate 			0,
1287c478bd9Sstevel@tonic-gate 			0,
1297c478bd9Sstevel@tonic-gate 			PCI_BUS_TYPE,
1307c478bd9Sstevel@tonic-gate 		},				/* dev.devid */
1317c478bd9Sstevel@tonic-gate 		0,				/* index */
1327c478bd9Sstevel@tonic-gate 		0,				/* type */
1337c478bd9Sstevel@tonic-gate 		PROBE_FIRST,			/* how_pobe */
1347c478bd9Sstevel@tonic-gate 		PROBE_NONE,			/* to_probe */
1357c478bd9Sstevel@tonic-gate 		0,				/* failsafe */
1367c478bd9Sstevel@tonic-gate 		0,				/* type_index */
1377c478bd9Sstevel@tonic-gate 		{},				/* state */
1387c478bd9Sstevel@tonic-gate 	},
1397c478bd9Sstevel@tonic-gate 	(int (*)(struct nic *, int))dummy,      /* poll */
1407c478bd9Sstevel@tonic-gate 	(void (*)(struct nic *, const char *,
1417c478bd9Sstevel@tonic-gate 		unsigned int, unsigned int,
1427c478bd9Sstevel@tonic-gate 		const char *))dummy,		/* transmit */
1437c478bd9Sstevel@tonic-gate 	(void (*)(struct nic *, irq_action_t))dummy, /* irq */
1447c478bd9Sstevel@tonic-gate 	0,					/* flags */
1457c478bd9Sstevel@tonic-gate 	&rom,					/* rom_info */
1467c478bd9Sstevel@tonic-gate 	arptable[ARP_CLIENT].node,		/* node_addr */
1477c478bd9Sstevel@tonic-gate 	packet + ETH_DATA_ALIGN,		/* packet */
1487c478bd9Sstevel@tonic-gate 	0,					/* packetlen */
1497c478bd9Sstevel@tonic-gate 	0,			/* ioaddr */
1507c478bd9Sstevel@tonic-gate 	0,			/* irqno */
1517c478bd9Sstevel@tonic-gate 	NULL,					/* priv_data */
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 
grub_eth_probe(void)1567c478bd9Sstevel@tonic-gate int grub_eth_probe(void)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	static int probed = 0;
1597c478bd9Sstevel@tonic-gate 	struct dev *dev;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	EnterFunction("grub_eth_probe");
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if (probed)
1647c478bd9Sstevel@tonic-gate 		return 1;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	network_ready = 0;
1677c478bd9Sstevel@tonic-gate 	grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
1687c478bd9Sstevel@tonic-gate 	dev = &nic.dev;
1697c478bd9Sstevel@tonic-gate 	dev->how_probe = -1;
1707c478bd9Sstevel@tonic-gate 	dev->type = NIC_DRIVER;
1717c478bd9Sstevel@tonic-gate 	dev->failsafe = 1;
1727c478bd9Sstevel@tonic-gate 	rom = *((struct rom_info *)ROM_INFO_LOCATION);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	probed = (eth_probe(dev) == PROBE_WORKED);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	LeaveFunction("grub_eth_probe");
1777c478bd9Sstevel@tonic-gate 	return probed;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
eth_probe(struct dev * dev)1807c478bd9Sstevel@tonic-gate int eth_probe(struct dev *dev)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	return probe(dev);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
eth_poll(int retrieve)1857c478bd9Sstevel@tonic-gate int eth_poll(int retrieve)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	return ((*nic.poll)(&nic, retrieve));
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
eth_transmit(const char * d,unsigned int t,unsigned int s,const void * p)1907c478bd9Sstevel@tonic-gate void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	(*nic.transmit)(&nic, d, t, s, p);
1937c478bd9Sstevel@tonic-gate 	if (t == IP) twiddle();
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
eth_disable(void)1967c478bd9Sstevel@tonic-gate void eth_disable(void)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
1997c478bd9Sstevel@tonic-gate 	int i;
2007c478bd9Sstevel@tonic-gate 	for(i = 0; i < MAX_IGMP; i++) {
2017c478bd9Sstevel@tonic-gate 		leave_group(i);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate #endif
2047c478bd9Sstevel@tonic-gate 	disable(&nic.dev);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
eth_irq(irq_action_t action)2077c478bd9Sstevel@tonic-gate void eth_irq (irq_action_t action)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	(*nic.irq)(&nic,action);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /**************************************************************************
2137c478bd9Sstevel@tonic-gate IPCHKSUM - Checksum IP Header
2147c478bd9Sstevel@tonic-gate **************************************************************************/
ipchksum(const void * data,unsigned long length)2157c478bd9Sstevel@tonic-gate uint16_t ipchksum(const void *data, unsigned long length)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate 	unsigned long sum;
2187c478bd9Sstevel@tonic-gate 	unsigned long i;
2197c478bd9Sstevel@tonic-gate 	const uint8_t *ptr;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* In the most straight forward way possible,
2227c478bd9Sstevel@tonic-gate 	 * compute an ip style checksum.
2237c478bd9Sstevel@tonic-gate 	 */
2247c478bd9Sstevel@tonic-gate 	sum = 0;
2257c478bd9Sstevel@tonic-gate 	ptr = data;
2267c478bd9Sstevel@tonic-gate 	for(i = 0; i < length; i++) {
2277c478bd9Sstevel@tonic-gate 		unsigned long value;
2287c478bd9Sstevel@tonic-gate 		value = ptr[i];
2297c478bd9Sstevel@tonic-gate 		if (i & 1) {
2307c478bd9Sstevel@tonic-gate 			value <<= 8;
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 		/* Add the new value */
2337c478bd9Sstevel@tonic-gate 		sum += value;
2347c478bd9Sstevel@tonic-gate 		/* Wrap around the carry */
2357c478bd9Sstevel@tonic-gate 		if (sum > 0xFFFF) {
2367c478bd9Sstevel@tonic-gate 			sum = (sum + (sum >> 16)) & 0xFFFF;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 	return (~cpu_to_le16(sum)) & 0xFFFF;
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
add_ipchksums(unsigned long offset,uint16_t sum,uint16_t new)2427c478bd9Sstevel@tonic-gate uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	unsigned long checksum;
2457c478bd9Sstevel@tonic-gate 	sum = ~sum & 0xFFFF;
2467c478bd9Sstevel@tonic-gate 	new = ~new & 0xFFFF;
2477c478bd9Sstevel@tonic-gate 	if (offset & 1) {
2487c478bd9Sstevel@tonic-gate 		/* byte swap the sum if it came from an odd offset
2497c478bd9Sstevel@tonic-gate 		 * since the computation is endian independant this
2507c478bd9Sstevel@tonic-gate 		 * works.
2517c478bd9Sstevel@tonic-gate 		 */
2527c478bd9Sstevel@tonic-gate 		new = bswap_16(new);
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 	checksum = sum + new;
2557c478bd9Sstevel@tonic-gate 	if (checksum > 0xFFFF) {
2567c478bd9Sstevel@tonic-gate 		checksum -= 0xFFFF;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	return (~checksum) & 0xFFFF;
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /**************************************************************************
2627c478bd9Sstevel@tonic-gate DEFAULT_NETMASK - Return default netmask for IP address
2637c478bd9Sstevel@tonic-gate **************************************************************************/
default_netmask(void)2647c478bd9Sstevel@tonic-gate static inline unsigned long default_netmask(void)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
2677c478bd9Sstevel@tonic-gate 	if (net <= 127)
2687c478bd9Sstevel@tonic-gate 		return(htonl(0xff000000));
2697c478bd9Sstevel@tonic-gate 	else if (net < 192)
2707c478bd9Sstevel@tonic-gate 		return(htonl(0xffff0000));
2717c478bd9Sstevel@tonic-gate 	else
2727c478bd9Sstevel@tonic-gate 		return(htonl(0xffffff00));
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /**************************************************************************
2767c478bd9Sstevel@tonic-gate IP_TRANSMIT - Send an IP datagram
2777c478bd9Sstevel@tonic-gate **************************************************************************/
await_arp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip __unused,struct udphdr * udp __unused)2787c478bd9Sstevel@tonic-gate static int await_arp(int ival, void *ptr,
2797c478bd9Sstevel@tonic-gate 	unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	struct	arprequest *arpreply;
2827c478bd9Sstevel@tonic-gate 	if (ptype != ARP)
2837c478bd9Sstevel@tonic-gate 		return 0;
2847c478bd9Sstevel@tonic-gate 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
2857c478bd9Sstevel@tonic-gate 		return 0;
2867c478bd9Sstevel@tonic-gate 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	if (arpreply->opcode != htons(ARP_REPLY))
2897c478bd9Sstevel@tonic-gate 		return 0;
2907c478bd9Sstevel@tonic-gate 	if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
2917c478bd9Sstevel@tonic-gate 		return 0;
2927c478bd9Sstevel@tonic-gate 	memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
2937c478bd9Sstevel@tonic-gate 	return 1;
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
ip_transmit(int len,const void * buf)2967c478bd9Sstevel@tonic-gate int ip_transmit(int len, const void *buf)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	unsigned long destip;
2997c478bd9Sstevel@tonic-gate 	struct iphdr *ip;
3007c478bd9Sstevel@tonic-gate 	struct arprequest arpreq;
3017c478bd9Sstevel@tonic-gate 	int arpentry, i;
3027c478bd9Sstevel@tonic-gate 	int retry;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	ip = (struct iphdr *)buf;
3057c478bd9Sstevel@tonic-gate 	destip = ip->dest.s_addr;
3067c478bd9Sstevel@tonic-gate 	if (destip == IP_BROADCAST) {
3077c478bd9Sstevel@tonic-gate 		eth_transmit(broadcast, IP, len, buf);
3087c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL1
3097c478bd9Sstevel@tonic-gate 	} else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
3107c478bd9Sstevel@tonic-gate 		unsigned char multicast[6];
3117c478bd9Sstevel@tonic-gate 		unsigned long hdestip;
3127c478bd9Sstevel@tonic-gate 		hdestip = ntohl(destip);
3137c478bd9Sstevel@tonic-gate 		multicast[0] = 0x01;
3147c478bd9Sstevel@tonic-gate 		multicast[1] = 0x00;
3157c478bd9Sstevel@tonic-gate 		multicast[2] = 0x5e;
3167c478bd9Sstevel@tonic-gate 		multicast[3] = (hdestip >> 16) & 0x7;
3177c478bd9Sstevel@tonic-gate 		multicast[4] = (hdestip >> 8) & 0xff;
3187c478bd9Sstevel@tonic-gate 		multicast[5] = hdestip & 0xff;
3197c478bd9Sstevel@tonic-gate 		eth_transmit(multicast, IP, len, buf);
3207c478bd9Sstevel@tonic-gate #endif
3217c478bd9Sstevel@tonic-gate 	} else {
3227c478bd9Sstevel@tonic-gate 		if (((destip & netmask) !=
3237c478bd9Sstevel@tonic-gate 		     (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
3247c478bd9Sstevel@tonic-gate 		    arptable[ARP_GATEWAY].ipaddr.s_addr)
3257c478bd9Sstevel@tonic-gate 			destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
3267c478bd9Sstevel@tonic-gate 		for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
3277c478bd9Sstevel@tonic-gate 			if (arptable[arpentry].ipaddr.s_addr == destip) break;
3287c478bd9Sstevel@tonic-gate 		if (arpentry == MAX_ARP) {
3297c478bd9Sstevel@tonic-gate 			printf("%@ is not in my arp table!\n", destip);
3307c478bd9Sstevel@tonic-gate 			return(0);
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 		for (i = 0; i < ETH_ALEN; i++)
3337c478bd9Sstevel@tonic-gate 			if (arptable[arpentry].node[i])
3347c478bd9Sstevel@tonic-gate 				break;
3357c478bd9Sstevel@tonic-gate 		if (i == ETH_ALEN) {	/* Need to do arp request */
3367c478bd9Sstevel@tonic-gate 			arpreq.hwtype = htons(1);
3377c478bd9Sstevel@tonic-gate 			arpreq.protocol = htons(IP);
3387c478bd9Sstevel@tonic-gate 			arpreq.hwlen = ETH_ALEN;
3397c478bd9Sstevel@tonic-gate 			arpreq.protolen = 4;
3407c478bd9Sstevel@tonic-gate 			arpreq.opcode = htons(ARP_REQUEST);
3417c478bd9Sstevel@tonic-gate 			memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
3427c478bd9Sstevel@tonic-gate 			memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
3437c478bd9Sstevel@tonic-gate 			memset(arpreq.thwaddr, 0, ETH_ALEN);
3447c478bd9Sstevel@tonic-gate 			memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
3457c478bd9Sstevel@tonic-gate 			for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
3467c478bd9Sstevel@tonic-gate 				long timeout;
3477c478bd9Sstevel@tonic-gate 				eth_transmit(broadcast, ARP, sizeof(arpreq),
3487c478bd9Sstevel@tonic-gate 					&arpreq);
3497c478bd9Sstevel@tonic-gate 				timeout = rfc2131_sleep_interval(TIMEOUT, retry);
3507c478bd9Sstevel@tonic-gate 				if (await_reply(await_arp, arpentry,
3517c478bd9Sstevel@tonic-gate 					arpreq.tipaddr, timeout)) goto xmit;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 			return(0);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate xmit:
3567c478bd9Sstevel@tonic-gate 		eth_transmit(arptable[arpentry].node, IP, len, buf);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	return 1;
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
build_ip_hdr(unsigned long destip,int ttl,int protocol,int option_len,int len,const void * buf)3617c478bd9Sstevel@tonic-gate void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
3627c478bd9Sstevel@tonic-gate 	int len, const void *buf)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	struct iphdr *ip;
3657c478bd9Sstevel@tonic-gate 	ip = (struct iphdr *)buf;
3667c478bd9Sstevel@tonic-gate 	ip->verhdrlen = 0x45;
3677c478bd9Sstevel@tonic-gate 	ip->verhdrlen += (option_len/4);
3687c478bd9Sstevel@tonic-gate 	ip->service = 0;
3697c478bd9Sstevel@tonic-gate 	ip->len = htons(len);
3707c478bd9Sstevel@tonic-gate 	ip->ident = 0;
3717c478bd9Sstevel@tonic-gate 	ip->frags = 0; /* Should we set don't fragment? */
3727c478bd9Sstevel@tonic-gate 	ip->ttl = ttl;
3737c478bd9Sstevel@tonic-gate 	ip->protocol = protocol;
3747c478bd9Sstevel@tonic-gate 	ip->chksum = 0;
3757c478bd9Sstevel@tonic-gate 	ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
3767c478bd9Sstevel@tonic-gate 	ip->dest.s_addr = destip;
3777c478bd9Sstevel@tonic-gate 	ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
udpchksum(struct iphdr * ip,struct udphdr * udp)3807c478bd9Sstevel@tonic-gate static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	struct udp_pseudo_hdr pseudo;
3837c478bd9Sstevel@tonic-gate 	uint16_t checksum;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* Compute the pseudo header */
3867c478bd9Sstevel@tonic-gate 	pseudo.src.s_addr  = ip->src.s_addr;
3877c478bd9Sstevel@tonic-gate 	pseudo.dest.s_addr = ip->dest.s_addr;
3887c478bd9Sstevel@tonic-gate 	pseudo.unused      = 0;
3897c478bd9Sstevel@tonic-gate 	pseudo.protocol    = IP_UDP;
3907c478bd9Sstevel@tonic-gate 	pseudo.len         = udp->len;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* Sum the pseudo header */
3937c478bd9Sstevel@tonic-gate 	checksum = ipchksum(&pseudo, 12);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* Sum the rest of the udp packet */
3967c478bd9Sstevel@tonic-gate 	checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
3977c478bd9Sstevel@tonic-gate 	return checksum;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 
build_udp_hdr(unsigned long destip,unsigned int srcsock,unsigned int destsock,int ttl,int len,const void * buf)4017c478bd9Sstevel@tonic-gate void build_udp_hdr(unsigned long destip,
4027c478bd9Sstevel@tonic-gate 	unsigned int srcsock, unsigned int destsock, int ttl,
4037c478bd9Sstevel@tonic-gate 	int len, const void *buf)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	struct iphdr *ip;
4067c478bd9Sstevel@tonic-gate 	struct udphdr *udp;
4077c478bd9Sstevel@tonic-gate 	ip = (struct iphdr *)buf;
4087c478bd9Sstevel@tonic-gate 	build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
4097c478bd9Sstevel@tonic-gate 	udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
4107c478bd9Sstevel@tonic-gate 	udp->src = htons(srcsock);
4117c478bd9Sstevel@tonic-gate 	udp->dest = htons(destsock);
4127c478bd9Sstevel@tonic-gate 	udp->len = htons(len - sizeof(struct iphdr));
4137c478bd9Sstevel@tonic-gate 	udp->chksum = 0;
4147c478bd9Sstevel@tonic-gate 	if ((udp->chksum = udpchksum(ip, udp)) == 0)
4157c478bd9Sstevel@tonic-gate 		udp->chksum = 0xffff;
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /**************************************************************************
4207c478bd9Sstevel@tonic-gate UDP_TRANSMIT - Send an UDP datagram
4217c478bd9Sstevel@tonic-gate **************************************************************************/
udp_transmit(unsigned long destip,unsigned int srcsock,unsigned int destsock,int len,const void * buf)4227c478bd9Sstevel@tonic-gate int udp_transmit(unsigned long destip, unsigned int srcsock,
4237c478bd9Sstevel@tonic-gate 	unsigned int destsock, int len, const void *buf)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
4267c478bd9Sstevel@tonic-gate 	return ip_transmit(len, buf);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /**************************************************************************
4307c478bd9Sstevel@tonic-gate QDRAIN - clear the nic's receive queue
4317c478bd9Sstevel@tonic-gate **************************************************************************/
await_qdrain(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp __unused)4327c478bd9Sstevel@tonic-gate static int await_qdrain(int ival __unused, void *ptr __unused,
4337c478bd9Sstevel@tonic-gate 	unsigned short ptype __unused,
4347c478bd9Sstevel@tonic-gate 	struct iphdr *ip __unused, struct udphdr *udp __unused)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	return 0;
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
rx_qdrain(void)4397c478bd9Sstevel@tonic-gate void rx_qdrain(void)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate 	/* Clear out the Rx queue first.  It contains nothing of interest,
4427c478bd9Sstevel@tonic-gate 	 * except possibly ARP requests from the DHCP/TFTP server.  We use
4437c478bd9Sstevel@tonic-gate 	 * polling throughout Etherboot, so some time may have passed since we
4447c478bd9Sstevel@tonic-gate 	 * last polled the receive queue, which may now be filled with
4457c478bd9Sstevel@tonic-gate 	 * broadcast packets.  This will cause the reply to the packets we are
4467c478bd9Sstevel@tonic-gate 	 * about to send to be lost immediately.  Not very clever.  */
4477c478bd9Sstevel@tonic-gate 	await_reply(await_qdrain, 0, NULL, 0);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /**
4517c478bd9Sstevel@tonic-gate  * rarp
4527c478bd9Sstevel@tonic-gate  *
4537c478bd9Sstevel@tonic-gate  * Get IP address by rarp. Just copy from etherboot
4547c478bd9Sstevel@tonic-gate  **/
await_rarp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip,struct udphdr * udp)4557c478bd9Sstevel@tonic-gate static int await_rarp(int ival, void *ptr, unsigned short ptype,
4567c478bd9Sstevel@tonic-gate 		      struct iphdr *ip, struct udphdr *udp)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	struct arprequest *arpreply;
4597c478bd9Sstevel@tonic-gate 	if (ptype != RARP)
4607c478bd9Sstevel@tonic-gate 		return 0;
4617c478bd9Sstevel@tonic-gate 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
4627c478bd9Sstevel@tonic-gate 		return 0;
4637c478bd9Sstevel@tonic-gate 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
4647c478bd9Sstevel@tonic-gate 	if (arpreply->opcode != htons(RARP_REPLY))
4657c478bd9Sstevel@tonic-gate 		return 0;
4667c478bd9Sstevel@tonic-gate 	if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
4677c478bd9Sstevel@tonic-gate 		memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
4687c478bd9Sstevel@tonic-gate 		memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
4697c478bd9Sstevel@tonic-gate 		memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
4702269adc8Sszhou 		memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
4717c478bd9Sstevel@tonic-gate 		return 1;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	return 0;
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
rarp(void)4767c478bd9Sstevel@tonic-gate int rarp(void)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	int retry;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/* arp and rarp requests share the same packet structure. */
4817c478bd9Sstevel@tonic-gate 	struct arprequest rarpreq;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	if(!grub_eth_probe())
4847c478bd9Sstevel@tonic-gate 		return 0;
4857c478bd9Sstevel@tonic-gate 	network_ready = 0;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	memset(&rarpreq, 0, sizeof(rarpreq));
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	rarpreq.hwtype = htons(1);
4907c478bd9Sstevel@tonic-gate 	rarpreq.protocol = htons(IP);
4917c478bd9Sstevel@tonic-gate 	rarpreq.hwlen = ETH_ALEN;
4927c478bd9Sstevel@tonic-gate 	rarpreq.protolen = 4;
4937c478bd9Sstevel@tonic-gate 	rarpreq.opcode = htons(RARP_REQUEST);
4947c478bd9Sstevel@tonic-gate 	memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4957c478bd9Sstevel@tonic-gate 	/* sipaddr is already zeroed out */
4967c478bd9Sstevel@tonic-gate 	memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4977c478bd9Sstevel@tonic-gate 	/* tipaddr is already zeroed out */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
5007c478bd9Sstevel@tonic-gate 		long timeout;
5017c478bd9Sstevel@tonic-gate 		eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		timeout = rfc2131_sleep_interval(TIMEOUT, retry);
5047c478bd9Sstevel@tonic-gate 		if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
5057c478bd9Sstevel@tonic-gate 			break;
5067c478bd9Sstevel@tonic-gate 		if (user_abort)
5077c478bd9Sstevel@tonic-gate 			return 0;
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if (retry == MAX_ARP_RETRIES) {
5117c478bd9Sstevel@tonic-gate 		return (0);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	network_ready = 1;
5157c478bd9Sstevel@tonic-gate   	update_network_configuration();
5167c478bd9Sstevel@tonic-gate 	return (1);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate /**
5207c478bd9Sstevel@tonic-gate  * bootp
5217c478bd9Sstevel@tonic-gate  *
5227c478bd9Sstevel@tonic-gate  * Get IP address by bootp, segregate from bootp in etherboot.
5237c478bd9Sstevel@tonic-gate  **/
await_bootp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)5247c478bd9Sstevel@tonic-gate static int await_bootp(int ival __unused, void *ptr __unused,
5257c478bd9Sstevel@tonic-gate 	unsigned short ptype __unused, struct iphdr *ip __unused,
5267c478bd9Sstevel@tonic-gate 	struct udphdr *udp)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	struct	bootp_t *bootpreply;
5297c478bd9Sstevel@tonic-gate 	int len;		/* Length of vendor */
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (!udp) {
5327c478bd9Sstevel@tonic-gate 		return 0;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 	bootpreply = (struct bootp_t *)
5357c478bd9Sstevel@tonic-gate 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
5367c478bd9Sstevel@tonic-gate 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
5377c478bd9Sstevel@tonic-gate 		sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
5387c478bd9Sstevel@tonic-gate 	if (len < 0) {
5397c478bd9Sstevel@tonic-gate 		return 0;
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 	if (udp->dest != htons(BOOTP_CLIENT))
5427c478bd9Sstevel@tonic-gate 		return 0;
5437c478bd9Sstevel@tonic-gate 	if (bootpreply->bp_op != BOOTP_REPLY)
5447c478bd9Sstevel@tonic-gate 		return 0;
5457c478bd9Sstevel@tonic-gate 	if (bootpreply->bp_xid != xid)
5467c478bd9Sstevel@tonic-gate 		return 0;
5477c478bd9Sstevel@tonic-gate 	if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
5487c478bd9Sstevel@tonic-gate 		return 0;
5497c478bd9Sstevel@tonic-gate 	if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
5507c478bd9Sstevel@tonic-gate 	    (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
5517c478bd9Sstevel@tonic-gate 		return 0;
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
5557c478bd9Sstevel@tonic-gate 	/* fill in netinfo */
5567c478bd9Sstevel@tonic-gate 	dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
5577c478bd9Sstevel@tonic-gate 	memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
5587c478bd9Sstevel@tonic-gate #endif
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
5617c478bd9Sstevel@tonic-gate 	netmask = default_netmask();
5627c478bd9Sstevel@tonic-gate 	arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
5637c478bd9Sstevel@tonic-gate 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
5647c478bd9Sstevel@tonic-gate 	arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
5657c478bd9Sstevel@tonic-gate 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
5662506833eSJan Setje-Eilers 	bootfile = bootpreply->bp_file;
5677c478bd9Sstevel@tonic-gate 	memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
5687c478bd9Sstevel@tonic-gate 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
5697c478bd9Sstevel@tonic-gate 	return(1);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
bootp(void)5727c478bd9Sstevel@tonic-gate int bootp(void)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	int retry;
5757c478bd9Sstevel@tonic-gate 	struct bootpip_t ip;
5767c478bd9Sstevel@tonic-gate 	unsigned long  starttime;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	EnterFunction("bootp");
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if(!grub_eth_probe())
5817c478bd9Sstevel@tonic-gate 		return 0;
5827c478bd9Sstevel@tonic-gate 	network_ready = 0;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	memset(&ip, 0, sizeof(struct bootpip_t));
5857c478bd9Sstevel@tonic-gate 	ip.bp.bp_op = BOOTP_REQUEST;
5867c478bd9Sstevel@tonic-gate 	ip.bp.bp_htype = 1;
5877c478bd9Sstevel@tonic-gate 	ip.bp.bp_hlen = ETH_ALEN;
5887c478bd9Sstevel@tonic-gate 	starttime = currticks();
5897c478bd9Sstevel@tonic-gate 	/* Use lower 32 bits of node address, more likely to be
5907c478bd9Sstevel@tonic-gate 	   distinct than the time since booting */
5917c478bd9Sstevel@tonic-gate 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
5927c478bd9Sstevel@tonic-gate 	ip.bp.bp_xid = xid += htonl(starttime);
5937c478bd9Sstevel@tonic-gate 	/* bp_secs defaults to zero */
5947c478bd9Sstevel@tonic-gate 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
5957c478bd9Sstevel@tonic-gate 	memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
5987c478bd9Sstevel@tonic-gate 		long timeout;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 		rx_qdrain();
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
6037c478bd9Sstevel@tonic-gate 			sizeof(struct bootpip_t), &ip);
6047c478bd9Sstevel@tonic-gate 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
6057c478bd9Sstevel@tonic-gate 		if (await_reply(await_bootp, 0, NULL, timeout)){
6067c478bd9Sstevel@tonic-gate 			network_ready = 1;
6077c478bd9Sstevel@tonic-gate 			return(1);
6087c478bd9Sstevel@tonic-gate 		}
6097c478bd9Sstevel@tonic-gate 		if (user_abort)
6107c478bd9Sstevel@tonic-gate 			return 0;
6117c478bd9Sstevel@tonic-gate 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 	return(0);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /**
6177c478bd9Sstevel@tonic-gate  * dhcp
6187c478bd9Sstevel@tonic-gate  *
6197c478bd9Sstevel@tonic-gate  * Get IP address by dhcp, segregate from bootp in etherboot.
6207c478bd9Sstevel@tonic-gate  **/
await_dhcp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)6217c478bd9Sstevel@tonic-gate static int await_dhcp(int ival __unused, void *ptr __unused,
6227c478bd9Sstevel@tonic-gate 	unsigned short ptype __unused, struct iphdr *ip __unused,
6237c478bd9Sstevel@tonic-gate 	struct udphdr *udp)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	struct	dhcp_t *dhcpreply;
6267c478bd9Sstevel@tonic-gate 	int len;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (!udp) {
6297c478bd9Sstevel@tonic-gate 		return 0;
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 	dhcpreply = (struct dhcp_t *)
6327c478bd9Sstevel@tonic-gate 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
6337c478bd9Sstevel@tonic-gate 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
6347c478bd9Sstevel@tonic-gate 		sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
6357c478bd9Sstevel@tonic-gate 	if (len < 0){
6367c478bd9Sstevel@tonic-gate 		return 0;
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	if (udp->dest != htons(BOOTP_CLIENT))
6397c478bd9Sstevel@tonic-gate 		return 0;
6407c478bd9Sstevel@tonic-gate 	if (dhcpreply->bp_op != BOOTP_REPLY)
6417c478bd9Sstevel@tonic-gate 		return 0;
6427c478bd9Sstevel@tonic-gate 	if (dhcpreply->bp_xid != xid)
6437c478bd9Sstevel@tonic-gate 		return 0;
6447c478bd9Sstevel@tonic-gate 	if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
6457c478bd9Sstevel@tonic-gate 		return 0;
6467c478bd9Sstevel@tonic-gate 	if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
6477c478bd9Sstevel@tonic-gate 	    (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
6487c478bd9Sstevel@tonic-gate 		return 0;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
6527c478bd9Sstevel@tonic-gate 	/* fill in netinfo */
6537c478bd9Sstevel@tonic-gate 	dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
6547c478bd9Sstevel@tonic-gate 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
6557c478bd9Sstevel@tonic-gate #endif
6567c478bd9Sstevel@tonic-gate 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6577c478bd9Sstevel@tonic-gate 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6587c478bd9Sstevel@tonic-gate 	netmask = default_netmask();
6597c478bd9Sstevel@tonic-gate 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
6607c478bd9Sstevel@tonic-gate 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
6617c478bd9Sstevel@tonic-gate 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
6627c478bd9Sstevel@tonic-gate 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
6632506833eSJan Setje-Eilers 	bootfile = dhcpreply->bp_file;
6647c478bd9Sstevel@tonic-gate 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
6657c478bd9Sstevel@tonic-gate 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
6667c478bd9Sstevel@tonic-gate 	return(1);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate 
dhcp(void)6697c478bd9Sstevel@tonic-gate int dhcp(void)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	int retry;
6727c478bd9Sstevel@tonic-gate 	int reqretry;
6737c478bd9Sstevel@tonic-gate 	struct dhcpip_t ip;
6747c478bd9Sstevel@tonic-gate 	unsigned long  starttime;
6757c478bd9Sstevel@tonic-gate 
67699ed6083Sszhou 	/* try bios pxe stack first */
67799ed6083Sszhou 	if (dhcp_undi())
67899ed6083Sszhou 		return 1;
67999ed6083Sszhou 
6807c478bd9Sstevel@tonic-gate 	if(!grub_eth_probe())
6817c478bd9Sstevel@tonic-gate 		return 0;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	network_ready = 0;
6847c478bd9Sstevel@tonic-gate 
6852269adc8Sszhou 	memset(&ip, 0, sizeof(ip));
6867c478bd9Sstevel@tonic-gate 	ip.bp.bp_op = BOOTP_REQUEST;
6877c478bd9Sstevel@tonic-gate 	ip.bp.bp_htype = 1;
6887c478bd9Sstevel@tonic-gate 	ip.bp.bp_hlen = ETH_ALEN;
6897c478bd9Sstevel@tonic-gate 	starttime = currticks();
6907c478bd9Sstevel@tonic-gate 	/* Use lower 32 bits of node address, more likely to be
6917c478bd9Sstevel@tonic-gate 	   distinct than the time since booting */
6927c478bd9Sstevel@tonic-gate 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
6937c478bd9Sstevel@tonic-gate 	ip.bp.bp_xid = xid += htonl(starttime);
6947c478bd9Sstevel@tonic-gate 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
6957c478bd9Sstevel@tonic-gate 	memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
6967c478bd9Sstevel@tonic-gate 	memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
6997c478bd9Sstevel@tonic-gate 		long timeout;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		rx_qdrain();
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7042269adc8Sszhou 			     sizeof(ip), &ip);
7057c478bd9Sstevel@tonic-gate 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
7067c478bd9Sstevel@tonic-gate 		if (await_reply(await_dhcp, 0, NULL, timeout)) {
7077c478bd9Sstevel@tonic-gate 			/* If not a DHCPOFFER then must be just a
7087c478bd9Sstevel@tonic-gate 			   BOOTP reply, be backward compatible with
7097c478bd9Sstevel@tonic-gate 			   BOOTP then. Jscott report a bug here, but I
7107c478bd9Sstevel@tonic-gate 			   don't know how it happened */
7117c478bd9Sstevel@tonic-gate 			if (dhcp_reply != DHCPOFFER){
7127c478bd9Sstevel@tonic-gate 				network_ready = 1;
7137c478bd9Sstevel@tonic-gate 				return(1);
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 			dhcp_reply = 0;
7167c478bd9Sstevel@tonic-gate 			memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
7177c478bd9Sstevel@tonic-gate 			memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
7187c478bd9Sstevel@tonic-gate 			/* Beware: the magic numbers 9 and 15 depend on
7197c478bd9Sstevel@tonic-gate 			   the layout of dhcprequest */
7207c478bd9Sstevel@tonic-gate 			memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
7217c478bd9Sstevel@tonic-gate 			memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
7227c478bd9Sstevel@tonic-gate 			for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
7237c478bd9Sstevel@tonic-gate 				udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7242269adc8Sszhou 					     sizeof(ip), &ip);
7257c478bd9Sstevel@tonic-gate 				dhcp_reply=0;
7267c478bd9Sstevel@tonic-gate 				timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
7277c478bd9Sstevel@tonic-gate 				if (await_reply(await_dhcp, 0, NULL, timeout))
7287c478bd9Sstevel@tonic-gate 					if (dhcp_reply == DHCPACK){
7297c478bd9Sstevel@tonic-gate 						network_ready = 1;
7307c478bd9Sstevel@tonic-gate 						return(1);
7317c478bd9Sstevel@tonic-gate 					}
7327c478bd9Sstevel@tonic-gate 				if (user_abort)
7337c478bd9Sstevel@tonic-gate 					return 0;
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 		if (user_abort)
7377c478bd9Sstevel@tonic-gate 			return 0;
7387c478bd9Sstevel@tonic-gate 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 	return(0);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
send_igmp_reports(unsigned long now)7447c478bd9Sstevel@tonic-gate static void send_igmp_reports(unsigned long now)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	int i;
7477c478bd9Sstevel@tonic-gate 	for(i = 0; i < MAX_IGMP; i++) {
7487c478bd9Sstevel@tonic-gate 		if (igmptable[i].time && (now >= igmptable[i].time)) {
7497c478bd9Sstevel@tonic-gate 			struct igmp_ip_t igmp;
7507c478bd9Sstevel@tonic-gate 			igmp.router_alert[0] = 0x94;
7517c478bd9Sstevel@tonic-gate 			igmp.router_alert[1] = 0x04;
7527c478bd9Sstevel@tonic-gate 			igmp.router_alert[2] = 0;
7537c478bd9Sstevel@tonic-gate 			igmp.router_alert[3] = 0;
7547c478bd9Sstevel@tonic-gate 			build_ip_hdr(igmptable[i].group.s_addr,
7557c478bd9Sstevel@tonic-gate 				1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
7567c478bd9Sstevel@tonic-gate 			igmp.igmp.type = IGMPv2_REPORT;
7577c478bd9Sstevel@tonic-gate 			if (last_igmpv1 &&
7587c478bd9Sstevel@tonic-gate 				(now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
7597c478bd9Sstevel@tonic-gate 				igmp.igmp.type = IGMPv1_REPORT;
7607c478bd9Sstevel@tonic-gate 			}
7617c478bd9Sstevel@tonic-gate 			igmp.igmp.response_time = 0;
7627c478bd9Sstevel@tonic-gate 			igmp.igmp.chksum = 0;
7637c478bd9Sstevel@tonic-gate 			igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
7647c478bd9Sstevel@tonic-gate 			igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
7657c478bd9Sstevel@tonic-gate 			ip_transmit(sizeof(igmp), &igmp);
7667c478bd9Sstevel@tonic-gate #ifdef	MDEBUG
7677c478bd9Sstevel@tonic-gate 			printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
7687c478bd9Sstevel@tonic-gate #endif
7697c478bd9Sstevel@tonic-gate 			/* Don't send another igmp report until asked */
7707c478bd9Sstevel@tonic-gate 			igmptable[i].time = 0;
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
process_igmp(struct iphdr * ip,unsigned long now)7757c478bd9Sstevel@tonic-gate static void process_igmp(struct iphdr *ip, unsigned long now)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	struct igmp *igmp;
7787c478bd9Sstevel@tonic-gate 	int i;
7797c478bd9Sstevel@tonic-gate 	unsigned iplen = 0;
7807c478bd9Sstevel@tonic-gate 	if (!ip || (ip->protocol == IP_IGMP) ||
7817c478bd9Sstevel@tonic-gate 		(nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
7827c478bd9Sstevel@tonic-gate 		return;
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 	iplen = (ip->verhdrlen & 0xf)*4;
7857c478bd9Sstevel@tonic-gate 	igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
7867c478bd9Sstevel@tonic-gate 	if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
7877c478bd9Sstevel@tonic-gate 		return;
7887c478bd9Sstevel@tonic-gate 	if ((igmp->type == IGMP_QUERY) &&
7897c478bd9Sstevel@tonic-gate 		(ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
7907c478bd9Sstevel@tonic-gate 		unsigned long interval = IGMP_INTERVAL;
7917c478bd9Sstevel@tonic-gate 		if (igmp->response_time == 0) {
7927c478bd9Sstevel@tonic-gate 			last_igmpv1 = now;
7937c478bd9Sstevel@tonic-gate 		} else {
7947c478bd9Sstevel@tonic-gate 			interval = (igmp->response_time * TICKS_PER_SEC)/10;
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate #ifdef	MDEBUG
7987c478bd9Sstevel@tonic-gate 		printf("Received IGMP query for: %@\n", igmp->group.s_addr);
7997c478bd9Sstevel@tonic-gate #endif
8007c478bd9Sstevel@tonic-gate 		for(i = 0; i < MAX_IGMP; i++) {
8017c478bd9Sstevel@tonic-gate 			uint32_t group = igmptable[i].group.s_addr;
8027c478bd9Sstevel@tonic-gate 			if ((group == 0) || (group == igmp->group.s_addr)) {
8037c478bd9Sstevel@tonic-gate 				unsigned long time;
8047c478bd9Sstevel@tonic-gate 				time = currticks() + rfc1112_sleep_interval(interval, 0);
8057c478bd9Sstevel@tonic-gate 				if (time < igmptable[i].time) {
8067c478bd9Sstevel@tonic-gate 					igmptable[i].time = time;
8077c478bd9Sstevel@tonic-gate 				}
8087c478bd9Sstevel@tonic-gate 			}
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 	if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
8127c478bd9Sstevel@tonic-gate 		(ip->dest.s_addr == igmp->group.s_addr)) {
8137c478bd9Sstevel@tonic-gate #ifdef	MDEBUG
8147c478bd9Sstevel@tonic-gate 		printf("Received IGMP report for: %@\n", igmp->group.s_addr);
8157c478bd9Sstevel@tonic-gate #endif
8167c478bd9Sstevel@tonic-gate 		for(i = 0; i < MAX_IGMP; i++) {
8177c478bd9Sstevel@tonic-gate 			if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
8187c478bd9Sstevel@tonic-gate 				igmptable[i].time != 0) {
8197c478bd9Sstevel@tonic-gate 				igmptable[i].time = 0;
8207c478bd9Sstevel@tonic-gate 			}
8217c478bd9Sstevel@tonic-gate 		}
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
leave_group(int slot)8257c478bd9Sstevel@tonic-gate void leave_group(int slot)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate 	/* Be very stupid and always send a leave group message if
8287c478bd9Sstevel@tonic-gate 	 * I have subscribed.  Imperfect but it is standards
8297c478bd9Sstevel@tonic-gate 	 * compliant, easy and reliable to implement.
8307c478bd9Sstevel@tonic-gate 	 *
8317c478bd9Sstevel@tonic-gate 	 * The optimal group leave method is to only send leave when,
8327c478bd9Sstevel@tonic-gate 	 * we were the last host to respond to a query on this group,
8337c478bd9Sstevel@tonic-gate 	 * and igmpv1 compatibility is not enabled.
8347c478bd9Sstevel@tonic-gate 	 */
8357c478bd9Sstevel@tonic-gate 	if (igmptable[slot].group.s_addr) {
8367c478bd9Sstevel@tonic-gate 		struct igmp_ip_t igmp;
8377c478bd9Sstevel@tonic-gate 		igmp.router_alert[0] = 0x94;
8387c478bd9Sstevel@tonic-gate 		igmp.router_alert[1] = 0x04;
8397c478bd9Sstevel@tonic-gate 		igmp.router_alert[2] = 0;
8407c478bd9Sstevel@tonic-gate 		igmp.router_alert[3] = 0;
8417c478bd9Sstevel@tonic-gate 		build_ip_hdr(htonl(GROUP_ALL_HOSTS),
8427c478bd9Sstevel@tonic-gate 			1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
8437c478bd9Sstevel@tonic-gate 		igmp.igmp.type = IGMP_LEAVE;
8447c478bd9Sstevel@tonic-gate 		igmp.igmp.response_time = 0;
8457c478bd9Sstevel@tonic-gate 		igmp.igmp.chksum = 0;
8467c478bd9Sstevel@tonic-gate 		igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
8477c478bd9Sstevel@tonic-gate 		igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
8487c478bd9Sstevel@tonic-gate 		ip_transmit(sizeof(igmp), &igmp);
8497c478bd9Sstevel@tonic-gate #ifdef	MDEBUG
8507c478bd9Sstevel@tonic-gate 		printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
8517c478bd9Sstevel@tonic-gate #endif
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 	memset(&igmptable[slot], 0, sizeof(igmptable[0]));
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
join_group(int slot,unsigned long group)8567c478bd9Sstevel@tonic-gate void join_group(int slot, unsigned long group)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate 	/* I have already joined */
8597c478bd9Sstevel@tonic-gate 	if (igmptable[slot].group.s_addr == group)
8607c478bd9Sstevel@tonic-gate 		return;
8617c478bd9Sstevel@tonic-gate 	if (igmptable[slot].group.s_addr) {
8627c478bd9Sstevel@tonic-gate 		leave_group(slot);
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	/* Only join a group if we are given a multicast ip, this way
8657c478bd9Sstevel@tonic-gate 	 * code can be given a non-multicast (broadcast or unicast ip)
8667c478bd9Sstevel@tonic-gate 	 * and still work...
8677c478bd9Sstevel@tonic-gate 	 */
8687c478bd9Sstevel@tonic-gate 	if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
8697c478bd9Sstevel@tonic-gate 		igmptable[slot].group.s_addr = group;
8707c478bd9Sstevel@tonic-gate 		igmptable[slot].time = currticks();
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate #else
8747c478bd9Sstevel@tonic-gate #define send_igmp_reports(now);
8757c478bd9Sstevel@tonic-gate #define process_igmp(ip, now)
8767c478bd9Sstevel@tonic-gate #endif
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /**************************************************************************
8797c478bd9Sstevel@tonic-gate AWAIT_REPLY - Wait until we get a response for our request
8807c478bd9Sstevel@tonic-gate ************f**************************************************************/
await_reply(reply_t reply,int ival,void * ptr,long timeout)8817c478bd9Sstevel@tonic-gate int await_reply(reply_t reply, int ival, void *ptr, long timeout)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	unsigned long time, now;
8847c478bd9Sstevel@tonic-gate 	struct	iphdr *ip;
8857c478bd9Sstevel@tonic-gate 	unsigned iplen = 0;
8867c478bd9Sstevel@tonic-gate 	struct	udphdr *udp;
8877c478bd9Sstevel@tonic-gate 	unsigned short ptype;
8887c478bd9Sstevel@tonic-gate 	int result;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	user_abort = 0;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	time = timeout + currticks();
8937c478bd9Sstevel@tonic-gate 	/* The timeout check is done below.  The timeout is only checked if
8947c478bd9Sstevel@tonic-gate 	 * there is no packet in the Rx queue.  This assumes that eth_poll()
8957c478bd9Sstevel@tonic-gate 	 * needs a negligible amount of time.
8967c478bd9Sstevel@tonic-gate 	 */
8977c478bd9Sstevel@tonic-gate 	for (;;) {
8987c478bd9Sstevel@tonic-gate 		now = currticks();
8997c478bd9Sstevel@tonic-gate 		send_igmp_reports(now);
9007c478bd9Sstevel@tonic-gate 		result = eth_poll(1);
9017c478bd9Sstevel@tonic-gate 		if (result == 0) {
9027c478bd9Sstevel@tonic-gate 			/* We don't have anything */
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 			/* Check for abort key only if the Rx queue is empty -
9057c478bd9Sstevel@tonic-gate 			 * as long as we have something to process, don't
9067c478bd9Sstevel@tonic-gate 			 * assume that something failed.  It is unlikely that
9077c478bd9Sstevel@tonic-gate 			 * we have no processing time left between packets.  */
9087c478bd9Sstevel@tonic-gate 			poll_interruptions();
9097c478bd9Sstevel@tonic-gate 			/* Do the timeout after at least a full queue walk.  */
9107c478bd9Sstevel@tonic-gate 			if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
9117c478bd9Sstevel@tonic-gate 				break;
9127c478bd9Sstevel@tonic-gate 			}
9137c478bd9Sstevel@tonic-gate 			continue;
9147c478bd9Sstevel@tonic-gate 		}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		/* We have something! */
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		/* Find the Ethernet packet type */
9197c478bd9Sstevel@tonic-gate 		if (nic.packetlen >= ETH_HLEN) {
9207c478bd9Sstevel@tonic-gate 			ptype = ((unsigned short) nic.packet[12]) << 8
9217c478bd9Sstevel@tonic-gate 				| ((unsigned short) nic.packet[13]);
9227c478bd9Sstevel@tonic-gate 		} else continue; /* what else could we do with it? */
9237c478bd9Sstevel@tonic-gate 		/* Verify an IP header */
9247c478bd9Sstevel@tonic-gate 		ip = 0;
9257c478bd9Sstevel@tonic-gate 		if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
9267c478bd9Sstevel@tonic-gate 			unsigned ipoptlen;
9277c478bd9Sstevel@tonic-gate 			ip = (struct iphdr *)&nic.packet[ETH_HLEN];
9287c478bd9Sstevel@tonic-gate 			if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
9297c478bd9Sstevel@tonic-gate 				continue;
9307c478bd9Sstevel@tonic-gate 			iplen = (ip->verhdrlen & 0xf) * 4;
9317c478bd9Sstevel@tonic-gate 			if (ipchksum(ip, iplen) != 0)
9327c478bd9Sstevel@tonic-gate 				continue;
9337c478bd9Sstevel@tonic-gate 			if (ip->frags & htons(0x3FFF)) {
9347c478bd9Sstevel@tonic-gate 				static int warned_fragmentation = 0;
9357c478bd9Sstevel@tonic-gate 				if (!warned_fragmentation) {
9367c478bd9Sstevel@tonic-gate 					printf("ALERT: got a fragmented packet - reconfigure your server\n");
9377c478bd9Sstevel@tonic-gate 					warned_fragmentation = 1;
9387c478bd9Sstevel@tonic-gate 				}
9397c478bd9Sstevel@tonic-gate 				continue;
9407c478bd9Sstevel@tonic-gate 			}
9417c478bd9Sstevel@tonic-gate 			if (ntohs(ip->len) > ETH_MAX_MTU)
9427c478bd9Sstevel@tonic-gate 				continue;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 			ipoptlen = iplen - sizeof(struct iphdr);
9457c478bd9Sstevel@tonic-gate 			if (ipoptlen) {
9467c478bd9Sstevel@tonic-gate 				/* Delete the ip options, to guarantee
9477c478bd9Sstevel@tonic-gate 				 * good alignment, and make etherboot simpler.
9487c478bd9Sstevel@tonic-gate 				 */
9497c478bd9Sstevel@tonic-gate 				memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
9507c478bd9Sstevel@tonic-gate 					&nic.packet[ETH_HLEN + iplen],
9517c478bd9Sstevel@tonic-gate 					nic.packetlen - ipoptlen);
9527c478bd9Sstevel@tonic-gate 				nic.packetlen -= ipoptlen;
9537c478bd9Sstevel@tonic-gate 			}
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 		udp = 0;
9567c478bd9Sstevel@tonic-gate 		if (ip && (ip->protocol == IP_UDP) &&
9577c478bd9Sstevel@tonic-gate 		    (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
9587c478bd9Sstevel@tonic-gate 			udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 			/* Make certain we have a reasonable packet length */
9617c478bd9Sstevel@tonic-gate 			if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
9627c478bd9Sstevel@tonic-gate 				continue;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 			if (udp->chksum && udpchksum(ip, udp)) {
9657c478bd9Sstevel@tonic-gate 				printf("UDP checksum error\n");
9667c478bd9Sstevel@tonic-gate 				continue;
9677c478bd9Sstevel@tonic-gate 			}
9687c478bd9Sstevel@tonic-gate 		}
9697c478bd9Sstevel@tonic-gate 		result = reply(ival, ptr, ptype, ip, udp);
9707c478bd9Sstevel@tonic-gate 		if (result > 0) {
9717c478bd9Sstevel@tonic-gate 			return result;
9727c478bd9Sstevel@tonic-gate 		}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		/* If it isn't a packet the upper layer wants see if there is a default
9757c478bd9Sstevel@tonic-gate 		 * action.  This allows us reply to arp and igmp queryies.
9767c478bd9Sstevel@tonic-gate 		 */
9777c478bd9Sstevel@tonic-gate 		if ((ptype == ARP) &&
9787c478bd9Sstevel@tonic-gate 		    (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
9797c478bd9Sstevel@tonic-gate 			struct	arprequest *arpreply;
9807c478bd9Sstevel@tonic-gate 			unsigned long tmp;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 			arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
9837c478bd9Sstevel@tonic-gate 			memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9847c478bd9Sstevel@tonic-gate 			if ((arpreply->opcode == htons(ARP_REQUEST)) &&
9857c478bd9Sstevel@tonic-gate 			    (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
9867c478bd9Sstevel@tonic-gate 				arpreply->opcode = htons(ARP_REPLY);
9877c478bd9Sstevel@tonic-gate 				memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
9887c478bd9Sstevel@tonic-gate 				memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
9897c478bd9Sstevel@tonic-gate 				memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
9907c478bd9Sstevel@tonic-gate 				memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
9917c478bd9Sstevel@tonic-gate 				eth_transmit(arpreply->thwaddr, ARP,
9927c478bd9Sstevel@tonic-gate 					     sizeof(struct  arprequest),
9937c478bd9Sstevel@tonic-gate 					     arpreply);
9947c478bd9Sstevel@tonic-gate #ifdef	MDEBUG
9957c478bd9Sstevel@tonic-gate 				memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9967c478bd9Sstevel@tonic-gate 				printf("Sent ARP reply to: %@\n",tmp);
9977c478bd9Sstevel@tonic-gate #endif	/* MDEBUG */
9987c478bd9Sstevel@tonic-gate 			}
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 		process_igmp(ip, now);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 	return(0);
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate #ifdef	REQUIRE_VCI_ETHERBOOT
10067c478bd9Sstevel@tonic-gate /**************************************************************************
10077c478bd9Sstevel@tonic-gate FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
10087c478bd9Sstevel@tonic-gate On entry p points to byte count of VCI options
10097c478bd9Sstevel@tonic-gate **************************************************************************/
find_vci_etherboot(unsigned char * p)10107c478bd9Sstevel@tonic-gate static int find_vci_etherboot(unsigned char *p)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	unsigned char	*end = p + 1 + *p;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	for (p++; p < end; ) {
10157c478bd9Sstevel@tonic-gate 		if (*p == RFC2132_VENDOR_CLASS_ID) {
10167c478bd9Sstevel@tonic-gate 			if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
10177c478bd9Sstevel@tonic-gate 				return (1);
10187c478bd9Sstevel@tonic-gate 		} else if (*p == RFC1533_END)
10197c478bd9Sstevel@tonic-gate 			return (0);
10207c478bd9Sstevel@tonic-gate 		p += TAG_LEN(p) + 2;
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 	return (0);
10237c478bd9Sstevel@tonic-gate }
10247c478bd9Sstevel@tonic-gate #endif	/* REQUIRE_VCI_ETHERBOOT */
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate /**
10277c478bd9Sstevel@tonic-gate  * decode_rfc1533
10287c478bd9Sstevel@tonic-gate  *
10297c478bd9Sstevel@tonic-gate  * Decodes RFC1533 header
10307c478bd9Sstevel@tonic-gate  **/
decode_rfc1533(unsigned char * p,unsigned int block,unsigned int len,int eof)10317c478bd9Sstevel@tonic-gate int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	static unsigned char *extdata = NULL, *extend = NULL;
10347c478bd9Sstevel@tonic-gate 	unsigned char        *extpath = NULL;
10357c478bd9Sstevel@tonic-gate 	unsigned char        *endp;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if (block == 0) {
10387c478bd9Sstevel@tonic-gate 		end_of_rfc1533 = NULL;
10397c478bd9Sstevel@tonic-gate 		if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10407c478bd9Sstevel@tonic-gate 			return(0); /* no RFC 1533 header found */
10417c478bd9Sstevel@tonic-gate 		p += 4;
10427c478bd9Sstevel@tonic-gate 		endp = p + len;
10437c478bd9Sstevel@tonic-gate 	} else {
10447c478bd9Sstevel@tonic-gate 		if (block == 1) {
10457c478bd9Sstevel@tonic-gate 			if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10467c478bd9Sstevel@tonic-gate 				return(0); /* no RFC 1533 header found */
10477c478bd9Sstevel@tonic-gate 			p += 4;
10487c478bd9Sstevel@tonic-gate 			len -= 4; }
10497c478bd9Sstevel@tonic-gate 		if (extend + len <= (unsigned char *)
10507c478bd9Sstevel@tonic-gate 		    rfc1533_venddata + sizeof(rfc1533_venddata)) {
10517c478bd9Sstevel@tonic-gate 			memcpy(extend, p, len);
10527c478bd9Sstevel@tonic-gate 			extend += len;
10537c478bd9Sstevel@tonic-gate 		} else {
10547c478bd9Sstevel@tonic-gate 			printf("Overflow in vendor data buffer! Aborting...\n");
10557c478bd9Sstevel@tonic-gate 			*extdata = RFC1533_END;
10567c478bd9Sstevel@tonic-gate 			return(0);
10577c478bd9Sstevel@tonic-gate 		}
10587c478bd9Sstevel@tonic-gate 		p = extdata; endp = extend;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 	if (!eof)
10617c478bd9Sstevel@tonic-gate 		return 1;
10627c478bd9Sstevel@tonic-gate 	while (p < endp) {
10637c478bd9Sstevel@tonic-gate 		unsigned char c = *p;
10647c478bd9Sstevel@tonic-gate 		if (c == RFC1533_PAD) {
10657c478bd9Sstevel@tonic-gate 			p++;
10667c478bd9Sstevel@tonic-gate 			continue;
10677c478bd9Sstevel@tonic-gate 		}
10687c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_END) {
10697c478bd9Sstevel@tonic-gate 			end_of_rfc1533 = endp = p;
10707c478bd9Sstevel@tonic-gate 			continue;
10717c478bd9Sstevel@tonic-gate 		}
10727c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_NETMASK)
10737c478bd9Sstevel@tonic-gate 			memcpy(&netmask, p+2, sizeof(in_addr));
10747c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_GATEWAY) {
10757c478bd9Sstevel@tonic-gate 			/* This is a little simplistic, but it will
10767c478bd9Sstevel@tonic-gate 			   usually be sufficient.
10777c478bd9Sstevel@tonic-gate 			   Take only the first entry */
10787c478bd9Sstevel@tonic-gate 			if (TAG_LEN(p) >= sizeof(in_addr))
10797c478bd9Sstevel@tonic-gate 				memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
10807c478bd9Sstevel@tonic-gate 		}
10817c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_EXTENSIONPATH)
10827c478bd9Sstevel@tonic-gate 			extpath = p;
10837c478bd9Sstevel@tonic-gate 		else if (c == RFC2132_MSG_TYPE)
10847c478bd9Sstevel@tonic-gate 			dhcp_reply=*(p+2);
10857c478bd9Sstevel@tonic-gate 		else if (c == RFC2132_SRV_ID)
10867c478bd9Sstevel@tonic-gate 			memcpy(&dhcp_server, p+2, sizeof(in_addr));
10877c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_HOSTNAME) {
10887c478bd9Sstevel@tonic-gate 			hostname = p + 2;
10897c478bd9Sstevel@tonic-gate 			hostnamelen = *(p + 1);
10907c478bd9Sstevel@tonic-gate 		}
10917c478bd9Sstevel@tonic-gate 		else if (c == RFC1533_VENDOR_CONFIGFILE){
10927c478bd9Sstevel@tonic-gate 			int l = TAG_LEN (p);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 			/* Eliminate the trailing NULs according to RFC 2132.  */
10957c478bd9Sstevel@tonic-gate 			while (*(p + 2 + l - 1) == '\000' && l > 0)
10967c478bd9Sstevel@tonic-gate 				l--;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 			/* XXX: Should check if LEN is less than the maximum length
10997c478bd9Sstevel@tonic-gate 			   of CONFIG_FILE. This kind of robustness will be a goal
11007c478bd9Sstevel@tonic-gate 			   in GRUB 1.0.  */
11017c478bd9Sstevel@tonic-gate 			memcpy (config_file, p + 2, l);
11027c478bd9Sstevel@tonic-gate 			config_file[l] = 0;
11032506833eSJan Setje-Eilers 			vendor_configfile = p + 2;
11042506833eSJan Setje-Eilers 			vendor_configfile_len = l;
11052506833eSJan Setje-Eilers 			configfile_origin = CFG_150;
11067c478bd9Sstevel@tonic-gate 		}
11077c478bd9Sstevel@tonic-gate 		else {
11087c478bd9Sstevel@tonic-gate 			;
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 		p += TAG_LEN(p) + 2;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	extdata = extend = endp;
11137c478bd9Sstevel@tonic-gate 	if (block <= 0 && extpath != NULL) {
11147c478bd9Sstevel@tonic-gate 		char fname[64];
11157c478bd9Sstevel@tonic-gate 		if (TAG_LEN(extpath) >= sizeof(fname)){
11167c478bd9Sstevel@tonic-gate 			printf("Overflow in vendor data buffer! Aborting...\n");
11177c478bd9Sstevel@tonic-gate 			*extdata = RFC1533_END;
11187c478bd9Sstevel@tonic-gate 			return(0);
11197c478bd9Sstevel@tonic-gate 		}
11207c478bd9Sstevel@tonic-gate 		memcpy(fname, extpath+2, TAG_LEN(extpath));
11217c478bd9Sstevel@tonic-gate 		fname[(int)TAG_LEN(extpath)] = '\0';
11227c478bd9Sstevel@tonic-gate 		printf("Loading BOOTP-extension file: %s\n",fname);
11237c478bd9Sstevel@tonic-gate 		tftp_file_read(fname, decode_rfc1533);
11247c478bd9Sstevel@tonic-gate 	}
11257c478bd9Sstevel@tonic-gate 	return 1;	/* proceed with next block */
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate /* FIXME double check TWO_SECOND_DIVISOR */
11307c478bd9Sstevel@tonic-gate #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
11317c478bd9Sstevel@tonic-gate /**************************************************************************
11327c478bd9Sstevel@tonic-gate RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
11337c478bd9Sstevel@tonic-gate **************************************************************************/
rfc2131_sleep_interval(long base,int exp)11347c478bd9Sstevel@tonic-gate long rfc2131_sleep_interval(long base, int exp)
11357c478bd9Sstevel@tonic-gate {
11367c478bd9Sstevel@tonic-gate 	unsigned long tmo;
11377c478bd9Sstevel@tonic-gate #ifdef BACKOFF_LIMIT
11387c478bd9Sstevel@tonic-gate 	if (exp > BACKOFF_LIMIT)
11397c478bd9Sstevel@tonic-gate 		exp = BACKOFF_LIMIT;
11407c478bd9Sstevel@tonic-gate #endif
11417c478bd9Sstevel@tonic-gate 	tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
11427c478bd9Sstevel@tonic-gate 	return tmo;
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
11467c478bd9Sstevel@tonic-gate /**************************************************************************
11477c478bd9Sstevel@tonic-gate RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
11487c478bd9Sstevel@tonic-gate **************************************************************************/
rfc1112_sleep_interval(long base,int exp)11497c478bd9Sstevel@tonic-gate long rfc1112_sleep_interval(long base, int exp)
11507c478bd9Sstevel@tonic-gate {
11517c478bd9Sstevel@tonic-gate 	unsigned long divisor, tmo;
11527c478bd9Sstevel@tonic-gate #ifdef BACKOFF_LIMIT
11537c478bd9Sstevel@tonic-gate 	if (exp > BACKOFF_LIMIT)
11547c478bd9Sstevel@tonic-gate 		exp = BACKOFF_LIMIT;
11557c478bd9Sstevel@tonic-gate #endif
11567c478bd9Sstevel@tonic-gate 	divisor = RAND_MAX/(base << exp);
11577c478bd9Sstevel@tonic-gate 	tmo = random()/divisor;
11587c478bd9Sstevel@tonic-gate 	return tmo;
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate #endif /* MULTICAST_LEVEL_2 */
11617c478bd9Sstevel@tonic-gate /* ifconfig - configure network interface.  */
11627c478bd9Sstevel@tonic-gate int
ifconfig(char * ip,char * sm,char * gw,char * svr)11637c478bd9Sstevel@tonic-gate ifconfig (char *ip, char *sm, char *gw, char *svr)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate   in_addr tmp;
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate   if (sm)
11687c478bd9Sstevel@tonic-gate     {
11697c478bd9Sstevel@tonic-gate       if (! inet_aton (sm, &tmp))
11707c478bd9Sstevel@tonic-gate 	return 0;
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate       netmask = tmp.s_addr;
11737c478bd9Sstevel@tonic-gate     }
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate   if (ip)
11767c478bd9Sstevel@tonic-gate     {
11777c478bd9Sstevel@tonic-gate       if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
11787c478bd9Sstevel@tonic-gate 	return 0;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate       if (! netmask && ! sm)
11817c478bd9Sstevel@tonic-gate 	netmask = default_netmask ();
11827c478bd9Sstevel@tonic-gate     }
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate   if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
11857c478bd9Sstevel@tonic-gate     return 0;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate   /* Clear out the ARP entry.  */
11887c478bd9Sstevel@tonic-gate   grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate   if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
11917c478bd9Sstevel@tonic-gate     return 0;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate   /* Likewise.  */
11947c478bd9Sstevel@tonic-gate   grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate   if (ip || sm)
11977c478bd9Sstevel@tonic-gate     {
11987c478bd9Sstevel@tonic-gate       if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
11997c478bd9Sstevel@tonic-gate 	  || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
12007c478bd9Sstevel@tonic-gate 	  || ! netmask)
12017c478bd9Sstevel@tonic-gate 	network_ready = 0;
12027c478bd9Sstevel@tonic-gate       else
12037c478bd9Sstevel@tonic-gate 	network_ready = 1;
12047c478bd9Sstevel@tonic-gate     }
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate   update_network_configuration();
12077c478bd9Sstevel@tonic-gate   return 1;
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate  * print_network_configuration
12127c478bd9Sstevel@tonic-gate  *
12137c478bd9Sstevel@tonic-gate  * Output the network configuration. It may broke the graphic console now.:-(
12147c478bd9Sstevel@tonic-gate  */
print_network_configuration(void)12157c478bd9Sstevel@tonic-gate void print_network_configuration (void)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate 	EnterFunction("print_network_configuration");
121899ed6083Sszhou 	if (! network_ready)
121999ed6083Sszhou 		grub_printf ("Network interface not initialized yet.\n");
12207c478bd9Sstevel@tonic-gate 	else {
12212506833eSJan Setje-Eilers 		if (hostnamelen == 0)
12222506833eSJan Setje-Eilers 			etherboot_printf ("Hostname: not set\n");
12232506833eSJan Setje-Eilers 		else
12242506833eSJan Setje-Eilers 			etherboot_printf ("Hostname: %s\n", hostname);
12252506833eSJan Setje-Eilers 
12267c478bd9Sstevel@tonic-gate 		etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
12277c478bd9Sstevel@tonic-gate 		etherboot_printf ("Netmask: %@\n", netmask);
12287c478bd9Sstevel@tonic-gate 		etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
12292506833eSJan Setje-Eilers 		etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
12302506833eSJan Setje-Eilers 		if (vendor_configfile == NULL) {
12312506833eSJan Setje-Eilers 			etherboot_printf ("Site Option 150: not set\n");
12322506833eSJan Setje-Eilers 		} else {
12332506833eSJan Setje-Eilers 			/*
12342506833eSJan Setje-Eilers 			 * vendor_configfile points into the packet and
12352506833eSJan Setje-Eilers 			 * is not NULL terminated, so it needs to be
12362506833eSJan Setje-Eilers 			 * patched up before printing it out
12372506833eSJan Setje-Eilers 			 */
12382506833eSJan Setje-Eilers 			char c = vendor_configfile[vendor_configfile_len];
12392506833eSJan Setje-Eilers 			vendor_configfile[vendor_configfile_len] = '\0';
12402506833eSJan Setje-Eilers 			etherboot_printf ("Site Option 150: %s\n",
12412506833eSJan Setje-Eilers 			    vendor_configfile);
12422506833eSJan Setje-Eilers 			vendor_configfile[vendor_configfile_len] = c;
12432506833eSJan Setje-Eilers 		}
12442506833eSJan Setje-Eilers 
12452506833eSJan Setje-Eilers 		if (bootfile == NULL)
12462506833eSJan Setje-Eilers 			etherboot_printf ("BootFile: not set\n");
12472506833eSJan Setje-Eilers 		else
12482506833eSJan Setje-Eilers 			etherboot_printf ("BootFile: %s\n", bootfile);
12492506833eSJan Setje-Eilers 
12502506833eSJan Setje-Eilers 		etherboot_printf ("GRUB menu file: %s", config_file);
12512506833eSJan Setje-Eilers 		switch (configfile_origin) {
12522506833eSJan Setje-Eilers 		case CFG_HARDCODED:
12532506833eSJan Setje-Eilers 			etherboot_printf (" from hardcoded default\n");
12542506833eSJan Setje-Eilers 			break;
12552506833eSJan Setje-Eilers 		case CFG_150:
12562506833eSJan Setje-Eilers 			etherboot_printf (" from Site Option 150\n");
12572506833eSJan Setje-Eilers 			break;
12582506833eSJan Setje-Eilers 		case CFG_MAC:
12592506833eSJan Setje-Eilers 			etherboot_printf (" inferred from system MAC\n");
12602506833eSJan Setje-Eilers 			break;
12612506833eSJan Setje-Eilers 		case CFG_BOOTFILE:
12622506833eSJan Setje-Eilers 			etherboot_printf (" inferred from BootFile\n");
12632506833eSJan Setje-Eilers 			break;
12642506833eSJan Setje-Eilers 		default:
12652506833eSJan Setje-Eilers 			etherboot_printf ("\n");
12662506833eSJan Setje-Eilers 		}
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 	LeaveFunction("print_network_configuration");
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  * update_network_configuration
12737c478bd9Sstevel@tonic-gate  *
12747c478bd9Sstevel@tonic-gate  * Update network configuration for diskless clients (Solaris only)
12757c478bd9Sstevel@tonic-gate  */
update_network_configuration(void)12767c478bd9Sstevel@tonic-gate static void update_network_configuration (void)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
12797c478bd9Sstevel@tonic-gate   	struct sol_netinfo {
12807c478bd9Sstevel@tonic-gate 	  	uint8_t sn_infotype;
12817c478bd9Sstevel@tonic-gate 		uint8_t sn_mactype;
12827c478bd9Sstevel@tonic-gate 		uint8_t sn_maclen;
12837c478bd9Sstevel@tonic-gate 	  	uint8_t sn_padding;
12847c478bd9Sstevel@tonic-gate 		unsigned long sn_ciaddr;
12857c478bd9Sstevel@tonic-gate 		unsigned long sn_siaddr;
12867c478bd9Sstevel@tonic-gate 		unsigned long sn_giaddr;
12877c478bd9Sstevel@tonic-gate 		unsigned long sn_netmask;
12887c478bd9Sstevel@tonic-gate 		uint8_t sn_macaddr[1];
12897c478bd9Sstevel@tonic-gate 	} *sip;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	if (! network_ready)
12927c478bd9Sstevel@tonic-gate 	  	return;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	sip = (struct sol_netinfo *)dhcpack_buf;
12957c478bd9Sstevel@tonic-gate 	sip->sn_infotype = 0xf0;	/* something not BOOTP_REPLY */
12967c478bd9Sstevel@tonic-gate 	sip->sn_mactype = 4;		/* DL_ETHER */
12977c478bd9Sstevel@tonic-gate 	sip->sn_maclen = ETH_ALEN;
12987c478bd9Sstevel@tonic-gate 	sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
12997c478bd9Sstevel@tonic-gate 	sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
13007c478bd9Sstevel@tonic-gate 	sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
13017c478bd9Sstevel@tonic-gate 	sip->sn_netmask = netmask;
13027c478bd9Sstevel@tonic-gate 	memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
13037c478bd9Sstevel@tonic-gate 	dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
13047c478bd9Sstevel@tonic-gate #endif /* SOLARIS_NETBOOT */
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate /**
13087c478bd9Sstevel@tonic-gate  * cleanup_net
13097c478bd9Sstevel@tonic-gate  *
13107c478bd9Sstevel@tonic-gate  * Mark network unusable, and disable NICs
13117c478bd9Sstevel@tonic-gate  */
cleanup_net(void)13127c478bd9Sstevel@tonic-gate void cleanup_net (void)
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate 	if (network_ready){
13157c478bd9Sstevel@tonic-gate 		/* Stop receiving packets.  */
131699ed6083Sszhou 		if (use_bios_pxe)
131799ed6083Sszhou 			undi_pxe_disable();
131899ed6083Sszhou 		else
131999ed6083Sszhou 			eth_disable ();
13207c478bd9Sstevel@tonic-gate 		network_ready = 0;
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate }
132399ed6083Sszhou 
132499ed6083Sszhou /*******************************************************************
132599ed6083Sszhou  * dhcp implementation reusing the BIOS pxe stack
132699ed6083Sszhou  */
132799ed6083Sszhou static void
dhcp_copy(struct dhcp_t * dhcpreply)132899ed6083Sszhou dhcp_copy(struct dhcp_t *dhcpreply)
132999ed6083Sszhou {
133099ed6083Sszhou 	unsigned long time;
133199ed6083Sszhou 	int ret, len = DHCP_OPT_LEN;
133299ed6083Sszhou 
133399ed6083Sszhou 	/* fill in netinfo */
133499ed6083Sszhou 	dhcpack_length = sizeof (struct dhcp_t);
133599ed6083Sszhou 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
133699ed6083Sszhou 
133799ed6083Sszhou 	memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
133899ed6083Sszhou 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
133999ed6083Sszhou 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
134099ed6083Sszhou 	netmask = default_netmask();
134199ed6083Sszhou 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
134299ed6083Sszhou 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
134399ed6083Sszhou 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
134499ed6083Sszhou 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
13452506833eSJan Setje-Eilers 	bootfile = dhcpreply->bp_file;
134699ed6083Sszhou 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
134799ed6083Sszhou 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
134899ed6083Sszhou }
134999ed6083Sszhou 
dhcp_undi(void)135099ed6083Sszhou int dhcp_undi(void)
135199ed6083Sszhou {
135299ed6083Sszhou 	struct dhcp_t *dhcpreply;
135399ed6083Sszhou 
135499ed6083Sszhou 	if (!undi_bios_pxe((void **)&dhcpreply))
135599ed6083Sszhou 		return 0;
135699ed6083Sszhou 
135799ed6083Sszhou 	dhcp_copy(dhcpreply);
135899ed6083Sszhou 	network_ready = 1;
135999ed6083Sszhou 	use_bios_pxe = 1;
136099ed6083Sszhou 	return (1);
136199ed6083Sszhou }
1362