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