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 102*2506833eSJan Setje-Eilers char *bootfile = NULL; 103*2506833eSJan Setje-Eilers configfile_origin_t configfile_origin = CFG_HARDCODED; 104*2506833eSJan Setje-Eilers char *vendor_configfile = NULL; 105*2506833eSJan Setje-Eilers char vendor_configfile_len; 106*2506833eSJan Setje-Eilers 1077c478bd9Sstevel@tonic-gate static void update_network_configuration(void); 1087c478bd9Sstevel@tonic-gate 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 */ 1207c478bd9Sstevel@tonic-gate static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned; 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 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 1807c478bd9Sstevel@tonic-gate int eth_probe(struct dev *dev) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate return probe(dev); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 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 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 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 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 **************************************************************************/ 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 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 **************************************************************************/ 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 **************************************************************************/ 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 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 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 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 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 **************************************************************************/ 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 **************************************************************************/ 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 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 **/ 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 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 **/ 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 */ 566*2506833eSJan 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 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 **/ 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 */ 663*2506833eSJan 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 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 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 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 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 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**************************************************************/ 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 **************************************************************************/ 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 **/ 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; 1103*2506833eSJan Setje-Eilers vendor_configfile = p + 2; 1104*2506833eSJan Setje-Eilers vendor_configfile_len = l; 1105*2506833eSJan 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 **************************************************************************/ 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 **************************************************************************/ 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 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 */ 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 { 1221*2506833eSJan Setje-Eilers if (hostnamelen == 0) 1222*2506833eSJan Setje-Eilers etherboot_printf ("Hostname: not set\n"); 1223*2506833eSJan Setje-Eilers else 1224*2506833eSJan Setje-Eilers etherboot_printf ("Hostname: %s\n", hostname); 1225*2506833eSJan 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); 1229*2506833eSJan Setje-Eilers etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr); 1230*2506833eSJan Setje-Eilers if (vendor_configfile == NULL) { 1231*2506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: not set\n"); 1232*2506833eSJan Setje-Eilers } else { 1233*2506833eSJan Setje-Eilers /* 1234*2506833eSJan Setje-Eilers * vendor_configfile points into the packet and 1235*2506833eSJan Setje-Eilers * is not NULL terminated, so it needs to be 1236*2506833eSJan Setje-Eilers * patched up before printing it out 1237*2506833eSJan Setje-Eilers */ 1238*2506833eSJan Setje-Eilers char c = vendor_configfile[vendor_configfile_len]; 1239*2506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = '\0'; 1240*2506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: %s\n", 1241*2506833eSJan Setje-Eilers vendor_configfile); 1242*2506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = c; 1243*2506833eSJan Setje-Eilers } 1244*2506833eSJan Setje-Eilers 1245*2506833eSJan Setje-Eilers if (bootfile == NULL) 1246*2506833eSJan Setje-Eilers etherboot_printf ("BootFile: not set\n"); 1247*2506833eSJan Setje-Eilers else 1248*2506833eSJan Setje-Eilers etherboot_printf ("BootFile: %s\n", bootfile); 1249*2506833eSJan Setje-Eilers 1250*2506833eSJan Setje-Eilers etherboot_printf ("GRUB menu file: %s", config_file); 1251*2506833eSJan Setje-Eilers switch (configfile_origin) { 1252*2506833eSJan Setje-Eilers case CFG_HARDCODED: 1253*2506833eSJan Setje-Eilers etherboot_printf (" from hardcoded default\n"); 1254*2506833eSJan Setje-Eilers break; 1255*2506833eSJan Setje-Eilers case CFG_150: 1256*2506833eSJan Setje-Eilers etherboot_printf (" from Site Option 150\n"); 1257*2506833eSJan Setje-Eilers break; 1258*2506833eSJan Setje-Eilers case CFG_MAC: 1259*2506833eSJan Setje-Eilers etherboot_printf (" inferred from system MAC\n"); 1260*2506833eSJan Setje-Eilers break; 1261*2506833eSJan Setje-Eilers case CFG_BOOTFILE: 1262*2506833eSJan Setje-Eilers etherboot_printf (" inferred from BootFile\n"); 1263*2506833eSJan Setje-Eilers break; 1264*2506833eSJan Setje-Eilers default: 1265*2506833eSJan Setje-Eilers etherboot_printf ("\n"); 1266*2506833eSJan 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 */ 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 */ 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 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 */ 1345*2506833eSJan 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 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