Merge branch 'master' of git://github.com/illumos/illumos-gate
[unleashed.git] / usr / src / grub / grub-0.97 / netboot / nic.c
blob23b8d59fc805f8f53ab10105958c630252080022
1 /**************************************************************************
2 Etherboot - Network Bootstrap Program
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
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"
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 };
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
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
94 /* See nic.h */
95 int user_abort = 0;
96 int network_ready = 0;
98 #ifdef REQUIRE_VCI_ETHERBOOT
99 int vci_etherboot;
100 #endif
102 char *bootfile = NULL;
103 configfile_origin_t configfile_origin = CFG_HARDCODED;
104 char *vendor_configfile = NULL;
105 char vendor_configfile_len;
107 static void update_network_configuration(void);
109 static int dummy(void *unused __unused)
111 return (0);
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.
120 static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
122 struct nic nic =
125 0, /* dev.disable */
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 */
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 */
156 int grub_eth_probe(void)
158 static int probed = 0;
159 struct dev *dev;
161 EnterFunction("grub_eth_probe");
163 if (probed)
164 return 1;
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);
174 probed = (eth_probe(dev) == PROBE_WORKED);
176 LeaveFunction("grub_eth_probe");
177 return probed;
180 int eth_probe(struct dev *dev)
182 return probe(dev);
185 int eth_poll(int retrieve)
187 return ((*nic.poll)(&nic, retrieve));
190 void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
192 (*nic.transmit)(&nic, d, t, s, p);
193 if (t == IP) twiddle();
196 void eth_disable(void)
198 #ifdef MULTICAST_LEVEL2
199 int i;
200 for(i = 0; i < MAX_IGMP; i++) {
201 leave_group(i);
203 #endif
204 disable(&nic.dev);
207 void eth_irq (irq_action_t action)
209 (*nic.irq)(&nic,action);
212 /**************************************************************************
213 IPCHKSUM - Checksum IP Header
214 **************************************************************************/
215 uint16_t ipchksum(const void *data, unsigned long length)
217 unsigned long sum;
218 unsigned long i;
219 const uint8_t *ptr;
221 /* In the most straight forward way possible,
222 * compute an ip style checksum.
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;
232 /* Add the new value */
233 sum += value;
234 /* Wrap around the carry */
235 if (sum > 0xFFFF) {
236 sum = (sum + (sum >> 16)) & 0xFFFF;
239 return (~cpu_to_le16(sum)) & 0xFFFF;
242 uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
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.
252 new = bswap_16(new);
254 checksum = sum + new;
255 if (checksum > 0xFFFF) {
256 checksum -= 0xFFFF;
258 return (~checksum) & 0xFFFF;
261 /**************************************************************************
262 DEFAULT_NETMASK - Return default netmask for IP address
263 **************************************************************************/
264 static inline unsigned long default_netmask(void)
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));
275 /**************************************************************************
276 IP_TRANSMIT - Send an IP datagram
277 **************************************************************************/
278 static int await_arp(int ival, void *ptr,
279 unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
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];
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;
296 int ip_transmit(int len, const void *buf)
298 unsigned long destip;
299 struct iphdr *ip;
300 struct arprequest arpreq;
301 int arpentry, i;
302 int retry;
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);
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;
353 return(0);
355 xmit:
356 eth_transmit(arptable[arpentry].node, IP, len, buf);
358 return 1;
361 void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
362 int len, const void *buf)
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);
380 static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
382 struct udp_pseudo_hdr pseudo;
383 uint16_t checksum;
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;
392 /* Sum the pseudo header */
393 checksum = ipchksum(&pseudo, 12);
395 /* Sum the rest of the udp packet */
396 checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
397 return checksum;
401 void build_udp_hdr(unsigned long destip,
402 unsigned int srcsock, unsigned int destsock, int ttl,
403 int len, const void *buf)
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;
419 /**************************************************************************
420 UDP_TRANSMIT - Send an UDP datagram
421 **************************************************************************/
422 int udp_transmit(unsigned long destip, unsigned int srcsock,
423 unsigned int destsock, int len, const void *buf)
425 build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
426 return ip_transmit(len, buf);
429 /**************************************************************************
430 QDRAIN - clear the nic's receive queue
431 **************************************************************************/
432 static int await_qdrain(int ival __unused, void *ptr __unused,
433 unsigned short ptype __unused,
434 struct iphdr *ip __unused, struct udphdr *udp __unused)
436 return 0;
439 void rx_qdrain(void)
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);
451 * rarp
453 * Get IP address by rarp. Just copy from etherboot
455 static int await_rarp(int ival, void *ptr, unsigned short ptype,
456 struct iphdr *ip, struct udphdr *udp)
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;
473 return 0;
476 int rarp(void)
478 int retry;
480 /* arp and rarp requests share the same packet structure. */
481 struct arprequest rarpreq;
483 if(!grub_eth_probe())
484 return 0;
485 network_ready = 0;
487 memset(&rarpreq, 0, sizeof(rarpreq));
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 */
499 for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
500 long timeout;
501 eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
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;
510 if (retry == MAX_ARP_RETRIES) {
511 return (0);
514 network_ready = 1;
515 update_network_configuration();
516 return (1);
520 * bootp
522 * Get IP address by bootp, segregate from bootp in etherboot.
524 static int await_bootp(int ival __unused, void *ptr __unused,
525 unsigned short ptype __unused, struct iphdr *ip __unused,
526 struct udphdr *udp)
528 struct bootp_t *bootpreply;
529 int len; /* Length of vendor */
531 if (!udp) {
532 return 0;
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;
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;
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
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);
572 int bootp(void)
574 int retry;
575 struct bootpip_t ip;
576 unsigned long starttime;
578 EnterFunction("bootp");
580 if(!grub_eth_probe())
581 return 0;
582 network_ready = 0;
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 */
597 for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
598 long timeout;
600 rx_qdrain();
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);
609 if (user_abort)
610 return 0;
611 ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
613 return(0);
617 * dhcp
619 * Get IP address by dhcp, segregate from bootp in etherboot.
621 static int await_dhcp(int ival __unused, void *ptr __unused,
622 unsigned short ptype __unused, struct iphdr *ip __unused,
623 struct udphdr *udp)
625 struct dhcp_t *dhcpreply;
626 int len;
628 if (!udp) {
629 return 0;
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;
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;
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);
669 int dhcp(void)
671 int retry;
672 int reqretry;
673 struct dhcpip_t ip;
674 unsigned long starttime;
676 /* try bios pxe stack first */
677 if (dhcp_undi())
678 return 1;
680 if(!grub_eth_probe())
681 return 0;
683 network_ready = 0;
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);
698 for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
699 long timeout;
701 rx_qdrain();
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);
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);
732 if (user_abort)
733 return 0;
736 if (user_abort)
737 return 0;
738 ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
740 return(0);
743 #ifdef MULTICAST_LEVEL2
744 static void send_igmp_reports(unsigned long now)
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;
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;
775 static void process_igmp(struct iphdr *ip, unsigned long now)
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;
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;
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;
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;
825 void leave_group(int slot)
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.
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.
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
853 memset(&igmptable[slot], 0, sizeof(igmptable[0]));
856 void join_group(int slot, unsigned long group)
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);
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...
868 if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
869 igmptable[slot].group.s_addr = group;
870 igmptable[slot].time = currticks();
873 #else
874 #define send_igmp_reports(now);
875 #define process_igmp(ip, now)
876 #endif
878 /**************************************************************************
879 AWAIT_REPLY - Wait until we get a response for our request
880 ************f**************************************************************/
881 int await_reply(reply_t reply, int ival, void *ptr, long timeout)
883 unsigned long time, now;
884 struct iphdr *ip;
885 unsigned iplen = 0;
886 struct udphdr *udp;
887 unsigned short ptype;
888 int result;
890 user_abort = 0;
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.
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 */
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;
913 continue;
916 /* We have something! */
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;
939 continue;
941 if (ntohs(ip->len) > ETH_MAX_MTU)
942 continue;
944 ipoptlen = iplen - sizeof(struct iphdr);
945 if (ipoptlen) {
946 /* Delete the ip options, to guarantee
947 * good alignment, and make etherboot simpler.
949 memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
950 &nic.packet[ETH_HLEN + iplen],
951 nic.packetlen - ipoptlen);
952 nic.packetlen -= ipoptlen;
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)];
960 /* Make certain we have a reasonable packet length */
961 if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
962 continue;
964 if (udp->chksum && udpchksum(ip, udp)) {
965 printf("UDP checksum error\n");
966 continue;
969 result = reply(ival, ptr, ptype, ip, udp);
970 if (result > 0) {
971 return result;
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.
977 if ((ptype == ARP) &&
978 (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
979 struct arprequest *arpreply;
980 unsigned long tmp;
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 */
1000 process_igmp(ip, now);
1002 return(0);
1005 #ifdef REQUIRE_VCI_ETHERBOOT
1006 /**************************************************************************
1007 FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
1008 On entry p points to byte count of VCI options
1009 **************************************************************************/
1010 static int find_vci_etherboot(unsigned char *p)
1012 unsigned char *end = p + 1 + *p;
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;
1022 return (0);
1024 #endif /* REQUIRE_VCI_ETHERBOOT */
1027 * decode_rfc1533
1029 * Decodes RFC1533 header
1031 int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
1033 static unsigned char *extdata = NULL, *extend = NULL;
1034 unsigned char *extpath = NULL;
1035 unsigned char *endp;
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);
1058 p = extdata; endp = extend;
1060 if (!eof)
1061 return 1;
1062 while (p < endp) {
1063 unsigned char c = *p;
1064 if (c == RFC1533_PAD) {
1065 p++;
1066 continue;
1068 else if (c == RFC1533_END) {
1069 end_of_rfc1533 = endp = p;
1070 continue;
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));
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);
1091 else if (c == RFC1533_VENDOR_CONFIGFILE){
1092 int l = TAG_LEN (p);
1094 /* Eliminate the trailing NULs according to RFC 2132. */
1095 while (*(p + 2 + l - 1) == '\000' && l > 0)
1096 l--;
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;
1107 else {
1110 p += TAG_LEN(p) + 2;
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);
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);
1125 return 1; /* proceed with next block */
1129 /* FIXME double check TWO_SECOND_DIVISOR */
1130 #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
1131 /**************************************************************************
1132 RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
1133 **************************************************************************/
1134 long rfc2131_sleep_interval(long base, int exp)
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;
1145 #ifdef MULTICAST_LEVEL2
1146 /**************************************************************************
1147 RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
1148 **************************************************************************/
1149 long rfc1112_sleep_interval(long base, int exp)
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;
1160 #endif /* MULTICAST_LEVEL_2 */
1161 /* ifconfig - configure network interface. */
1163 ifconfig (char *ip, char *sm, char *gw, char *svr)
1165 in_addr tmp;
1167 if (sm)
1169 if (! inet_aton (sm, &tmp))
1170 return 0;
1172 netmask = tmp.s_addr;
1175 if (ip)
1177 if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
1178 return 0;
1180 if (! netmask && ! sm)
1181 netmask = default_netmask ();
1184 if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
1185 return 0;
1187 /* Clear out the ARP entry. */
1188 grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
1190 if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
1191 return 0;
1193 /* Likewise. */
1194 grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
1196 if (ip || sm)
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;
1206 update_network_configuration();
1207 return 1;
1211 * print_network_configuration
1213 * Output the network configuration. It may broke the graphic console now.:-(
1215 void print_network_configuration (void)
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);
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 {
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
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;
1245 if (bootfile == NULL)
1246 etherboot_printf ("BootFile: not set\n");
1247 else
1248 etherboot_printf ("BootFile: %s\n", bootfile);
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");
1268 LeaveFunction("print_network_configuration");
1272 * update_network_configuration
1274 * Update network configuration for diskless clients (Solaris only)
1276 static void update_network_configuration (void)
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;
1291 if (! network_ready)
1292 return;
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 */
1308 * cleanup_net
1310 * Mark network unusable, and disable NICs
1312 void cleanup_net (void)
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;
1324 /*******************************************************************
1325 * dhcp implementation reusing the BIOS pxe stack
1327 static void
1328 dhcp_copy(struct dhcp_t *dhcpreply)
1330 unsigned long time;
1331 int ret, len = DHCP_OPT_LEN;
1333 /* fill in netinfo */
1334 dhcpack_length = sizeof (struct dhcp_t);
1335 memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
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);
1350 int dhcp_undi(void)
1352 struct dhcp_t *dhcpreply;
1354 if (!undi_bios_pxe((void **)&dhcpreply))
1355 return 0;
1357 dhcp_copy(dhcpreply);
1358 network_ready = 1;
1359 use_bios_pxe = 1;
1360 return (1);