xref: /titanic_53/usr/src/grub/grub-0.97/netboot/nic.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
1*1b8adde7SWilliam Kucharski /**************************************************************************
2*1b8adde7SWilliam Kucharski Etherboot -  Network Bootstrap Program
3*1b8adde7SWilliam Kucharski 
4*1b8adde7SWilliam Kucharski Literature dealing with the network protocols:
5*1b8adde7SWilliam Kucharski 	ARP - RFC826
6*1b8adde7SWilliam Kucharski 	RARP - RFC903
7*1b8adde7SWilliam Kucharski         IP - RFC791
8*1b8adde7SWilliam Kucharski 	UDP - RFC768
9*1b8adde7SWilliam Kucharski 	BOOTP - RFC951, RFC2132 (vendor extensions)
10*1b8adde7SWilliam Kucharski 	DHCP - RFC2131, RFC2132 (options)
11*1b8adde7SWilliam Kucharski 	TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
12*1b8adde7SWilliam Kucharski 	RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
13*1b8adde7SWilliam Kucharski 	NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
14*1b8adde7SWilliam Kucharski 	IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
15*1b8adde7SWilliam Kucharski 
16*1b8adde7SWilliam Kucharski **************************************************************************/
17*1b8adde7SWilliam Kucharski #include "etherboot.h"
18*1b8adde7SWilliam Kucharski #include "grub.h"
19*1b8adde7SWilliam Kucharski #include "nic.h"
20*1b8adde7SWilliam Kucharski #include "elf.h" /* FOR EM_CURRENT */
21*1b8adde7SWilliam Kucharski #include "bootp.h"
22*1b8adde7SWilliam Kucharski #include "if_arp.h"
23*1b8adde7SWilliam Kucharski #include "tftp.h"
24*1b8adde7SWilliam Kucharski #include "timer.h"
25*1b8adde7SWilliam Kucharski #include "ip.h"
26*1b8adde7SWilliam Kucharski #include "udp.h"
27*1b8adde7SWilliam Kucharski 
28*1b8adde7SWilliam Kucharski /* Currently no other module uses rom, but it is available */
29*1b8adde7SWilliam Kucharski struct rom_info		rom;
30*1b8adde7SWilliam Kucharski struct arptable_t	arptable[MAX_ARP];
31*1b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
32*1b8adde7SWilliam Kucharski unsigned long last_igmpv1 = 0;
33*1b8adde7SWilliam Kucharski struct igmptable_t	igmptable[MAX_IGMP];
34*1b8adde7SWilliam Kucharski #endif
35*1b8adde7SWilliam Kucharski static unsigned long	netmask;
36*1b8adde7SWilliam Kucharski /* Used by nfs.c */
37*1b8adde7SWilliam Kucharski char *hostname = "";
38*1b8adde7SWilliam Kucharski int hostnamelen = 0;
39*1b8adde7SWilliam Kucharski /* Used by fsys_tftp.c */
40*1b8adde7SWilliam Kucharski int use_bios_pxe = 0;
41*1b8adde7SWilliam Kucharski static uint32_t xid;
42*1b8adde7SWilliam Kucharski static unsigned char *end_of_rfc1533 = NULL;
43*1b8adde7SWilliam Kucharski static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
44*1b8adde7SWilliam Kucharski static const in_addr zeroIP = { 0L };
45*1b8adde7SWilliam Kucharski static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
46*1b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
47*1b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
48*1b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
49*1b8adde7SWilliam Kucharski static int dhcp_reply;
50*1b8adde7SWilliam Kucharski static in_addr dhcp_server = { 0L };
51*1b8adde7SWilliam Kucharski static in_addr dhcp_addr = { 0L };
52*1b8adde7SWilliam Kucharski 
53*1b8adde7SWilliam Kucharski static const unsigned char dhcpdiscover[] = {
54*1b8adde7SWilliam Kucharski 	RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
55*1b8adde7SWilliam Kucharski 	RFC2132_MAX_SIZE, 2,	/* request as much as we can */
56*1b8adde7SWilliam Kucharski 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
57*1b8adde7SWilliam Kucharski 	/* Vendor class identifier */
58*1b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
59*1b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
60*1b8adde7SWilliam Kucharski 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
61*1b8adde7SWilliam Kucharski 	'0','0','2','0','0','1',
62*1b8adde7SWilliam Kucharski #else
63*1b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
64*1b8adde7SWilliam Kucharski #endif
65*1b8adde7SWilliam Kucharski 	RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
66*1b8adde7SWilliam Kucharski 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
67*1b8adde7SWilliam Kucharski };
68*1b8adde7SWilliam Kucharski static const unsigned char dhcprequest [] = {
69*1b8adde7SWilliam Kucharski 	RFC2132_MSG_TYPE,1,DHCPREQUEST,
70*1b8adde7SWilliam Kucharski 	RFC2132_SRV_ID,4,0,0,0,0,
71*1b8adde7SWilliam Kucharski 	RFC2132_REQ_ADDR,4,0,0,0,0,
72*1b8adde7SWilliam Kucharski 	RFC2132_MAX_SIZE,2,	/* request as much as we can */
73*1b8adde7SWilliam Kucharski 	ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
74*1b8adde7SWilliam Kucharski 	/* Vendor class identifier */
75*1b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
76*1b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
77*1b8adde7SWilliam Kucharski 	'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
78*1b8adde7SWilliam Kucharski 	'0','0','2','0','0','1',
79*1b8adde7SWilliam Kucharski #else
80*1b8adde7SWilliam Kucharski 	RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
81*1b8adde7SWilliam Kucharski #endif
82*1b8adde7SWilliam Kucharski 	RFC2132_PARAM_LIST,
83*1b8adde7SWilliam Kucharski 	/* 4 standard + 2 vendortags */
84*1b8adde7SWilliam Kucharski 	4 + 2,
85*1b8adde7SWilliam Kucharski 	/* Standard parameters */
86*1b8adde7SWilliam Kucharski 	RFC1533_NETMASK, RFC1533_GATEWAY,
87*1b8adde7SWilliam Kucharski 	RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
88*1b8adde7SWilliam Kucharski 	/* Etherboot vendortags */
89*1b8adde7SWilliam Kucharski 	RFC1533_VENDOR_MAGIC,
90*1b8adde7SWilliam Kucharski 	RFC1533_VENDOR_CONFIGFILE,
91*1b8adde7SWilliam Kucharski 	RFC1533_END
92*1b8adde7SWilliam Kucharski };
93*1b8adde7SWilliam Kucharski 
94*1b8adde7SWilliam Kucharski /* See nic.h */
95*1b8adde7SWilliam Kucharski int user_abort = 0;
96*1b8adde7SWilliam Kucharski int network_ready = 0;
97*1b8adde7SWilliam Kucharski 
98*1b8adde7SWilliam Kucharski #ifdef	REQUIRE_VCI_ETHERBOOT
99*1b8adde7SWilliam Kucharski int	vci_etherboot;
100*1b8adde7SWilliam Kucharski #endif
101*1b8adde7SWilliam Kucharski 
102*1b8adde7SWilliam Kucharski static void update_network_configuration(void);
103*1b8adde7SWilliam Kucharski 
104*1b8adde7SWilliam Kucharski static int dummy(void *unused __unused)
105*1b8adde7SWilliam Kucharski {
106*1b8adde7SWilliam Kucharski 	return (0);
107*1b8adde7SWilliam Kucharski }
108*1b8adde7SWilliam Kucharski 
109*1b8adde7SWilliam Kucharski /* Careful.  We need an aligned buffer to avoid problems on machines
110*1b8adde7SWilliam Kucharski  * that care about alignment.  To trivally align the ethernet data
111*1b8adde7SWilliam Kucharski  * (the ip hdr and arp requests) we offset the packet by 2 bytes.
112*1b8adde7SWilliam Kucharski  * leaving the ethernet data 16 byte aligned.  Beyond this
113*1b8adde7SWilliam Kucharski  * we use memmove but this makes the common cast simple and fast.
114*1b8adde7SWilliam Kucharski  */
115*1b8adde7SWilliam Kucharski static char	packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
116*1b8adde7SWilliam Kucharski 
117*1b8adde7SWilliam Kucharski struct nic	nic =
118*1b8adde7SWilliam Kucharski {
119*1b8adde7SWilliam Kucharski 	{
120*1b8adde7SWilliam Kucharski 		0,				/* dev.disable */
121*1b8adde7SWilliam Kucharski 		{
122*1b8adde7SWilliam Kucharski 			0,
123*1b8adde7SWilliam Kucharski 			0,
124*1b8adde7SWilliam Kucharski 			PCI_BUS_TYPE,
125*1b8adde7SWilliam Kucharski 		},				/* dev.devid */
126*1b8adde7SWilliam Kucharski 		0,				/* index */
127*1b8adde7SWilliam Kucharski 		0,				/* type */
128*1b8adde7SWilliam Kucharski 		PROBE_FIRST,			/* how_pobe */
129*1b8adde7SWilliam Kucharski 		PROBE_NONE,			/* to_probe */
130*1b8adde7SWilliam Kucharski 		0,				/* failsafe */
131*1b8adde7SWilliam Kucharski 		0,				/* type_index */
132*1b8adde7SWilliam Kucharski 		{},				/* state */
133*1b8adde7SWilliam Kucharski 	},
134*1b8adde7SWilliam Kucharski 	(int (*)(struct nic *, int))dummy,      /* poll */
135*1b8adde7SWilliam Kucharski 	(void (*)(struct nic *, const char *,
136*1b8adde7SWilliam Kucharski 		unsigned int, unsigned int,
137*1b8adde7SWilliam Kucharski 		const char *))dummy,		/* transmit */
138*1b8adde7SWilliam Kucharski 	(void (*)(struct nic *, irq_action_t))dummy, /* irq */
139*1b8adde7SWilliam Kucharski 	0,					/* flags */
140*1b8adde7SWilliam Kucharski 	&rom,					/* rom_info */
141*1b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].node,		/* node_addr */
142*1b8adde7SWilliam Kucharski 	packet + ETH_DATA_ALIGN,		/* packet */
143*1b8adde7SWilliam Kucharski 	0,					/* packetlen */
144*1b8adde7SWilliam Kucharski 	0,			/* ioaddr */
145*1b8adde7SWilliam Kucharski 	0,			/* irqno */
146*1b8adde7SWilliam Kucharski 	NULL,					/* priv_data */
147*1b8adde7SWilliam Kucharski };
148*1b8adde7SWilliam Kucharski 
149*1b8adde7SWilliam Kucharski 
150*1b8adde7SWilliam Kucharski 
151*1b8adde7SWilliam Kucharski int grub_eth_probe(void)
152*1b8adde7SWilliam Kucharski {
153*1b8adde7SWilliam Kucharski 	static int probed = 0;
154*1b8adde7SWilliam Kucharski 	struct dev *dev;
155*1b8adde7SWilliam Kucharski 
156*1b8adde7SWilliam Kucharski 	EnterFunction("grub_eth_probe");
157*1b8adde7SWilliam Kucharski 
158*1b8adde7SWilliam Kucharski 	if (probed)
159*1b8adde7SWilliam Kucharski 		return 1;
160*1b8adde7SWilliam Kucharski 
161*1b8adde7SWilliam Kucharski 	network_ready = 0;
162*1b8adde7SWilliam Kucharski 	grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
163*1b8adde7SWilliam Kucharski 	dev = &nic.dev;
164*1b8adde7SWilliam Kucharski 	dev->how_probe = -1;
165*1b8adde7SWilliam Kucharski 	dev->type = NIC_DRIVER;
166*1b8adde7SWilliam Kucharski 	dev->failsafe = 1;
167*1b8adde7SWilliam Kucharski 	rom = *((struct rom_info *)ROM_INFO_LOCATION);
168*1b8adde7SWilliam Kucharski 
169*1b8adde7SWilliam Kucharski 	probed = (eth_probe(dev) == PROBE_WORKED);
170*1b8adde7SWilliam Kucharski 
171*1b8adde7SWilliam Kucharski 	LeaveFunction("grub_eth_probe");
172*1b8adde7SWilliam Kucharski 	return probed;
173*1b8adde7SWilliam Kucharski }
174*1b8adde7SWilliam Kucharski 
175*1b8adde7SWilliam Kucharski int eth_probe(struct dev *dev)
176*1b8adde7SWilliam Kucharski {
177*1b8adde7SWilliam Kucharski 	return probe(dev);
178*1b8adde7SWilliam Kucharski }
179*1b8adde7SWilliam Kucharski 
180*1b8adde7SWilliam Kucharski int eth_poll(int retrieve)
181*1b8adde7SWilliam Kucharski {
182*1b8adde7SWilliam Kucharski 	return ((*nic.poll)(&nic, retrieve));
183*1b8adde7SWilliam Kucharski }
184*1b8adde7SWilliam Kucharski 
185*1b8adde7SWilliam Kucharski void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
186*1b8adde7SWilliam Kucharski {
187*1b8adde7SWilliam Kucharski 	(*nic.transmit)(&nic, d, t, s, p);
188*1b8adde7SWilliam Kucharski 	if (t == IP) twiddle();
189*1b8adde7SWilliam Kucharski }
190*1b8adde7SWilliam Kucharski 
191*1b8adde7SWilliam Kucharski void eth_disable(void)
192*1b8adde7SWilliam Kucharski {
193*1b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
194*1b8adde7SWilliam Kucharski 	int i;
195*1b8adde7SWilliam Kucharski 	for(i = 0; i < MAX_IGMP; i++) {
196*1b8adde7SWilliam Kucharski 		leave_group(i);
197*1b8adde7SWilliam Kucharski 	}
198*1b8adde7SWilliam Kucharski #endif
199*1b8adde7SWilliam Kucharski 	disable(&nic.dev);
200*1b8adde7SWilliam Kucharski }
201*1b8adde7SWilliam Kucharski 
202*1b8adde7SWilliam Kucharski void eth_irq (irq_action_t action)
203*1b8adde7SWilliam Kucharski {
204*1b8adde7SWilliam Kucharski 	(*nic.irq)(&nic,action);
205*1b8adde7SWilliam Kucharski }
206*1b8adde7SWilliam Kucharski 
207*1b8adde7SWilliam Kucharski /**************************************************************************
208*1b8adde7SWilliam Kucharski IPCHKSUM - Checksum IP Header
209*1b8adde7SWilliam Kucharski **************************************************************************/
210*1b8adde7SWilliam Kucharski uint16_t ipchksum(const void *data, unsigned long length)
211*1b8adde7SWilliam Kucharski {
212*1b8adde7SWilliam Kucharski 	unsigned long sum;
213*1b8adde7SWilliam Kucharski 	unsigned long i;
214*1b8adde7SWilliam Kucharski 	const uint8_t *ptr;
215*1b8adde7SWilliam Kucharski 
216*1b8adde7SWilliam Kucharski 	/* In the most straight forward way possible,
217*1b8adde7SWilliam Kucharski 	 * compute an ip style checksum.
218*1b8adde7SWilliam Kucharski 	 */
219*1b8adde7SWilliam Kucharski 	sum = 0;
220*1b8adde7SWilliam Kucharski 	ptr = data;
221*1b8adde7SWilliam Kucharski 	for(i = 0; i < length; i++) {
222*1b8adde7SWilliam Kucharski 		unsigned long value;
223*1b8adde7SWilliam Kucharski 		value = ptr[i];
224*1b8adde7SWilliam Kucharski 		if (i & 1) {
225*1b8adde7SWilliam Kucharski 			value <<= 8;
226*1b8adde7SWilliam Kucharski 		}
227*1b8adde7SWilliam Kucharski 		/* Add the new value */
228*1b8adde7SWilliam Kucharski 		sum += value;
229*1b8adde7SWilliam Kucharski 		/* Wrap around the carry */
230*1b8adde7SWilliam Kucharski 		if (sum > 0xFFFF) {
231*1b8adde7SWilliam Kucharski 			sum = (sum + (sum >> 16)) & 0xFFFF;
232*1b8adde7SWilliam Kucharski 		}
233*1b8adde7SWilliam Kucharski 	}
234*1b8adde7SWilliam Kucharski 	return (~cpu_to_le16(sum)) & 0xFFFF;
235*1b8adde7SWilliam Kucharski }
236*1b8adde7SWilliam Kucharski 
237*1b8adde7SWilliam Kucharski uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
238*1b8adde7SWilliam Kucharski {
239*1b8adde7SWilliam Kucharski 	unsigned long checksum;
240*1b8adde7SWilliam Kucharski 	sum = ~sum & 0xFFFF;
241*1b8adde7SWilliam Kucharski 	new = ~new & 0xFFFF;
242*1b8adde7SWilliam Kucharski 	if (offset & 1) {
243*1b8adde7SWilliam Kucharski 		/* byte swap the sum if it came from an odd offset
244*1b8adde7SWilliam Kucharski 		 * since the computation is endian independant this
245*1b8adde7SWilliam Kucharski 		 * works.
246*1b8adde7SWilliam Kucharski 		 */
247*1b8adde7SWilliam Kucharski 		new = bswap_16(new);
248*1b8adde7SWilliam Kucharski 	}
249*1b8adde7SWilliam Kucharski 	checksum = sum + new;
250*1b8adde7SWilliam Kucharski 	if (checksum > 0xFFFF) {
251*1b8adde7SWilliam Kucharski 		checksum -= 0xFFFF;
252*1b8adde7SWilliam Kucharski 	}
253*1b8adde7SWilliam Kucharski 	return (~checksum) & 0xFFFF;
254*1b8adde7SWilliam Kucharski }
255*1b8adde7SWilliam Kucharski 
256*1b8adde7SWilliam Kucharski /**************************************************************************
257*1b8adde7SWilliam Kucharski DEFAULT_NETMASK - Return default netmask for IP address
258*1b8adde7SWilliam Kucharski **************************************************************************/
259*1b8adde7SWilliam Kucharski static inline unsigned long default_netmask(void)
260*1b8adde7SWilliam Kucharski {
261*1b8adde7SWilliam Kucharski 	int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
262*1b8adde7SWilliam Kucharski 	if (net <= 127)
263*1b8adde7SWilliam Kucharski 		return(htonl(0xff000000));
264*1b8adde7SWilliam Kucharski 	else if (net < 192)
265*1b8adde7SWilliam Kucharski 		return(htonl(0xffff0000));
266*1b8adde7SWilliam Kucharski 	else
267*1b8adde7SWilliam Kucharski 		return(htonl(0xffffff00));
268*1b8adde7SWilliam Kucharski }
269*1b8adde7SWilliam Kucharski 
270*1b8adde7SWilliam Kucharski /**************************************************************************
271*1b8adde7SWilliam Kucharski IP_TRANSMIT - Send an IP datagram
272*1b8adde7SWilliam Kucharski **************************************************************************/
273*1b8adde7SWilliam Kucharski static int await_arp(int ival, void *ptr,
274*1b8adde7SWilliam Kucharski 	unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
275*1b8adde7SWilliam Kucharski {
276*1b8adde7SWilliam Kucharski 	struct	arprequest *arpreply;
277*1b8adde7SWilliam Kucharski 	if (ptype != ARP)
278*1b8adde7SWilliam Kucharski 		return 0;
279*1b8adde7SWilliam Kucharski 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
280*1b8adde7SWilliam Kucharski 		return 0;
281*1b8adde7SWilliam Kucharski 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
282*1b8adde7SWilliam Kucharski 
283*1b8adde7SWilliam Kucharski 	if (arpreply->opcode != htons(ARP_REPLY))
284*1b8adde7SWilliam Kucharski 		return 0;
285*1b8adde7SWilliam Kucharski 	if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
286*1b8adde7SWilliam Kucharski 		return 0;
287*1b8adde7SWilliam Kucharski 	memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
288*1b8adde7SWilliam Kucharski 	return 1;
289*1b8adde7SWilliam Kucharski }
290*1b8adde7SWilliam Kucharski 
291*1b8adde7SWilliam Kucharski int ip_transmit(int len, const void *buf)
292*1b8adde7SWilliam Kucharski {
293*1b8adde7SWilliam Kucharski 	unsigned long destip;
294*1b8adde7SWilliam Kucharski 	struct iphdr *ip;
295*1b8adde7SWilliam Kucharski 	struct arprequest arpreq;
296*1b8adde7SWilliam Kucharski 	int arpentry, i;
297*1b8adde7SWilliam Kucharski 	int retry;
298*1b8adde7SWilliam Kucharski 
299*1b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
300*1b8adde7SWilliam Kucharski 	destip = ip->dest.s_addr;
301*1b8adde7SWilliam Kucharski 	if (destip == IP_BROADCAST) {
302*1b8adde7SWilliam Kucharski 		eth_transmit(broadcast, IP, len, buf);
303*1b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL1
304*1b8adde7SWilliam Kucharski 	} else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
305*1b8adde7SWilliam Kucharski 		unsigned char multicast[6];
306*1b8adde7SWilliam Kucharski 		unsigned long hdestip;
307*1b8adde7SWilliam Kucharski 		hdestip = ntohl(destip);
308*1b8adde7SWilliam Kucharski 		multicast[0] = 0x01;
309*1b8adde7SWilliam Kucharski 		multicast[1] = 0x00;
310*1b8adde7SWilliam Kucharski 		multicast[2] = 0x5e;
311*1b8adde7SWilliam Kucharski 		multicast[3] = (hdestip >> 16) & 0x7;
312*1b8adde7SWilliam Kucharski 		multicast[4] = (hdestip >> 8) & 0xff;
313*1b8adde7SWilliam Kucharski 		multicast[5] = hdestip & 0xff;
314*1b8adde7SWilliam Kucharski 		eth_transmit(multicast, IP, len, buf);
315*1b8adde7SWilliam Kucharski #endif
316*1b8adde7SWilliam Kucharski 	} else {
317*1b8adde7SWilliam Kucharski 		if (((destip & netmask) !=
318*1b8adde7SWilliam Kucharski 		     (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
319*1b8adde7SWilliam Kucharski 		    arptable[ARP_GATEWAY].ipaddr.s_addr)
320*1b8adde7SWilliam Kucharski 			destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
321*1b8adde7SWilliam Kucharski 		for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
322*1b8adde7SWilliam Kucharski 			if (arptable[arpentry].ipaddr.s_addr == destip) break;
323*1b8adde7SWilliam Kucharski 		if (arpentry == MAX_ARP) {
324*1b8adde7SWilliam Kucharski 			printf("%@ is not in my arp table!\n", destip);
325*1b8adde7SWilliam Kucharski 			return(0);
326*1b8adde7SWilliam Kucharski 		}
327*1b8adde7SWilliam Kucharski 		for (i = 0; i < ETH_ALEN; i++)
328*1b8adde7SWilliam Kucharski 			if (arptable[arpentry].node[i])
329*1b8adde7SWilliam Kucharski 				break;
330*1b8adde7SWilliam Kucharski 		if (i == ETH_ALEN) {	/* Need to do arp request */
331*1b8adde7SWilliam Kucharski 			arpreq.hwtype = htons(1);
332*1b8adde7SWilliam Kucharski 			arpreq.protocol = htons(IP);
333*1b8adde7SWilliam Kucharski 			arpreq.hwlen = ETH_ALEN;
334*1b8adde7SWilliam Kucharski 			arpreq.protolen = 4;
335*1b8adde7SWilliam Kucharski 			arpreq.opcode = htons(ARP_REQUEST);
336*1b8adde7SWilliam Kucharski 			memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
337*1b8adde7SWilliam Kucharski 			memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
338*1b8adde7SWilliam Kucharski 			memset(arpreq.thwaddr, 0, ETH_ALEN);
339*1b8adde7SWilliam Kucharski 			memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
340*1b8adde7SWilliam Kucharski 			for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
341*1b8adde7SWilliam Kucharski 				long timeout;
342*1b8adde7SWilliam Kucharski 				eth_transmit(broadcast, ARP, sizeof(arpreq),
343*1b8adde7SWilliam Kucharski 					&arpreq);
344*1b8adde7SWilliam Kucharski 				timeout = rfc2131_sleep_interval(TIMEOUT, retry);
345*1b8adde7SWilliam Kucharski 				if (await_reply(await_arp, arpentry,
346*1b8adde7SWilliam Kucharski 					arpreq.tipaddr, timeout)) goto xmit;
347*1b8adde7SWilliam Kucharski 			}
348*1b8adde7SWilliam Kucharski 			return(0);
349*1b8adde7SWilliam Kucharski 		}
350*1b8adde7SWilliam Kucharski xmit:
351*1b8adde7SWilliam Kucharski 		eth_transmit(arptable[arpentry].node, IP, len, buf);
352*1b8adde7SWilliam Kucharski 	}
353*1b8adde7SWilliam Kucharski 	return 1;
354*1b8adde7SWilliam Kucharski }
355*1b8adde7SWilliam Kucharski 
356*1b8adde7SWilliam Kucharski void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
357*1b8adde7SWilliam Kucharski 	int len, const void *buf)
358*1b8adde7SWilliam Kucharski {
359*1b8adde7SWilliam Kucharski 	struct iphdr *ip;
360*1b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
361*1b8adde7SWilliam Kucharski 	ip->verhdrlen = 0x45;
362*1b8adde7SWilliam Kucharski 	ip->verhdrlen += (option_len/4);
363*1b8adde7SWilliam Kucharski 	ip->service = 0;
364*1b8adde7SWilliam Kucharski 	ip->len = htons(len);
365*1b8adde7SWilliam Kucharski 	ip->ident = 0;
366*1b8adde7SWilliam Kucharski 	ip->frags = 0; /* Should we set don't fragment? */
367*1b8adde7SWilliam Kucharski 	ip->ttl = ttl;
368*1b8adde7SWilliam Kucharski 	ip->protocol = protocol;
369*1b8adde7SWilliam Kucharski 	ip->chksum = 0;
370*1b8adde7SWilliam Kucharski 	ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
371*1b8adde7SWilliam Kucharski 	ip->dest.s_addr = destip;
372*1b8adde7SWilliam Kucharski 	ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
373*1b8adde7SWilliam Kucharski }
374*1b8adde7SWilliam Kucharski 
375*1b8adde7SWilliam Kucharski static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
376*1b8adde7SWilliam Kucharski {
377*1b8adde7SWilliam Kucharski 	struct udp_pseudo_hdr pseudo;
378*1b8adde7SWilliam Kucharski 	uint16_t checksum;
379*1b8adde7SWilliam Kucharski 
380*1b8adde7SWilliam Kucharski 	/* Compute the pseudo header */
381*1b8adde7SWilliam Kucharski 	pseudo.src.s_addr  = ip->src.s_addr;
382*1b8adde7SWilliam Kucharski 	pseudo.dest.s_addr = ip->dest.s_addr;
383*1b8adde7SWilliam Kucharski 	pseudo.unused      = 0;
384*1b8adde7SWilliam Kucharski 	pseudo.protocol    = IP_UDP;
385*1b8adde7SWilliam Kucharski 	pseudo.len         = udp->len;
386*1b8adde7SWilliam Kucharski 
387*1b8adde7SWilliam Kucharski 	/* Sum the pseudo header */
388*1b8adde7SWilliam Kucharski 	checksum = ipchksum(&pseudo, 12);
389*1b8adde7SWilliam Kucharski 
390*1b8adde7SWilliam Kucharski 	/* Sum the rest of the udp packet */
391*1b8adde7SWilliam Kucharski 	checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
392*1b8adde7SWilliam Kucharski 	return checksum;
393*1b8adde7SWilliam Kucharski }
394*1b8adde7SWilliam Kucharski 
395*1b8adde7SWilliam Kucharski 
396*1b8adde7SWilliam Kucharski void build_udp_hdr(unsigned long destip,
397*1b8adde7SWilliam Kucharski 	unsigned int srcsock, unsigned int destsock, int ttl,
398*1b8adde7SWilliam Kucharski 	int len, const void *buf)
399*1b8adde7SWilliam Kucharski {
400*1b8adde7SWilliam Kucharski 	struct iphdr *ip;
401*1b8adde7SWilliam Kucharski 	struct udphdr *udp;
402*1b8adde7SWilliam Kucharski 	ip = (struct iphdr *)buf;
403*1b8adde7SWilliam Kucharski 	build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
404*1b8adde7SWilliam Kucharski 	udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
405*1b8adde7SWilliam Kucharski 	udp->src = htons(srcsock);
406*1b8adde7SWilliam Kucharski 	udp->dest = htons(destsock);
407*1b8adde7SWilliam Kucharski 	udp->len = htons(len - sizeof(struct iphdr));
408*1b8adde7SWilliam Kucharski 	udp->chksum = 0;
409*1b8adde7SWilliam Kucharski 	if ((udp->chksum = udpchksum(ip, udp)) == 0)
410*1b8adde7SWilliam Kucharski 		udp->chksum = 0xffff;
411*1b8adde7SWilliam Kucharski }
412*1b8adde7SWilliam Kucharski 
413*1b8adde7SWilliam Kucharski 
414*1b8adde7SWilliam Kucharski /**************************************************************************
415*1b8adde7SWilliam Kucharski UDP_TRANSMIT - Send an UDP datagram
416*1b8adde7SWilliam Kucharski **************************************************************************/
417*1b8adde7SWilliam Kucharski int udp_transmit(unsigned long destip, unsigned int srcsock,
418*1b8adde7SWilliam Kucharski 	unsigned int destsock, int len, const void *buf)
419*1b8adde7SWilliam Kucharski {
420*1b8adde7SWilliam Kucharski 	build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
421*1b8adde7SWilliam Kucharski 	return ip_transmit(len, buf);
422*1b8adde7SWilliam Kucharski }
423*1b8adde7SWilliam Kucharski 
424*1b8adde7SWilliam Kucharski /**************************************************************************
425*1b8adde7SWilliam Kucharski QDRAIN - clear the nic's receive queue
426*1b8adde7SWilliam Kucharski **************************************************************************/
427*1b8adde7SWilliam Kucharski static int await_qdrain(int ival __unused, void *ptr __unused,
428*1b8adde7SWilliam Kucharski 	unsigned short ptype __unused,
429*1b8adde7SWilliam Kucharski 	struct iphdr *ip __unused, struct udphdr *udp __unused)
430*1b8adde7SWilliam Kucharski {
431*1b8adde7SWilliam Kucharski 	return 0;
432*1b8adde7SWilliam Kucharski }
433*1b8adde7SWilliam Kucharski 
434*1b8adde7SWilliam Kucharski void rx_qdrain(void)
435*1b8adde7SWilliam Kucharski {
436*1b8adde7SWilliam Kucharski 	/* Clear out the Rx queue first.  It contains nothing of interest,
437*1b8adde7SWilliam Kucharski 	 * except possibly ARP requests from the DHCP/TFTP server.  We use
438*1b8adde7SWilliam Kucharski 	 * polling throughout Etherboot, so some time may have passed since we
439*1b8adde7SWilliam Kucharski 	 * last polled the receive queue, which may now be filled with
440*1b8adde7SWilliam Kucharski 	 * broadcast packets.  This will cause the reply to the packets we are
441*1b8adde7SWilliam Kucharski 	 * about to send to be lost immediately.  Not very clever.  */
442*1b8adde7SWilliam Kucharski 	await_reply(await_qdrain, 0, NULL, 0);
443*1b8adde7SWilliam Kucharski }
444*1b8adde7SWilliam Kucharski 
445*1b8adde7SWilliam Kucharski /**
446*1b8adde7SWilliam Kucharski  * rarp
447*1b8adde7SWilliam Kucharski  *
448*1b8adde7SWilliam Kucharski  * Get IP address by rarp. Just copy from etherboot
449*1b8adde7SWilliam Kucharski  **/
450*1b8adde7SWilliam Kucharski static int await_rarp(int ival, void *ptr, unsigned short ptype,
451*1b8adde7SWilliam Kucharski 		      struct iphdr *ip, struct udphdr *udp)
452*1b8adde7SWilliam Kucharski {
453*1b8adde7SWilliam Kucharski 	struct arprequest *arpreply;
454*1b8adde7SWilliam Kucharski 	if (ptype != RARP)
455*1b8adde7SWilliam Kucharski 		return 0;
456*1b8adde7SWilliam Kucharski 	if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
457*1b8adde7SWilliam Kucharski 		return 0;
458*1b8adde7SWilliam Kucharski 	arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
459*1b8adde7SWilliam Kucharski 	if (arpreply->opcode != htons(RARP_REPLY))
460*1b8adde7SWilliam Kucharski 		return 0;
461*1b8adde7SWilliam Kucharski 	if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
462*1b8adde7SWilliam Kucharski 		memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
463*1b8adde7SWilliam Kucharski 		memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
464*1b8adde7SWilliam Kucharski 		memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
465*1b8adde7SWilliam Kucharski 		memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
466*1b8adde7SWilliam Kucharski 		return 1;
467*1b8adde7SWilliam Kucharski 	}
468*1b8adde7SWilliam Kucharski 	return 0;
469*1b8adde7SWilliam Kucharski }
470*1b8adde7SWilliam Kucharski 
471*1b8adde7SWilliam Kucharski int rarp(void)
472*1b8adde7SWilliam Kucharski {
473*1b8adde7SWilliam Kucharski 	int retry;
474*1b8adde7SWilliam Kucharski 
475*1b8adde7SWilliam Kucharski 	/* arp and rarp requests share the same packet structure. */
476*1b8adde7SWilliam Kucharski 	struct arprequest rarpreq;
477*1b8adde7SWilliam Kucharski 
478*1b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
479*1b8adde7SWilliam Kucharski 		return 0;
480*1b8adde7SWilliam Kucharski 	network_ready = 0;
481*1b8adde7SWilliam Kucharski 
482*1b8adde7SWilliam Kucharski 	memset(&rarpreq, 0, sizeof(rarpreq));
483*1b8adde7SWilliam Kucharski 
484*1b8adde7SWilliam Kucharski 	rarpreq.hwtype = htons(1);
485*1b8adde7SWilliam Kucharski 	rarpreq.protocol = htons(IP);
486*1b8adde7SWilliam Kucharski 	rarpreq.hwlen = ETH_ALEN;
487*1b8adde7SWilliam Kucharski 	rarpreq.protolen = 4;
488*1b8adde7SWilliam Kucharski 	rarpreq.opcode = htons(RARP_REQUEST);
489*1b8adde7SWilliam Kucharski 	memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
490*1b8adde7SWilliam Kucharski 	/* sipaddr is already zeroed out */
491*1b8adde7SWilliam Kucharski 	memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
492*1b8adde7SWilliam Kucharski 	/* tipaddr is already zeroed out */
493*1b8adde7SWilliam Kucharski 
494*1b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
495*1b8adde7SWilliam Kucharski 		long timeout;
496*1b8adde7SWilliam Kucharski 		eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
497*1b8adde7SWilliam Kucharski 
498*1b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry);
499*1b8adde7SWilliam Kucharski 		if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
500*1b8adde7SWilliam Kucharski 			break;
501*1b8adde7SWilliam Kucharski 		if (user_abort)
502*1b8adde7SWilliam Kucharski 			return 0;
503*1b8adde7SWilliam Kucharski 	}
504*1b8adde7SWilliam Kucharski 
505*1b8adde7SWilliam Kucharski 	if (retry == MAX_ARP_RETRIES) {
506*1b8adde7SWilliam Kucharski 		return (0);
507*1b8adde7SWilliam Kucharski 	}
508*1b8adde7SWilliam Kucharski 
509*1b8adde7SWilliam Kucharski 	network_ready = 1;
510*1b8adde7SWilliam Kucharski   	update_network_configuration();
511*1b8adde7SWilliam Kucharski 	return (1);
512*1b8adde7SWilliam Kucharski }
513*1b8adde7SWilliam Kucharski 
514*1b8adde7SWilliam Kucharski /**
515*1b8adde7SWilliam Kucharski  * bootp
516*1b8adde7SWilliam Kucharski  *
517*1b8adde7SWilliam Kucharski  * Get IP address by bootp, segregate from bootp in etherboot.
518*1b8adde7SWilliam Kucharski  **/
519*1b8adde7SWilliam Kucharski static int await_bootp(int ival __unused, void *ptr __unused,
520*1b8adde7SWilliam Kucharski 	unsigned short ptype __unused, struct iphdr *ip __unused,
521*1b8adde7SWilliam Kucharski 	struct udphdr *udp)
522*1b8adde7SWilliam Kucharski {
523*1b8adde7SWilliam Kucharski 	struct	bootp_t *bootpreply;
524*1b8adde7SWilliam Kucharski 	int len;		/* Length of vendor */
525*1b8adde7SWilliam Kucharski 
526*1b8adde7SWilliam Kucharski 	if (!udp) {
527*1b8adde7SWilliam Kucharski 		return 0;
528*1b8adde7SWilliam Kucharski 	}
529*1b8adde7SWilliam Kucharski 	bootpreply = (struct bootp_t *)
530*1b8adde7SWilliam Kucharski 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
531*1b8adde7SWilliam Kucharski 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
532*1b8adde7SWilliam Kucharski 		sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
533*1b8adde7SWilliam Kucharski 	if (len < 0) {
534*1b8adde7SWilliam Kucharski 		return 0;
535*1b8adde7SWilliam Kucharski 	}
536*1b8adde7SWilliam Kucharski 	if (udp->dest != htons(BOOTP_CLIENT))
537*1b8adde7SWilliam Kucharski 		return 0;
538*1b8adde7SWilliam Kucharski 	if (bootpreply->bp_op != BOOTP_REPLY)
539*1b8adde7SWilliam Kucharski 		return 0;
540*1b8adde7SWilliam Kucharski 	if (bootpreply->bp_xid != xid)
541*1b8adde7SWilliam Kucharski 		return 0;
542*1b8adde7SWilliam Kucharski 	if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
543*1b8adde7SWilliam Kucharski 		return 0;
544*1b8adde7SWilliam Kucharski 	if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
545*1b8adde7SWilliam Kucharski 	    (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
546*1b8adde7SWilliam Kucharski 		return 0;
547*1b8adde7SWilliam Kucharski 	}
548*1b8adde7SWilliam Kucharski 
549*1b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
550*1b8adde7SWilliam Kucharski 	/* fill in netinfo */
551*1b8adde7SWilliam Kucharski 	dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
552*1b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
553*1b8adde7SWilliam Kucharski #endif
554*1b8adde7SWilliam Kucharski 
555*1b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
556*1b8adde7SWilliam Kucharski 	netmask = default_netmask();
557*1b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
558*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
559*1b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
560*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
561*1b8adde7SWilliam Kucharski 	/* We don't care bootpreply->bp_file, it must be 'pxegrub':-) */
562*1b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
563*1b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
564*1b8adde7SWilliam Kucharski 	return(1);
565*1b8adde7SWilliam Kucharski }
566*1b8adde7SWilliam Kucharski 
567*1b8adde7SWilliam Kucharski int bootp(void)
568*1b8adde7SWilliam Kucharski {
569*1b8adde7SWilliam Kucharski 	int retry;
570*1b8adde7SWilliam Kucharski 	struct bootpip_t ip;
571*1b8adde7SWilliam Kucharski 	unsigned long  starttime;
572*1b8adde7SWilliam Kucharski 
573*1b8adde7SWilliam Kucharski 	EnterFunction("bootp");
574*1b8adde7SWilliam Kucharski 
575*1b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
576*1b8adde7SWilliam Kucharski 		return 0;
577*1b8adde7SWilliam Kucharski 	network_ready = 0;
578*1b8adde7SWilliam Kucharski 
579*1b8adde7SWilliam Kucharski 	memset(&ip, 0, sizeof(struct bootpip_t));
580*1b8adde7SWilliam Kucharski 	ip.bp.bp_op = BOOTP_REQUEST;
581*1b8adde7SWilliam Kucharski 	ip.bp.bp_htype = 1;
582*1b8adde7SWilliam Kucharski 	ip.bp.bp_hlen = ETH_ALEN;
583*1b8adde7SWilliam Kucharski 	starttime = currticks();
584*1b8adde7SWilliam Kucharski 	/* Use lower 32 bits of node address, more likely to be
585*1b8adde7SWilliam Kucharski 	   distinct than the time since booting */
586*1b8adde7SWilliam Kucharski 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
587*1b8adde7SWilliam Kucharski 	ip.bp.bp_xid = xid += htonl(starttime);
588*1b8adde7SWilliam Kucharski 	/* bp_secs defaults to zero */
589*1b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
590*1b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
591*1b8adde7SWilliam Kucharski 
592*1b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
593*1b8adde7SWilliam Kucharski 		long timeout;
594*1b8adde7SWilliam Kucharski 
595*1b8adde7SWilliam Kucharski 		rx_qdrain();
596*1b8adde7SWilliam Kucharski 
597*1b8adde7SWilliam Kucharski 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
598*1b8adde7SWilliam Kucharski 			sizeof(struct bootpip_t), &ip);
599*1b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
600*1b8adde7SWilliam Kucharski 		if (await_reply(await_bootp, 0, NULL, timeout)){
601*1b8adde7SWilliam Kucharski 			network_ready = 1;
602*1b8adde7SWilliam Kucharski 			return(1);
603*1b8adde7SWilliam Kucharski 		}
604*1b8adde7SWilliam Kucharski 		if (user_abort)
605*1b8adde7SWilliam Kucharski 			return 0;
606*1b8adde7SWilliam Kucharski 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
607*1b8adde7SWilliam Kucharski 	}
608*1b8adde7SWilliam Kucharski 	return(0);
609*1b8adde7SWilliam Kucharski }
610*1b8adde7SWilliam Kucharski 
611*1b8adde7SWilliam Kucharski /**
612*1b8adde7SWilliam Kucharski  * dhcp
613*1b8adde7SWilliam Kucharski  *
614*1b8adde7SWilliam Kucharski  * Get IP address by dhcp, segregate from bootp in etherboot.
615*1b8adde7SWilliam Kucharski  **/
616*1b8adde7SWilliam Kucharski static int await_dhcp(int ival __unused, void *ptr __unused,
617*1b8adde7SWilliam Kucharski 	unsigned short ptype __unused, struct iphdr *ip __unused,
618*1b8adde7SWilliam Kucharski 	struct udphdr *udp)
619*1b8adde7SWilliam Kucharski {
620*1b8adde7SWilliam Kucharski 	struct	dhcp_t *dhcpreply;
621*1b8adde7SWilliam Kucharski 	int len;
622*1b8adde7SWilliam Kucharski 
623*1b8adde7SWilliam Kucharski 	if (!udp) {
624*1b8adde7SWilliam Kucharski 		return 0;
625*1b8adde7SWilliam Kucharski 	}
626*1b8adde7SWilliam Kucharski 	dhcpreply = (struct dhcp_t *)
627*1b8adde7SWilliam Kucharski 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
628*1b8adde7SWilliam Kucharski 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
629*1b8adde7SWilliam Kucharski 		sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
630*1b8adde7SWilliam Kucharski 	if (len < 0){
631*1b8adde7SWilliam Kucharski 		return 0;
632*1b8adde7SWilliam Kucharski 	}
633*1b8adde7SWilliam Kucharski 	if (udp->dest != htons(BOOTP_CLIENT))
634*1b8adde7SWilliam Kucharski 		return 0;
635*1b8adde7SWilliam Kucharski 	if (dhcpreply->bp_op != BOOTP_REPLY)
636*1b8adde7SWilliam Kucharski 		return 0;
637*1b8adde7SWilliam Kucharski 	if (dhcpreply->bp_xid != xid)
638*1b8adde7SWilliam Kucharski 		return 0;
639*1b8adde7SWilliam Kucharski 	if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
640*1b8adde7SWilliam Kucharski 		return 0;
641*1b8adde7SWilliam Kucharski 	if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
642*1b8adde7SWilliam Kucharski 	    (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
643*1b8adde7SWilliam Kucharski 		return 0;
644*1b8adde7SWilliam Kucharski 	}
645*1b8adde7SWilliam Kucharski 
646*1b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
647*1b8adde7SWilliam Kucharski 	/* fill in netinfo */
648*1b8adde7SWilliam Kucharski 	dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
649*1b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
650*1b8adde7SWilliam Kucharski #endif
651*1b8adde7SWilliam Kucharski 
652*1b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
653*1b8adde7SWilliam Kucharski 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
654*1b8adde7SWilliam Kucharski 	netmask = default_netmask();
655*1b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
656*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
657*1b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
658*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
659*1b8adde7SWilliam Kucharski 	/* We don't care bootpreply->bp_file. It must be 'pxegrub' */
660*1b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
661*1b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
662*1b8adde7SWilliam Kucharski 	return(1);
663*1b8adde7SWilliam Kucharski }
664*1b8adde7SWilliam Kucharski 
665*1b8adde7SWilliam Kucharski int dhcp(void)
666*1b8adde7SWilliam Kucharski {
667*1b8adde7SWilliam Kucharski 	int retry;
668*1b8adde7SWilliam Kucharski 	int reqretry;
669*1b8adde7SWilliam Kucharski 	struct dhcpip_t ip;
670*1b8adde7SWilliam Kucharski 	unsigned long  starttime;
671*1b8adde7SWilliam Kucharski 
672*1b8adde7SWilliam Kucharski 	/* try bios pxe stack first */
673*1b8adde7SWilliam Kucharski 	if (dhcp_undi())
674*1b8adde7SWilliam Kucharski 		return 1;
675*1b8adde7SWilliam Kucharski 
676*1b8adde7SWilliam Kucharski 	if(!grub_eth_probe())
677*1b8adde7SWilliam Kucharski 		return 0;
678*1b8adde7SWilliam Kucharski 
679*1b8adde7SWilliam Kucharski 	network_ready = 0;
680*1b8adde7SWilliam Kucharski 
681*1b8adde7SWilliam Kucharski 	memset(&ip, 0, sizeof(ip));
682*1b8adde7SWilliam Kucharski 	ip.bp.bp_op = BOOTP_REQUEST;
683*1b8adde7SWilliam Kucharski 	ip.bp.bp_htype = 1;
684*1b8adde7SWilliam Kucharski 	ip.bp.bp_hlen = ETH_ALEN;
685*1b8adde7SWilliam Kucharski 	starttime = currticks();
686*1b8adde7SWilliam Kucharski 	/* Use lower 32 bits of node address, more likely to be
687*1b8adde7SWilliam Kucharski 	   distinct than the time since booting */
688*1b8adde7SWilliam Kucharski 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
689*1b8adde7SWilliam Kucharski 	ip.bp.bp_xid = xid += htonl(starttime);
690*1b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
691*1b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
692*1b8adde7SWilliam Kucharski 	memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
693*1b8adde7SWilliam Kucharski 
694*1b8adde7SWilliam Kucharski 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
695*1b8adde7SWilliam Kucharski 		long timeout;
696*1b8adde7SWilliam Kucharski 
697*1b8adde7SWilliam Kucharski 		rx_qdrain();
698*1b8adde7SWilliam Kucharski 
699*1b8adde7SWilliam Kucharski 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
700*1b8adde7SWilliam Kucharski 			     sizeof(ip), &ip);
701*1b8adde7SWilliam Kucharski 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
702*1b8adde7SWilliam Kucharski 		if (await_reply(await_dhcp, 0, NULL, timeout)) {
703*1b8adde7SWilliam Kucharski 			/* If not a DHCPOFFER then must be just a
704*1b8adde7SWilliam Kucharski 			   BOOTP reply, be backward compatible with
705*1b8adde7SWilliam Kucharski 			   BOOTP then. Jscott report a bug here, but I
706*1b8adde7SWilliam Kucharski 			   don't know how it happened */
707*1b8adde7SWilliam Kucharski 			if (dhcp_reply != DHCPOFFER){
708*1b8adde7SWilliam Kucharski 				network_ready = 1;
709*1b8adde7SWilliam Kucharski 				return(1);
710*1b8adde7SWilliam Kucharski 			}
711*1b8adde7SWilliam Kucharski 			dhcp_reply = 0;
712*1b8adde7SWilliam Kucharski 			memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
713*1b8adde7SWilliam Kucharski 			memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
714*1b8adde7SWilliam Kucharski 			/* Beware: the magic numbers 9 and 15 depend on
715*1b8adde7SWilliam Kucharski 			   the layout of dhcprequest */
716*1b8adde7SWilliam Kucharski 			memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
717*1b8adde7SWilliam Kucharski 			memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
718*1b8adde7SWilliam Kucharski 			for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
719*1b8adde7SWilliam Kucharski 				udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
720*1b8adde7SWilliam Kucharski 					     sizeof(ip), &ip);
721*1b8adde7SWilliam Kucharski 				dhcp_reply=0;
722*1b8adde7SWilliam Kucharski 				timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
723*1b8adde7SWilliam Kucharski 				if (await_reply(await_dhcp, 0, NULL, timeout))
724*1b8adde7SWilliam Kucharski 					if (dhcp_reply == DHCPACK){
725*1b8adde7SWilliam Kucharski 						network_ready = 1;
726*1b8adde7SWilliam Kucharski 						return(1);
727*1b8adde7SWilliam Kucharski 					}
728*1b8adde7SWilliam Kucharski 				if (user_abort)
729*1b8adde7SWilliam Kucharski 					return 0;
730*1b8adde7SWilliam Kucharski 			}
731*1b8adde7SWilliam Kucharski 		}
732*1b8adde7SWilliam Kucharski 		if (user_abort)
733*1b8adde7SWilliam Kucharski 			return 0;
734*1b8adde7SWilliam Kucharski 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
735*1b8adde7SWilliam Kucharski 	}
736*1b8adde7SWilliam Kucharski 	return(0);
737*1b8adde7SWilliam Kucharski }
738*1b8adde7SWilliam Kucharski 
739*1b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
740*1b8adde7SWilliam Kucharski static void send_igmp_reports(unsigned long now)
741*1b8adde7SWilliam Kucharski {
742*1b8adde7SWilliam Kucharski 	int i;
743*1b8adde7SWilliam Kucharski 	for(i = 0; i < MAX_IGMP; i++) {
744*1b8adde7SWilliam Kucharski 		if (igmptable[i].time && (now >= igmptable[i].time)) {
745*1b8adde7SWilliam Kucharski 			struct igmp_ip_t igmp;
746*1b8adde7SWilliam Kucharski 			igmp.router_alert[0] = 0x94;
747*1b8adde7SWilliam Kucharski 			igmp.router_alert[1] = 0x04;
748*1b8adde7SWilliam Kucharski 			igmp.router_alert[2] = 0;
749*1b8adde7SWilliam Kucharski 			igmp.router_alert[3] = 0;
750*1b8adde7SWilliam Kucharski 			build_ip_hdr(igmptable[i].group.s_addr,
751*1b8adde7SWilliam Kucharski 				1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
752*1b8adde7SWilliam Kucharski 			igmp.igmp.type = IGMPv2_REPORT;
753*1b8adde7SWilliam Kucharski 			if (last_igmpv1 &&
754*1b8adde7SWilliam Kucharski 				(now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
755*1b8adde7SWilliam Kucharski 				igmp.igmp.type = IGMPv1_REPORT;
756*1b8adde7SWilliam Kucharski 			}
757*1b8adde7SWilliam Kucharski 			igmp.igmp.response_time = 0;
758*1b8adde7SWilliam Kucharski 			igmp.igmp.chksum = 0;
759*1b8adde7SWilliam Kucharski 			igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
760*1b8adde7SWilliam Kucharski 			igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
761*1b8adde7SWilliam Kucharski 			ip_transmit(sizeof(igmp), &igmp);
762*1b8adde7SWilliam Kucharski #ifdef	MDEBUG
763*1b8adde7SWilliam Kucharski 			printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
764*1b8adde7SWilliam Kucharski #endif
765*1b8adde7SWilliam Kucharski 			/* Don't send another igmp report until asked */
766*1b8adde7SWilliam Kucharski 			igmptable[i].time = 0;
767*1b8adde7SWilliam Kucharski 		}
768*1b8adde7SWilliam Kucharski 	}
769*1b8adde7SWilliam Kucharski }
770*1b8adde7SWilliam Kucharski 
771*1b8adde7SWilliam Kucharski static void process_igmp(struct iphdr *ip, unsigned long now)
772*1b8adde7SWilliam Kucharski {
773*1b8adde7SWilliam Kucharski 	struct igmp *igmp;
774*1b8adde7SWilliam Kucharski 	int i;
775*1b8adde7SWilliam Kucharski 	unsigned iplen = 0;
776*1b8adde7SWilliam Kucharski 	if (!ip || (ip->protocol == IP_IGMP) ||
777*1b8adde7SWilliam Kucharski 		(nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
778*1b8adde7SWilliam Kucharski 		return;
779*1b8adde7SWilliam Kucharski 	}
780*1b8adde7SWilliam Kucharski 	iplen = (ip->verhdrlen & 0xf)*4;
781*1b8adde7SWilliam Kucharski 	igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
782*1b8adde7SWilliam Kucharski 	if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
783*1b8adde7SWilliam Kucharski 		return;
784*1b8adde7SWilliam Kucharski 	if ((igmp->type == IGMP_QUERY) &&
785*1b8adde7SWilliam Kucharski 		(ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
786*1b8adde7SWilliam Kucharski 		unsigned long interval = IGMP_INTERVAL;
787*1b8adde7SWilliam Kucharski 		if (igmp->response_time == 0) {
788*1b8adde7SWilliam Kucharski 			last_igmpv1 = now;
789*1b8adde7SWilliam Kucharski 		} else {
790*1b8adde7SWilliam Kucharski 			interval = (igmp->response_time * TICKS_PER_SEC)/10;
791*1b8adde7SWilliam Kucharski 		}
792*1b8adde7SWilliam Kucharski 
793*1b8adde7SWilliam Kucharski #ifdef	MDEBUG
794*1b8adde7SWilliam Kucharski 		printf("Received IGMP query for: %@\n", igmp->group.s_addr);
795*1b8adde7SWilliam Kucharski #endif
796*1b8adde7SWilliam Kucharski 		for(i = 0; i < MAX_IGMP; i++) {
797*1b8adde7SWilliam Kucharski 			uint32_t group = igmptable[i].group.s_addr;
798*1b8adde7SWilliam Kucharski 			if ((group == 0) || (group == igmp->group.s_addr)) {
799*1b8adde7SWilliam Kucharski 				unsigned long time;
800*1b8adde7SWilliam Kucharski 				time = currticks() + rfc1112_sleep_interval(interval, 0);
801*1b8adde7SWilliam Kucharski 				if (time < igmptable[i].time) {
802*1b8adde7SWilliam Kucharski 					igmptable[i].time = time;
803*1b8adde7SWilliam Kucharski 				}
804*1b8adde7SWilliam Kucharski 			}
805*1b8adde7SWilliam Kucharski 		}
806*1b8adde7SWilliam Kucharski 	}
807*1b8adde7SWilliam Kucharski 	if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
808*1b8adde7SWilliam Kucharski 		(ip->dest.s_addr == igmp->group.s_addr)) {
809*1b8adde7SWilliam Kucharski #ifdef	MDEBUG
810*1b8adde7SWilliam Kucharski 		printf("Received IGMP report for: %@\n", igmp->group.s_addr);
811*1b8adde7SWilliam Kucharski #endif
812*1b8adde7SWilliam Kucharski 		for(i = 0; i < MAX_IGMP; i++) {
813*1b8adde7SWilliam Kucharski 			if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
814*1b8adde7SWilliam Kucharski 				igmptable[i].time != 0) {
815*1b8adde7SWilliam Kucharski 				igmptable[i].time = 0;
816*1b8adde7SWilliam Kucharski 			}
817*1b8adde7SWilliam Kucharski 		}
818*1b8adde7SWilliam Kucharski 	}
819*1b8adde7SWilliam Kucharski }
820*1b8adde7SWilliam Kucharski 
821*1b8adde7SWilliam Kucharski void leave_group(int slot)
822*1b8adde7SWilliam Kucharski {
823*1b8adde7SWilliam Kucharski 	/* Be very stupid and always send a leave group message if
824*1b8adde7SWilliam Kucharski 	 * I have subscribed.  Imperfect but it is standards
825*1b8adde7SWilliam Kucharski 	 * compliant, easy and reliable to implement.
826*1b8adde7SWilliam Kucharski 	 *
827*1b8adde7SWilliam Kucharski 	 * The optimal group leave method is to only send leave when,
828*1b8adde7SWilliam Kucharski 	 * we were the last host to respond to a query on this group,
829*1b8adde7SWilliam Kucharski 	 * and igmpv1 compatibility is not enabled.
830*1b8adde7SWilliam Kucharski 	 */
831*1b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr) {
832*1b8adde7SWilliam Kucharski 		struct igmp_ip_t igmp;
833*1b8adde7SWilliam Kucharski 		igmp.router_alert[0] = 0x94;
834*1b8adde7SWilliam Kucharski 		igmp.router_alert[1] = 0x04;
835*1b8adde7SWilliam Kucharski 		igmp.router_alert[2] = 0;
836*1b8adde7SWilliam Kucharski 		igmp.router_alert[3] = 0;
837*1b8adde7SWilliam Kucharski 		build_ip_hdr(htonl(GROUP_ALL_HOSTS),
838*1b8adde7SWilliam Kucharski 			1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
839*1b8adde7SWilliam Kucharski 		igmp.igmp.type = IGMP_LEAVE;
840*1b8adde7SWilliam Kucharski 		igmp.igmp.response_time = 0;
841*1b8adde7SWilliam Kucharski 		igmp.igmp.chksum = 0;
842*1b8adde7SWilliam Kucharski 		igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
843*1b8adde7SWilliam Kucharski 		igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
844*1b8adde7SWilliam Kucharski 		ip_transmit(sizeof(igmp), &igmp);
845*1b8adde7SWilliam Kucharski #ifdef	MDEBUG
846*1b8adde7SWilliam Kucharski 		printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
847*1b8adde7SWilliam Kucharski #endif
848*1b8adde7SWilliam Kucharski 	}
849*1b8adde7SWilliam Kucharski 	memset(&igmptable[slot], 0, sizeof(igmptable[0]));
850*1b8adde7SWilliam Kucharski }
851*1b8adde7SWilliam Kucharski 
852*1b8adde7SWilliam Kucharski void join_group(int slot, unsigned long group)
853*1b8adde7SWilliam Kucharski {
854*1b8adde7SWilliam Kucharski 	/* I have already joined */
855*1b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr == group)
856*1b8adde7SWilliam Kucharski 		return;
857*1b8adde7SWilliam Kucharski 	if (igmptable[slot].group.s_addr) {
858*1b8adde7SWilliam Kucharski 		leave_group(slot);
859*1b8adde7SWilliam Kucharski 	}
860*1b8adde7SWilliam Kucharski 	/* Only join a group if we are given a multicast ip, this way
861*1b8adde7SWilliam Kucharski 	 * code can be given a non-multicast (broadcast or unicast ip)
862*1b8adde7SWilliam Kucharski 	 * and still work...
863*1b8adde7SWilliam Kucharski 	 */
864*1b8adde7SWilliam Kucharski 	if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
865*1b8adde7SWilliam Kucharski 		igmptable[slot].group.s_addr = group;
866*1b8adde7SWilliam Kucharski 		igmptable[slot].time = currticks();
867*1b8adde7SWilliam Kucharski 	}
868*1b8adde7SWilliam Kucharski }
869*1b8adde7SWilliam Kucharski #else
870*1b8adde7SWilliam Kucharski #define send_igmp_reports(now);
871*1b8adde7SWilliam Kucharski #define process_igmp(ip, now)
872*1b8adde7SWilliam Kucharski #endif
873*1b8adde7SWilliam Kucharski 
874*1b8adde7SWilliam Kucharski /**************************************************************************
875*1b8adde7SWilliam Kucharski AWAIT_REPLY - Wait until we get a response for our request
876*1b8adde7SWilliam Kucharski ************f**************************************************************/
877*1b8adde7SWilliam Kucharski int await_reply(reply_t reply, int ival, void *ptr, long timeout)
878*1b8adde7SWilliam Kucharski {
879*1b8adde7SWilliam Kucharski 	unsigned long time, now;
880*1b8adde7SWilliam Kucharski 	struct	iphdr *ip;
881*1b8adde7SWilliam Kucharski 	unsigned iplen = 0;
882*1b8adde7SWilliam Kucharski 	struct	udphdr *udp;
883*1b8adde7SWilliam Kucharski 	unsigned short ptype;
884*1b8adde7SWilliam Kucharski 	int result;
885*1b8adde7SWilliam Kucharski 
886*1b8adde7SWilliam Kucharski 	user_abort = 0;
887*1b8adde7SWilliam Kucharski 
888*1b8adde7SWilliam Kucharski 	time = timeout + currticks();
889*1b8adde7SWilliam Kucharski 	/* The timeout check is done below.  The timeout is only checked if
890*1b8adde7SWilliam Kucharski 	 * there is no packet in the Rx queue.  This assumes that eth_poll()
891*1b8adde7SWilliam Kucharski 	 * needs a negligible amount of time.
892*1b8adde7SWilliam Kucharski 	 */
893*1b8adde7SWilliam Kucharski 	for (;;) {
894*1b8adde7SWilliam Kucharski 		now = currticks();
895*1b8adde7SWilliam Kucharski 		send_igmp_reports(now);
896*1b8adde7SWilliam Kucharski 		result = eth_poll(1);
897*1b8adde7SWilliam Kucharski 		if (result == 0) {
898*1b8adde7SWilliam Kucharski 			/* We don't have anything */
899*1b8adde7SWilliam Kucharski 
900*1b8adde7SWilliam Kucharski 			/* Check for abort key only if the Rx queue is empty -
901*1b8adde7SWilliam Kucharski 			 * as long as we have something to process, don't
902*1b8adde7SWilliam Kucharski 			 * assume that something failed.  It is unlikely that
903*1b8adde7SWilliam Kucharski 			 * we have no processing time left between packets.  */
904*1b8adde7SWilliam Kucharski 			poll_interruptions();
905*1b8adde7SWilliam Kucharski 			/* Do the timeout after at least a full queue walk.  */
906*1b8adde7SWilliam Kucharski 			if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
907*1b8adde7SWilliam Kucharski 				break;
908*1b8adde7SWilliam Kucharski 			}
909*1b8adde7SWilliam Kucharski 			continue;
910*1b8adde7SWilliam Kucharski 		}
911*1b8adde7SWilliam Kucharski 
912*1b8adde7SWilliam Kucharski 		/* We have something! */
913*1b8adde7SWilliam Kucharski 
914*1b8adde7SWilliam Kucharski 		/* Find the Ethernet packet type */
915*1b8adde7SWilliam Kucharski 		if (nic.packetlen >= ETH_HLEN) {
916*1b8adde7SWilliam Kucharski 			ptype = ((unsigned short) nic.packet[12]) << 8
917*1b8adde7SWilliam Kucharski 				| ((unsigned short) nic.packet[13]);
918*1b8adde7SWilliam Kucharski 		} else continue; /* what else could we do with it? */
919*1b8adde7SWilliam Kucharski 		/* Verify an IP header */
920*1b8adde7SWilliam Kucharski 		ip = 0;
921*1b8adde7SWilliam Kucharski 		if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
922*1b8adde7SWilliam Kucharski 			unsigned ipoptlen;
923*1b8adde7SWilliam Kucharski 			ip = (struct iphdr *)&nic.packet[ETH_HLEN];
924*1b8adde7SWilliam Kucharski 			if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
925*1b8adde7SWilliam Kucharski 				continue;
926*1b8adde7SWilliam Kucharski 			iplen = (ip->verhdrlen & 0xf) * 4;
927*1b8adde7SWilliam Kucharski 			if (ipchksum(ip, iplen) != 0)
928*1b8adde7SWilliam Kucharski 				continue;
929*1b8adde7SWilliam Kucharski 			if (ip->frags & htons(0x3FFF)) {
930*1b8adde7SWilliam Kucharski 				static int warned_fragmentation = 0;
931*1b8adde7SWilliam Kucharski 				if (!warned_fragmentation) {
932*1b8adde7SWilliam Kucharski 					printf("ALERT: got a fragmented packet - reconfigure your server\n");
933*1b8adde7SWilliam Kucharski 					warned_fragmentation = 1;
934*1b8adde7SWilliam Kucharski 				}
935*1b8adde7SWilliam Kucharski 				continue;
936*1b8adde7SWilliam Kucharski 			}
937*1b8adde7SWilliam Kucharski 			if (ntohs(ip->len) > ETH_MAX_MTU)
938*1b8adde7SWilliam Kucharski 				continue;
939*1b8adde7SWilliam Kucharski 
940*1b8adde7SWilliam Kucharski 			ipoptlen = iplen - sizeof(struct iphdr);
941*1b8adde7SWilliam Kucharski 			if (ipoptlen) {
942*1b8adde7SWilliam Kucharski 				/* Delete the ip options, to guarantee
943*1b8adde7SWilliam Kucharski 				 * good alignment, and make etherboot simpler.
944*1b8adde7SWilliam Kucharski 				 */
945*1b8adde7SWilliam Kucharski 				memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
946*1b8adde7SWilliam Kucharski 					&nic.packet[ETH_HLEN + iplen],
947*1b8adde7SWilliam Kucharski 					nic.packetlen - ipoptlen);
948*1b8adde7SWilliam Kucharski 				nic.packetlen -= ipoptlen;
949*1b8adde7SWilliam Kucharski 			}
950*1b8adde7SWilliam Kucharski 		}
951*1b8adde7SWilliam Kucharski 		udp = 0;
952*1b8adde7SWilliam Kucharski 		if (ip && (ip->protocol == IP_UDP) &&
953*1b8adde7SWilliam Kucharski 		    (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
954*1b8adde7SWilliam Kucharski 			udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
955*1b8adde7SWilliam Kucharski 
956*1b8adde7SWilliam Kucharski 			/* Make certain we have a reasonable packet length */
957*1b8adde7SWilliam Kucharski 			if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
958*1b8adde7SWilliam Kucharski 				continue;
959*1b8adde7SWilliam Kucharski 
960*1b8adde7SWilliam Kucharski 			if (udp->chksum && udpchksum(ip, udp)) {
961*1b8adde7SWilliam Kucharski 				printf("UDP checksum error\n");
962*1b8adde7SWilliam Kucharski 				continue;
963*1b8adde7SWilliam Kucharski 			}
964*1b8adde7SWilliam Kucharski 		}
965*1b8adde7SWilliam Kucharski 		result = reply(ival, ptr, ptype, ip, udp);
966*1b8adde7SWilliam Kucharski 		if (result > 0) {
967*1b8adde7SWilliam Kucharski 			return result;
968*1b8adde7SWilliam Kucharski 		}
969*1b8adde7SWilliam Kucharski 
970*1b8adde7SWilliam Kucharski 		/* If it isn't a packet the upper layer wants see if there is a default
971*1b8adde7SWilliam Kucharski 		 * action.  This allows us reply to arp and igmp queryies.
972*1b8adde7SWilliam Kucharski 		 */
973*1b8adde7SWilliam Kucharski 		if ((ptype == ARP) &&
974*1b8adde7SWilliam Kucharski 		    (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
975*1b8adde7SWilliam Kucharski 			struct	arprequest *arpreply;
976*1b8adde7SWilliam Kucharski 			unsigned long tmp;
977*1b8adde7SWilliam Kucharski 
978*1b8adde7SWilliam Kucharski 			arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
979*1b8adde7SWilliam Kucharski 			memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
980*1b8adde7SWilliam Kucharski 			if ((arpreply->opcode == htons(ARP_REQUEST)) &&
981*1b8adde7SWilliam Kucharski 			    (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
982*1b8adde7SWilliam Kucharski 				arpreply->opcode = htons(ARP_REPLY);
983*1b8adde7SWilliam Kucharski 				memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
984*1b8adde7SWilliam Kucharski 				memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
985*1b8adde7SWilliam Kucharski 				memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
986*1b8adde7SWilliam Kucharski 				memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
987*1b8adde7SWilliam Kucharski 				eth_transmit(arpreply->thwaddr, ARP,
988*1b8adde7SWilliam Kucharski 					     sizeof(struct  arprequest),
989*1b8adde7SWilliam Kucharski 					     arpreply);
990*1b8adde7SWilliam Kucharski #ifdef	MDEBUG
991*1b8adde7SWilliam Kucharski 				memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
992*1b8adde7SWilliam Kucharski 				printf("Sent ARP reply to: %@\n",tmp);
993*1b8adde7SWilliam Kucharski #endif	/* MDEBUG */
994*1b8adde7SWilliam Kucharski 			}
995*1b8adde7SWilliam Kucharski 		}
996*1b8adde7SWilliam Kucharski 		process_igmp(ip, now);
997*1b8adde7SWilliam Kucharski 	}
998*1b8adde7SWilliam Kucharski 	return(0);
999*1b8adde7SWilliam Kucharski }
1000*1b8adde7SWilliam Kucharski 
1001*1b8adde7SWilliam Kucharski #ifdef	REQUIRE_VCI_ETHERBOOT
1002*1b8adde7SWilliam Kucharski /**************************************************************************
1003*1b8adde7SWilliam Kucharski FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
1004*1b8adde7SWilliam Kucharski On entry p points to byte count of VCI options
1005*1b8adde7SWilliam Kucharski **************************************************************************/
1006*1b8adde7SWilliam Kucharski static int find_vci_etherboot(unsigned char *p)
1007*1b8adde7SWilliam Kucharski {
1008*1b8adde7SWilliam Kucharski 	unsigned char	*end = p + 1 + *p;
1009*1b8adde7SWilliam Kucharski 
1010*1b8adde7SWilliam Kucharski 	for (p++; p < end; ) {
1011*1b8adde7SWilliam Kucharski 		if (*p == RFC2132_VENDOR_CLASS_ID) {
1012*1b8adde7SWilliam Kucharski 			if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
1013*1b8adde7SWilliam Kucharski 				return (1);
1014*1b8adde7SWilliam Kucharski 		} else if (*p == RFC1533_END)
1015*1b8adde7SWilliam Kucharski 			return (0);
1016*1b8adde7SWilliam Kucharski 		p += TAG_LEN(p) + 2;
1017*1b8adde7SWilliam Kucharski 	}
1018*1b8adde7SWilliam Kucharski 	return (0);
1019*1b8adde7SWilliam Kucharski }
1020*1b8adde7SWilliam Kucharski #endif	/* REQUIRE_VCI_ETHERBOOT */
1021*1b8adde7SWilliam Kucharski 
1022*1b8adde7SWilliam Kucharski /**
1023*1b8adde7SWilliam Kucharski  * decode_rfc1533
1024*1b8adde7SWilliam Kucharski  *
1025*1b8adde7SWilliam Kucharski  * Decodes RFC1533 header
1026*1b8adde7SWilliam Kucharski  **/
1027*1b8adde7SWilliam Kucharski int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
1028*1b8adde7SWilliam Kucharski {
1029*1b8adde7SWilliam Kucharski 	static unsigned char *extdata = NULL, *extend = NULL;
1030*1b8adde7SWilliam Kucharski 	unsigned char        *extpath = NULL;
1031*1b8adde7SWilliam Kucharski 	unsigned char        *endp;
1032*1b8adde7SWilliam Kucharski 
1033*1b8adde7SWilliam Kucharski 	if (block == 0) {
1034*1b8adde7SWilliam Kucharski 		end_of_rfc1533 = NULL;
1035*1b8adde7SWilliam Kucharski 		if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
1036*1b8adde7SWilliam Kucharski 			return(0); /* no RFC 1533 header found */
1037*1b8adde7SWilliam Kucharski 		p += 4;
1038*1b8adde7SWilliam Kucharski 		endp = p + len;
1039*1b8adde7SWilliam Kucharski 	} else {
1040*1b8adde7SWilliam Kucharski 		if (block == 1) {
1041*1b8adde7SWilliam Kucharski 			if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
1042*1b8adde7SWilliam Kucharski 				return(0); /* no RFC 1533 header found */
1043*1b8adde7SWilliam Kucharski 			p += 4;
1044*1b8adde7SWilliam Kucharski 			len -= 4; }
1045*1b8adde7SWilliam Kucharski 		if (extend + len <= (unsigned char *)
1046*1b8adde7SWilliam Kucharski 		    rfc1533_venddata + sizeof(rfc1533_venddata)) {
1047*1b8adde7SWilliam Kucharski 			memcpy(extend, p, len);
1048*1b8adde7SWilliam Kucharski 			extend += len;
1049*1b8adde7SWilliam Kucharski 		} else {
1050*1b8adde7SWilliam Kucharski 			printf("Overflow in vendor data buffer! Aborting...\n");
1051*1b8adde7SWilliam Kucharski 			*extdata = RFC1533_END;
1052*1b8adde7SWilliam Kucharski 			return(0);
1053*1b8adde7SWilliam Kucharski 		}
1054*1b8adde7SWilliam Kucharski 		p = extdata; endp = extend;
1055*1b8adde7SWilliam Kucharski 	}
1056*1b8adde7SWilliam Kucharski 	if (!eof)
1057*1b8adde7SWilliam Kucharski 		return 1;
1058*1b8adde7SWilliam Kucharski 	while (p < endp) {
1059*1b8adde7SWilliam Kucharski 		unsigned char c = *p;
1060*1b8adde7SWilliam Kucharski 		if (c == RFC1533_PAD) {
1061*1b8adde7SWilliam Kucharski 			p++;
1062*1b8adde7SWilliam Kucharski 			continue;
1063*1b8adde7SWilliam Kucharski 		}
1064*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_END) {
1065*1b8adde7SWilliam Kucharski 			end_of_rfc1533 = endp = p;
1066*1b8adde7SWilliam Kucharski 			continue;
1067*1b8adde7SWilliam Kucharski 		}
1068*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_NETMASK)
1069*1b8adde7SWilliam Kucharski 			memcpy(&netmask, p+2, sizeof(in_addr));
1070*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_GATEWAY) {
1071*1b8adde7SWilliam Kucharski 			/* This is a little simplistic, but it will
1072*1b8adde7SWilliam Kucharski 			   usually be sufficient.
1073*1b8adde7SWilliam Kucharski 			   Take only the first entry */
1074*1b8adde7SWilliam Kucharski 			if (TAG_LEN(p) >= sizeof(in_addr))
1075*1b8adde7SWilliam Kucharski 				memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
1076*1b8adde7SWilliam Kucharski 		}
1077*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_EXTENSIONPATH)
1078*1b8adde7SWilliam Kucharski 			extpath = p;
1079*1b8adde7SWilliam Kucharski 		else if (c == RFC2132_MSG_TYPE)
1080*1b8adde7SWilliam Kucharski 			dhcp_reply=*(p+2);
1081*1b8adde7SWilliam Kucharski 		else if (c == RFC2132_SRV_ID)
1082*1b8adde7SWilliam Kucharski 			memcpy(&dhcp_server, p+2, sizeof(in_addr));
1083*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_HOSTNAME) {
1084*1b8adde7SWilliam Kucharski 			hostname = p + 2;
1085*1b8adde7SWilliam Kucharski 			hostnamelen = *(p + 1);
1086*1b8adde7SWilliam Kucharski 		}
1087*1b8adde7SWilliam Kucharski 		else if (c == RFC1533_VENDOR_CONFIGFILE){
1088*1b8adde7SWilliam Kucharski 			int l = TAG_LEN (p);
1089*1b8adde7SWilliam Kucharski 
1090*1b8adde7SWilliam Kucharski 			/* Eliminate the trailing NULs according to RFC 2132.  */
1091*1b8adde7SWilliam Kucharski 			while (*(p + 2 + l - 1) == '\000' && l > 0)
1092*1b8adde7SWilliam Kucharski 				l--;
1093*1b8adde7SWilliam Kucharski 
1094*1b8adde7SWilliam Kucharski 			/* XXX: Should check if LEN is less than the maximum length
1095*1b8adde7SWilliam Kucharski 			   of CONFIG_FILE. This kind of robustness will be a goal
1096*1b8adde7SWilliam Kucharski 			   in GRUB 1.0.  */
1097*1b8adde7SWilliam Kucharski 			memcpy (config_file, p + 2, l);
1098*1b8adde7SWilliam Kucharski 			config_file[l] = 0;
1099*1b8adde7SWilliam Kucharski 		}
1100*1b8adde7SWilliam Kucharski 		else {
1101*1b8adde7SWilliam Kucharski 			;
1102*1b8adde7SWilliam Kucharski 		}
1103*1b8adde7SWilliam Kucharski 		p += TAG_LEN(p) + 2;
1104*1b8adde7SWilliam Kucharski 	}
1105*1b8adde7SWilliam Kucharski 	extdata = extend = endp;
1106*1b8adde7SWilliam Kucharski 	if (block <= 0 && extpath != NULL) {
1107*1b8adde7SWilliam Kucharski 		char fname[64];
1108*1b8adde7SWilliam Kucharski 		if (TAG_LEN(extpath) >= sizeof(fname)){
1109*1b8adde7SWilliam Kucharski 			printf("Overflow in vendor data buffer! Aborting...\n");
1110*1b8adde7SWilliam Kucharski 			*extdata = RFC1533_END;
1111*1b8adde7SWilliam Kucharski 			return(0);
1112*1b8adde7SWilliam Kucharski 		}
1113*1b8adde7SWilliam Kucharski 		memcpy(fname, extpath+2, TAG_LEN(extpath));
1114*1b8adde7SWilliam Kucharski 		fname[(int)TAG_LEN(extpath)] = '\0';
1115*1b8adde7SWilliam Kucharski 		printf("Loading BOOTP-extension file: %s\n",fname);
1116*1b8adde7SWilliam Kucharski 		tftp_file_read(fname, decode_rfc1533);
1117*1b8adde7SWilliam Kucharski 	}
1118*1b8adde7SWilliam Kucharski 	return 1;	/* proceed with next block */
1119*1b8adde7SWilliam Kucharski }
1120*1b8adde7SWilliam Kucharski 
1121*1b8adde7SWilliam Kucharski 
1122*1b8adde7SWilliam Kucharski /* FIXME double check TWO_SECOND_DIVISOR */
1123*1b8adde7SWilliam Kucharski #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
1124*1b8adde7SWilliam Kucharski /**************************************************************************
1125*1b8adde7SWilliam Kucharski RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
1126*1b8adde7SWilliam Kucharski **************************************************************************/
1127*1b8adde7SWilliam Kucharski long rfc2131_sleep_interval(long base, int exp)
1128*1b8adde7SWilliam Kucharski {
1129*1b8adde7SWilliam Kucharski 	unsigned long tmo;
1130*1b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
1131*1b8adde7SWilliam Kucharski 	if (exp > BACKOFF_LIMIT)
1132*1b8adde7SWilliam Kucharski 		exp = BACKOFF_LIMIT;
1133*1b8adde7SWilliam Kucharski #endif
1134*1b8adde7SWilliam Kucharski 	tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
1135*1b8adde7SWilliam Kucharski 	return tmo;
1136*1b8adde7SWilliam Kucharski }
1137*1b8adde7SWilliam Kucharski 
1138*1b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
1139*1b8adde7SWilliam Kucharski /**************************************************************************
1140*1b8adde7SWilliam Kucharski RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
1141*1b8adde7SWilliam Kucharski **************************************************************************/
1142*1b8adde7SWilliam Kucharski long rfc1112_sleep_interval(long base, int exp)
1143*1b8adde7SWilliam Kucharski {
1144*1b8adde7SWilliam Kucharski 	unsigned long divisor, tmo;
1145*1b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
1146*1b8adde7SWilliam Kucharski 	if (exp > BACKOFF_LIMIT)
1147*1b8adde7SWilliam Kucharski 		exp = BACKOFF_LIMIT;
1148*1b8adde7SWilliam Kucharski #endif
1149*1b8adde7SWilliam Kucharski 	divisor = RAND_MAX/(base << exp);
1150*1b8adde7SWilliam Kucharski 	tmo = random()/divisor;
1151*1b8adde7SWilliam Kucharski 	return tmo;
1152*1b8adde7SWilliam Kucharski }
1153*1b8adde7SWilliam Kucharski #endif /* MULTICAST_LEVEL_2 */
1154*1b8adde7SWilliam Kucharski /* ifconfig - configure network interface.  */
1155*1b8adde7SWilliam Kucharski int
1156*1b8adde7SWilliam Kucharski ifconfig (char *ip, char *sm, char *gw, char *svr)
1157*1b8adde7SWilliam Kucharski {
1158*1b8adde7SWilliam Kucharski   in_addr tmp;
1159*1b8adde7SWilliam Kucharski 
1160*1b8adde7SWilliam Kucharski   if (sm)
1161*1b8adde7SWilliam Kucharski     {
1162*1b8adde7SWilliam Kucharski       if (! inet_aton (sm, &tmp))
1163*1b8adde7SWilliam Kucharski 	return 0;
1164*1b8adde7SWilliam Kucharski 
1165*1b8adde7SWilliam Kucharski       netmask = tmp.s_addr;
1166*1b8adde7SWilliam Kucharski     }
1167*1b8adde7SWilliam Kucharski 
1168*1b8adde7SWilliam Kucharski   if (ip)
1169*1b8adde7SWilliam Kucharski     {
1170*1b8adde7SWilliam Kucharski       if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
1171*1b8adde7SWilliam Kucharski 	return 0;
1172*1b8adde7SWilliam Kucharski 
1173*1b8adde7SWilliam Kucharski       if (! netmask && ! sm)
1174*1b8adde7SWilliam Kucharski 	netmask = default_netmask ();
1175*1b8adde7SWilliam Kucharski     }
1176*1b8adde7SWilliam Kucharski 
1177*1b8adde7SWilliam Kucharski   if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
1178*1b8adde7SWilliam Kucharski     return 0;
1179*1b8adde7SWilliam Kucharski 
1180*1b8adde7SWilliam Kucharski   /* Clear out the ARP entry.  */
1181*1b8adde7SWilliam Kucharski   grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
1182*1b8adde7SWilliam Kucharski 
1183*1b8adde7SWilliam Kucharski   if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
1184*1b8adde7SWilliam Kucharski     return 0;
1185*1b8adde7SWilliam Kucharski 
1186*1b8adde7SWilliam Kucharski   /* Likewise.  */
1187*1b8adde7SWilliam Kucharski   grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
1188*1b8adde7SWilliam Kucharski 
1189*1b8adde7SWilliam Kucharski   if (ip || sm)
1190*1b8adde7SWilliam Kucharski     {
1191*1b8adde7SWilliam Kucharski       if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
1192*1b8adde7SWilliam Kucharski 	  || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
1193*1b8adde7SWilliam Kucharski 	  || ! netmask)
1194*1b8adde7SWilliam Kucharski 	network_ready = 0;
1195*1b8adde7SWilliam Kucharski       else
1196*1b8adde7SWilliam Kucharski 	network_ready = 1;
1197*1b8adde7SWilliam Kucharski     }
1198*1b8adde7SWilliam Kucharski 
1199*1b8adde7SWilliam Kucharski   update_network_configuration();
1200*1b8adde7SWilliam Kucharski   return 1;
1201*1b8adde7SWilliam Kucharski }
1202*1b8adde7SWilliam Kucharski 
1203*1b8adde7SWilliam Kucharski /*
1204*1b8adde7SWilliam Kucharski  * print_network_configuration
1205*1b8adde7SWilliam Kucharski  *
1206*1b8adde7SWilliam Kucharski  * Output the network configuration. It may broke the graphic console now.:-(
1207*1b8adde7SWilliam Kucharski  */
1208*1b8adde7SWilliam Kucharski void print_network_configuration (void)
1209*1b8adde7SWilliam Kucharski {
1210*1b8adde7SWilliam Kucharski 	EnterFunction("print_network_configuration");
1211*1b8adde7SWilliam Kucharski 	if (! network_ready)
1212*1b8adde7SWilliam Kucharski 		grub_printf ("Network interface not initialized yet.\n");
1213*1b8adde7SWilliam Kucharski 	else {
1214*1b8adde7SWilliam Kucharski 		etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
1215*1b8adde7SWilliam Kucharski 		etherboot_printf ("Netmask: %@\n", netmask);
1216*1b8adde7SWilliam Kucharski 		etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
1217*1b8adde7SWilliam Kucharski 		etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
1218*1b8adde7SWilliam Kucharski 	}
1219*1b8adde7SWilliam Kucharski 	LeaveFunction("print_network_configuration");
1220*1b8adde7SWilliam Kucharski }
1221*1b8adde7SWilliam Kucharski 
1222*1b8adde7SWilliam Kucharski /*
1223*1b8adde7SWilliam Kucharski  * update_network_configuration
1224*1b8adde7SWilliam Kucharski  *
1225*1b8adde7SWilliam Kucharski  * Update network configuration for diskless clients (Solaris only)
1226*1b8adde7SWilliam Kucharski  */
1227*1b8adde7SWilliam Kucharski static void update_network_configuration (void)
1228*1b8adde7SWilliam Kucharski {
1229*1b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
1230*1b8adde7SWilliam Kucharski   	struct sol_netinfo {
1231*1b8adde7SWilliam Kucharski 	  	uint8_t sn_infotype;
1232*1b8adde7SWilliam Kucharski 		uint8_t sn_mactype;
1233*1b8adde7SWilliam Kucharski 		uint8_t sn_maclen;
1234*1b8adde7SWilliam Kucharski 	  	uint8_t sn_padding;
1235*1b8adde7SWilliam Kucharski 		unsigned long sn_ciaddr;
1236*1b8adde7SWilliam Kucharski 		unsigned long sn_siaddr;
1237*1b8adde7SWilliam Kucharski 		unsigned long sn_giaddr;
1238*1b8adde7SWilliam Kucharski 		unsigned long sn_netmask;
1239*1b8adde7SWilliam Kucharski 		uint8_t sn_macaddr[1];
1240*1b8adde7SWilliam Kucharski 	} *sip;
1241*1b8adde7SWilliam Kucharski 
1242*1b8adde7SWilliam Kucharski 	if (! network_ready)
1243*1b8adde7SWilliam Kucharski 	  	return;
1244*1b8adde7SWilliam Kucharski 
1245*1b8adde7SWilliam Kucharski 	sip = (struct sol_netinfo *)dhcpack_buf;
1246*1b8adde7SWilliam Kucharski 	sip->sn_infotype = 0xf0;	/* something not BOOTP_REPLY */
1247*1b8adde7SWilliam Kucharski 	sip->sn_mactype = 4;		/* DL_ETHER */
1248*1b8adde7SWilliam Kucharski 	sip->sn_maclen = ETH_ALEN;
1249*1b8adde7SWilliam Kucharski 	sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
1250*1b8adde7SWilliam Kucharski 	sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
1251*1b8adde7SWilliam Kucharski 	sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
1252*1b8adde7SWilliam Kucharski 	sip->sn_netmask = netmask;
1253*1b8adde7SWilliam Kucharski 	memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
1254*1b8adde7SWilliam Kucharski 	dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
1255*1b8adde7SWilliam Kucharski #endif /* SOLARIS_NETBOOT */
1256*1b8adde7SWilliam Kucharski }
1257*1b8adde7SWilliam Kucharski 
1258*1b8adde7SWilliam Kucharski /**
1259*1b8adde7SWilliam Kucharski  * cleanup_net
1260*1b8adde7SWilliam Kucharski  *
1261*1b8adde7SWilliam Kucharski  * Mark network unusable, and disable NICs
1262*1b8adde7SWilliam Kucharski  */
1263*1b8adde7SWilliam Kucharski void cleanup_net (void)
1264*1b8adde7SWilliam Kucharski {
1265*1b8adde7SWilliam Kucharski 	if (network_ready){
1266*1b8adde7SWilliam Kucharski 		/* Stop receiving packets.  */
1267*1b8adde7SWilliam Kucharski 		if (use_bios_pxe)
1268*1b8adde7SWilliam Kucharski 			undi_pxe_disable();
1269*1b8adde7SWilliam Kucharski 		else
1270*1b8adde7SWilliam Kucharski 			eth_disable ();
1271*1b8adde7SWilliam Kucharski 		network_ready = 0;
1272*1b8adde7SWilliam Kucharski 	}
1273*1b8adde7SWilliam Kucharski }
1274*1b8adde7SWilliam Kucharski 
1275*1b8adde7SWilliam Kucharski /*******************************************************************
1276*1b8adde7SWilliam Kucharski  * dhcp implementation reusing the BIOS pxe stack
1277*1b8adde7SWilliam Kucharski  */
1278*1b8adde7SWilliam Kucharski static void
1279*1b8adde7SWilliam Kucharski dhcp_copy(struct dhcp_t *dhcpreply)
1280*1b8adde7SWilliam Kucharski {
1281*1b8adde7SWilliam Kucharski 	unsigned long time;
1282*1b8adde7SWilliam Kucharski 	int ret, len = DHCP_OPT_LEN;
1283*1b8adde7SWilliam Kucharski 
1284*1b8adde7SWilliam Kucharski 	/* fill in netinfo */
1285*1b8adde7SWilliam Kucharski 	dhcpack_length = sizeof (struct dhcp_t);
1286*1b8adde7SWilliam Kucharski 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
1287*1b8adde7SWilliam Kucharski 
1288*1b8adde7SWilliam Kucharski 	memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
1289*1b8adde7SWilliam Kucharski 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
1290*1b8adde7SWilliam Kucharski 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
1291*1b8adde7SWilliam Kucharski 	netmask = default_netmask();
1292*1b8adde7SWilliam Kucharski 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
1293*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
1294*1b8adde7SWilliam Kucharski 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
1295*1b8adde7SWilliam Kucharski 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
1296*1b8adde7SWilliam Kucharski 	/* We don't care bootpreply->bp_file. It must be 'pxegrub' */
1297*1b8adde7SWilliam Kucharski 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
1298*1b8adde7SWilliam Kucharski 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
1299*1b8adde7SWilliam Kucharski }
1300*1b8adde7SWilliam Kucharski 
1301*1b8adde7SWilliam Kucharski int dhcp_undi(void)
1302*1b8adde7SWilliam Kucharski {
1303*1b8adde7SWilliam Kucharski 	struct dhcp_t *dhcpreply;
1304*1b8adde7SWilliam Kucharski 
1305*1b8adde7SWilliam Kucharski 	if (!undi_bios_pxe((void **)&dhcpreply))
1306*1b8adde7SWilliam Kucharski 		return 0;
1307*1b8adde7SWilliam Kucharski 
1308*1b8adde7SWilliam Kucharski 	dhcp_copy(dhcpreply);
1309*1b8adde7SWilliam Kucharski 	network_ready = 1;
1310*1b8adde7SWilliam Kucharski 	use_bios_pxe = 1;
1311*1b8adde7SWilliam Kucharski 	return (1);
1312*1b8adde7SWilliam Kucharski }
1313