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