17c478bd9Sstevel@tonic-gate /**************************************************************************
27c478bd9Sstevel@tonic-gate Etherboot - Network Bootstrap Program
37c478bd9Sstevel@tonic-gate
47c478bd9Sstevel@tonic-gate Literature dealing with the network protocols:
57c478bd9Sstevel@tonic-gate ARP - RFC826
67c478bd9Sstevel@tonic-gate RARP - RFC903
77c478bd9Sstevel@tonic-gate IP - RFC791
87c478bd9Sstevel@tonic-gate UDP - RFC768
97c478bd9Sstevel@tonic-gate BOOTP - RFC951, RFC2132 (vendor extensions)
107c478bd9Sstevel@tonic-gate DHCP - RFC2131, RFC2132 (options)
117c478bd9Sstevel@tonic-gate TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
127c478bd9Sstevel@tonic-gate RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
137c478bd9Sstevel@tonic-gate NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
147c478bd9Sstevel@tonic-gate IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
157c478bd9Sstevel@tonic-gate
167c478bd9Sstevel@tonic-gate **************************************************************************/
177c478bd9Sstevel@tonic-gate #include "etherboot.h"
187c478bd9Sstevel@tonic-gate #include "grub.h"
197c478bd9Sstevel@tonic-gate #include "nic.h"
207c478bd9Sstevel@tonic-gate #include "elf.h" /* FOR EM_CURRENT */
217c478bd9Sstevel@tonic-gate #include "bootp.h"
227c478bd9Sstevel@tonic-gate #include "if_arp.h"
237c478bd9Sstevel@tonic-gate #include "tftp.h"
247c478bd9Sstevel@tonic-gate #include "timer.h"
257c478bd9Sstevel@tonic-gate #include "ip.h"
267c478bd9Sstevel@tonic-gate #include "udp.h"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /* Currently no other module uses rom, but it is available */
297c478bd9Sstevel@tonic-gate struct rom_info rom;
307c478bd9Sstevel@tonic-gate struct arptable_t arptable[MAX_ARP];
317c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
327c478bd9Sstevel@tonic-gate unsigned long last_igmpv1 = 0;
337c478bd9Sstevel@tonic-gate struct igmptable_t igmptable[MAX_IGMP];
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate static unsigned long netmask;
367c478bd9Sstevel@tonic-gate /* Used by nfs.c */
377c478bd9Sstevel@tonic-gate char *hostname = "";
387c478bd9Sstevel@tonic-gate int hostnamelen = 0;
3999ed6083Sszhou /* Used by fsys_tftp.c */
4099ed6083Sszhou int use_bios_pxe = 0;
417c478bd9Sstevel@tonic-gate static uint32_t xid;
427c478bd9Sstevel@tonic-gate static unsigned char *end_of_rfc1533 = NULL;
437c478bd9Sstevel@tonic-gate static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
447c478bd9Sstevel@tonic-gate static const in_addr zeroIP = { 0L };
457c478bd9Sstevel@tonic-gate static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
467c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
477c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
487c478bd9Sstevel@tonic-gate static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
497c478bd9Sstevel@tonic-gate static int dhcp_reply;
507c478bd9Sstevel@tonic-gate static in_addr dhcp_server = { 0L };
517c478bd9Sstevel@tonic-gate static in_addr dhcp_addr = { 0L };
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate static const unsigned char dhcpdiscover[] = {
547c478bd9Sstevel@tonic-gate RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
557c478bd9Sstevel@tonic-gate RFC2132_MAX_SIZE, 2, /* request as much as we can */
567c478bd9Sstevel@tonic-gate ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
577c478bd9Sstevel@tonic-gate /* Vendor class identifier */
587c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
597c478bd9Sstevel@tonic-gate RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
607c478bd9Sstevel@tonic-gate 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
617c478bd9Sstevel@tonic-gate '0','0','2','0','0','1',
627c478bd9Sstevel@tonic-gate #else
637c478bd9Sstevel@tonic-gate RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
647c478bd9Sstevel@tonic-gate #endif
657c478bd9Sstevel@tonic-gate RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
667c478bd9Sstevel@tonic-gate RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
677c478bd9Sstevel@tonic-gate };
687c478bd9Sstevel@tonic-gate static const unsigned char dhcprequest [] = {
697c478bd9Sstevel@tonic-gate RFC2132_MSG_TYPE,1,DHCPREQUEST,
707c478bd9Sstevel@tonic-gate RFC2132_SRV_ID,4,0,0,0,0,
717c478bd9Sstevel@tonic-gate RFC2132_REQ_ADDR,4,0,0,0,0,
727c478bd9Sstevel@tonic-gate RFC2132_MAX_SIZE,2, /* request as much as we can */
737c478bd9Sstevel@tonic-gate ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
747c478bd9Sstevel@tonic-gate /* Vendor class identifier */
757c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
767c478bd9Sstevel@tonic-gate RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
777c478bd9Sstevel@tonic-gate 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
787c478bd9Sstevel@tonic-gate '0','0','2','0','0','1',
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate RFC2132_PARAM_LIST,
837c478bd9Sstevel@tonic-gate /* 4 standard + 2 vendortags */
847c478bd9Sstevel@tonic-gate 4 + 2,
857c478bd9Sstevel@tonic-gate /* Standard parameters */
867c478bd9Sstevel@tonic-gate RFC1533_NETMASK, RFC1533_GATEWAY,
877c478bd9Sstevel@tonic-gate RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
887c478bd9Sstevel@tonic-gate /* Etherboot vendortags */
897c478bd9Sstevel@tonic-gate RFC1533_VENDOR_MAGIC,
907c478bd9Sstevel@tonic-gate RFC1533_VENDOR_CONFIGFILE,
917c478bd9Sstevel@tonic-gate RFC1533_END
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /* See nic.h */
957c478bd9Sstevel@tonic-gate int user_abort = 0;
967c478bd9Sstevel@tonic-gate int network_ready = 0;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate #ifdef REQUIRE_VCI_ETHERBOOT
997c478bd9Sstevel@tonic-gate int vci_etherboot;
1007c478bd9Sstevel@tonic-gate #endif
1017c478bd9Sstevel@tonic-gate
1022506833eSJan Setje-Eilers char *bootfile = NULL;
1032506833eSJan Setje-Eilers configfile_origin_t configfile_origin = CFG_HARDCODED;
1042506833eSJan Setje-Eilers char *vendor_configfile = NULL;
1052506833eSJan Setje-Eilers char vendor_configfile_len;
1062506833eSJan Setje-Eilers
1077c478bd9Sstevel@tonic-gate static void update_network_configuration(void);
1087c478bd9Sstevel@tonic-gate
dummy(void * unused __unused)1097c478bd9Sstevel@tonic-gate static int dummy(void *unused __unused)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate return (0);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate /* Careful. We need an aligned buffer to avoid problems on machines
1157c478bd9Sstevel@tonic-gate * that care about alignment. To trivally align the ethernet data
1167c478bd9Sstevel@tonic-gate * (the ip hdr and arp requests) we offset the packet by 2 bytes.
1177c478bd9Sstevel@tonic-gate * leaving the ethernet data 16 byte aligned. Beyond this
1187c478bd9Sstevel@tonic-gate * we use memmove but this makes the common cast simple and fast.
1197c478bd9Sstevel@tonic-gate */
120*5f82aa32SToomas Soome static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned(16);
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate struct nic nic =
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 0, /* dev.disable */
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 0,
1287c478bd9Sstevel@tonic-gate 0,
1297c478bd9Sstevel@tonic-gate PCI_BUS_TYPE,
1307c478bd9Sstevel@tonic-gate }, /* dev.devid */
1317c478bd9Sstevel@tonic-gate 0, /* index */
1327c478bd9Sstevel@tonic-gate 0, /* type */
1337c478bd9Sstevel@tonic-gate PROBE_FIRST, /* how_pobe */
1347c478bd9Sstevel@tonic-gate PROBE_NONE, /* to_probe */
1357c478bd9Sstevel@tonic-gate 0, /* failsafe */
1367c478bd9Sstevel@tonic-gate 0, /* type_index */
1377c478bd9Sstevel@tonic-gate {}, /* state */
1387c478bd9Sstevel@tonic-gate },
1397c478bd9Sstevel@tonic-gate (int (*)(struct nic *, int))dummy, /* poll */
1407c478bd9Sstevel@tonic-gate (void (*)(struct nic *, const char *,
1417c478bd9Sstevel@tonic-gate unsigned int, unsigned int,
1427c478bd9Sstevel@tonic-gate const char *))dummy, /* transmit */
1437c478bd9Sstevel@tonic-gate (void (*)(struct nic *, irq_action_t))dummy, /* irq */
1447c478bd9Sstevel@tonic-gate 0, /* flags */
1457c478bd9Sstevel@tonic-gate &rom, /* rom_info */
1467c478bd9Sstevel@tonic-gate arptable[ARP_CLIENT].node, /* node_addr */
1477c478bd9Sstevel@tonic-gate packet + ETH_DATA_ALIGN, /* packet */
1487c478bd9Sstevel@tonic-gate 0, /* packetlen */
1497c478bd9Sstevel@tonic-gate 0, /* ioaddr */
1507c478bd9Sstevel@tonic-gate 0, /* irqno */
1517c478bd9Sstevel@tonic-gate NULL, /* priv_data */
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate
grub_eth_probe(void)1567c478bd9Sstevel@tonic-gate int grub_eth_probe(void)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate static int probed = 0;
1597c478bd9Sstevel@tonic-gate struct dev *dev;
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate EnterFunction("grub_eth_probe");
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate if (probed)
1647c478bd9Sstevel@tonic-gate return 1;
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate network_ready = 0;
1677c478bd9Sstevel@tonic-gate grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
1687c478bd9Sstevel@tonic-gate dev = &nic.dev;
1697c478bd9Sstevel@tonic-gate dev->how_probe = -1;
1707c478bd9Sstevel@tonic-gate dev->type = NIC_DRIVER;
1717c478bd9Sstevel@tonic-gate dev->failsafe = 1;
1727c478bd9Sstevel@tonic-gate rom = *((struct rom_info *)ROM_INFO_LOCATION);
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate probed = (eth_probe(dev) == PROBE_WORKED);
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate LeaveFunction("grub_eth_probe");
1777c478bd9Sstevel@tonic-gate return probed;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
eth_probe(struct dev * dev)1807c478bd9Sstevel@tonic-gate int eth_probe(struct dev *dev)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate return probe(dev);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate
eth_poll(int retrieve)1857c478bd9Sstevel@tonic-gate int eth_poll(int retrieve)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate return ((*nic.poll)(&nic, retrieve));
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
eth_transmit(const char * d,unsigned int t,unsigned int s,const void * p)1907c478bd9Sstevel@tonic-gate void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate (*nic.transmit)(&nic, d, t, s, p);
1937c478bd9Sstevel@tonic-gate if (t == IP) twiddle();
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
eth_disable(void)1967c478bd9Sstevel@tonic-gate void eth_disable(void)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
1997c478bd9Sstevel@tonic-gate int i;
2007c478bd9Sstevel@tonic-gate for(i = 0; i < MAX_IGMP; i++) {
2017c478bd9Sstevel@tonic-gate leave_group(i);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate #endif
2047c478bd9Sstevel@tonic-gate disable(&nic.dev);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate
eth_irq(irq_action_t action)2077c478bd9Sstevel@tonic-gate void eth_irq (irq_action_t action)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate (*nic.irq)(&nic,action);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /**************************************************************************
2137c478bd9Sstevel@tonic-gate IPCHKSUM - Checksum IP Header
2147c478bd9Sstevel@tonic-gate **************************************************************************/
ipchksum(const void * data,unsigned long length)2157c478bd9Sstevel@tonic-gate uint16_t ipchksum(const void *data, unsigned long length)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate unsigned long sum;
2187c478bd9Sstevel@tonic-gate unsigned long i;
2197c478bd9Sstevel@tonic-gate const uint8_t *ptr;
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /* In the most straight forward way possible,
2227c478bd9Sstevel@tonic-gate * compute an ip style checksum.
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate sum = 0;
2257c478bd9Sstevel@tonic-gate ptr = data;
2267c478bd9Sstevel@tonic-gate for(i = 0; i < length; i++) {
2277c478bd9Sstevel@tonic-gate unsigned long value;
2287c478bd9Sstevel@tonic-gate value = ptr[i];
2297c478bd9Sstevel@tonic-gate if (i & 1) {
2307c478bd9Sstevel@tonic-gate value <<= 8;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate /* Add the new value */
2337c478bd9Sstevel@tonic-gate sum += value;
2347c478bd9Sstevel@tonic-gate /* Wrap around the carry */
2357c478bd9Sstevel@tonic-gate if (sum > 0xFFFF) {
2367c478bd9Sstevel@tonic-gate sum = (sum + (sum >> 16)) & 0xFFFF;
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate return (~cpu_to_le16(sum)) & 0xFFFF;
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
add_ipchksums(unsigned long offset,uint16_t sum,uint16_t new)2427c478bd9Sstevel@tonic-gate uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate unsigned long checksum;
2457c478bd9Sstevel@tonic-gate sum = ~sum & 0xFFFF;
2467c478bd9Sstevel@tonic-gate new = ~new & 0xFFFF;
2477c478bd9Sstevel@tonic-gate if (offset & 1) {
2487c478bd9Sstevel@tonic-gate /* byte swap the sum if it came from an odd offset
2497c478bd9Sstevel@tonic-gate * since the computation is endian independant this
2507c478bd9Sstevel@tonic-gate * works.
2517c478bd9Sstevel@tonic-gate */
2527c478bd9Sstevel@tonic-gate new = bswap_16(new);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate checksum = sum + new;
2557c478bd9Sstevel@tonic-gate if (checksum > 0xFFFF) {
2567c478bd9Sstevel@tonic-gate checksum -= 0xFFFF;
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate return (~checksum) & 0xFFFF;
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate /**************************************************************************
2627c478bd9Sstevel@tonic-gate DEFAULT_NETMASK - Return default netmask for IP address
2637c478bd9Sstevel@tonic-gate **************************************************************************/
default_netmask(void)2647c478bd9Sstevel@tonic-gate static inline unsigned long default_netmask(void)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
2677c478bd9Sstevel@tonic-gate if (net <= 127)
2687c478bd9Sstevel@tonic-gate return(htonl(0xff000000));
2697c478bd9Sstevel@tonic-gate else if (net < 192)
2707c478bd9Sstevel@tonic-gate return(htonl(0xffff0000));
2717c478bd9Sstevel@tonic-gate else
2727c478bd9Sstevel@tonic-gate return(htonl(0xffffff00));
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /**************************************************************************
2767c478bd9Sstevel@tonic-gate IP_TRANSMIT - Send an IP datagram
2777c478bd9Sstevel@tonic-gate **************************************************************************/
await_arp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip __unused,struct udphdr * udp __unused)2787c478bd9Sstevel@tonic-gate static int await_arp(int ival, void *ptr,
2797c478bd9Sstevel@tonic-gate unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate struct arprequest *arpreply;
2827c478bd9Sstevel@tonic-gate if (ptype != ARP)
2837c478bd9Sstevel@tonic-gate return 0;
2847c478bd9Sstevel@tonic-gate if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
2857c478bd9Sstevel@tonic-gate return 0;
2867c478bd9Sstevel@tonic-gate arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (arpreply->opcode != htons(ARP_REPLY))
2897c478bd9Sstevel@tonic-gate return 0;
2907c478bd9Sstevel@tonic-gate if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
2917c478bd9Sstevel@tonic-gate return 0;
2927c478bd9Sstevel@tonic-gate memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
2937c478bd9Sstevel@tonic-gate return 1;
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
ip_transmit(int len,const void * buf)2967c478bd9Sstevel@tonic-gate int ip_transmit(int len, const void *buf)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate unsigned long destip;
2997c478bd9Sstevel@tonic-gate struct iphdr *ip;
3007c478bd9Sstevel@tonic-gate struct arprequest arpreq;
3017c478bd9Sstevel@tonic-gate int arpentry, i;
3027c478bd9Sstevel@tonic-gate int retry;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate ip = (struct iphdr *)buf;
3057c478bd9Sstevel@tonic-gate destip = ip->dest.s_addr;
3067c478bd9Sstevel@tonic-gate if (destip == IP_BROADCAST) {
3077c478bd9Sstevel@tonic-gate eth_transmit(broadcast, IP, len, buf);
3087c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL1
3097c478bd9Sstevel@tonic-gate } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
3107c478bd9Sstevel@tonic-gate unsigned char multicast[6];
3117c478bd9Sstevel@tonic-gate unsigned long hdestip;
3127c478bd9Sstevel@tonic-gate hdestip = ntohl(destip);
3137c478bd9Sstevel@tonic-gate multicast[0] = 0x01;
3147c478bd9Sstevel@tonic-gate multicast[1] = 0x00;
3157c478bd9Sstevel@tonic-gate multicast[2] = 0x5e;
3167c478bd9Sstevel@tonic-gate multicast[3] = (hdestip >> 16) & 0x7;
3177c478bd9Sstevel@tonic-gate multicast[4] = (hdestip >> 8) & 0xff;
3187c478bd9Sstevel@tonic-gate multicast[5] = hdestip & 0xff;
3197c478bd9Sstevel@tonic-gate eth_transmit(multicast, IP, len, buf);
3207c478bd9Sstevel@tonic-gate #endif
3217c478bd9Sstevel@tonic-gate } else {
3227c478bd9Sstevel@tonic-gate if (((destip & netmask) !=
3237c478bd9Sstevel@tonic-gate (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
3247c478bd9Sstevel@tonic-gate arptable[ARP_GATEWAY].ipaddr.s_addr)
3257c478bd9Sstevel@tonic-gate destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
3267c478bd9Sstevel@tonic-gate for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
3277c478bd9Sstevel@tonic-gate if (arptable[arpentry].ipaddr.s_addr == destip) break;
3287c478bd9Sstevel@tonic-gate if (arpentry == MAX_ARP) {
3297c478bd9Sstevel@tonic-gate printf("%@ is not in my arp table!\n", destip);
3307c478bd9Sstevel@tonic-gate return(0);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate for (i = 0; i < ETH_ALEN; i++)
3337c478bd9Sstevel@tonic-gate if (arptable[arpentry].node[i])
3347c478bd9Sstevel@tonic-gate break;
3357c478bd9Sstevel@tonic-gate if (i == ETH_ALEN) { /* Need to do arp request */
3367c478bd9Sstevel@tonic-gate arpreq.hwtype = htons(1);
3377c478bd9Sstevel@tonic-gate arpreq.protocol = htons(IP);
3387c478bd9Sstevel@tonic-gate arpreq.hwlen = ETH_ALEN;
3397c478bd9Sstevel@tonic-gate arpreq.protolen = 4;
3407c478bd9Sstevel@tonic-gate arpreq.opcode = htons(ARP_REQUEST);
3417c478bd9Sstevel@tonic-gate memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
3427c478bd9Sstevel@tonic-gate memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
3437c478bd9Sstevel@tonic-gate memset(arpreq.thwaddr, 0, ETH_ALEN);
3447c478bd9Sstevel@tonic-gate memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
3457c478bd9Sstevel@tonic-gate for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
3467c478bd9Sstevel@tonic-gate long timeout;
3477c478bd9Sstevel@tonic-gate eth_transmit(broadcast, ARP, sizeof(arpreq),
3487c478bd9Sstevel@tonic-gate &arpreq);
3497c478bd9Sstevel@tonic-gate timeout = rfc2131_sleep_interval(TIMEOUT, retry);
3507c478bd9Sstevel@tonic-gate if (await_reply(await_arp, arpentry,
3517c478bd9Sstevel@tonic-gate arpreq.tipaddr, timeout)) goto xmit;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate return(0);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate xmit:
3567c478bd9Sstevel@tonic-gate eth_transmit(arptable[arpentry].node, IP, len, buf);
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate return 1;
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
build_ip_hdr(unsigned long destip,int ttl,int protocol,int option_len,int len,const void * buf)3617c478bd9Sstevel@tonic-gate void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
3627c478bd9Sstevel@tonic-gate int len, const void *buf)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate struct iphdr *ip;
3657c478bd9Sstevel@tonic-gate ip = (struct iphdr *)buf;
3667c478bd9Sstevel@tonic-gate ip->verhdrlen = 0x45;
3677c478bd9Sstevel@tonic-gate ip->verhdrlen += (option_len/4);
3687c478bd9Sstevel@tonic-gate ip->service = 0;
3697c478bd9Sstevel@tonic-gate ip->len = htons(len);
3707c478bd9Sstevel@tonic-gate ip->ident = 0;
3717c478bd9Sstevel@tonic-gate ip->frags = 0; /* Should we set don't fragment? */
3727c478bd9Sstevel@tonic-gate ip->ttl = ttl;
3737c478bd9Sstevel@tonic-gate ip->protocol = protocol;
3747c478bd9Sstevel@tonic-gate ip->chksum = 0;
3757c478bd9Sstevel@tonic-gate ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
3767c478bd9Sstevel@tonic-gate ip->dest.s_addr = destip;
3777c478bd9Sstevel@tonic-gate ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
udpchksum(struct iphdr * ip,struct udphdr * udp)3807c478bd9Sstevel@tonic-gate static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate struct udp_pseudo_hdr pseudo;
3837c478bd9Sstevel@tonic-gate uint16_t checksum;
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate /* Compute the pseudo header */
3867c478bd9Sstevel@tonic-gate pseudo.src.s_addr = ip->src.s_addr;
3877c478bd9Sstevel@tonic-gate pseudo.dest.s_addr = ip->dest.s_addr;
3887c478bd9Sstevel@tonic-gate pseudo.unused = 0;
3897c478bd9Sstevel@tonic-gate pseudo.protocol = IP_UDP;
3907c478bd9Sstevel@tonic-gate pseudo.len = udp->len;
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate /* Sum the pseudo header */
3937c478bd9Sstevel@tonic-gate checksum = ipchksum(&pseudo, 12);
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /* Sum the rest of the udp packet */
3967c478bd9Sstevel@tonic-gate checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
3977c478bd9Sstevel@tonic-gate return checksum;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate
build_udp_hdr(unsigned long destip,unsigned int srcsock,unsigned int destsock,int ttl,int len,const void * buf)4017c478bd9Sstevel@tonic-gate void build_udp_hdr(unsigned long destip,
4027c478bd9Sstevel@tonic-gate unsigned int srcsock, unsigned int destsock, int ttl,
4037c478bd9Sstevel@tonic-gate int len, const void *buf)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate struct iphdr *ip;
4067c478bd9Sstevel@tonic-gate struct udphdr *udp;
4077c478bd9Sstevel@tonic-gate ip = (struct iphdr *)buf;
4087c478bd9Sstevel@tonic-gate build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
4097c478bd9Sstevel@tonic-gate udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
4107c478bd9Sstevel@tonic-gate udp->src = htons(srcsock);
4117c478bd9Sstevel@tonic-gate udp->dest = htons(destsock);
4127c478bd9Sstevel@tonic-gate udp->len = htons(len - sizeof(struct iphdr));
4137c478bd9Sstevel@tonic-gate udp->chksum = 0;
4147c478bd9Sstevel@tonic-gate if ((udp->chksum = udpchksum(ip, udp)) == 0)
4157c478bd9Sstevel@tonic-gate udp->chksum = 0xffff;
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /**************************************************************************
4207c478bd9Sstevel@tonic-gate UDP_TRANSMIT - Send an UDP datagram
4217c478bd9Sstevel@tonic-gate **************************************************************************/
udp_transmit(unsigned long destip,unsigned int srcsock,unsigned int destsock,int len,const void * buf)4227c478bd9Sstevel@tonic-gate int udp_transmit(unsigned long destip, unsigned int srcsock,
4237c478bd9Sstevel@tonic-gate unsigned int destsock, int len, const void *buf)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
4267c478bd9Sstevel@tonic-gate return ip_transmit(len, buf);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate /**************************************************************************
4307c478bd9Sstevel@tonic-gate QDRAIN - clear the nic's receive queue
4317c478bd9Sstevel@tonic-gate **************************************************************************/
await_qdrain(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp __unused)4327c478bd9Sstevel@tonic-gate static int await_qdrain(int ival __unused, void *ptr __unused,
4337c478bd9Sstevel@tonic-gate unsigned short ptype __unused,
4347c478bd9Sstevel@tonic-gate struct iphdr *ip __unused, struct udphdr *udp __unused)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate return 0;
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
rx_qdrain(void)4397c478bd9Sstevel@tonic-gate void rx_qdrain(void)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate /* Clear out the Rx queue first. It contains nothing of interest,
4427c478bd9Sstevel@tonic-gate * except possibly ARP requests from the DHCP/TFTP server. We use
4437c478bd9Sstevel@tonic-gate * polling throughout Etherboot, so some time may have passed since we
4447c478bd9Sstevel@tonic-gate * last polled the receive queue, which may now be filled with
4457c478bd9Sstevel@tonic-gate * broadcast packets. This will cause the reply to the packets we are
4467c478bd9Sstevel@tonic-gate * about to send to be lost immediately. Not very clever. */
4477c478bd9Sstevel@tonic-gate await_reply(await_qdrain, 0, NULL, 0);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /**
4517c478bd9Sstevel@tonic-gate * rarp
4527c478bd9Sstevel@tonic-gate *
4537c478bd9Sstevel@tonic-gate * Get IP address by rarp. Just copy from etherboot
4547c478bd9Sstevel@tonic-gate **/
await_rarp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip,struct udphdr * udp)4557c478bd9Sstevel@tonic-gate static int await_rarp(int ival, void *ptr, unsigned short ptype,
4567c478bd9Sstevel@tonic-gate struct iphdr *ip, struct udphdr *udp)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate struct arprequest *arpreply;
4597c478bd9Sstevel@tonic-gate if (ptype != RARP)
4607c478bd9Sstevel@tonic-gate return 0;
4617c478bd9Sstevel@tonic-gate if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
4627c478bd9Sstevel@tonic-gate return 0;
4637c478bd9Sstevel@tonic-gate arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
4647c478bd9Sstevel@tonic-gate if (arpreply->opcode != htons(RARP_REPLY))
4657c478bd9Sstevel@tonic-gate return 0;
4667c478bd9Sstevel@tonic-gate if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
4677c478bd9Sstevel@tonic-gate memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
4687c478bd9Sstevel@tonic-gate memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
4697c478bd9Sstevel@tonic-gate memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
4702269adc8Sszhou memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
4717c478bd9Sstevel@tonic-gate return 1;
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate return 0;
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
rarp(void)4767c478bd9Sstevel@tonic-gate int rarp(void)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate int retry;
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate /* arp and rarp requests share the same packet structure. */
4817c478bd9Sstevel@tonic-gate struct arprequest rarpreq;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate if(!grub_eth_probe())
4847c478bd9Sstevel@tonic-gate return 0;
4857c478bd9Sstevel@tonic-gate network_ready = 0;
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate memset(&rarpreq, 0, sizeof(rarpreq));
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate rarpreq.hwtype = htons(1);
4907c478bd9Sstevel@tonic-gate rarpreq.protocol = htons(IP);
4917c478bd9Sstevel@tonic-gate rarpreq.hwlen = ETH_ALEN;
4927c478bd9Sstevel@tonic-gate rarpreq.protolen = 4;
4937c478bd9Sstevel@tonic-gate rarpreq.opcode = htons(RARP_REQUEST);
4947c478bd9Sstevel@tonic-gate memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4957c478bd9Sstevel@tonic-gate /* sipaddr is already zeroed out */
4967c478bd9Sstevel@tonic-gate memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4977c478bd9Sstevel@tonic-gate /* tipaddr is already zeroed out */
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
5007c478bd9Sstevel@tonic-gate long timeout;
5017c478bd9Sstevel@tonic-gate eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate timeout = rfc2131_sleep_interval(TIMEOUT, retry);
5047c478bd9Sstevel@tonic-gate if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
5057c478bd9Sstevel@tonic-gate break;
5067c478bd9Sstevel@tonic-gate if (user_abort)
5077c478bd9Sstevel@tonic-gate return 0;
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate if (retry == MAX_ARP_RETRIES) {
5117c478bd9Sstevel@tonic-gate return (0);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate network_ready = 1;
5157c478bd9Sstevel@tonic-gate update_network_configuration();
5167c478bd9Sstevel@tonic-gate return (1);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate /**
5207c478bd9Sstevel@tonic-gate * bootp
5217c478bd9Sstevel@tonic-gate *
5227c478bd9Sstevel@tonic-gate * Get IP address by bootp, segregate from bootp in etherboot.
5237c478bd9Sstevel@tonic-gate **/
await_bootp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)5247c478bd9Sstevel@tonic-gate static int await_bootp(int ival __unused, void *ptr __unused,
5257c478bd9Sstevel@tonic-gate unsigned short ptype __unused, struct iphdr *ip __unused,
5267c478bd9Sstevel@tonic-gate struct udphdr *udp)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate struct bootp_t *bootpreply;
5297c478bd9Sstevel@tonic-gate int len; /* Length of vendor */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (!udp) {
5327c478bd9Sstevel@tonic-gate return 0;
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate bootpreply = (struct bootp_t *)
5357c478bd9Sstevel@tonic-gate &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
5367c478bd9Sstevel@tonic-gate len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
5377c478bd9Sstevel@tonic-gate sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
5387c478bd9Sstevel@tonic-gate if (len < 0) {
5397c478bd9Sstevel@tonic-gate return 0;
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate if (udp->dest != htons(BOOTP_CLIENT))
5427c478bd9Sstevel@tonic-gate return 0;
5437c478bd9Sstevel@tonic-gate if (bootpreply->bp_op != BOOTP_REPLY)
5447c478bd9Sstevel@tonic-gate return 0;
5457c478bd9Sstevel@tonic-gate if (bootpreply->bp_xid != xid)
5467c478bd9Sstevel@tonic-gate return 0;
5477c478bd9Sstevel@tonic-gate if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
5487c478bd9Sstevel@tonic-gate return 0;
5497c478bd9Sstevel@tonic-gate if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
5507c478bd9Sstevel@tonic-gate (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
5517c478bd9Sstevel@tonic-gate return 0;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
5557c478bd9Sstevel@tonic-gate /* fill in netinfo */
5567c478bd9Sstevel@tonic-gate dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
5577c478bd9Sstevel@tonic-gate memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
5587c478bd9Sstevel@tonic-gate #endif
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
5617c478bd9Sstevel@tonic-gate netmask = default_netmask();
5627c478bd9Sstevel@tonic-gate arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
5637c478bd9Sstevel@tonic-gate memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
5647c478bd9Sstevel@tonic-gate arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
5657c478bd9Sstevel@tonic-gate memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
5662506833eSJan Setje-Eilers bootfile = bootpreply->bp_file;
5677c478bd9Sstevel@tonic-gate memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
5687c478bd9Sstevel@tonic-gate decode_rfc1533(rfc1533_venddata, 0, len, 1);
5697c478bd9Sstevel@tonic-gate return(1);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate
bootp(void)5727c478bd9Sstevel@tonic-gate int bootp(void)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate int retry;
5757c478bd9Sstevel@tonic-gate struct bootpip_t ip;
5767c478bd9Sstevel@tonic-gate unsigned long starttime;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate EnterFunction("bootp");
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate if(!grub_eth_probe())
5817c478bd9Sstevel@tonic-gate return 0;
5827c478bd9Sstevel@tonic-gate network_ready = 0;
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate memset(&ip, 0, sizeof(struct bootpip_t));
5857c478bd9Sstevel@tonic-gate ip.bp.bp_op = BOOTP_REQUEST;
5867c478bd9Sstevel@tonic-gate ip.bp.bp_htype = 1;
5877c478bd9Sstevel@tonic-gate ip.bp.bp_hlen = ETH_ALEN;
5887c478bd9Sstevel@tonic-gate starttime = currticks();
5897c478bd9Sstevel@tonic-gate /* Use lower 32 bits of node address, more likely to be
5907c478bd9Sstevel@tonic-gate distinct than the time since booting */
5917c478bd9Sstevel@tonic-gate memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
5927c478bd9Sstevel@tonic-gate ip.bp.bp_xid = xid += htonl(starttime);
5937c478bd9Sstevel@tonic-gate /* bp_secs defaults to zero */
5947c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
5957c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
5987c478bd9Sstevel@tonic-gate long timeout;
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate rx_qdrain();
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
6037c478bd9Sstevel@tonic-gate sizeof(struct bootpip_t), &ip);
6047c478bd9Sstevel@tonic-gate timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
6057c478bd9Sstevel@tonic-gate if (await_reply(await_bootp, 0, NULL, timeout)){
6067c478bd9Sstevel@tonic-gate network_ready = 1;
6077c478bd9Sstevel@tonic-gate return(1);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate if (user_abort)
6107c478bd9Sstevel@tonic-gate return 0;
6117c478bd9Sstevel@tonic-gate ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate return(0);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate /**
6177c478bd9Sstevel@tonic-gate * dhcp
6187c478bd9Sstevel@tonic-gate *
6197c478bd9Sstevel@tonic-gate * Get IP address by dhcp, segregate from bootp in etherboot.
6207c478bd9Sstevel@tonic-gate **/
await_dhcp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)6217c478bd9Sstevel@tonic-gate static int await_dhcp(int ival __unused, void *ptr __unused,
6227c478bd9Sstevel@tonic-gate unsigned short ptype __unused, struct iphdr *ip __unused,
6237c478bd9Sstevel@tonic-gate struct udphdr *udp)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate struct dhcp_t *dhcpreply;
6267c478bd9Sstevel@tonic-gate int len;
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate if (!udp) {
6297c478bd9Sstevel@tonic-gate return 0;
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate dhcpreply = (struct dhcp_t *)
6327c478bd9Sstevel@tonic-gate &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
6337c478bd9Sstevel@tonic-gate len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
6347c478bd9Sstevel@tonic-gate sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
6357c478bd9Sstevel@tonic-gate if (len < 0){
6367c478bd9Sstevel@tonic-gate return 0;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate if (udp->dest != htons(BOOTP_CLIENT))
6397c478bd9Sstevel@tonic-gate return 0;
6407c478bd9Sstevel@tonic-gate if (dhcpreply->bp_op != BOOTP_REPLY)
6417c478bd9Sstevel@tonic-gate return 0;
6427c478bd9Sstevel@tonic-gate if (dhcpreply->bp_xid != xid)
6437c478bd9Sstevel@tonic-gate return 0;
6447c478bd9Sstevel@tonic-gate if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
6457c478bd9Sstevel@tonic-gate return 0;
6467c478bd9Sstevel@tonic-gate if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
6477c478bd9Sstevel@tonic-gate (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
6487c478bd9Sstevel@tonic-gate return 0;
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
6527c478bd9Sstevel@tonic-gate /* fill in netinfo */
6537c478bd9Sstevel@tonic-gate dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
6547c478bd9Sstevel@tonic-gate memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
6557c478bd9Sstevel@tonic-gate #endif
6567c478bd9Sstevel@tonic-gate arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6577c478bd9Sstevel@tonic-gate dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6587c478bd9Sstevel@tonic-gate netmask = default_netmask();
6597c478bd9Sstevel@tonic-gate arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
6607c478bd9Sstevel@tonic-gate memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
6617c478bd9Sstevel@tonic-gate arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
6627c478bd9Sstevel@tonic-gate memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
6632506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file;
6647c478bd9Sstevel@tonic-gate memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
6657c478bd9Sstevel@tonic-gate decode_rfc1533(rfc1533_venddata, 0, len, 1);
6667c478bd9Sstevel@tonic-gate return(1);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate
dhcp(void)6697c478bd9Sstevel@tonic-gate int dhcp(void)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate int retry;
6727c478bd9Sstevel@tonic-gate int reqretry;
6737c478bd9Sstevel@tonic-gate struct dhcpip_t ip;
6747c478bd9Sstevel@tonic-gate unsigned long starttime;
6757c478bd9Sstevel@tonic-gate
67699ed6083Sszhou /* try bios pxe stack first */
67799ed6083Sszhou if (dhcp_undi())
67899ed6083Sszhou return 1;
67999ed6083Sszhou
6807c478bd9Sstevel@tonic-gate if(!grub_eth_probe())
6817c478bd9Sstevel@tonic-gate return 0;
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate network_ready = 0;
6847c478bd9Sstevel@tonic-gate
6852269adc8Sszhou memset(&ip, 0, sizeof(ip));
6867c478bd9Sstevel@tonic-gate ip.bp.bp_op = BOOTP_REQUEST;
6877c478bd9Sstevel@tonic-gate ip.bp.bp_htype = 1;
6887c478bd9Sstevel@tonic-gate ip.bp.bp_hlen = ETH_ALEN;
6897c478bd9Sstevel@tonic-gate starttime = currticks();
6907c478bd9Sstevel@tonic-gate /* Use lower 32 bits of node address, more likely to be
6917c478bd9Sstevel@tonic-gate distinct than the time since booting */
6927c478bd9Sstevel@tonic-gate memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
6937c478bd9Sstevel@tonic-gate ip.bp.bp_xid = xid += htonl(starttime);
6947c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
6957c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
6967c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
6997c478bd9Sstevel@tonic-gate long timeout;
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate rx_qdrain();
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7042269adc8Sszhou sizeof(ip), &ip);
7057c478bd9Sstevel@tonic-gate timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
7067c478bd9Sstevel@tonic-gate if (await_reply(await_dhcp, 0, NULL, timeout)) {
7077c478bd9Sstevel@tonic-gate /* If not a DHCPOFFER then must be just a
7087c478bd9Sstevel@tonic-gate BOOTP reply, be backward compatible with
7097c478bd9Sstevel@tonic-gate BOOTP then. Jscott report a bug here, but I
7107c478bd9Sstevel@tonic-gate don't know how it happened */
7117c478bd9Sstevel@tonic-gate if (dhcp_reply != DHCPOFFER){
7127c478bd9Sstevel@tonic-gate network_ready = 1;
7137c478bd9Sstevel@tonic-gate return(1);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate dhcp_reply = 0;
7167c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
7177c478bd9Sstevel@tonic-gate memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
7187c478bd9Sstevel@tonic-gate /* Beware: the magic numbers 9 and 15 depend on
7197c478bd9Sstevel@tonic-gate the layout of dhcprequest */
7207c478bd9Sstevel@tonic-gate memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
7217c478bd9Sstevel@tonic-gate memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
7227c478bd9Sstevel@tonic-gate for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
7237c478bd9Sstevel@tonic-gate udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7242269adc8Sszhou sizeof(ip), &ip);
7257c478bd9Sstevel@tonic-gate dhcp_reply=0;
7267c478bd9Sstevel@tonic-gate timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
7277c478bd9Sstevel@tonic-gate if (await_reply(await_dhcp, 0, NULL, timeout))
7287c478bd9Sstevel@tonic-gate if (dhcp_reply == DHCPACK){
7297c478bd9Sstevel@tonic-gate network_ready = 1;
7307c478bd9Sstevel@tonic-gate return(1);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate if (user_abort)
7337c478bd9Sstevel@tonic-gate return 0;
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate if (user_abort)
7377c478bd9Sstevel@tonic-gate return 0;
7387c478bd9Sstevel@tonic-gate ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate return(0);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
send_igmp_reports(unsigned long now)7447c478bd9Sstevel@tonic-gate static void send_igmp_reports(unsigned long now)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate int i;
7477c478bd9Sstevel@tonic-gate for(i = 0; i < MAX_IGMP; i++) {
7487c478bd9Sstevel@tonic-gate if (igmptable[i].time && (now >= igmptable[i].time)) {
7497c478bd9Sstevel@tonic-gate struct igmp_ip_t igmp;
7507c478bd9Sstevel@tonic-gate igmp.router_alert[0] = 0x94;
7517c478bd9Sstevel@tonic-gate igmp.router_alert[1] = 0x04;
7527c478bd9Sstevel@tonic-gate igmp.router_alert[2] = 0;
7537c478bd9Sstevel@tonic-gate igmp.router_alert[3] = 0;
7547c478bd9Sstevel@tonic-gate build_ip_hdr(igmptable[i].group.s_addr,
7557c478bd9Sstevel@tonic-gate 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
7567c478bd9Sstevel@tonic-gate igmp.igmp.type = IGMPv2_REPORT;
7577c478bd9Sstevel@tonic-gate if (last_igmpv1 &&
7587c478bd9Sstevel@tonic-gate (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
7597c478bd9Sstevel@tonic-gate igmp.igmp.type = IGMPv1_REPORT;
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate igmp.igmp.response_time = 0;
7627c478bd9Sstevel@tonic-gate igmp.igmp.chksum = 0;
7637c478bd9Sstevel@tonic-gate igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
7647c478bd9Sstevel@tonic-gate igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
7657c478bd9Sstevel@tonic-gate ip_transmit(sizeof(igmp), &igmp);
7667c478bd9Sstevel@tonic-gate #ifdef MDEBUG
7677c478bd9Sstevel@tonic-gate printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
7687c478bd9Sstevel@tonic-gate #endif
7697c478bd9Sstevel@tonic-gate /* Don't send another igmp report until asked */
7707c478bd9Sstevel@tonic-gate igmptable[i].time = 0;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
process_igmp(struct iphdr * ip,unsigned long now)7757c478bd9Sstevel@tonic-gate static void process_igmp(struct iphdr *ip, unsigned long now)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate struct igmp *igmp;
7787c478bd9Sstevel@tonic-gate int i;
7797c478bd9Sstevel@tonic-gate unsigned iplen = 0;
7807c478bd9Sstevel@tonic-gate if (!ip || (ip->protocol == IP_IGMP) ||
7817c478bd9Sstevel@tonic-gate (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
7827c478bd9Sstevel@tonic-gate return;
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate iplen = (ip->verhdrlen & 0xf)*4;
7857c478bd9Sstevel@tonic-gate igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
7867c478bd9Sstevel@tonic-gate if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
7877c478bd9Sstevel@tonic-gate return;
7887c478bd9Sstevel@tonic-gate if ((igmp->type == IGMP_QUERY) &&
7897c478bd9Sstevel@tonic-gate (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
7907c478bd9Sstevel@tonic-gate unsigned long interval = IGMP_INTERVAL;
7917c478bd9Sstevel@tonic-gate if (igmp->response_time == 0) {
7927c478bd9Sstevel@tonic-gate last_igmpv1 = now;
7937c478bd9Sstevel@tonic-gate } else {
7947c478bd9Sstevel@tonic-gate interval = (igmp->response_time * TICKS_PER_SEC)/10;
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate #ifdef MDEBUG
7987c478bd9Sstevel@tonic-gate printf("Received IGMP query for: %@\n", igmp->group.s_addr);
7997c478bd9Sstevel@tonic-gate #endif
8007c478bd9Sstevel@tonic-gate for(i = 0; i < MAX_IGMP; i++) {
8017c478bd9Sstevel@tonic-gate uint32_t group = igmptable[i].group.s_addr;
8027c478bd9Sstevel@tonic-gate if ((group == 0) || (group == igmp->group.s_addr)) {
8037c478bd9Sstevel@tonic-gate unsigned long time;
8047c478bd9Sstevel@tonic-gate time = currticks() + rfc1112_sleep_interval(interval, 0);
8057c478bd9Sstevel@tonic-gate if (time < igmptable[i].time) {
8067c478bd9Sstevel@tonic-gate igmptable[i].time = time;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
8127c478bd9Sstevel@tonic-gate (ip->dest.s_addr == igmp->group.s_addr)) {
8137c478bd9Sstevel@tonic-gate #ifdef MDEBUG
8147c478bd9Sstevel@tonic-gate printf("Received IGMP report for: %@\n", igmp->group.s_addr);
8157c478bd9Sstevel@tonic-gate #endif
8167c478bd9Sstevel@tonic-gate for(i = 0; i < MAX_IGMP; i++) {
8177c478bd9Sstevel@tonic-gate if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
8187c478bd9Sstevel@tonic-gate igmptable[i].time != 0) {
8197c478bd9Sstevel@tonic-gate igmptable[i].time = 0;
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate
leave_group(int slot)8257c478bd9Sstevel@tonic-gate void leave_group(int slot)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate /* Be very stupid and always send a leave group message if
8287c478bd9Sstevel@tonic-gate * I have subscribed. Imperfect but it is standards
8297c478bd9Sstevel@tonic-gate * compliant, easy and reliable to implement.
8307c478bd9Sstevel@tonic-gate *
8317c478bd9Sstevel@tonic-gate * The optimal group leave method is to only send leave when,
8327c478bd9Sstevel@tonic-gate * we were the last host to respond to a query on this group,
8337c478bd9Sstevel@tonic-gate * and igmpv1 compatibility is not enabled.
8347c478bd9Sstevel@tonic-gate */
8357c478bd9Sstevel@tonic-gate if (igmptable[slot].group.s_addr) {
8367c478bd9Sstevel@tonic-gate struct igmp_ip_t igmp;
8377c478bd9Sstevel@tonic-gate igmp.router_alert[0] = 0x94;
8387c478bd9Sstevel@tonic-gate igmp.router_alert[1] = 0x04;
8397c478bd9Sstevel@tonic-gate igmp.router_alert[2] = 0;
8407c478bd9Sstevel@tonic-gate igmp.router_alert[3] = 0;
8417c478bd9Sstevel@tonic-gate build_ip_hdr(htonl(GROUP_ALL_HOSTS),
8427c478bd9Sstevel@tonic-gate 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
8437c478bd9Sstevel@tonic-gate igmp.igmp.type = IGMP_LEAVE;
8447c478bd9Sstevel@tonic-gate igmp.igmp.response_time = 0;
8457c478bd9Sstevel@tonic-gate igmp.igmp.chksum = 0;
8467c478bd9Sstevel@tonic-gate igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
8477c478bd9Sstevel@tonic-gate igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
8487c478bd9Sstevel@tonic-gate ip_transmit(sizeof(igmp), &igmp);
8497c478bd9Sstevel@tonic-gate #ifdef MDEBUG
8507c478bd9Sstevel@tonic-gate printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
8517c478bd9Sstevel@tonic-gate #endif
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate memset(&igmptable[slot], 0, sizeof(igmptable[0]));
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate
join_group(int slot,unsigned long group)8567c478bd9Sstevel@tonic-gate void join_group(int slot, unsigned long group)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate /* I have already joined */
8597c478bd9Sstevel@tonic-gate if (igmptable[slot].group.s_addr == group)
8607c478bd9Sstevel@tonic-gate return;
8617c478bd9Sstevel@tonic-gate if (igmptable[slot].group.s_addr) {
8627c478bd9Sstevel@tonic-gate leave_group(slot);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate /* Only join a group if we are given a multicast ip, this way
8657c478bd9Sstevel@tonic-gate * code can be given a non-multicast (broadcast or unicast ip)
8667c478bd9Sstevel@tonic-gate * and still work...
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
8697c478bd9Sstevel@tonic-gate igmptable[slot].group.s_addr = group;
8707c478bd9Sstevel@tonic-gate igmptable[slot].time = currticks();
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate #else
8747c478bd9Sstevel@tonic-gate #define send_igmp_reports(now);
8757c478bd9Sstevel@tonic-gate #define process_igmp(ip, now)
8767c478bd9Sstevel@tonic-gate #endif
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /**************************************************************************
8797c478bd9Sstevel@tonic-gate AWAIT_REPLY - Wait until we get a response for our request
8807c478bd9Sstevel@tonic-gate ************f**************************************************************/
await_reply(reply_t reply,int ival,void * ptr,long timeout)8817c478bd9Sstevel@tonic-gate int await_reply(reply_t reply, int ival, void *ptr, long timeout)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate unsigned long time, now;
8847c478bd9Sstevel@tonic-gate struct iphdr *ip;
8857c478bd9Sstevel@tonic-gate unsigned iplen = 0;
8867c478bd9Sstevel@tonic-gate struct udphdr *udp;
8877c478bd9Sstevel@tonic-gate unsigned short ptype;
8887c478bd9Sstevel@tonic-gate int result;
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate user_abort = 0;
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate time = timeout + currticks();
8937c478bd9Sstevel@tonic-gate /* The timeout check is done below. The timeout is only checked if
8947c478bd9Sstevel@tonic-gate * there is no packet in the Rx queue. This assumes that eth_poll()
8957c478bd9Sstevel@tonic-gate * needs a negligible amount of time.
8967c478bd9Sstevel@tonic-gate */
8977c478bd9Sstevel@tonic-gate for (;;) {
8987c478bd9Sstevel@tonic-gate now = currticks();
8997c478bd9Sstevel@tonic-gate send_igmp_reports(now);
9007c478bd9Sstevel@tonic-gate result = eth_poll(1);
9017c478bd9Sstevel@tonic-gate if (result == 0) {
9027c478bd9Sstevel@tonic-gate /* We don't have anything */
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Check for abort key only if the Rx queue is empty -
9057c478bd9Sstevel@tonic-gate * as long as we have something to process, don't
9067c478bd9Sstevel@tonic-gate * assume that something failed. It is unlikely that
9077c478bd9Sstevel@tonic-gate * we have no processing time left between packets. */
9087c478bd9Sstevel@tonic-gate poll_interruptions();
9097c478bd9Sstevel@tonic-gate /* Do the timeout after at least a full queue walk. */
9107c478bd9Sstevel@tonic-gate if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
9117c478bd9Sstevel@tonic-gate break;
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate continue;
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate /* We have something! */
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate /* Find the Ethernet packet type */
9197c478bd9Sstevel@tonic-gate if (nic.packetlen >= ETH_HLEN) {
9207c478bd9Sstevel@tonic-gate ptype = ((unsigned short) nic.packet[12]) << 8
9217c478bd9Sstevel@tonic-gate | ((unsigned short) nic.packet[13]);
9227c478bd9Sstevel@tonic-gate } else continue; /* what else could we do with it? */
9237c478bd9Sstevel@tonic-gate /* Verify an IP header */
9247c478bd9Sstevel@tonic-gate ip = 0;
9257c478bd9Sstevel@tonic-gate if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
9267c478bd9Sstevel@tonic-gate unsigned ipoptlen;
9277c478bd9Sstevel@tonic-gate ip = (struct iphdr *)&nic.packet[ETH_HLEN];
9287c478bd9Sstevel@tonic-gate if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
9297c478bd9Sstevel@tonic-gate continue;
9307c478bd9Sstevel@tonic-gate iplen = (ip->verhdrlen & 0xf) * 4;
9317c478bd9Sstevel@tonic-gate if (ipchksum(ip, iplen) != 0)
9327c478bd9Sstevel@tonic-gate continue;
9337c478bd9Sstevel@tonic-gate if (ip->frags & htons(0x3FFF)) {
9347c478bd9Sstevel@tonic-gate static int warned_fragmentation = 0;
9357c478bd9Sstevel@tonic-gate if (!warned_fragmentation) {
9367c478bd9Sstevel@tonic-gate printf("ALERT: got a fragmented packet - reconfigure your server\n");
9377c478bd9Sstevel@tonic-gate warned_fragmentation = 1;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate continue;
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate if (ntohs(ip->len) > ETH_MAX_MTU)
9427c478bd9Sstevel@tonic-gate continue;
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate ipoptlen = iplen - sizeof(struct iphdr);
9457c478bd9Sstevel@tonic-gate if (ipoptlen) {
9467c478bd9Sstevel@tonic-gate /* Delete the ip options, to guarantee
9477c478bd9Sstevel@tonic-gate * good alignment, and make etherboot simpler.
9487c478bd9Sstevel@tonic-gate */
9497c478bd9Sstevel@tonic-gate memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
9507c478bd9Sstevel@tonic-gate &nic.packet[ETH_HLEN + iplen],
9517c478bd9Sstevel@tonic-gate nic.packetlen - ipoptlen);
9527c478bd9Sstevel@tonic-gate nic.packetlen -= ipoptlen;
9537c478bd9Sstevel@tonic-gate }
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate udp = 0;
9567c478bd9Sstevel@tonic-gate if (ip && (ip->protocol == IP_UDP) &&
9577c478bd9Sstevel@tonic-gate (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
9587c478bd9Sstevel@tonic-gate udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate /* Make certain we have a reasonable packet length */
9617c478bd9Sstevel@tonic-gate if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
9627c478bd9Sstevel@tonic-gate continue;
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate if (udp->chksum && udpchksum(ip, udp)) {
9657c478bd9Sstevel@tonic-gate printf("UDP checksum error\n");
9667c478bd9Sstevel@tonic-gate continue;
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate result = reply(ival, ptr, ptype, ip, udp);
9707c478bd9Sstevel@tonic-gate if (result > 0) {
9717c478bd9Sstevel@tonic-gate return result;
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate /* If it isn't a packet the upper layer wants see if there is a default
9757c478bd9Sstevel@tonic-gate * action. This allows us reply to arp and igmp queryies.
9767c478bd9Sstevel@tonic-gate */
9777c478bd9Sstevel@tonic-gate if ((ptype == ARP) &&
9787c478bd9Sstevel@tonic-gate (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
9797c478bd9Sstevel@tonic-gate struct arprequest *arpreply;
9807c478bd9Sstevel@tonic-gate unsigned long tmp;
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
9837c478bd9Sstevel@tonic-gate memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9847c478bd9Sstevel@tonic-gate if ((arpreply->opcode == htons(ARP_REQUEST)) &&
9857c478bd9Sstevel@tonic-gate (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
9867c478bd9Sstevel@tonic-gate arpreply->opcode = htons(ARP_REPLY);
9877c478bd9Sstevel@tonic-gate memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
9887c478bd9Sstevel@tonic-gate memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
9897c478bd9Sstevel@tonic-gate memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
9907c478bd9Sstevel@tonic-gate memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
9917c478bd9Sstevel@tonic-gate eth_transmit(arpreply->thwaddr, ARP,
9927c478bd9Sstevel@tonic-gate sizeof(struct arprequest),
9937c478bd9Sstevel@tonic-gate arpreply);
9947c478bd9Sstevel@tonic-gate #ifdef MDEBUG
9957c478bd9Sstevel@tonic-gate memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9967c478bd9Sstevel@tonic-gate printf("Sent ARP reply to: %@\n",tmp);
9977c478bd9Sstevel@tonic-gate #endif /* MDEBUG */
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate process_igmp(ip, now);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate return(0);
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate #ifdef REQUIRE_VCI_ETHERBOOT
10067c478bd9Sstevel@tonic-gate /**************************************************************************
10077c478bd9Sstevel@tonic-gate FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
10087c478bd9Sstevel@tonic-gate On entry p points to byte count of VCI options
10097c478bd9Sstevel@tonic-gate **************************************************************************/
find_vci_etherboot(unsigned char * p)10107c478bd9Sstevel@tonic-gate static int find_vci_etherboot(unsigned char *p)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate unsigned char *end = p + 1 + *p;
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate for (p++; p < end; ) {
10157c478bd9Sstevel@tonic-gate if (*p == RFC2132_VENDOR_CLASS_ID) {
10167c478bd9Sstevel@tonic-gate if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
10177c478bd9Sstevel@tonic-gate return (1);
10187c478bd9Sstevel@tonic-gate } else if (*p == RFC1533_END)
10197c478bd9Sstevel@tonic-gate return (0);
10207c478bd9Sstevel@tonic-gate p += TAG_LEN(p) + 2;
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate return (0);
10237c478bd9Sstevel@tonic-gate }
10247c478bd9Sstevel@tonic-gate #endif /* REQUIRE_VCI_ETHERBOOT */
10257c478bd9Sstevel@tonic-gate
10267c478bd9Sstevel@tonic-gate /**
10277c478bd9Sstevel@tonic-gate * decode_rfc1533
10287c478bd9Sstevel@tonic-gate *
10297c478bd9Sstevel@tonic-gate * Decodes RFC1533 header
10307c478bd9Sstevel@tonic-gate **/
decode_rfc1533(unsigned char * p,unsigned int block,unsigned int len,int eof)10317c478bd9Sstevel@tonic-gate int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate static unsigned char *extdata = NULL, *extend = NULL;
10347c478bd9Sstevel@tonic-gate unsigned char *extpath = NULL;
10357c478bd9Sstevel@tonic-gate unsigned char *endp;
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate if (block == 0) {
10387c478bd9Sstevel@tonic-gate end_of_rfc1533 = NULL;
10397c478bd9Sstevel@tonic-gate if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10407c478bd9Sstevel@tonic-gate return(0); /* no RFC 1533 header found */
10417c478bd9Sstevel@tonic-gate p += 4;
10427c478bd9Sstevel@tonic-gate endp = p + len;
10437c478bd9Sstevel@tonic-gate } else {
10447c478bd9Sstevel@tonic-gate if (block == 1) {
10457c478bd9Sstevel@tonic-gate if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10467c478bd9Sstevel@tonic-gate return(0); /* no RFC 1533 header found */
10477c478bd9Sstevel@tonic-gate p += 4;
10487c478bd9Sstevel@tonic-gate len -= 4; }
10497c478bd9Sstevel@tonic-gate if (extend + len <= (unsigned char *)
10507c478bd9Sstevel@tonic-gate rfc1533_venddata + sizeof(rfc1533_venddata)) {
10517c478bd9Sstevel@tonic-gate memcpy(extend, p, len);
10527c478bd9Sstevel@tonic-gate extend += len;
10537c478bd9Sstevel@tonic-gate } else {
10547c478bd9Sstevel@tonic-gate printf("Overflow in vendor data buffer! Aborting...\n");
10557c478bd9Sstevel@tonic-gate *extdata = RFC1533_END;
10567c478bd9Sstevel@tonic-gate return(0);
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate p = extdata; endp = extend;
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate if (!eof)
10617c478bd9Sstevel@tonic-gate return 1;
10627c478bd9Sstevel@tonic-gate while (p < endp) {
10637c478bd9Sstevel@tonic-gate unsigned char c = *p;
10647c478bd9Sstevel@tonic-gate if (c == RFC1533_PAD) {
10657c478bd9Sstevel@tonic-gate p++;
10667c478bd9Sstevel@tonic-gate continue;
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate else if (c == RFC1533_END) {
10697c478bd9Sstevel@tonic-gate end_of_rfc1533 = endp = p;
10707c478bd9Sstevel@tonic-gate continue;
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate else if (c == RFC1533_NETMASK)
10737c478bd9Sstevel@tonic-gate memcpy(&netmask, p+2, sizeof(in_addr));
10747c478bd9Sstevel@tonic-gate else if (c == RFC1533_GATEWAY) {
10757c478bd9Sstevel@tonic-gate /* This is a little simplistic, but it will
10767c478bd9Sstevel@tonic-gate usually be sufficient.
10777c478bd9Sstevel@tonic-gate Take only the first entry */
10787c478bd9Sstevel@tonic-gate if (TAG_LEN(p) >= sizeof(in_addr))
10797c478bd9Sstevel@tonic-gate memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate else if (c == RFC1533_EXTENSIONPATH)
10827c478bd9Sstevel@tonic-gate extpath = p;
10837c478bd9Sstevel@tonic-gate else if (c == RFC2132_MSG_TYPE)
10847c478bd9Sstevel@tonic-gate dhcp_reply=*(p+2);
10857c478bd9Sstevel@tonic-gate else if (c == RFC2132_SRV_ID)
10867c478bd9Sstevel@tonic-gate memcpy(&dhcp_server, p+2, sizeof(in_addr));
10877c478bd9Sstevel@tonic-gate else if (c == RFC1533_HOSTNAME) {
10887c478bd9Sstevel@tonic-gate hostname = p + 2;
10897c478bd9Sstevel@tonic-gate hostnamelen = *(p + 1);
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate else if (c == RFC1533_VENDOR_CONFIGFILE){
10927c478bd9Sstevel@tonic-gate int l = TAG_LEN (p);
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate /* Eliminate the trailing NULs according to RFC 2132. */
10957c478bd9Sstevel@tonic-gate while (*(p + 2 + l - 1) == '\000' && l > 0)
10967c478bd9Sstevel@tonic-gate l--;
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate /* XXX: Should check if LEN is less than the maximum length
10997c478bd9Sstevel@tonic-gate of CONFIG_FILE. This kind of robustness will be a goal
11007c478bd9Sstevel@tonic-gate in GRUB 1.0. */
11017c478bd9Sstevel@tonic-gate memcpy (config_file, p + 2, l);
11027c478bd9Sstevel@tonic-gate config_file[l] = 0;
11032506833eSJan Setje-Eilers vendor_configfile = p + 2;
11042506833eSJan Setje-Eilers vendor_configfile_len = l;
11052506833eSJan Setje-Eilers configfile_origin = CFG_150;
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate else {
11087c478bd9Sstevel@tonic-gate ;
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate p += TAG_LEN(p) + 2;
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate extdata = extend = endp;
11137c478bd9Sstevel@tonic-gate if (block <= 0 && extpath != NULL) {
11147c478bd9Sstevel@tonic-gate char fname[64];
11157c478bd9Sstevel@tonic-gate if (TAG_LEN(extpath) >= sizeof(fname)){
11167c478bd9Sstevel@tonic-gate printf("Overflow in vendor data buffer! Aborting...\n");
11177c478bd9Sstevel@tonic-gate *extdata = RFC1533_END;
11187c478bd9Sstevel@tonic-gate return(0);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate memcpy(fname, extpath+2, TAG_LEN(extpath));
11217c478bd9Sstevel@tonic-gate fname[(int)TAG_LEN(extpath)] = '\0';
11227c478bd9Sstevel@tonic-gate printf("Loading BOOTP-extension file: %s\n",fname);
11237c478bd9Sstevel@tonic-gate tftp_file_read(fname, decode_rfc1533);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate return 1; /* proceed with next block */
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /* FIXME double check TWO_SECOND_DIVISOR */
11307c478bd9Sstevel@tonic-gate #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
11317c478bd9Sstevel@tonic-gate /**************************************************************************
11327c478bd9Sstevel@tonic-gate RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
11337c478bd9Sstevel@tonic-gate **************************************************************************/
rfc2131_sleep_interval(long base,int exp)11347c478bd9Sstevel@tonic-gate long rfc2131_sleep_interval(long base, int exp)
11357c478bd9Sstevel@tonic-gate {
11367c478bd9Sstevel@tonic-gate unsigned long tmo;
11377c478bd9Sstevel@tonic-gate #ifdef BACKOFF_LIMIT
11387c478bd9Sstevel@tonic-gate if (exp > BACKOFF_LIMIT)
11397c478bd9Sstevel@tonic-gate exp = BACKOFF_LIMIT;
11407c478bd9Sstevel@tonic-gate #endif
11417c478bd9Sstevel@tonic-gate tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
11427c478bd9Sstevel@tonic-gate return tmo;
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate #ifdef MULTICAST_LEVEL2
11467c478bd9Sstevel@tonic-gate /**************************************************************************
11477c478bd9Sstevel@tonic-gate RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
11487c478bd9Sstevel@tonic-gate **************************************************************************/
rfc1112_sleep_interval(long base,int exp)11497c478bd9Sstevel@tonic-gate long rfc1112_sleep_interval(long base, int exp)
11507c478bd9Sstevel@tonic-gate {
11517c478bd9Sstevel@tonic-gate unsigned long divisor, tmo;
11527c478bd9Sstevel@tonic-gate #ifdef BACKOFF_LIMIT
11537c478bd9Sstevel@tonic-gate if (exp > BACKOFF_LIMIT)
11547c478bd9Sstevel@tonic-gate exp = BACKOFF_LIMIT;
11557c478bd9Sstevel@tonic-gate #endif
11567c478bd9Sstevel@tonic-gate divisor = RAND_MAX/(base << exp);
11577c478bd9Sstevel@tonic-gate tmo = random()/divisor;
11587c478bd9Sstevel@tonic-gate return tmo;
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate #endif /* MULTICAST_LEVEL_2 */
11617c478bd9Sstevel@tonic-gate /* ifconfig - configure network interface. */
11627c478bd9Sstevel@tonic-gate int
ifconfig(char * ip,char * sm,char * gw,char * svr)11637c478bd9Sstevel@tonic-gate ifconfig (char *ip, char *sm, char *gw, char *svr)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate in_addr tmp;
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate if (sm)
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate if (! inet_aton (sm, &tmp))
11707c478bd9Sstevel@tonic-gate return 0;
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate netmask = tmp.s_addr;
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate if (ip)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
11787c478bd9Sstevel@tonic-gate return 0;
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate if (! netmask && ! sm)
11817c478bd9Sstevel@tonic-gate netmask = default_netmask ();
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate
11847c478bd9Sstevel@tonic-gate if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
11857c478bd9Sstevel@tonic-gate return 0;
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate /* Clear out the ARP entry. */
11887c478bd9Sstevel@tonic-gate grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
11897c478bd9Sstevel@tonic-gate
11907c478bd9Sstevel@tonic-gate if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
11917c478bd9Sstevel@tonic-gate return 0;
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate /* Likewise. */
11947c478bd9Sstevel@tonic-gate grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
11957c478bd9Sstevel@tonic-gate
11967c478bd9Sstevel@tonic-gate if (ip || sm)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
11997c478bd9Sstevel@tonic-gate || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
12007c478bd9Sstevel@tonic-gate || ! netmask)
12017c478bd9Sstevel@tonic-gate network_ready = 0;
12027c478bd9Sstevel@tonic-gate else
12037c478bd9Sstevel@tonic-gate network_ready = 1;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate update_network_configuration();
12077c478bd9Sstevel@tonic-gate return 1;
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate * print_network_configuration
12127c478bd9Sstevel@tonic-gate *
12137c478bd9Sstevel@tonic-gate * Output the network configuration. It may broke the graphic console now.:-(
12147c478bd9Sstevel@tonic-gate */
print_network_configuration(void)12157c478bd9Sstevel@tonic-gate void print_network_configuration (void)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate EnterFunction("print_network_configuration");
121899ed6083Sszhou if (! network_ready)
121999ed6083Sszhou grub_printf ("Network interface not initialized yet.\n");
12207c478bd9Sstevel@tonic-gate else {
12212506833eSJan Setje-Eilers if (hostnamelen == 0)
12222506833eSJan Setje-Eilers etherboot_printf ("Hostname: not set\n");
12232506833eSJan Setje-Eilers else
12242506833eSJan Setje-Eilers etherboot_printf ("Hostname: %s\n", hostname);
12252506833eSJan Setje-Eilers
12267c478bd9Sstevel@tonic-gate etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
12277c478bd9Sstevel@tonic-gate etherboot_printf ("Netmask: %@\n", netmask);
12287c478bd9Sstevel@tonic-gate etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
12292506833eSJan Setje-Eilers etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
12302506833eSJan Setje-Eilers if (vendor_configfile == NULL) {
12312506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: not set\n");
12322506833eSJan Setje-Eilers } else {
12332506833eSJan Setje-Eilers /*
12342506833eSJan Setje-Eilers * vendor_configfile points into the packet and
12352506833eSJan Setje-Eilers * is not NULL terminated, so it needs to be
12362506833eSJan Setje-Eilers * patched up before printing it out
12372506833eSJan Setje-Eilers */
12382506833eSJan Setje-Eilers char c = vendor_configfile[vendor_configfile_len];
12392506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = '\0';
12402506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: %s\n",
12412506833eSJan Setje-Eilers vendor_configfile);
12422506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = c;
12432506833eSJan Setje-Eilers }
12442506833eSJan Setje-Eilers
12452506833eSJan Setje-Eilers if (bootfile == NULL)
12462506833eSJan Setje-Eilers etherboot_printf ("BootFile: not set\n");
12472506833eSJan Setje-Eilers else
12482506833eSJan Setje-Eilers etherboot_printf ("BootFile: %s\n", bootfile);
12492506833eSJan Setje-Eilers
12502506833eSJan Setje-Eilers etherboot_printf ("GRUB menu file: %s", config_file);
12512506833eSJan Setje-Eilers switch (configfile_origin) {
12522506833eSJan Setje-Eilers case CFG_HARDCODED:
12532506833eSJan Setje-Eilers etherboot_printf (" from hardcoded default\n");
12542506833eSJan Setje-Eilers break;
12552506833eSJan Setje-Eilers case CFG_150:
12562506833eSJan Setje-Eilers etherboot_printf (" from Site Option 150\n");
12572506833eSJan Setje-Eilers break;
12582506833eSJan Setje-Eilers case CFG_MAC:
12592506833eSJan Setje-Eilers etherboot_printf (" inferred from system MAC\n");
12602506833eSJan Setje-Eilers break;
12612506833eSJan Setje-Eilers case CFG_BOOTFILE:
12622506833eSJan Setje-Eilers etherboot_printf (" inferred from BootFile\n");
12632506833eSJan Setje-Eilers break;
12642506833eSJan Setje-Eilers default:
12652506833eSJan Setje-Eilers etherboot_printf ("\n");
12662506833eSJan Setje-Eilers }
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate LeaveFunction("print_network_configuration");
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate * update_network_configuration
12737c478bd9Sstevel@tonic-gate *
12747c478bd9Sstevel@tonic-gate * Update network configuration for diskless clients (Solaris only)
12757c478bd9Sstevel@tonic-gate */
update_network_configuration(void)12767c478bd9Sstevel@tonic-gate static void update_network_configuration (void)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
12797c478bd9Sstevel@tonic-gate struct sol_netinfo {
12807c478bd9Sstevel@tonic-gate uint8_t sn_infotype;
12817c478bd9Sstevel@tonic-gate uint8_t sn_mactype;
12827c478bd9Sstevel@tonic-gate uint8_t sn_maclen;
12837c478bd9Sstevel@tonic-gate uint8_t sn_padding;
12847c478bd9Sstevel@tonic-gate unsigned long sn_ciaddr;
12857c478bd9Sstevel@tonic-gate unsigned long sn_siaddr;
12867c478bd9Sstevel@tonic-gate unsigned long sn_giaddr;
12877c478bd9Sstevel@tonic-gate unsigned long sn_netmask;
12887c478bd9Sstevel@tonic-gate uint8_t sn_macaddr[1];
12897c478bd9Sstevel@tonic-gate } *sip;
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate if (! network_ready)
12927c478bd9Sstevel@tonic-gate return;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate sip = (struct sol_netinfo *)dhcpack_buf;
12957c478bd9Sstevel@tonic-gate sip->sn_infotype = 0xf0; /* something not BOOTP_REPLY */
12967c478bd9Sstevel@tonic-gate sip->sn_mactype = 4; /* DL_ETHER */
12977c478bd9Sstevel@tonic-gate sip->sn_maclen = ETH_ALEN;
12987c478bd9Sstevel@tonic-gate sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
12997c478bd9Sstevel@tonic-gate sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
13007c478bd9Sstevel@tonic-gate sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
13017c478bd9Sstevel@tonic-gate sip->sn_netmask = netmask;
13027c478bd9Sstevel@tonic-gate memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
13037c478bd9Sstevel@tonic-gate dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
13047c478bd9Sstevel@tonic-gate #endif /* SOLARIS_NETBOOT */
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate /**
13087c478bd9Sstevel@tonic-gate * cleanup_net
13097c478bd9Sstevel@tonic-gate *
13107c478bd9Sstevel@tonic-gate * Mark network unusable, and disable NICs
13117c478bd9Sstevel@tonic-gate */
cleanup_net(void)13127c478bd9Sstevel@tonic-gate void cleanup_net (void)
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate if (network_ready){
13157c478bd9Sstevel@tonic-gate /* Stop receiving packets. */
131699ed6083Sszhou if (use_bios_pxe)
131799ed6083Sszhou undi_pxe_disable();
131899ed6083Sszhou else
131999ed6083Sszhou eth_disable ();
13207c478bd9Sstevel@tonic-gate network_ready = 0;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate }
132399ed6083Sszhou
132499ed6083Sszhou /*******************************************************************
132599ed6083Sszhou * dhcp implementation reusing the BIOS pxe stack
132699ed6083Sszhou */
132799ed6083Sszhou static void
dhcp_copy(struct dhcp_t * dhcpreply)132899ed6083Sszhou dhcp_copy(struct dhcp_t *dhcpreply)
132999ed6083Sszhou {
133099ed6083Sszhou unsigned long time;
133199ed6083Sszhou int ret, len = DHCP_OPT_LEN;
133299ed6083Sszhou
133399ed6083Sszhou /* fill in netinfo */
133499ed6083Sszhou dhcpack_length = sizeof (struct dhcp_t);
133599ed6083Sszhou memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
133699ed6083Sszhou
133799ed6083Sszhou memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
133899ed6083Sszhou arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
133999ed6083Sszhou dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
134099ed6083Sszhou netmask = default_netmask();
134199ed6083Sszhou arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
134299ed6083Sszhou memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
134399ed6083Sszhou arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
134499ed6083Sszhou memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
13452506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file;
134699ed6083Sszhou memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
134799ed6083Sszhou decode_rfc1533(rfc1533_venddata, 0, len, 1);
134899ed6083Sszhou }
134999ed6083Sszhou
dhcp_undi(void)135099ed6083Sszhou int dhcp_undi(void)
135199ed6083Sszhou {
135299ed6083Sszhou struct dhcp_t *dhcpreply;
135399ed6083Sszhou
135499ed6083Sszhou if (!undi_bios_pxe((void **)&dhcpreply))
135599ed6083Sszhou return 0;
135699ed6083Sszhou
135799ed6083Sszhou dhcp_copy(dhcpreply);
135899ed6083Sszhou network_ready = 1;
135999ed6083Sszhou use_bios_pxe = 1;
136099ed6083Sszhou return (1);
136199ed6083Sszhou }
1362