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