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