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 		memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
464 		return 1;
465 	}
466 	return 0;
467 }
468 
469 int rarp(void)
470 {
471 	int retry;
472 
473 	/* arp and rarp requests share the same packet structure. */
474 	struct arprequest rarpreq;
475 
476 	if(!grub_eth_probe())
477 		return 0;
478 	network_ready = 0;
479 
480 	memset(&rarpreq, 0, sizeof(rarpreq));
481 
482 	rarpreq.hwtype = htons(1);
483 	rarpreq.protocol = htons(IP);
484 	rarpreq.hwlen = ETH_ALEN;
485 	rarpreq.protolen = 4;
486 	rarpreq.opcode = htons(RARP_REQUEST);
487 	memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
488 	/* sipaddr is already zeroed out */
489 	memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
490 	/* tipaddr is already zeroed out */
491 
492 	for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
493 		long timeout;
494 		eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
495 
496 		timeout = rfc2131_sleep_interval(TIMEOUT, retry);
497 		if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
498 			break;
499 		if (user_abort)
500 			return 0;
501 	}
502 
503 	if (retry == MAX_ARP_RETRIES) {
504 		return (0);
505 	}
506 
507 	network_ready = 1;
508   	update_network_configuration();
509 	return (1);
510 }
511 
512 /**
513  * bootp
514  *
515  * Get IP address by bootp, segregate from bootp in etherboot.
516  **/
517 static int await_bootp(int ival __unused, void *ptr __unused,
518 	unsigned short ptype __unused, struct iphdr *ip __unused,
519 	struct udphdr *udp)
520 {
521 	struct	bootp_t *bootpreply;
522 	int len;		/* Length of vendor */
523 
524 	if (!udp) {
525 		return 0;
526 	}
527 	bootpreply = (struct bootp_t *)
528 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
529 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
530 		sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
531 	if (len < 0) {
532 		return 0;
533 	}
534 	if (udp->dest != htons(BOOTP_CLIENT))
535 		return 0;
536 	if (bootpreply->bp_op != BOOTP_REPLY)
537 		return 0;
538 	if (bootpreply->bp_xid != xid)
539 		return 0;
540 	if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
541 		return 0;
542 	if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
543 	    (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
544 		return 0;
545 	}
546 
547 #ifdef SOLARIS_NETBOOT
548 	/* fill in netinfo */
549 	dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
550 	memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
551 #endif
552 
553 	arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
554 	netmask = default_netmask();
555 	arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
556 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
557 	arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
558 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
559 	/* We don't care bootpreply->bp_file, it must be 'pxegrub':-) */
560 	memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
561 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
562 	return(1);
563 }
564 
565 int bootp(void)
566 {
567 	int retry;
568 	struct bootpip_t ip;
569 	unsigned long  starttime;
570 
571 	EnterFunction("bootp");
572 
573 	if(!grub_eth_probe())
574 		return 0;
575 	network_ready = 0;
576 
577 	memset(&ip, 0, sizeof(struct bootpip_t));
578 	ip.bp.bp_op = BOOTP_REQUEST;
579 	ip.bp.bp_htype = 1;
580 	ip.bp.bp_hlen = ETH_ALEN;
581 	starttime = currticks();
582 	/* Use lower 32 bits of node address, more likely to be
583 	   distinct than the time since booting */
584 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
585 	ip.bp.bp_xid = xid += htonl(starttime);
586 	/* bp_secs defaults to zero */
587 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
588 	memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
589 
590 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
591 		long timeout;
592 
593 		rx_qdrain();
594 
595 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
596 			sizeof(struct bootpip_t), &ip);
597 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
598 		if (await_reply(await_bootp, 0, NULL, timeout)){
599 			network_ready = 1;
600 			return(1);
601 		}
602 		if (user_abort)
603 			return 0;
604 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
605 	}
606 	return(0);
607 }
608 
609 /**
610  * dhcp
611  *
612  * Get IP address by dhcp, segregate from bootp in etherboot.
613  **/
614 static int await_dhcp(int ival __unused, void *ptr __unused,
615 	unsigned short ptype __unused, struct iphdr *ip __unused,
616 	struct udphdr *udp)
617 {
618 	struct	dhcp_t *dhcpreply;
619 	int len;
620 
621 	if (!udp) {
622 		return 0;
623 	}
624 	dhcpreply = (struct dhcp_t *)
625 		&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
626 	len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
627 		sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
628 	if (len < 0){
629 		return 0;
630 	}
631 	if (udp->dest != htons(BOOTP_CLIENT))
632 		return 0;
633 	if (dhcpreply->bp_op != BOOTP_REPLY)
634 		return 0;
635 	if (dhcpreply->bp_xid != xid)
636 		return 0;
637 	if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
638 		return 0;
639 	if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
640 	    (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
641 		return 0;
642 	}
643 
644 #ifdef SOLARIS_NETBOOT
645 	/* fill in netinfo */
646 	dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
647 	memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
648 #endif
649 
650 	arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
651 	dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
652 	netmask = default_netmask();
653 	arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
654 	memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);  /* Kill arp */
655 	arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
656 	memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN);  /* Kill arp */
657 	/* We don't care bootpreply->bp_file. It must be 'pxegrub' */
658 	memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
659 	decode_rfc1533(rfc1533_venddata, 0, len, 1);
660 	return(1);
661 }
662 
663 int dhcp(void)
664 {
665 	int retry;
666 	int reqretry;
667 	struct dhcpip_t ip;
668 	unsigned long  starttime;
669 
670 	if(!grub_eth_probe())
671 		return 0;
672 
673 	network_ready = 0;
674 
675 	memset(&ip, 0, sizeof(ip));
676 	ip.bp.bp_op = BOOTP_REQUEST;
677 	ip.bp.bp_htype = 1;
678 	ip.bp.bp_hlen = ETH_ALEN;
679 	starttime = currticks();
680 	/* Use lower 32 bits of node address, more likely to be
681 	   distinct than the time since booting */
682 	memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
683 	ip.bp.bp_xid = xid += htonl(starttime);
684 	memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
685 	memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
686 	memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
687 
688 	for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
689 		long timeout;
690 
691 		rx_qdrain();
692 
693 		udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
694 			     sizeof(ip), &ip);
695 		timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
696 		if (await_reply(await_dhcp, 0, NULL, timeout)) {
697 			/* If not a DHCPOFFER then must be just a
698 			   BOOTP reply, be backward compatible with
699 			   BOOTP then. Jscott report a bug here, but I
700 			   don't know how it happened */
701 			if (dhcp_reply != DHCPOFFER){
702 				network_ready = 1;
703 				return(1);
704 			}
705 			dhcp_reply = 0;
706 			memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
707 			memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
708 			/* Beware: the magic numbers 9 and 15 depend on
709 			   the layout of dhcprequest */
710 			memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
711 			memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
712 			for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
713 				udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
714 					     sizeof(ip), &ip);
715 				dhcp_reply=0;
716 				timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
717 				if (await_reply(await_dhcp, 0, NULL, timeout))
718 					if (dhcp_reply == DHCPACK){
719 						network_ready = 1;
720 						return(1);
721 					}
722 				if (user_abort)
723 					return 0;
724 			}
725 		}
726 		if (user_abort)
727 			return 0;
728 		ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
729 	}
730 	return(0);
731 }
732 
733 #ifdef MULTICAST_LEVEL2
734 static void send_igmp_reports(unsigned long now)
735 {
736 	int i;
737 	for(i = 0; i < MAX_IGMP; i++) {
738 		if (igmptable[i].time && (now >= igmptable[i].time)) {
739 			struct igmp_ip_t igmp;
740 			igmp.router_alert[0] = 0x94;
741 			igmp.router_alert[1] = 0x04;
742 			igmp.router_alert[2] = 0;
743 			igmp.router_alert[3] = 0;
744 			build_ip_hdr(igmptable[i].group.s_addr,
745 				1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
746 			igmp.igmp.type = IGMPv2_REPORT;
747 			if (last_igmpv1 &&
748 				(now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
749 				igmp.igmp.type = IGMPv1_REPORT;
750 			}
751 			igmp.igmp.response_time = 0;
752 			igmp.igmp.chksum = 0;
753 			igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
754 			igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
755 			ip_transmit(sizeof(igmp), &igmp);
756 #ifdef	MDEBUG
757 			printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
758 #endif
759 			/* Don't send another igmp report until asked */
760 			igmptable[i].time = 0;
761 		}
762 	}
763 }
764 
765 static void process_igmp(struct iphdr *ip, unsigned long now)
766 {
767 	struct igmp *igmp;
768 	int i;
769 	unsigned iplen = 0;
770 	if (!ip || (ip->protocol == IP_IGMP) ||
771 		(nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
772 		return;
773 	}
774 	iplen = (ip->verhdrlen & 0xf)*4;
775 	igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
776 	if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
777 		return;
778 	if ((igmp->type == IGMP_QUERY) &&
779 		(ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
780 		unsigned long interval = IGMP_INTERVAL;
781 		if (igmp->response_time == 0) {
782 			last_igmpv1 = now;
783 		} else {
784 			interval = (igmp->response_time * TICKS_PER_SEC)/10;
785 		}
786 
787 #ifdef	MDEBUG
788 		printf("Received IGMP query for: %@\n", igmp->group.s_addr);
789 #endif
790 		for(i = 0; i < MAX_IGMP; i++) {
791 			uint32_t group = igmptable[i].group.s_addr;
792 			if ((group == 0) || (group == igmp->group.s_addr)) {
793 				unsigned long time;
794 				time = currticks() + rfc1112_sleep_interval(interval, 0);
795 				if (time < igmptable[i].time) {
796 					igmptable[i].time = time;
797 				}
798 			}
799 		}
800 	}
801 	if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
802 		(ip->dest.s_addr == igmp->group.s_addr)) {
803 #ifdef	MDEBUG
804 		printf("Received IGMP report for: %@\n", igmp->group.s_addr);
805 #endif
806 		for(i = 0; i < MAX_IGMP; i++) {
807 			if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
808 				igmptable[i].time != 0) {
809 				igmptable[i].time = 0;
810 			}
811 		}
812 	}
813 }
814 
815 void leave_group(int slot)
816 {
817 	/* Be very stupid and always send a leave group message if
818 	 * I have subscribed.  Imperfect but it is standards
819 	 * compliant, easy and reliable to implement.
820 	 *
821 	 * The optimal group leave method is to only send leave when,
822 	 * we were the last host to respond to a query on this group,
823 	 * and igmpv1 compatibility is not enabled.
824 	 */
825 	if (igmptable[slot].group.s_addr) {
826 		struct igmp_ip_t igmp;
827 		igmp.router_alert[0] = 0x94;
828 		igmp.router_alert[1] = 0x04;
829 		igmp.router_alert[2] = 0;
830 		igmp.router_alert[3] = 0;
831 		build_ip_hdr(htonl(GROUP_ALL_HOSTS),
832 			1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
833 		igmp.igmp.type = IGMP_LEAVE;
834 		igmp.igmp.response_time = 0;
835 		igmp.igmp.chksum = 0;
836 		igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
837 		igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
838 		ip_transmit(sizeof(igmp), &igmp);
839 #ifdef	MDEBUG
840 		printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
841 #endif
842 	}
843 	memset(&igmptable[slot], 0, sizeof(igmptable[0]));
844 }
845 
846 void join_group(int slot, unsigned long group)
847 {
848 	/* I have already joined */
849 	if (igmptable[slot].group.s_addr == group)
850 		return;
851 	if (igmptable[slot].group.s_addr) {
852 		leave_group(slot);
853 	}
854 	/* Only join a group if we are given a multicast ip, this way
855 	 * code can be given a non-multicast (broadcast or unicast ip)
856 	 * and still work...
857 	 */
858 	if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
859 		igmptable[slot].group.s_addr = group;
860 		igmptable[slot].time = currticks();
861 	}
862 }
863 #else
864 #define send_igmp_reports(now);
865 #define process_igmp(ip, now)
866 #endif
867 
868 /**************************************************************************
869 AWAIT_REPLY - Wait until we get a response for our request
870 ************f**************************************************************/
871 int await_reply(reply_t reply, int ival, void *ptr, long timeout)
872 {
873 	unsigned long time, now;
874 	struct	iphdr *ip;
875 	unsigned iplen = 0;
876 	struct	udphdr *udp;
877 	unsigned short ptype;
878 	int result;
879 
880 	user_abort = 0;
881 
882 	time = timeout + currticks();
883 	/* The timeout check is done below.  The timeout is only checked if
884 	 * there is no packet in the Rx queue.  This assumes that eth_poll()
885 	 * needs a negligible amount of time.
886 	 */
887 	for (;;) {
888 		now = currticks();
889 		send_igmp_reports(now);
890 		result = eth_poll(1);
891 		if (result == 0) {
892 			/* We don't have anything */
893 
894 			/* Check for abort key only if the Rx queue is empty -
895 			 * as long as we have something to process, don't
896 			 * assume that something failed.  It is unlikely that
897 			 * we have no processing time left between packets.  */
898 			poll_interruptions();
899 			/* Do the timeout after at least a full queue walk.  */
900 			if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
901 				break;
902 			}
903 			continue;
904 		}
905 
906 		/* We have something! */
907 
908 		/* Find the Ethernet packet type */
909 		if (nic.packetlen >= ETH_HLEN) {
910 			ptype = ((unsigned short) nic.packet[12]) << 8
911 				| ((unsigned short) nic.packet[13]);
912 		} else continue; /* what else could we do with it? */
913 		/* Verify an IP header */
914 		ip = 0;
915 		if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
916 			unsigned ipoptlen;
917 			ip = (struct iphdr *)&nic.packet[ETH_HLEN];
918 			if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
919 				continue;
920 			iplen = (ip->verhdrlen & 0xf) * 4;
921 			if (ipchksum(ip, iplen) != 0)
922 				continue;
923 			if (ip->frags & htons(0x3FFF)) {
924 				static int warned_fragmentation = 0;
925 				if (!warned_fragmentation) {
926 					printf("ALERT: got a fragmented packet - reconfigure your server\n");
927 					warned_fragmentation = 1;
928 				}
929 				continue;
930 			}
931 			if (ntohs(ip->len) > ETH_MAX_MTU)
932 				continue;
933 
934 			ipoptlen = iplen - sizeof(struct iphdr);
935 			if (ipoptlen) {
936 				/* Delete the ip options, to guarantee
937 				 * good alignment, and make etherboot simpler.
938 				 */
939 				memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
940 					&nic.packet[ETH_HLEN + iplen],
941 					nic.packetlen - ipoptlen);
942 				nic.packetlen -= ipoptlen;
943 			}
944 		}
945 		udp = 0;
946 		if (ip && (ip->protocol == IP_UDP) &&
947 		    (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
948 			udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
949 
950 			/* Make certain we have a reasonable packet length */
951 			if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
952 				continue;
953 
954 			if (udp->chksum && udpchksum(ip, udp)) {
955 				printf("UDP checksum error\n");
956 				continue;
957 			}
958 		}
959 		result = reply(ival, ptr, ptype, ip, udp);
960 		if (result > 0) {
961 			return result;
962 		}
963 
964 		/* If it isn't a packet the upper layer wants see if there is a default
965 		 * action.  This allows us reply to arp and igmp queryies.
966 		 */
967 		if ((ptype == ARP) &&
968 		    (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
969 			struct	arprequest *arpreply;
970 			unsigned long tmp;
971 
972 			arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
973 			memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
974 			if ((arpreply->opcode == htons(ARP_REQUEST)) &&
975 			    (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
976 				arpreply->opcode = htons(ARP_REPLY);
977 				memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
978 				memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
979 				memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
980 				memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
981 				eth_transmit(arpreply->thwaddr, ARP,
982 					     sizeof(struct  arprequest),
983 					     arpreply);
984 #ifdef	MDEBUG
985 				memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
986 				printf("Sent ARP reply to: %@\n",tmp);
987 #endif	/* MDEBUG */
988 			}
989 		}
990 		process_igmp(ip, now);
991 	}
992 	return(0);
993 }
994 
995 #ifdef	REQUIRE_VCI_ETHERBOOT
996 /**************************************************************************
997 FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
998 On entry p points to byte count of VCI options
999 **************************************************************************/
1000 static int find_vci_etherboot(unsigned char *p)
1001 {
1002 	unsigned char	*end = p + 1 + *p;
1003 
1004 	for (p++; p < end; ) {
1005 		if (*p == RFC2132_VENDOR_CLASS_ID) {
1006 			if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
1007 				return (1);
1008 		} else if (*p == RFC1533_END)
1009 			return (0);
1010 		p += TAG_LEN(p) + 2;
1011 	}
1012 	return (0);
1013 }
1014 #endif	/* REQUIRE_VCI_ETHERBOOT */
1015 
1016 /**
1017  * decode_rfc1533
1018  *
1019  * Decodes RFC1533 header
1020  **/
1021 int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
1022 {
1023 	static unsigned char *extdata = NULL, *extend = NULL;
1024 	unsigned char        *extpath = NULL;
1025 	unsigned char        *endp;
1026 
1027 	if (block == 0) {
1028 		end_of_rfc1533 = NULL;
1029 		if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
1030 			return(0); /* no RFC 1533 header found */
1031 		p += 4;
1032 		endp = p + len;
1033 	} else {
1034 		if (block == 1) {
1035 			if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
1036 				return(0); /* no RFC 1533 header found */
1037 			p += 4;
1038 			len -= 4; }
1039 		if (extend + len <= (unsigned char *)
1040 		    rfc1533_venddata + sizeof(rfc1533_venddata)) {
1041 			memcpy(extend, p, len);
1042 			extend += len;
1043 		} else {
1044 			printf("Overflow in vendor data buffer! Aborting...\n");
1045 			*extdata = RFC1533_END;
1046 			return(0);
1047 		}
1048 		p = extdata; endp = extend;
1049 	}
1050 	if (!eof)
1051 		return 1;
1052 	while (p < endp) {
1053 		unsigned char c = *p;
1054 		if (c == RFC1533_PAD) {
1055 			p++;
1056 			continue;
1057 		}
1058 		else if (c == RFC1533_END) {
1059 			end_of_rfc1533 = endp = p;
1060 			continue;
1061 		}
1062 		else if (c == RFC1533_NETMASK)
1063 			memcpy(&netmask, p+2, sizeof(in_addr));
1064 		else if (c == RFC1533_GATEWAY) {
1065 			/* This is a little simplistic, but it will
1066 			   usually be sufficient.
1067 			   Take only the first entry */
1068 			if (TAG_LEN(p) >= sizeof(in_addr))
1069 				memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
1070 		}
1071 		else if (c == RFC1533_EXTENSIONPATH)
1072 			extpath = p;
1073 		else if (c == RFC2132_MSG_TYPE)
1074 			dhcp_reply=*(p+2);
1075 		else if (c == RFC2132_SRV_ID)
1076 			memcpy(&dhcp_server, p+2, sizeof(in_addr));
1077 		else if (c == RFC1533_HOSTNAME) {
1078 			hostname = p + 2;
1079 			hostnamelen = *(p + 1);
1080 		}
1081 		else if (c == RFC1533_VENDOR_CONFIGFILE){
1082 			int l = TAG_LEN (p);
1083 
1084 			/* Eliminate the trailing NULs according to RFC 2132.  */
1085 			while (*(p + 2 + l - 1) == '\000' && l > 0)
1086 				l--;
1087 
1088 			/* XXX: Should check if LEN is less than the maximum length
1089 			   of CONFIG_FILE. This kind of robustness will be a goal
1090 			   in GRUB 1.0.  */
1091 			memcpy (config_file, p + 2, l);
1092 			config_file[l] = 0;
1093 		}
1094 		else {
1095 			;
1096 		}
1097 		p += TAG_LEN(p) + 2;
1098 	}
1099 	extdata = extend = endp;
1100 	if (block <= 0 && extpath != NULL) {
1101 		char fname[64];
1102 		if (TAG_LEN(extpath) >= sizeof(fname)){
1103 			printf("Overflow in vendor data buffer! Aborting...\n");
1104 			*extdata = RFC1533_END;
1105 			return(0);
1106 		}
1107 		memcpy(fname, extpath+2, TAG_LEN(extpath));
1108 		fname[(int)TAG_LEN(extpath)] = '\0';
1109 		printf("Loading BOOTP-extension file: %s\n",fname);
1110 		tftp_file_read(fname, decode_rfc1533);
1111 	}
1112 	return 1;	/* proceed with next block */
1113 }
1114 
1115 
1116 /* FIXME double check TWO_SECOND_DIVISOR */
1117 #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
1118 /**************************************************************************
1119 RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
1120 **************************************************************************/
1121 long rfc2131_sleep_interval(long base, int exp)
1122 {
1123 	unsigned long tmo;
1124 #ifdef BACKOFF_LIMIT
1125 	if (exp > BACKOFF_LIMIT)
1126 		exp = BACKOFF_LIMIT;
1127 #endif
1128 	tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
1129 	return tmo;
1130 }
1131 
1132 #ifdef MULTICAST_LEVEL2
1133 /**************************************************************************
1134 RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
1135 **************************************************************************/
1136 long rfc1112_sleep_interval(long base, int exp)
1137 {
1138 	unsigned long divisor, tmo;
1139 #ifdef BACKOFF_LIMIT
1140 	if (exp > BACKOFF_LIMIT)
1141 		exp = BACKOFF_LIMIT;
1142 #endif
1143 	divisor = RAND_MAX/(base << exp);
1144 	tmo = random()/divisor;
1145 	return tmo;
1146 }
1147 #endif /* MULTICAST_LEVEL_2 */
1148 /* ifconfig - configure network interface.  */
1149 int
1150 ifconfig (char *ip, char *sm, char *gw, char *svr)
1151 {
1152   in_addr tmp;
1153 
1154   if (sm)
1155     {
1156       if (! inet_aton (sm, &tmp))
1157 	return 0;
1158 
1159       netmask = tmp.s_addr;
1160     }
1161 
1162   if (ip)
1163     {
1164       if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
1165 	return 0;
1166 
1167       if (! netmask && ! sm)
1168 	netmask = default_netmask ();
1169     }
1170 
1171   if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
1172     return 0;
1173 
1174   /* Clear out the ARP entry.  */
1175   grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
1176 
1177   if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
1178     return 0;
1179 
1180   /* Likewise.  */
1181   grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
1182 
1183   if (ip || sm)
1184     {
1185       if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
1186 	  || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
1187 	  || ! netmask)
1188 	network_ready = 0;
1189       else
1190 	network_ready = 1;
1191     }
1192 
1193   update_network_configuration();
1194   return 1;
1195 }
1196 
1197 /*
1198  * print_network_configuration
1199  *
1200  * Output the network configuration. It may broke the graphic console now.:-(
1201  */
1202 void print_network_configuration (void)
1203 {
1204 	EnterFunction("print_network_configuration");
1205 	if (! grub_eth_probe ())
1206 		grub_printf ("No ethernet card found.\n");
1207 	else if (! network_ready)
1208 		grub_printf ("Not initialized yet.\n");
1209 	else {
1210 		etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
1211 		etherboot_printf ("Netmask: %@\n", netmask);
1212 		etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
1213 		etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
1214 	}
1215 	LeaveFunction("print_network_configuration");
1216 }
1217 
1218 /*
1219  * update_network_configuration
1220  *
1221  * Update network configuration for diskless clients (Solaris only)
1222  */
1223 static void update_network_configuration (void)
1224 {
1225 #ifdef SOLARIS_NETBOOT
1226   	struct sol_netinfo {
1227 	  	uint8_t sn_infotype;
1228 		uint8_t sn_mactype;
1229 		uint8_t sn_maclen;
1230 	  	uint8_t sn_padding;
1231 		unsigned long sn_ciaddr;
1232 		unsigned long sn_siaddr;
1233 		unsigned long sn_giaddr;
1234 		unsigned long sn_netmask;
1235 		uint8_t sn_macaddr[1];
1236 	} *sip;
1237 
1238 	if (! network_ready)
1239 	  	return;
1240 
1241 	sip = (struct sol_netinfo *)dhcpack_buf;
1242 	sip->sn_infotype = 0xf0;	/* something not BOOTP_REPLY */
1243 	sip->sn_mactype = 4;		/* DL_ETHER */
1244 	sip->sn_maclen = ETH_ALEN;
1245 	sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
1246 	sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
1247 	sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
1248 	sip->sn_netmask = netmask;
1249 	memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
1250 	dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
1251 #endif /* SOLARIS_NETBOOT */
1252 }
1253 
1254 /**
1255  * cleanup_net
1256  *
1257  * Mark network unusable, and disable NICs
1258  */
1259 void cleanup_net (void)
1260 {
1261 	if (network_ready){
1262 		/* Stop receiving packets.  */
1263 		eth_disable ();
1264 		network_ready = 0;
1265 	}
1266 }
1267