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