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