11b8adde7SWilliam Kucharski /************************************************************************** 21b8adde7SWilliam Kucharski Etherboot - Network Bootstrap Program 31b8adde7SWilliam Kucharski 41b8adde7SWilliam Kucharski Literature dealing with the network protocols: 51b8adde7SWilliam Kucharski ARP - RFC826 61b8adde7SWilliam Kucharski RARP - RFC903 71b8adde7SWilliam Kucharski IP - RFC791 81b8adde7SWilliam Kucharski UDP - RFC768 91b8adde7SWilliam Kucharski BOOTP - RFC951, RFC2132 (vendor extensions) 101b8adde7SWilliam Kucharski DHCP - RFC2131, RFC2132 (options) 111b8adde7SWilliam Kucharski TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize) 121b8adde7SWilliam Kucharski RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper) 131b8adde7SWilliam Kucharski NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented) 141b8adde7SWilliam Kucharski IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171 151b8adde7SWilliam Kucharski 161b8adde7SWilliam Kucharski **************************************************************************/ 171b8adde7SWilliam Kucharski #include "etherboot.h" 181b8adde7SWilliam Kucharski #include "grub.h" 191b8adde7SWilliam Kucharski #include "nic.h" 201b8adde7SWilliam Kucharski #include "elf.h" /* FOR EM_CURRENT */ 211b8adde7SWilliam Kucharski #include "bootp.h" 221b8adde7SWilliam Kucharski #include "if_arp.h" 231b8adde7SWilliam Kucharski #include "tftp.h" 241b8adde7SWilliam Kucharski #include "timer.h" 251b8adde7SWilliam Kucharski #include "ip.h" 261b8adde7SWilliam Kucharski #include "udp.h" 271b8adde7SWilliam Kucharski 281b8adde7SWilliam Kucharski /* Currently no other module uses rom, but it is available */ 291b8adde7SWilliam Kucharski struct rom_info rom; 301b8adde7SWilliam Kucharski struct arptable_t arptable[MAX_ARP]; 311b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2 321b8adde7SWilliam Kucharski unsigned long last_igmpv1 = 0; 331b8adde7SWilliam Kucharski struct igmptable_t igmptable[MAX_IGMP]; 341b8adde7SWilliam Kucharski #endif 351b8adde7SWilliam Kucharski static unsigned long netmask; 361b8adde7SWilliam Kucharski /* Used by nfs.c */ 371b8adde7SWilliam Kucharski char *hostname = ""; 381b8adde7SWilliam Kucharski int hostnamelen = 0; 391b8adde7SWilliam Kucharski /* Used by fsys_tftp.c */ 401b8adde7SWilliam Kucharski int use_bios_pxe = 0; 411b8adde7SWilliam Kucharski static uint32_t xid; 421b8adde7SWilliam Kucharski static unsigned char *end_of_rfc1533 = NULL; 431b8adde7SWilliam Kucharski static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 441b8adde7SWilliam Kucharski static const in_addr zeroIP = { 0L }; 451b8adde7SWilliam Kucharski static char rfc1533_venddata[MAX_RFC1533_VENDLEN]; 461b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE }; 471b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END }; 481b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE }; 491b8adde7SWilliam Kucharski static int dhcp_reply; 501b8adde7SWilliam Kucharski static in_addr dhcp_server = { 0L }; 511b8adde7SWilliam Kucharski static in_addr dhcp_addr = { 0L }; 521b8adde7SWilliam Kucharski 531b8adde7SWilliam Kucharski static const unsigned char dhcpdiscover[] = { 541b8adde7SWilliam Kucharski RFC2132_MSG_TYPE, 1, DHCPDISCOVER, 551b8adde7SWilliam Kucharski RFC2132_MAX_SIZE, 2, /* request as much as we can */ 561b8adde7SWilliam Kucharski ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, 571b8adde7SWilliam Kucharski /* Vendor class identifier */ 581b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT 591b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':', 601b8adde7SWilliam Kucharski 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':', 611b8adde7SWilliam Kucharski '0','0','2','0','0','1', 621b8adde7SWilliam Kucharski #else 631b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't', 641b8adde7SWilliam Kucharski #endif 651b8adde7SWilliam Kucharski RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY, 661b8adde7SWilliam Kucharski RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END 671b8adde7SWilliam Kucharski }; 681b8adde7SWilliam Kucharski static const unsigned char dhcprequest [] = { 691b8adde7SWilliam Kucharski RFC2132_MSG_TYPE,1,DHCPREQUEST, 701b8adde7SWilliam Kucharski RFC2132_SRV_ID,4,0,0,0,0, 711b8adde7SWilliam Kucharski RFC2132_REQ_ADDR,4,0,0,0,0, 721b8adde7SWilliam Kucharski RFC2132_MAX_SIZE,2, /* request as much as we can */ 731b8adde7SWilliam Kucharski ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, 741b8adde7SWilliam Kucharski /* Vendor class identifier */ 751b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT 761b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':', 771b8adde7SWilliam Kucharski 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':', 781b8adde7SWilliam Kucharski '0','0','2','0','0','1', 791b8adde7SWilliam Kucharski #else 801b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't', 811b8adde7SWilliam Kucharski #endif 821b8adde7SWilliam Kucharski RFC2132_PARAM_LIST, 831b8adde7SWilliam Kucharski /* 4 standard + 2 vendortags */ 841b8adde7SWilliam Kucharski 4 + 2, 851b8adde7SWilliam Kucharski /* Standard parameters */ 861b8adde7SWilliam Kucharski RFC1533_NETMASK, RFC1533_GATEWAY, 871b8adde7SWilliam Kucharski RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, 881b8adde7SWilliam Kucharski /* Etherboot vendortags */ 891b8adde7SWilliam Kucharski RFC1533_VENDOR_MAGIC, 901b8adde7SWilliam Kucharski RFC1533_VENDOR_CONFIGFILE, 911b8adde7SWilliam Kucharski RFC1533_END 921b8adde7SWilliam Kucharski }; 931b8adde7SWilliam Kucharski 941b8adde7SWilliam Kucharski /* See nic.h */ 951b8adde7SWilliam Kucharski int user_abort = 0; 961b8adde7SWilliam Kucharski int network_ready = 0; 971b8adde7SWilliam Kucharski 981b8adde7SWilliam Kucharski #ifdef REQUIRE_VCI_ETHERBOOT 991b8adde7SWilliam Kucharski int vci_etherboot; 1001b8adde7SWilliam Kucharski #endif 1011b8adde7SWilliam Kucharski 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 1071b8adde7SWilliam Kucharski static void update_network_configuration(void); 1081b8adde7SWilliam Kucharski 1091b8adde7SWilliam Kucharski static int dummy(void *unused __unused) 1101b8adde7SWilliam Kucharski { 1111b8adde7SWilliam Kucharski return (0); 1121b8adde7SWilliam Kucharski } 1131b8adde7SWilliam Kucharski 1141b8adde7SWilliam Kucharski /* Careful. We need an aligned buffer to avoid problems on machines 1151b8adde7SWilliam Kucharski * that care about alignment. To trivally align the ethernet data 1161b8adde7SWilliam Kucharski * (the ip hdr and arp requests) we offset the packet by 2 bytes. 1171b8adde7SWilliam Kucharski * leaving the ethernet data 16 byte aligned. Beyond this 1181b8adde7SWilliam Kucharski * we use memmove but this makes the common cast simple and fast. 1191b8adde7SWilliam Kucharski */ 120*34f09ee1SToomas Soome static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned(16); 1211b8adde7SWilliam Kucharski 1221b8adde7SWilliam Kucharski struct nic nic = 1231b8adde7SWilliam Kucharski { 1241b8adde7SWilliam Kucharski { 1251b8adde7SWilliam Kucharski 0, /* dev.disable */ 1261b8adde7SWilliam Kucharski { 1271b8adde7SWilliam Kucharski 0, 1281b8adde7SWilliam Kucharski 0, 1291b8adde7SWilliam Kucharski PCI_BUS_TYPE, 1301b8adde7SWilliam Kucharski }, /* dev.devid */ 1311b8adde7SWilliam Kucharski 0, /* index */ 1321b8adde7SWilliam Kucharski 0, /* type */ 1331b8adde7SWilliam Kucharski PROBE_FIRST, /* how_pobe */ 1341b8adde7SWilliam Kucharski PROBE_NONE, /* to_probe */ 1351b8adde7SWilliam Kucharski 0, /* failsafe */ 1361b8adde7SWilliam Kucharski 0, /* type_index */ 1371b8adde7SWilliam Kucharski {}, /* state */ 1381b8adde7SWilliam Kucharski }, 1391b8adde7SWilliam Kucharski (int (*)(struct nic *, int))dummy, /* poll */ 1401b8adde7SWilliam Kucharski (void (*)(struct nic *, const char *, 1411b8adde7SWilliam Kucharski unsigned int, unsigned int, 1421b8adde7SWilliam Kucharski const char *))dummy, /* transmit */ 1431b8adde7SWilliam Kucharski (void (*)(struct nic *, irq_action_t))dummy, /* irq */ 1441b8adde7SWilliam Kucharski 0, /* flags */ 1451b8adde7SWilliam Kucharski &rom, /* rom_info */ 1461b8adde7SWilliam Kucharski arptable[ARP_CLIENT].node, /* node_addr */ 1471b8adde7SWilliam Kucharski packet + ETH_DATA_ALIGN, /* packet */ 1481b8adde7SWilliam Kucharski 0, /* packetlen */ 1491b8adde7SWilliam Kucharski 0, /* ioaddr */ 1501b8adde7SWilliam Kucharski 0, /* irqno */ 1511b8adde7SWilliam Kucharski NULL, /* priv_data */ 1521b8adde7SWilliam Kucharski }; 1531b8adde7SWilliam Kucharski 1541b8adde7SWilliam Kucharski 1551b8adde7SWilliam Kucharski 1561b8adde7SWilliam Kucharski int grub_eth_probe(void) 1571b8adde7SWilliam Kucharski { 1581b8adde7SWilliam Kucharski static int probed = 0; 1591b8adde7SWilliam Kucharski struct dev *dev; 1601b8adde7SWilliam Kucharski 1611b8adde7SWilliam Kucharski EnterFunction("grub_eth_probe"); 1621b8adde7SWilliam Kucharski 1631b8adde7SWilliam Kucharski if (probed) 1641b8adde7SWilliam Kucharski return 1; 1651b8adde7SWilliam Kucharski 1661b8adde7SWilliam Kucharski network_ready = 0; 1671b8adde7SWilliam Kucharski grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t)); 1681b8adde7SWilliam Kucharski dev = &nic.dev; 1691b8adde7SWilliam Kucharski dev->how_probe = -1; 1701b8adde7SWilliam Kucharski dev->type = NIC_DRIVER; 1711b8adde7SWilliam Kucharski dev->failsafe = 1; 1721b8adde7SWilliam Kucharski rom = *((struct rom_info *)ROM_INFO_LOCATION); 1731b8adde7SWilliam Kucharski 1741b8adde7SWilliam Kucharski probed = (eth_probe(dev) == PROBE_WORKED); 1751b8adde7SWilliam Kucharski 1761b8adde7SWilliam Kucharski LeaveFunction("grub_eth_probe"); 1771b8adde7SWilliam Kucharski return probed; 1781b8adde7SWilliam Kucharski } 1791b8adde7SWilliam Kucharski 1801b8adde7SWilliam Kucharski int eth_probe(struct dev *dev) 1811b8adde7SWilliam Kucharski { 1821b8adde7SWilliam Kucharski return probe(dev); 1831b8adde7SWilliam Kucharski } 1841b8adde7SWilliam Kucharski 1851b8adde7SWilliam Kucharski int eth_poll(int retrieve) 1861b8adde7SWilliam Kucharski { 1871b8adde7SWilliam Kucharski return ((*nic.poll)(&nic, retrieve)); 1881b8adde7SWilliam Kucharski } 1891b8adde7SWilliam Kucharski 1901b8adde7SWilliam Kucharski void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p) 1911b8adde7SWilliam Kucharski { 1921b8adde7SWilliam Kucharski (*nic.transmit)(&nic, d, t, s, p); 1931b8adde7SWilliam Kucharski if (t == IP) twiddle(); 1941b8adde7SWilliam Kucharski } 1951b8adde7SWilliam Kucharski 1961b8adde7SWilliam Kucharski void eth_disable(void) 1971b8adde7SWilliam Kucharski { 1981b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2 1991b8adde7SWilliam Kucharski int i; 2001b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) { 2011b8adde7SWilliam Kucharski leave_group(i); 2021b8adde7SWilliam Kucharski } 2031b8adde7SWilliam Kucharski #endif 2041b8adde7SWilliam Kucharski disable(&nic.dev); 2051b8adde7SWilliam Kucharski } 2061b8adde7SWilliam Kucharski 2071b8adde7SWilliam Kucharski void eth_irq (irq_action_t action) 2081b8adde7SWilliam Kucharski { 2091b8adde7SWilliam Kucharski (*nic.irq)(&nic,action); 2101b8adde7SWilliam Kucharski } 2111b8adde7SWilliam Kucharski 2121b8adde7SWilliam Kucharski /************************************************************************** 2131b8adde7SWilliam Kucharski IPCHKSUM - Checksum IP Header 2141b8adde7SWilliam Kucharski **************************************************************************/ 2151b8adde7SWilliam Kucharski uint16_t ipchksum(const void *data, unsigned long length) 2161b8adde7SWilliam Kucharski { 2171b8adde7SWilliam Kucharski unsigned long sum; 2181b8adde7SWilliam Kucharski unsigned long i; 2191b8adde7SWilliam Kucharski const uint8_t *ptr; 2201b8adde7SWilliam Kucharski 2211b8adde7SWilliam Kucharski /* In the most straight forward way possible, 2221b8adde7SWilliam Kucharski * compute an ip style checksum. 2231b8adde7SWilliam Kucharski */ 2241b8adde7SWilliam Kucharski sum = 0; 2251b8adde7SWilliam Kucharski ptr = data; 2261b8adde7SWilliam Kucharski for(i = 0; i < length; i++) { 2271b8adde7SWilliam Kucharski unsigned long value; 2281b8adde7SWilliam Kucharski value = ptr[i]; 2291b8adde7SWilliam Kucharski if (i & 1) { 2301b8adde7SWilliam Kucharski value <<= 8; 2311b8adde7SWilliam Kucharski } 2321b8adde7SWilliam Kucharski /* Add the new value */ 2331b8adde7SWilliam Kucharski sum += value; 2341b8adde7SWilliam Kucharski /* Wrap around the carry */ 2351b8adde7SWilliam Kucharski if (sum > 0xFFFF) { 2361b8adde7SWilliam Kucharski sum = (sum + (sum >> 16)) & 0xFFFF; 2371b8adde7SWilliam Kucharski } 2381b8adde7SWilliam Kucharski } 2391b8adde7SWilliam Kucharski return (~cpu_to_le16(sum)) & 0xFFFF; 2401b8adde7SWilliam Kucharski } 2411b8adde7SWilliam Kucharski 2421b8adde7SWilliam Kucharski uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new) 2431b8adde7SWilliam Kucharski { 2441b8adde7SWilliam Kucharski unsigned long checksum; 2451b8adde7SWilliam Kucharski sum = ~sum & 0xFFFF; 2461b8adde7SWilliam Kucharski new = ~new & 0xFFFF; 2471b8adde7SWilliam Kucharski if (offset & 1) { 2481b8adde7SWilliam Kucharski /* byte swap the sum if it came from an odd offset 2491b8adde7SWilliam Kucharski * since the computation is endian independant this 2501b8adde7SWilliam Kucharski * works. 2511b8adde7SWilliam Kucharski */ 2521b8adde7SWilliam Kucharski new = bswap_16(new); 2531b8adde7SWilliam Kucharski } 2541b8adde7SWilliam Kucharski checksum = sum + new; 2551b8adde7SWilliam Kucharski if (checksum > 0xFFFF) { 2561b8adde7SWilliam Kucharski checksum -= 0xFFFF; 2571b8adde7SWilliam Kucharski } 2581b8adde7SWilliam Kucharski return (~checksum) & 0xFFFF; 2591b8adde7SWilliam Kucharski } 2601b8adde7SWilliam Kucharski 2611b8adde7SWilliam Kucharski /************************************************************************** 2621b8adde7SWilliam Kucharski DEFAULT_NETMASK - Return default netmask for IP address 2631b8adde7SWilliam Kucharski **************************************************************************/ 2641b8adde7SWilliam Kucharski static inline unsigned long default_netmask(void) 2651b8adde7SWilliam Kucharski { 2661b8adde7SWilliam Kucharski int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24; 2671b8adde7SWilliam Kucharski if (net <= 127) 2681b8adde7SWilliam Kucharski return(htonl(0xff000000)); 2691b8adde7SWilliam Kucharski else if (net < 192) 2701b8adde7SWilliam Kucharski return(htonl(0xffff0000)); 2711b8adde7SWilliam Kucharski else 2721b8adde7SWilliam Kucharski return(htonl(0xffffff00)); 2731b8adde7SWilliam Kucharski } 2741b8adde7SWilliam Kucharski 2751b8adde7SWilliam Kucharski /************************************************************************** 2761b8adde7SWilliam Kucharski IP_TRANSMIT - Send an IP datagram 2771b8adde7SWilliam Kucharski **************************************************************************/ 2781b8adde7SWilliam Kucharski static int await_arp(int ival, void *ptr, 2791b8adde7SWilliam Kucharski unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused) 2801b8adde7SWilliam Kucharski { 2811b8adde7SWilliam Kucharski struct arprequest *arpreply; 2821b8adde7SWilliam Kucharski if (ptype != ARP) 2831b8adde7SWilliam Kucharski return 0; 2841b8adde7SWilliam Kucharski if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest)) 2851b8adde7SWilliam Kucharski return 0; 2861b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN]; 2871b8adde7SWilliam Kucharski 2881b8adde7SWilliam Kucharski if (arpreply->opcode != htons(ARP_REPLY)) 2891b8adde7SWilliam Kucharski return 0; 2901b8adde7SWilliam Kucharski if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0) 2911b8adde7SWilliam Kucharski return 0; 2921b8adde7SWilliam Kucharski memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN); 2931b8adde7SWilliam Kucharski return 1; 2941b8adde7SWilliam Kucharski } 2951b8adde7SWilliam Kucharski 2961b8adde7SWilliam Kucharski int ip_transmit(int len, const void *buf) 2971b8adde7SWilliam Kucharski { 2981b8adde7SWilliam Kucharski unsigned long destip; 2991b8adde7SWilliam Kucharski struct iphdr *ip; 3001b8adde7SWilliam Kucharski struct arprequest arpreq; 3011b8adde7SWilliam Kucharski int arpentry, i; 3021b8adde7SWilliam Kucharski int retry; 3031b8adde7SWilliam Kucharski 3041b8adde7SWilliam Kucharski ip = (struct iphdr *)buf; 3051b8adde7SWilliam Kucharski destip = ip->dest.s_addr; 3061b8adde7SWilliam Kucharski if (destip == IP_BROADCAST) { 3071b8adde7SWilliam Kucharski eth_transmit(broadcast, IP, len, buf); 3081b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL1 3091b8adde7SWilliam Kucharski } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) { 3101b8adde7SWilliam Kucharski unsigned char multicast[6]; 3111b8adde7SWilliam Kucharski unsigned long hdestip; 3121b8adde7SWilliam Kucharski hdestip = ntohl(destip); 3131b8adde7SWilliam Kucharski multicast[0] = 0x01; 3141b8adde7SWilliam Kucharski multicast[1] = 0x00; 3151b8adde7SWilliam Kucharski multicast[2] = 0x5e; 3161b8adde7SWilliam Kucharski multicast[3] = (hdestip >> 16) & 0x7; 3171b8adde7SWilliam Kucharski multicast[4] = (hdestip >> 8) & 0xff; 3181b8adde7SWilliam Kucharski multicast[5] = hdestip & 0xff; 3191b8adde7SWilliam Kucharski eth_transmit(multicast, IP, len, buf); 3201b8adde7SWilliam Kucharski #endif 3211b8adde7SWilliam Kucharski } else { 3221b8adde7SWilliam Kucharski if (((destip & netmask) != 3231b8adde7SWilliam Kucharski (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) && 3241b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr) 3251b8adde7SWilliam Kucharski destip = arptable[ARP_GATEWAY].ipaddr.s_addr; 3261b8adde7SWilliam Kucharski for(arpentry = 0; arpentry<MAX_ARP; arpentry++) 3271b8adde7SWilliam Kucharski if (arptable[arpentry].ipaddr.s_addr == destip) break; 3281b8adde7SWilliam Kucharski if (arpentry == MAX_ARP) { 3291b8adde7SWilliam Kucharski printf("%@ is not in my arp table!\n", destip); 3301b8adde7SWilliam Kucharski return(0); 3311b8adde7SWilliam Kucharski } 3321b8adde7SWilliam Kucharski for (i = 0; i < ETH_ALEN; i++) 3331b8adde7SWilliam Kucharski if (arptable[arpentry].node[i]) 3341b8adde7SWilliam Kucharski break; 3351b8adde7SWilliam Kucharski if (i == ETH_ALEN) { /* Need to do arp request */ 3361b8adde7SWilliam Kucharski arpreq.hwtype = htons(1); 3371b8adde7SWilliam Kucharski arpreq.protocol = htons(IP); 3381b8adde7SWilliam Kucharski arpreq.hwlen = ETH_ALEN; 3391b8adde7SWilliam Kucharski arpreq.protolen = 4; 3401b8adde7SWilliam Kucharski arpreq.opcode = htons(ARP_REQUEST); 3411b8adde7SWilliam Kucharski memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 3421b8adde7SWilliam Kucharski memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); 3431b8adde7SWilliam Kucharski memset(arpreq.thwaddr, 0, ETH_ALEN); 3441b8adde7SWilliam Kucharski memcpy(arpreq.tipaddr, &destip, sizeof(in_addr)); 3451b8adde7SWilliam Kucharski for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { 3461b8adde7SWilliam Kucharski long timeout; 3471b8adde7SWilliam Kucharski eth_transmit(broadcast, ARP, sizeof(arpreq), 3481b8adde7SWilliam Kucharski &arpreq); 3491b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry); 3501b8adde7SWilliam Kucharski if (await_reply(await_arp, arpentry, 3511b8adde7SWilliam Kucharski arpreq.tipaddr, timeout)) goto xmit; 3521b8adde7SWilliam Kucharski } 3531b8adde7SWilliam Kucharski return(0); 3541b8adde7SWilliam Kucharski } 3551b8adde7SWilliam Kucharski xmit: 3561b8adde7SWilliam Kucharski eth_transmit(arptable[arpentry].node, IP, len, buf); 3571b8adde7SWilliam Kucharski } 3581b8adde7SWilliam Kucharski return 1; 3591b8adde7SWilliam Kucharski } 3601b8adde7SWilliam Kucharski 3611b8adde7SWilliam Kucharski void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len, 3621b8adde7SWilliam Kucharski int len, const void *buf) 3631b8adde7SWilliam Kucharski { 3641b8adde7SWilliam Kucharski struct iphdr *ip; 3651b8adde7SWilliam Kucharski ip = (struct iphdr *)buf; 3661b8adde7SWilliam Kucharski ip->verhdrlen = 0x45; 3671b8adde7SWilliam Kucharski ip->verhdrlen += (option_len/4); 3681b8adde7SWilliam Kucharski ip->service = 0; 3691b8adde7SWilliam Kucharski ip->len = htons(len); 3701b8adde7SWilliam Kucharski ip->ident = 0; 3711b8adde7SWilliam Kucharski ip->frags = 0; /* Should we set don't fragment? */ 3721b8adde7SWilliam Kucharski ip->ttl = ttl; 3731b8adde7SWilliam Kucharski ip->protocol = protocol; 3741b8adde7SWilliam Kucharski ip->chksum = 0; 3751b8adde7SWilliam Kucharski ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; 3761b8adde7SWilliam Kucharski ip->dest.s_addr = destip; 3771b8adde7SWilliam Kucharski ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len); 3781b8adde7SWilliam Kucharski } 3791b8adde7SWilliam Kucharski 3801b8adde7SWilliam Kucharski static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp) 3811b8adde7SWilliam Kucharski { 3821b8adde7SWilliam Kucharski struct udp_pseudo_hdr pseudo; 3831b8adde7SWilliam Kucharski uint16_t checksum; 3841b8adde7SWilliam Kucharski 3851b8adde7SWilliam Kucharski /* Compute the pseudo header */ 3861b8adde7SWilliam Kucharski pseudo.src.s_addr = ip->src.s_addr; 3871b8adde7SWilliam Kucharski pseudo.dest.s_addr = ip->dest.s_addr; 3881b8adde7SWilliam Kucharski pseudo.unused = 0; 3891b8adde7SWilliam Kucharski pseudo.protocol = IP_UDP; 3901b8adde7SWilliam Kucharski pseudo.len = udp->len; 3911b8adde7SWilliam Kucharski 3921b8adde7SWilliam Kucharski /* Sum the pseudo header */ 3931b8adde7SWilliam Kucharski checksum = ipchksum(&pseudo, 12); 3941b8adde7SWilliam Kucharski 3951b8adde7SWilliam Kucharski /* Sum the rest of the udp packet */ 3961b8adde7SWilliam Kucharski checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len))); 3971b8adde7SWilliam Kucharski return checksum; 3981b8adde7SWilliam Kucharski } 3991b8adde7SWilliam Kucharski 4001b8adde7SWilliam Kucharski 4011b8adde7SWilliam Kucharski void build_udp_hdr(unsigned long destip, 4021b8adde7SWilliam Kucharski unsigned int srcsock, unsigned int destsock, int ttl, 4031b8adde7SWilliam Kucharski int len, const void *buf) 4041b8adde7SWilliam Kucharski { 4051b8adde7SWilliam Kucharski struct iphdr *ip; 4061b8adde7SWilliam Kucharski struct udphdr *udp; 4071b8adde7SWilliam Kucharski ip = (struct iphdr *)buf; 4081b8adde7SWilliam Kucharski build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf); 4091b8adde7SWilliam Kucharski udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr)); 4101b8adde7SWilliam Kucharski udp->src = htons(srcsock); 4111b8adde7SWilliam Kucharski udp->dest = htons(destsock); 4121b8adde7SWilliam Kucharski udp->len = htons(len - sizeof(struct iphdr)); 4131b8adde7SWilliam Kucharski udp->chksum = 0; 4141b8adde7SWilliam Kucharski if ((udp->chksum = udpchksum(ip, udp)) == 0) 4151b8adde7SWilliam Kucharski udp->chksum = 0xffff; 4161b8adde7SWilliam Kucharski } 4171b8adde7SWilliam Kucharski 4181b8adde7SWilliam Kucharski 4191b8adde7SWilliam Kucharski /************************************************************************** 4201b8adde7SWilliam Kucharski UDP_TRANSMIT - Send an UDP datagram 4211b8adde7SWilliam Kucharski **************************************************************************/ 4221b8adde7SWilliam Kucharski int udp_transmit(unsigned long destip, unsigned int srcsock, 4231b8adde7SWilliam Kucharski unsigned int destsock, int len, const void *buf) 4241b8adde7SWilliam Kucharski { 4251b8adde7SWilliam Kucharski build_udp_hdr(destip, srcsock, destsock, 60, len, buf); 4261b8adde7SWilliam Kucharski return ip_transmit(len, buf); 4271b8adde7SWilliam Kucharski } 4281b8adde7SWilliam Kucharski 4291b8adde7SWilliam Kucharski /************************************************************************** 4301b8adde7SWilliam Kucharski QDRAIN - clear the nic's receive queue 4311b8adde7SWilliam Kucharski **************************************************************************/ 4321b8adde7SWilliam Kucharski static int await_qdrain(int ival __unused, void *ptr __unused, 4331b8adde7SWilliam Kucharski unsigned short ptype __unused, 4341b8adde7SWilliam Kucharski struct iphdr *ip __unused, struct udphdr *udp __unused) 4351b8adde7SWilliam Kucharski { 4361b8adde7SWilliam Kucharski return 0; 4371b8adde7SWilliam Kucharski } 4381b8adde7SWilliam Kucharski 4391b8adde7SWilliam Kucharski void rx_qdrain(void) 4401b8adde7SWilliam Kucharski { 4411b8adde7SWilliam Kucharski /* Clear out the Rx queue first. It contains nothing of interest, 4421b8adde7SWilliam Kucharski * except possibly ARP requests from the DHCP/TFTP server. We use 4431b8adde7SWilliam Kucharski * polling throughout Etherboot, so some time may have passed since we 4441b8adde7SWilliam Kucharski * last polled the receive queue, which may now be filled with 4451b8adde7SWilliam Kucharski * broadcast packets. This will cause the reply to the packets we are 4461b8adde7SWilliam Kucharski * about to send to be lost immediately. Not very clever. */ 4471b8adde7SWilliam Kucharski await_reply(await_qdrain, 0, NULL, 0); 4481b8adde7SWilliam Kucharski } 4491b8adde7SWilliam Kucharski 4501b8adde7SWilliam Kucharski /** 4511b8adde7SWilliam Kucharski * rarp 4521b8adde7SWilliam Kucharski * 4531b8adde7SWilliam Kucharski * Get IP address by rarp. Just copy from etherboot 4541b8adde7SWilliam Kucharski **/ 4551b8adde7SWilliam Kucharski static int await_rarp(int ival, void *ptr, unsigned short ptype, 4561b8adde7SWilliam Kucharski struct iphdr *ip, struct udphdr *udp) 4571b8adde7SWilliam Kucharski { 4581b8adde7SWilliam Kucharski struct arprequest *arpreply; 4591b8adde7SWilliam Kucharski if (ptype != RARP) 4601b8adde7SWilliam Kucharski return 0; 4611b8adde7SWilliam Kucharski if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest)) 4621b8adde7SWilliam Kucharski return 0; 4631b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN]; 4641b8adde7SWilliam Kucharski if (arpreply->opcode != htons(RARP_REPLY)) 4651b8adde7SWilliam Kucharski return 0; 4661b8adde7SWilliam Kucharski if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){ 4671b8adde7SWilliam Kucharski memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN); 4681b8adde7SWilliam Kucharski memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr)); 4691b8adde7SWilliam Kucharski memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr)); 4701b8adde7SWilliam Kucharski memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr)); 4711b8adde7SWilliam Kucharski return 1; 4721b8adde7SWilliam Kucharski } 4731b8adde7SWilliam Kucharski return 0; 4741b8adde7SWilliam Kucharski } 4751b8adde7SWilliam Kucharski 4761b8adde7SWilliam Kucharski int rarp(void) 4771b8adde7SWilliam Kucharski { 4781b8adde7SWilliam Kucharski int retry; 4791b8adde7SWilliam Kucharski 4801b8adde7SWilliam Kucharski /* arp and rarp requests share the same packet structure. */ 4811b8adde7SWilliam Kucharski struct arprequest rarpreq; 4821b8adde7SWilliam Kucharski 4831b8adde7SWilliam Kucharski if(!grub_eth_probe()) 4841b8adde7SWilliam Kucharski return 0; 4851b8adde7SWilliam Kucharski network_ready = 0; 4861b8adde7SWilliam Kucharski 4871b8adde7SWilliam Kucharski memset(&rarpreq, 0, sizeof(rarpreq)); 4881b8adde7SWilliam Kucharski 4891b8adde7SWilliam Kucharski rarpreq.hwtype = htons(1); 4901b8adde7SWilliam Kucharski rarpreq.protocol = htons(IP); 4911b8adde7SWilliam Kucharski rarpreq.hwlen = ETH_ALEN; 4921b8adde7SWilliam Kucharski rarpreq.protolen = 4; 4931b8adde7SWilliam Kucharski rarpreq.opcode = htons(RARP_REQUEST); 4941b8adde7SWilliam Kucharski memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 4951b8adde7SWilliam Kucharski /* sipaddr is already zeroed out */ 4961b8adde7SWilliam Kucharski memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 4971b8adde7SWilliam Kucharski /* tipaddr is already zeroed out */ 4981b8adde7SWilliam Kucharski 4991b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { 5001b8adde7SWilliam Kucharski long timeout; 5011b8adde7SWilliam Kucharski eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq); 5021b8adde7SWilliam Kucharski 5031b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry); 5041b8adde7SWilliam Kucharski if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout)) 5051b8adde7SWilliam Kucharski break; 5061b8adde7SWilliam Kucharski if (user_abort) 5071b8adde7SWilliam Kucharski return 0; 5081b8adde7SWilliam Kucharski } 5091b8adde7SWilliam Kucharski 5101b8adde7SWilliam Kucharski if (retry == MAX_ARP_RETRIES) { 5111b8adde7SWilliam Kucharski return (0); 5121b8adde7SWilliam Kucharski } 5131b8adde7SWilliam Kucharski 5141b8adde7SWilliam Kucharski network_ready = 1; 5151b8adde7SWilliam Kucharski update_network_configuration(); 5161b8adde7SWilliam Kucharski return (1); 5171b8adde7SWilliam Kucharski } 5181b8adde7SWilliam Kucharski 5191b8adde7SWilliam Kucharski /** 5201b8adde7SWilliam Kucharski * bootp 5211b8adde7SWilliam Kucharski * 5221b8adde7SWilliam Kucharski * Get IP address by bootp, segregate from bootp in etherboot. 5231b8adde7SWilliam Kucharski **/ 5241b8adde7SWilliam Kucharski static int await_bootp(int ival __unused, void *ptr __unused, 5251b8adde7SWilliam Kucharski unsigned short ptype __unused, struct iphdr *ip __unused, 5261b8adde7SWilliam Kucharski struct udphdr *udp) 5271b8adde7SWilliam Kucharski { 5281b8adde7SWilliam Kucharski struct bootp_t *bootpreply; 5291b8adde7SWilliam Kucharski int len; /* Length of vendor */ 5301b8adde7SWilliam Kucharski 5311b8adde7SWilliam Kucharski if (!udp) { 5321b8adde7SWilliam Kucharski return 0; 5331b8adde7SWilliam Kucharski } 5341b8adde7SWilliam Kucharski bootpreply = (struct bootp_t *) 5351b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)]; 5361b8adde7SWilliam Kucharski len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) + 5371b8adde7SWilliam Kucharski sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN); 5381b8adde7SWilliam Kucharski if (len < 0) { 5391b8adde7SWilliam Kucharski return 0; 5401b8adde7SWilliam Kucharski } 5411b8adde7SWilliam Kucharski if (udp->dest != htons(BOOTP_CLIENT)) 5421b8adde7SWilliam Kucharski return 0; 5431b8adde7SWilliam Kucharski if (bootpreply->bp_op != BOOTP_REPLY) 5441b8adde7SWilliam Kucharski return 0; 5451b8adde7SWilliam Kucharski if (bootpreply->bp_xid != xid) 5461b8adde7SWilliam Kucharski return 0; 5471b8adde7SWilliam Kucharski if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0) 5481b8adde7SWilliam Kucharski return 0; 5491b8adde7SWilliam Kucharski if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) && 5501b8adde7SWilliam Kucharski (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) { 5511b8adde7SWilliam Kucharski return 0; 5521b8adde7SWilliam Kucharski } 5531b8adde7SWilliam Kucharski 5541b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT 5551b8adde7SWilliam Kucharski /* fill in netinfo */ 5561b8adde7SWilliam Kucharski dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN; 5571b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length); 5581b8adde7SWilliam Kucharski #endif 5591b8adde7SWilliam Kucharski 5601b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr; 5611b8adde7SWilliam Kucharski netmask = default_netmask(); 5621b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr; 5631b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */ 5641b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr; 5651b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */ 5662506833eSJan Setje-Eilers bootfile = bootpreply->bp_file; 5671b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len); 5681b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1); 5691b8adde7SWilliam Kucharski return(1); 5701b8adde7SWilliam Kucharski } 5711b8adde7SWilliam Kucharski 5721b8adde7SWilliam Kucharski int bootp(void) 5731b8adde7SWilliam Kucharski { 5741b8adde7SWilliam Kucharski int retry; 5751b8adde7SWilliam Kucharski struct bootpip_t ip; 5761b8adde7SWilliam Kucharski unsigned long starttime; 5771b8adde7SWilliam Kucharski 5781b8adde7SWilliam Kucharski EnterFunction("bootp"); 5791b8adde7SWilliam Kucharski 5801b8adde7SWilliam Kucharski if(!grub_eth_probe()) 5811b8adde7SWilliam Kucharski return 0; 5821b8adde7SWilliam Kucharski network_ready = 0; 5831b8adde7SWilliam Kucharski 5841b8adde7SWilliam Kucharski memset(&ip, 0, sizeof(struct bootpip_t)); 5851b8adde7SWilliam Kucharski ip.bp.bp_op = BOOTP_REQUEST; 5861b8adde7SWilliam Kucharski ip.bp.bp_htype = 1; 5871b8adde7SWilliam Kucharski ip.bp.bp_hlen = ETH_ALEN; 5881b8adde7SWilliam Kucharski starttime = currticks(); 5891b8adde7SWilliam Kucharski /* Use lower 32 bits of node address, more likely to be 5901b8adde7SWilliam Kucharski distinct than the time since booting */ 5911b8adde7SWilliam Kucharski memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); 5921b8adde7SWilliam Kucharski ip.bp.bp_xid = xid += htonl(starttime); 5931b8adde7SWilliam Kucharski /* bp_secs defaults to zero */ 5941b8adde7SWilliam Kucharski memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 5951b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */ 5961b8adde7SWilliam Kucharski 5971b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { 5981b8adde7SWilliam Kucharski long timeout; 5991b8adde7SWilliam Kucharski 6001b8adde7SWilliam Kucharski rx_qdrain(); 6011b8adde7SWilliam Kucharski 6021b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, 6031b8adde7SWilliam Kucharski sizeof(struct bootpip_t), &ip); 6041b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry++); 6051b8adde7SWilliam Kucharski if (await_reply(await_bootp, 0, NULL, timeout)){ 6061b8adde7SWilliam Kucharski network_ready = 1; 6071b8adde7SWilliam Kucharski return(1); 6081b8adde7SWilliam Kucharski } 6091b8adde7SWilliam Kucharski if (user_abort) 6101b8adde7SWilliam Kucharski return 0; 6111b8adde7SWilliam Kucharski ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC); 6121b8adde7SWilliam Kucharski } 6131b8adde7SWilliam Kucharski return(0); 6141b8adde7SWilliam Kucharski } 6151b8adde7SWilliam Kucharski 6161b8adde7SWilliam Kucharski /** 6171b8adde7SWilliam Kucharski * dhcp 6181b8adde7SWilliam Kucharski * 6191b8adde7SWilliam Kucharski * Get IP address by dhcp, segregate from bootp in etherboot. 6201b8adde7SWilliam Kucharski **/ 6211b8adde7SWilliam Kucharski static int await_dhcp(int ival __unused, void *ptr __unused, 6221b8adde7SWilliam Kucharski unsigned short ptype __unused, struct iphdr *ip __unused, 6231b8adde7SWilliam Kucharski struct udphdr *udp) 6241b8adde7SWilliam Kucharski { 6251b8adde7SWilliam Kucharski struct dhcp_t *dhcpreply; 6261b8adde7SWilliam Kucharski int len; 6271b8adde7SWilliam Kucharski 6281b8adde7SWilliam Kucharski if (!udp) { 6291b8adde7SWilliam Kucharski return 0; 6301b8adde7SWilliam Kucharski } 6311b8adde7SWilliam Kucharski dhcpreply = (struct dhcp_t *) 6321b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)]; 6331b8adde7SWilliam Kucharski len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) + 6341b8adde7SWilliam Kucharski sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN); 6351b8adde7SWilliam Kucharski if (len < 0){ 6361b8adde7SWilliam Kucharski return 0; 6371b8adde7SWilliam Kucharski } 6381b8adde7SWilliam Kucharski if (udp->dest != htons(BOOTP_CLIENT)) 6391b8adde7SWilliam Kucharski return 0; 6401b8adde7SWilliam Kucharski if (dhcpreply->bp_op != BOOTP_REPLY) 6411b8adde7SWilliam Kucharski return 0; 6421b8adde7SWilliam Kucharski if (dhcpreply->bp_xid != xid) 6431b8adde7SWilliam Kucharski return 0; 6441b8adde7SWilliam Kucharski if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0) 6451b8adde7SWilliam Kucharski return 0; 6461b8adde7SWilliam Kucharski if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) && 6471b8adde7SWilliam Kucharski (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) { 6481b8adde7SWilliam Kucharski return 0; 6491b8adde7SWilliam Kucharski } 6501b8adde7SWilliam Kucharski 6511b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT 6521b8adde7SWilliam Kucharski /* fill in netinfo */ 6531b8adde7SWilliam Kucharski dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN; 6541b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length); 6551b8adde7SWilliam Kucharski #endif 6561b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr; 6571b8adde7SWilliam Kucharski dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr; 6581b8adde7SWilliam Kucharski netmask = default_netmask(); 6591b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr; 6601b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */ 6611b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr; 6621b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */ 6632506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file; 6641b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len); 6651b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1); 6661b8adde7SWilliam Kucharski return(1); 6671b8adde7SWilliam Kucharski } 6681b8adde7SWilliam Kucharski 6691b8adde7SWilliam Kucharski int dhcp(void) 6701b8adde7SWilliam Kucharski { 6711b8adde7SWilliam Kucharski int retry; 6721b8adde7SWilliam Kucharski int reqretry; 6731b8adde7SWilliam Kucharski struct dhcpip_t ip; 6741b8adde7SWilliam Kucharski unsigned long starttime; 6751b8adde7SWilliam Kucharski 6761b8adde7SWilliam Kucharski /* try bios pxe stack first */ 6771b8adde7SWilliam Kucharski if (dhcp_undi()) 6781b8adde7SWilliam Kucharski return 1; 6791b8adde7SWilliam Kucharski 6801b8adde7SWilliam Kucharski if(!grub_eth_probe()) 6811b8adde7SWilliam Kucharski return 0; 6821b8adde7SWilliam Kucharski 6831b8adde7SWilliam Kucharski network_ready = 0; 6841b8adde7SWilliam Kucharski 6851b8adde7SWilliam Kucharski memset(&ip, 0, sizeof(ip)); 6861b8adde7SWilliam Kucharski ip.bp.bp_op = BOOTP_REQUEST; 6871b8adde7SWilliam Kucharski ip.bp.bp_htype = 1; 6881b8adde7SWilliam Kucharski ip.bp.bp_hlen = ETH_ALEN; 6891b8adde7SWilliam Kucharski starttime = currticks(); 6901b8adde7SWilliam Kucharski /* Use lower 32 bits of node address, more likely to be 6911b8adde7SWilliam Kucharski distinct than the time since booting */ 6921b8adde7SWilliam Kucharski memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); 6931b8adde7SWilliam Kucharski ip.bp.bp_xid = xid += htonl(starttime); 6941b8adde7SWilliam Kucharski memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 6951b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */ 6961b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover); 6971b8adde7SWilliam Kucharski 6981b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { 6991b8adde7SWilliam Kucharski long timeout; 7001b8adde7SWilliam Kucharski 7011b8adde7SWilliam Kucharski rx_qdrain(); 7021b8adde7SWilliam Kucharski 7031b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, 7041b8adde7SWilliam Kucharski sizeof(ip), &ip); 7051b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry++); 7061b8adde7SWilliam Kucharski if (await_reply(await_dhcp, 0, NULL, timeout)) { 7071b8adde7SWilliam Kucharski /* If not a DHCPOFFER then must be just a 7081b8adde7SWilliam Kucharski BOOTP reply, be backward compatible with 7091b8adde7SWilliam Kucharski BOOTP then. Jscott report a bug here, but I 7101b8adde7SWilliam Kucharski don't know how it happened */ 7111b8adde7SWilliam Kucharski if (dhcp_reply != DHCPOFFER){ 7121b8adde7SWilliam Kucharski network_ready = 1; 7131b8adde7SWilliam Kucharski return(1); 7141b8adde7SWilliam Kucharski } 7151b8adde7SWilliam Kucharski dhcp_reply = 0; 7161b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); 7171b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest); 7181b8adde7SWilliam Kucharski /* Beware: the magic numbers 9 and 15 depend on 7191b8adde7SWilliam Kucharski the layout of dhcprequest */ 7201b8adde7SWilliam Kucharski memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr)); 7211b8adde7SWilliam Kucharski memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr)); 7221b8adde7SWilliam Kucharski for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) { 7231b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, 7241b8adde7SWilliam Kucharski sizeof(ip), &ip); 7251b8adde7SWilliam Kucharski dhcp_reply=0; 7261b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++); 7271b8adde7SWilliam Kucharski if (await_reply(await_dhcp, 0, NULL, timeout)) 7281b8adde7SWilliam Kucharski if (dhcp_reply == DHCPACK){ 7291b8adde7SWilliam Kucharski network_ready = 1; 7301b8adde7SWilliam Kucharski return(1); 7311b8adde7SWilliam Kucharski } 7321b8adde7SWilliam Kucharski if (user_abort) 7331b8adde7SWilliam Kucharski return 0; 7341b8adde7SWilliam Kucharski } 7351b8adde7SWilliam Kucharski } 7361b8adde7SWilliam Kucharski if (user_abort) 7371b8adde7SWilliam Kucharski return 0; 7381b8adde7SWilliam Kucharski ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC); 7391b8adde7SWilliam Kucharski } 7401b8adde7SWilliam Kucharski return(0); 7411b8adde7SWilliam Kucharski } 7421b8adde7SWilliam Kucharski 7431b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2 7441b8adde7SWilliam Kucharski static void send_igmp_reports(unsigned long now) 7451b8adde7SWilliam Kucharski { 7461b8adde7SWilliam Kucharski int i; 7471b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) { 7481b8adde7SWilliam Kucharski if (igmptable[i].time && (now >= igmptable[i].time)) { 7491b8adde7SWilliam Kucharski struct igmp_ip_t igmp; 7501b8adde7SWilliam Kucharski igmp.router_alert[0] = 0x94; 7511b8adde7SWilliam Kucharski igmp.router_alert[1] = 0x04; 7521b8adde7SWilliam Kucharski igmp.router_alert[2] = 0; 7531b8adde7SWilliam Kucharski igmp.router_alert[3] = 0; 7541b8adde7SWilliam Kucharski build_ip_hdr(igmptable[i].group.s_addr, 7551b8adde7SWilliam Kucharski 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp); 7561b8adde7SWilliam Kucharski igmp.igmp.type = IGMPv2_REPORT; 7571b8adde7SWilliam Kucharski if (last_igmpv1 && 7581b8adde7SWilliam Kucharski (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) { 7591b8adde7SWilliam Kucharski igmp.igmp.type = IGMPv1_REPORT; 7601b8adde7SWilliam Kucharski } 7611b8adde7SWilliam Kucharski igmp.igmp.response_time = 0; 7621b8adde7SWilliam Kucharski igmp.igmp.chksum = 0; 7631b8adde7SWilliam Kucharski igmp.igmp.group.s_addr = igmptable[i].group.s_addr; 7641b8adde7SWilliam Kucharski igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp)); 7651b8adde7SWilliam Kucharski ip_transmit(sizeof(igmp), &igmp); 7661b8adde7SWilliam Kucharski #ifdef MDEBUG 7671b8adde7SWilliam Kucharski printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr); 7681b8adde7SWilliam Kucharski #endif 7691b8adde7SWilliam Kucharski /* Don't send another igmp report until asked */ 7701b8adde7SWilliam Kucharski igmptable[i].time = 0; 7711b8adde7SWilliam Kucharski } 7721b8adde7SWilliam Kucharski } 7731b8adde7SWilliam Kucharski } 7741b8adde7SWilliam Kucharski 7751b8adde7SWilliam Kucharski static void process_igmp(struct iphdr *ip, unsigned long now) 7761b8adde7SWilliam Kucharski { 7771b8adde7SWilliam Kucharski struct igmp *igmp; 7781b8adde7SWilliam Kucharski int i; 7791b8adde7SWilliam Kucharski unsigned iplen = 0; 7801b8adde7SWilliam Kucharski if (!ip || (ip->protocol == IP_IGMP) || 7811b8adde7SWilliam Kucharski (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) { 7821b8adde7SWilliam Kucharski return; 7831b8adde7SWilliam Kucharski } 7841b8adde7SWilliam Kucharski iplen = (ip->verhdrlen & 0xf)*4; 7851b8adde7SWilliam Kucharski igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)]; 7861b8adde7SWilliam Kucharski if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0) 7871b8adde7SWilliam Kucharski return; 7881b8adde7SWilliam Kucharski if ((igmp->type == IGMP_QUERY) && 7891b8adde7SWilliam Kucharski (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) { 7901b8adde7SWilliam Kucharski unsigned long interval = IGMP_INTERVAL; 7911b8adde7SWilliam Kucharski if (igmp->response_time == 0) { 7921b8adde7SWilliam Kucharski last_igmpv1 = now; 7931b8adde7SWilliam Kucharski } else { 7941b8adde7SWilliam Kucharski interval = (igmp->response_time * TICKS_PER_SEC)/10; 7951b8adde7SWilliam Kucharski } 7961b8adde7SWilliam Kucharski 7971b8adde7SWilliam Kucharski #ifdef MDEBUG 7981b8adde7SWilliam Kucharski printf("Received IGMP query for: %@\n", igmp->group.s_addr); 7991b8adde7SWilliam Kucharski #endif 8001b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) { 8011b8adde7SWilliam Kucharski uint32_t group = igmptable[i].group.s_addr; 8021b8adde7SWilliam Kucharski if ((group == 0) || (group == igmp->group.s_addr)) { 8031b8adde7SWilliam Kucharski unsigned long time; 8041b8adde7SWilliam Kucharski time = currticks() + rfc1112_sleep_interval(interval, 0); 8051b8adde7SWilliam Kucharski if (time < igmptable[i].time) { 8061b8adde7SWilliam Kucharski igmptable[i].time = time; 8071b8adde7SWilliam Kucharski } 8081b8adde7SWilliam Kucharski } 8091b8adde7SWilliam Kucharski } 8101b8adde7SWilliam Kucharski } 8111b8adde7SWilliam Kucharski if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) && 8121b8adde7SWilliam Kucharski (ip->dest.s_addr == igmp->group.s_addr)) { 8131b8adde7SWilliam Kucharski #ifdef MDEBUG 8141b8adde7SWilliam Kucharski printf("Received IGMP report for: %@\n", igmp->group.s_addr); 8151b8adde7SWilliam Kucharski #endif 8161b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) { 8171b8adde7SWilliam Kucharski if ((igmptable[i].group.s_addr == igmp->group.s_addr) && 8181b8adde7SWilliam Kucharski igmptable[i].time != 0) { 8191b8adde7SWilliam Kucharski igmptable[i].time = 0; 8201b8adde7SWilliam Kucharski } 8211b8adde7SWilliam Kucharski } 8221b8adde7SWilliam Kucharski } 8231b8adde7SWilliam Kucharski } 8241b8adde7SWilliam Kucharski 8251b8adde7SWilliam Kucharski void leave_group(int slot) 8261b8adde7SWilliam Kucharski { 8271b8adde7SWilliam Kucharski /* Be very stupid and always send a leave group message if 8281b8adde7SWilliam Kucharski * I have subscribed. Imperfect but it is standards 8291b8adde7SWilliam Kucharski * compliant, easy and reliable to implement. 8301b8adde7SWilliam Kucharski * 8311b8adde7SWilliam Kucharski * The optimal group leave method is to only send leave when, 8321b8adde7SWilliam Kucharski * we were the last host to respond to a query on this group, 8331b8adde7SWilliam Kucharski * and igmpv1 compatibility is not enabled. 8341b8adde7SWilliam Kucharski */ 8351b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr) { 8361b8adde7SWilliam Kucharski struct igmp_ip_t igmp; 8371b8adde7SWilliam Kucharski igmp.router_alert[0] = 0x94; 8381b8adde7SWilliam Kucharski igmp.router_alert[1] = 0x04; 8391b8adde7SWilliam Kucharski igmp.router_alert[2] = 0; 8401b8adde7SWilliam Kucharski igmp.router_alert[3] = 0; 8411b8adde7SWilliam Kucharski build_ip_hdr(htonl(GROUP_ALL_HOSTS), 8421b8adde7SWilliam Kucharski 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp); 8431b8adde7SWilliam Kucharski igmp.igmp.type = IGMP_LEAVE; 8441b8adde7SWilliam Kucharski igmp.igmp.response_time = 0; 8451b8adde7SWilliam Kucharski igmp.igmp.chksum = 0; 8461b8adde7SWilliam Kucharski igmp.igmp.group.s_addr = igmptable[slot].group.s_addr; 8471b8adde7SWilliam Kucharski igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp)); 8481b8adde7SWilliam Kucharski ip_transmit(sizeof(igmp), &igmp); 8491b8adde7SWilliam Kucharski #ifdef MDEBUG 8501b8adde7SWilliam Kucharski printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr); 8511b8adde7SWilliam Kucharski #endif 8521b8adde7SWilliam Kucharski } 8531b8adde7SWilliam Kucharski memset(&igmptable[slot], 0, sizeof(igmptable[0])); 8541b8adde7SWilliam Kucharski } 8551b8adde7SWilliam Kucharski 8561b8adde7SWilliam Kucharski void join_group(int slot, unsigned long group) 8571b8adde7SWilliam Kucharski { 8581b8adde7SWilliam Kucharski /* I have already joined */ 8591b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr == group) 8601b8adde7SWilliam Kucharski return; 8611b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr) { 8621b8adde7SWilliam Kucharski leave_group(slot); 8631b8adde7SWilliam Kucharski } 8641b8adde7SWilliam Kucharski /* Only join a group if we are given a multicast ip, this way 8651b8adde7SWilliam Kucharski * code can be given a non-multicast (broadcast or unicast ip) 8661b8adde7SWilliam Kucharski * and still work... 8671b8adde7SWilliam Kucharski */ 8681b8adde7SWilliam Kucharski if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) { 8691b8adde7SWilliam Kucharski igmptable[slot].group.s_addr = group; 8701b8adde7SWilliam Kucharski igmptable[slot].time = currticks(); 8711b8adde7SWilliam Kucharski } 8721b8adde7SWilliam Kucharski } 8731b8adde7SWilliam Kucharski #else 8741b8adde7SWilliam Kucharski #define send_igmp_reports(now); 8751b8adde7SWilliam Kucharski #define process_igmp(ip, now) 8761b8adde7SWilliam Kucharski #endif 8771b8adde7SWilliam Kucharski 8781b8adde7SWilliam Kucharski /************************************************************************** 8791b8adde7SWilliam Kucharski AWAIT_REPLY - Wait until we get a response for our request 8801b8adde7SWilliam Kucharski ************f**************************************************************/ 8811b8adde7SWilliam Kucharski int await_reply(reply_t reply, int ival, void *ptr, long timeout) 8821b8adde7SWilliam Kucharski { 8831b8adde7SWilliam Kucharski unsigned long time, now; 8841b8adde7SWilliam Kucharski struct iphdr *ip; 8851b8adde7SWilliam Kucharski unsigned iplen = 0; 8861b8adde7SWilliam Kucharski struct udphdr *udp; 8871b8adde7SWilliam Kucharski unsigned short ptype; 8881b8adde7SWilliam Kucharski int result; 8891b8adde7SWilliam Kucharski 8901b8adde7SWilliam Kucharski user_abort = 0; 8911b8adde7SWilliam Kucharski 8921b8adde7SWilliam Kucharski time = timeout + currticks(); 8931b8adde7SWilliam Kucharski /* The timeout check is done below. The timeout is only checked if 8941b8adde7SWilliam Kucharski * there is no packet in the Rx queue. This assumes that eth_poll() 8951b8adde7SWilliam Kucharski * needs a negligible amount of time. 8961b8adde7SWilliam Kucharski */ 8971b8adde7SWilliam Kucharski for (;;) { 8981b8adde7SWilliam Kucharski now = currticks(); 8991b8adde7SWilliam Kucharski send_igmp_reports(now); 9001b8adde7SWilliam Kucharski result = eth_poll(1); 9011b8adde7SWilliam Kucharski if (result == 0) { 9021b8adde7SWilliam Kucharski /* We don't have anything */ 9031b8adde7SWilliam Kucharski 9041b8adde7SWilliam Kucharski /* Check for abort key only if the Rx queue is empty - 9051b8adde7SWilliam Kucharski * as long as we have something to process, don't 9061b8adde7SWilliam Kucharski * assume that something failed. It is unlikely that 9071b8adde7SWilliam Kucharski * we have no processing time left between packets. */ 9081b8adde7SWilliam Kucharski poll_interruptions(); 9091b8adde7SWilliam Kucharski /* Do the timeout after at least a full queue walk. */ 9101b8adde7SWilliam Kucharski if ((timeout == 0) || (currticks() > time) || user_abort == 1) { 9111b8adde7SWilliam Kucharski break; 9121b8adde7SWilliam Kucharski } 9131b8adde7SWilliam Kucharski continue; 9141b8adde7SWilliam Kucharski } 9151b8adde7SWilliam Kucharski 9161b8adde7SWilliam Kucharski /* We have something! */ 9171b8adde7SWilliam Kucharski 9181b8adde7SWilliam Kucharski /* Find the Ethernet packet type */ 9191b8adde7SWilliam Kucharski if (nic.packetlen >= ETH_HLEN) { 9201b8adde7SWilliam Kucharski ptype = ((unsigned short) nic.packet[12]) << 8 9211b8adde7SWilliam Kucharski | ((unsigned short) nic.packet[13]); 9221b8adde7SWilliam Kucharski } else continue; /* what else could we do with it? */ 9231b8adde7SWilliam Kucharski /* Verify an IP header */ 9241b8adde7SWilliam Kucharski ip = 0; 9251b8adde7SWilliam Kucharski if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) { 9261b8adde7SWilliam Kucharski unsigned ipoptlen; 9271b8adde7SWilliam Kucharski ip = (struct iphdr *)&nic.packet[ETH_HLEN]; 9281b8adde7SWilliam Kucharski if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F)) 9291b8adde7SWilliam Kucharski continue; 9301b8adde7SWilliam Kucharski iplen = (ip->verhdrlen & 0xf) * 4; 9311b8adde7SWilliam Kucharski if (ipchksum(ip, iplen) != 0) 9321b8adde7SWilliam Kucharski continue; 9331b8adde7SWilliam Kucharski if (ip->frags & htons(0x3FFF)) { 9341b8adde7SWilliam Kucharski static int warned_fragmentation = 0; 9351b8adde7SWilliam Kucharski if (!warned_fragmentation) { 9361b8adde7SWilliam Kucharski printf("ALERT: got a fragmented packet - reconfigure your server\n"); 9371b8adde7SWilliam Kucharski warned_fragmentation = 1; 9381b8adde7SWilliam Kucharski } 9391b8adde7SWilliam Kucharski continue; 9401b8adde7SWilliam Kucharski } 9411b8adde7SWilliam Kucharski if (ntohs(ip->len) > ETH_MAX_MTU) 9421b8adde7SWilliam Kucharski continue; 9431b8adde7SWilliam Kucharski 9441b8adde7SWilliam Kucharski ipoptlen = iplen - sizeof(struct iphdr); 9451b8adde7SWilliam Kucharski if (ipoptlen) { 9461b8adde7SWilliam Kucharski /* Delete the ip options, to guarantee 9471b8adde7SWilliam Kucharski * good alignment, and make etherboot simpler. 9481b8adde7SWilliam Kucharski */ 9491b8adde7SWilliam Kucharski memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)], 9501b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + iplen], 9511b8adde7SWilliam Kucharski nic.packetlen - ipoptlen); 9521b8adde7SWilliam Kucharski nic.packetlen -= ipoptlen; 9531b8adde7SWilliam Kucharski } 9541b8adde7SWilliam Kucharski } 9551b8adde7SWilliam Kucharski udp = 0; 9561b8adde7SWilliam Kucharski if (ip && (ip->protocol == IP_UDP) && 9571b8adde7SWilliam Kucharski (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) { 9581b8adde7SWilliam Kucharski udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)]; 9591b8adde7SWilliam Kucharski 9601b8adde7SWilliam Kucharski /* Make certain we have a reasonable packet length */ 9611b8adde7SWilliam Kucharski if (ntohs(udp->len) > (ntohs(ip->len) - iplen)) 9621b8adde7SWilliam Kucharski continue; 9631b8adde7SWilliam Kucharski 9641b8adde7SWilliam Kucharski if (udp->chksum && udpchksum(ip, udp)) { 9651b8adde7SWilliam Kucharski printf("UDP checksum error\n"); 9661b8adde7SWilliam Kucharski continue; 9671b8adde7SWilliam Kucharski } 9681b8adde7SWilliam Kucharski } 9691b8adde7SWilliam Kucharski result = reply(ival, ptr, ptype, ip, udp); 9701b8adde7SWilliam Kucharski if (result > 0) { 9711b8adde7SWilliam Kucharski return result; 9721b8adde7SWilliam Kucharski } 9731b8adde7SWilliam Kucharski 9741b8adde7SWilliam Kucharski /* If it isn't a packet the upper layer wants see if there is a default 9751b8adde7SWilliam Kucharski * action. This allows us reply to arp and igmp queryies. 9761b8adde7SWilliam Kucharski */ 9771b8adde7SWilliam Kucharski if ((ptype == ARP) && 9781b8adde7SWilliam Kucharski (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) { 9791b8adde7SWilliam Kucharski struct arprequest *arpreply; 9801b8adde7SWilliam Kucharski unsigned long tmp; 9811b8adde7SWilliam Kucharski 9821b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN]; 9831b8adde7SWilliam Kucharski memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); 9841b8adde7SWilliam Kucharski if ((arpreply->opcode == htons(ARP_REQUEST)) && 9851b8adde7SWilliam Kucharski (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) { 9861b8adde7SWilliam Kucharski arpreply->opcode = htons(ARP_REPLY); 9871b8adde7SWilliam Kucharski memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr)); 9881b8adde7SWilliam Kucharski memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN); 9891b8adde7SWilliam Kucharski memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); 9901b8adde7SWilliam Kucharski memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 9911b8adde7SWilliam Kucharski eth_transmit(arpreply->thwaddr, ARP, 9921b8adde7SWilliam Kucharski sizeof(struct arprequest), 9931b8adde7SWilliam Kucharski arpreply); 9941b8adde7SWilliam Kucharski #ifdef MDEBUG 9951b8adde7SWilliam Kucharski memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr)); 9961b8adde7SWilliam Kucharski printf("Sent ARP reply to: %@\n",tmp); 9971b8adde7SWilliam Kucharski #endif /* MDEBUG */ 9981b8adde7SWilliam Kucharski } 9991b8adde7SWilliam Kucharski } 10001b8adde7SWilliam Kucharski process_igmp(ip, now); 10011b8adde7SWilliam Kucharski } 10021b8adde7SWilliam Kucharski return(0); 10031b8adde7SWilliam Kucharski } 10041b8adde7SWilliam Kucharski 10051b8adde7SWilliam Kucharski #ifdef REQUIRE_VCI_ETHERBOOT 10061b8adde7SWilliam Kucharski /************************************************************************** 10071b8adde7SWilliam Kucharski FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers 10081b8adde7SWilliam Kucharski On entry p points to byte count of VCI options 10091b8adde7SWilliam Kucharski **************************************************************************/ 10101b8adde7SWilliam Kucharski static int find_vci_etherboot(unsigned char *p) 10111b8adde7SWilliam Kucharski { 10121b8adde7SWilliam Kucharski unsigned char *end = p + 1 + *p; 10131b8adde7SWilliam Kucharski 10141b8adde7SWilliam Kucharski for (p++; p < end; ) { 10151b8adde7SWilliam Kucharski if (*p == RFC2132_VENDOR_CLASS_ID) { 10161b8adde7SWilliam Kucharski if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0) 10171b8adde7SWilliam Kucharski return (1); 10181b8adde7SWilliam Kucharski } else if (*p == RFC1533_END) 10191b8adde7SWilliam Kucharski return (0); 10201b8adde7SWilliam Kucharski p += TAG_LEN(p) + 2; 10211b8adde7SWilliam Kucharski } 10221b8adde7SWilliam Kucharski return (0); 10231b8adde7SWilliam Kucharski } 10241b8adde7SWilliam Kucharski #endif /* REQUIRE_VCI_ETHERBOOT */ 10251b8adde7SWilliam Kucharski 10261b8adde7SWilliam Kucharski /** 10271b8adde7SWilliam Kucharski * decode_rfc1533 10281b8adde7SWilliam Kucharski * 10291b8adde7SWilliam Kucharski * Decodes RFC1533 header 10301b8adde7SWilliam Kucharski **/ 10311b8adde7SWilliam Kucharski int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof) 10321b8adde7SWilliam Kucharski { 10331b8adde7SWilliam Kucharski static unsigned char *extdata = NULL, *extend = NULL; 10341b8adde7SWilliam Kucharski unsigned char *extpath = NULL; 10351b8adde7SWilliam Kucharski unsigned char *endp; 10361b8adde7SWilliam Kucharski 10371b8adde7SWilliam Kucharski if (block == 0) { 10381b8adde7SWilliam Kucharski end_of_rfc1533 = NULL; 10391b8adde7SWilliam Kucharski if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie))) 10401b8adde7SWilliam Kucharski return(0); /* no RFC 1533 header found */ 10411b8adde7SWilliam Kucharski p += 4; 10421b8adde7SWilliam Kucharski endp = p + len; 10431b8adde7SWilliam Kucharski } else { 10441b8adde7SWilliam Kucharski if (block == 1) { 10451b8adde7SWilliam Kucharski if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie))) 10461b8adde7SWilliam Kucharski return(0); /* no RFC 1533 header found */ 10471b8adde7SWilliam Kucharski p += 4; 10481b8adde7SWilliam Kucharski len -= 4; } 10491b8adde7SWilliam Kucharski if (extend + len <= (unsigned char *) 10501b8adde7SWilliam Kucharski rfc1533_venddata + sizeof(rfc1533_venddata)) { 10511b8adde7SWilliam Kucharski memcpy(extend, p, len); 10521b8adde7SWilliam Kucharski extend += len; 10531b8adde7SWilliam Kucharski } else { 10541b8adde7SWilliam Kucharski printf("Overflow in vendor data buffer! Aborting...\n"); 10551b8adde7SWilliam Kucharski *extdata = RFC1533_END; 10561b8adde7SWilliam Kucharski return(0); 10571b8adde7SWilliam Kucharski } 10581b8adde7SWilliam Kucharski p = extdata; endp = extend; 10591b8adde7SWilliam Kucharski } 10601b8adde7SWilliam Kucharski if (!eof) 10611b8adde7SWilliam Kucharski return 1; 10621b8adde7SWilliam Kucharski while (p < endp) { 10631b8adde7SWilliam Kucharski unsigned char c = *p; 10641b8adde7SWilliam Kucharski if (c == RFC1533_PAD) { 10651b8adde7SWilliam Kucharski p++; 10661b8adde7SWilliam Kucharski continue; 10671b8adde7SWilliam Kucharski } 10681b8adde7SWilliam Kucharski else if (c == RFC1533_END) { 10691b8adde7SWilliam Kucharski end_of_rfc1533 = endp = p; 10701b8adde7SWilliam Kucharski continue; 10711b8adde7SWilliam Kucharski } 10721b8adde7SWilliam Kucharski else if (c == RFC1533_NETMASK) 10731b8adde7SWilliam Kucharski memcpy(&netmask, p+2, sizeof(in_addr)); 10741b8adde7SWilliam Kucharski else if (c == RFC1533_GATEWAY) { 10751b8adde7SWilliam Kucharski /* This is a little simplistic, but it will 10761b8adde7SWilliam Kucharski usually be sufficient. 10771b8adde7SWilliam Kucharski Take only the first entry */ 10781b8adde7SWilliam Kucharski if (TAG_LEN(p) >= sizeof(in_addr)) 10791b8adde7SWilliam Kucharski memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr)); 10801b8adde7SWilliam Kucharski } 10811b8adde7SWilliam Kucharski else if (c == RFC1533_EXTENSIONPATH) 10821b8adde7SWilliam Kucharski extpath = p; 10831b8adde7SWilliam Kucharski else if (c == RFC2132_MSG_TYPE) 10841b8adde7SWilliam Kucharski dhcp_reply=*(p+2); 10851b8adde7SWilliam Kucharski else if (c == RFC2132_SRV_ID) 10861b8adde7SWilliam Kucharski memcpy(&dhcp_server, p+2, sizeof(in_addr)); 10871b8adde7SWilliam Kucharski else if (c == RFC1533_HOSTNAME) { 10881b8adde7SWilliam Kucharski hostname = p + 2; 10891b8adde7SWilliam Kucharski hostnamelen = *(p + 1); 10901b8adde7SWilliam Kucharski } 10911b8adde7SWilliam Kucharski else if (c == RFC1533_VENDOR_CONFIGFILE){ 10921b8adde7SWilliam Kucharski int l = TAG_LEN (p); 10931b8adde7SWilliam Kucharski 10941b8adde7SWilliam Kucharski /* Eliminate the trailing NULs according to RFC 2132. */ 10951b8adde7SWilliam Kucharski while (*(p + 2 + l - 1) == '\000' && l > 0) 10961b8adde7SWilliam Kucharski l--; 10971b8adde7SWilliam Kucharski 10981b8adde7SWilliam Kucharski /* XXX: Should check if LEN is less than the maximum length 10991b8adde7SWilliam Kucharski of CONFIG_FILE. This kind of robustness will be a goal 11001b8adde7SWilliam Kucharski in GRUB 1.0. */ 11011b8adde7SWilliam Kucharski memcpy (config_file, p + 2, l); 11021b8adde7SWilliam Kucharski 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; 11061b8adde7SWilliam Kucharski } 11071b8adde7SWilliam Kucharski else { 11081b8adde7SWilliam Kucharski ; 11091b8adde7SWilliam Kucharski } 11101b8adde7SWilliam Kucharski p += TAG_LEN(p) + 2; 11111b8adde7SWilliam Kucharski } 11121b8adde7SWilliam Kucharski extdata = extend = endp; 11131b8adde7SWilliam Kucharski if (block <= 0 && extpath != NULL) { 11141b8adde7SWilliam Kucharski char fname[64]; 11151b8adde7SWilliam Kucharski if (TAG_LEN(extpath) >= sizeof(fname)){ 11161b8adde7SWilliam Kucharski printf("Overflow in vendor data buffer! Aborting...\n"); 11171b8adde7SWilliam Kucharski *extdata = RFC1533_END; 11181b8adde7SWilliam Kucharski return(0); 11191b8adde7SWilliam Kucharski } 11201b8adde7SWilliam Kucharski memcpy(fname, extpath+2, TAG_LEN(extpath)); 11211b8adde7SWilliam Kucharski fname[(int)TAG_LEN(extpath)] = '\0'; 11221b8adde7SWilliam Kucharski printf("Loading BOOTP-extension file: %s\n",fname); 11231b8adde7SWilliam Kucharski tftp_file_read(fname, decode_rfc1533); 11241b8adde7SWilliam Kucharski } 11251b8adde7SWilliam Kucharski return 1; /* proceed with next block */ 11261b8adde7SWilliam Kucharski } 11271b8adde7SWilliam Kucharski 11281b8adde7SWilliam Kucharski 11291b8adde7SWilliam Kucharski /* FIXME double check TWO_SECOND_DIVISOR */ 11301b8adde7SWilliam Kucharski #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC) 11311b8adde7SWilliam Kucharski /************************************************************************** 11321b8adde7SWilliam Kucharski RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec) 11331b8adde7SWilliam Kucharski **************************************************************************/ 11341b8adde7SWilliam Kucharski long rfc2131_sleep_interval(long base, int exp) 11351b8adde7SWilliam Kucharski { 11361b8adde7SWilliam Kucharski unsigned long tmo; 11371b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT 11381b8adde7SWilliam Kucharski if (exp > BACKOFF_LIMIT) 11391b8adde7SWilliam Kucharski exp = BACKOFF_LIMIT; 11401b8adde7SWilliam Kucharski #endif 11411b8adde7SWilliam Kucharski tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR)); 11421b8adde7SWilliam Kucharski return tmo; 11431b8adde7SWilliam Kucharski } 11441b8adde7SWilliam Kucharski 11451b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2 11461b8adde7SWilliam Kucharski /************************************************************************** 11471b8adde7SWilliam Kucharski RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp) 11481b8adde7SWilliam Kucharski **************************************************************************/ 11491b8adde7SWilliam Kucharski long rfc1112_sleep_interval(long base, int exp) 11501b8adde7SWilliam Kucharski { 11511b8adde7SWilliam Kucharski unsigned long divisor, tmo; 11521b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT 11531b8adde7SWilliam Kucharski if (exp > BACKOFF_LIMIT) 11541b8adde7SWilliam Kucharski exp = BACKOFF_LIMIT; 11551b8adde7SWilliam Kucharski #endif 11561b8adde7SWilliam Kucharski divisor = RAND_MAX/(base << exp); 11571b8adde7SWilliam Kucharski tmo = random()/divisor; 11581b8adde7SWilliam Kucharski return tmo; 11591b8adde7SWilliam Kucharski } 11601b8adde7SWilliam Kucharski #endif /* MULTICAST_LEVEL_2 */ 11611b8adde7SWilliam Kucharski /* ifconfig - configure network interface. */ 11621b8adde7SWilliam Kucharski int 11631b8adde7SWilliam Kucharski ifconfig (char *ip, char *sm, char *gw, char *svr) 11641b8adde7SWilliam Kucharski { 11651b8adde7SWilliam Kucharski in_addr tmp; 11661b8adde7SWilliam Kucharski 11671b8adde7SWilliam Kucharski if (sm) 11681b8adde7SWilliam Kucharski { 11691b8adde7SWilliam Kucharski if (! inet_aton (sm, &tmp)) 11701b8adde7SWilliam Kucharski return 0; 11711b8adde7SWilliam Kucharski 11721b8adde7SWilliam Kucharski netmask = tmp.s_addr; 11731b8adde7SWilliam Kucharski } 11741b8adde7SWilliam Kucharski 11751b8adde7SWilliam Kucharski if (ip) 11761b8adde7SWilliam Kucharski { 11771b8adde7SWilliam Kucharski if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr)) 11781b8adde7SWilliam Kucharski return 0; 11791b8adde7SWilliam Kucharski 11801b8adde7SWilliam Kucharski if (! netmask && ! sm) 11811b8adde7SWilliam Kucharski netmask = default_netmask (); 11821b8adde7SWilliam Kucharski } 11831b8adde7SWilliam Kucharski 11841b8adde7SWilliam Kucharski if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr)) 11851b8adde7SWilliam Kucharski return 0; 11861b8adde7SWilliam Kucharski 11871b8adde7SWilliam Kucharski /* Clear out the ARP entry. */ 11881b8adde7SWilliam Kucharski grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN); 11891b8adde7SWilliam Kucharski 11901b8adde7SWilliam Kucharski if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr)) 11911b8adde7SWilliam Kucharski return 0; 11921b8adde7SWilliam Kucharski 11931b8adde7SWilliam Kucharski /* Likewise. */ 11941b8adde7SWilliam Kucharski grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN); 11951b8adde7SWilliam Kucharski 11961b8adde7SWilliam Kucharski if (ip || sm) 11971b8adde7SWilliam Kucharski { 11981b8adde7SWilliam Kucharski if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr) 11991b8adde7SWilliam Kucharski || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr) 12001b8adde7SWilliam Kucharski || ! netmask) 12011b8adde7SWilliam Kucharski network_ready = 0; 12021b8adde7SWilliam Kucharski else 12031b8adde7SWilliam Kucharski network_ready = 1; 12041b8adde7SWilliam Kucharski } 12051b8adde7SWilliam Kucharski 12061b8adde7SWilliam Kucharski update_network_configuration(); 12071b8adde7SWilliam Kucharski return 1; 12081b8adde7SWilliam Kucharski } 12091b8adde7SWilliam Kucharski 12101b8adde7SWilliam Kucharski /* 12111b8adde7SWilliam Kucharski * print_network_configuration 12121b8adde7SWilliam Kucharski * 12131b8adde7SWilliam Kucharski * Output the network configuration. It may broke the graphic console now.:-( 12141b8adde7SWilliam Kucharski */ 12151b8adde7SWilliam Kucharski void print_network_configuration (void) 12161b8adde7SWilliam Kucharski { 12171b8adde7SWilliam Kucharski EnterFunction("print_network_configuration"); 12181b8adde7SWilliam Kucharski if (! network_ready) 12191b8adde7SWilliam Kucharski grub_printf ("Network interface not initialized yet.\n"); 12201b8adde7SWilliam Kucharski 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 12261b8adde7SWilliam Kucharski etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr); 12271b8adde7SWilliam Kucharski etherboot_printf ("Netmask: %@\n", netmask); 12281b8adde7SWilliam Kucharski 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 } 12671b8adde7SWilliam Kucharski } 12681b8adde7SWilliam Kucharski LeaveFunction("print_network_configuration"); 12691b8adde7SWilliam Kucharski } 12701b8adde7SWilliam Kucharski 12711b8adde7SWilliam Kucharski /* 12721b8adde7SWilliam Kucharski * update_network_configuration 12731b8adde7SWilliam Kucharski * 12741b8adde7SWilliam Kucharski * Update network configuration for diskless clients (Solaris only) 12751b8adde7SWilliam Kucharski */ 12761b8adde7SWilliam Kucharski static void update_network_configuration (void) 12771b8adde7SWilliam Kucharski { 12781b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT 12791b8adde7SWilliam Kucharski struct sol_netinfo { 12801b8adde7SWilliam Kucharski uint8_t sn_infotype; 12811b8adde7SWilliam Kucharski uint8_t sn_mactype; 12821b8adde7SWilliam Kucharski uint8_t sn_maclen; 12831b8adde7SWilliam Kucharski uint8_t sn_padding; 12841b8adde7SWilliam Kucharski unsigned long sn_ciaddr; 12851b8adde7SWilliam Kucharski unsigned long sn_siaddr; 12861b8adde7SWilliam Kucharski unsigned long sn_giaddr; 12871b8adde7SWilliam Kucharski unsigned long sn_netmask; 12881b8adde7SWilliam Kucharski uint8_t sn_macaddr[1]; 12891b8adde7SWilliam Kucharski } *sip; 12901b8adde7SWilliam Kucharski 12911b8adde7SWilliam Kucharski if (! network_ready) 12921b8adde7SWilliam Kucharski return; 12931b8adde7SWilliam Kucharski 12941b8adde7SWilliam Kucharski sip = (struct sol_netinfo *)dhcpack_buf; 12951b8adde7SWilliam Kucharski sip->sn_infotype = 0xf0; /* something not BOOTP_REPLY */ 12961b8adde7SWilliam Kucharski sip->sn_mactype = 4; /* DL_ETHER */ 12971b8adde7SWilliam Kucharski sip->sn_maclen = ETH_ALEN; 12981b8adde7SWilliam Kucharski sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr; 12991b8adde7SWilliam Kucharski sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr; 13001b8adde7SWilliam Kucharski sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr; 13011b8adde7SWilliam Kucharski sip->sn_netmask = netmask; 13021b8adde7SWilliam Kucharski memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN); 13031b8adde7SWilliam Kucharski dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1; 13041b8adde7SWilliam Kucharski #endif /* SOLARIS_NETBOOT */ 13051b8adde7SWilliam Kucharski } 13061b8adde7SWilliam Kucharski 13071b8adde7SWilliam Kucharski /** 13081b8adde7SWilliam Kucharski * cleanup_net 13091b8adde7SWilliam Kucharski * 13101b8adde7SWilliam Kucharski * Mark network unusable, and disable NICs 13111b8adde7SWilliam Kucharski */ 13121b8adde7SWilliam Kucharski void cleanup_net (void) 13131b8adde7SWilliam Kucharski { 13141b8adde7SWilliam Kucharski if (network_ready){ 13151b8adde7SWilliam Kucharski /* Stop receiving packets. */ 13161b8adde7SWilliam Kucharski if (use_bios_pxe) 13171b8adde7SWilliam Kucharski undi_pxe_disable(); 13181b8adde7SWilliam Kucharski else 13191b8adde7SWilliam Kucharski eth_disable (); 13201b8adde7SWilliam Kucharski network_ready = 0; 13211b8adde7SWilliam Kucharski } 13221b8adde7SWilliam Kucharski } 13231b8adde7SWilliam Kucharski 13241b8adde7SWilliam Kucharski /******************************************************************* 13251b8adde7SWilliam Kucharski * dhcp implementation reusing the BIOS pxe stack 13261b8adde7SWilliam Kucharski */ 13271b8adde7SWilliam Kucharski static void 13281b8adde7SWilliam Kucharski dhcp_copy(struct dhcp_t *dhcpreply) 13291b8adde7SWilliam Kucharski { 13301b8adde7SWilliam Kucharski unsigned long time; 13311b8adde7SWilliam Kucharski int ret, len = DHCP_OPT_LEN; 13321b8adde7SWilliam Kucharski 13331b8adde7SWilliam Kucharski /* fill in netinfo */ 13341b8adde7SWilliam Kucharski dhcpack_length = sizeof (struct dhcp_t); 13351b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length); 13361b8adde7SWilliam Kucharski 13371b8adde7SWilliam Kucharski memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN); 13381b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr; 13391b8adde7SWilliam Kucharski dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr; 13401b8adde7SWilliam Kucharski netmask = default_netmask(); 13411b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr; 13421b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */ 13431b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr; 13441b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */ 13452506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file; 13461b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len); 13471b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1); 13481b8adde7SWilliam Kucharski } 13491b8adde7SWilliam Kucharski 13501b8adde7SWilliam Kucharski int dhcp_undi(void) 13511b8adde7SWilliam Kucharski { 13521b8adde7SWilliam Kucharski struct dhcp_t *dhcpreply; 13531b8adde7SWilliam Kucharski 13541b8adde7SWilliam Kucharski if (!undi_bios_pxe((void **)&dhcpreply)) 13551b8adde7SWilliam Kucharski return 0; 13561b8adde7SWilliam Kucharski 13571b8adde7SWilliam Kucharski dhcp_copy(dhcpreply); 13581b8adde7SWilliam Kucharski network_ready = 1; 13591b8adde7SWilliam Kucharski use_bios_pxe = 1; 13601b8adde7SWilliam Kucharski return (1); 13611b8adde7SWilliam Kucharski } 1362