1/* $NetBSD: ndbootd.c,v 1.13 2021/10/30 10:44:25 nia Exp $ */ 2 3/* ndbootd.c - the Sun Network Disk (nd) daemon: */ 4 5/* 6 * Copyright (c) 2001 Matthew Fredette. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Matthew Fredette. 19 * 4. The name of Matthew Fredette may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28/* <<Header: /data/home/fredette/project/THE-WEIGHT-CVS/ndbootd/ndbootd.c,v 1.9 2001/06/13 21:19:11 fredette Exp >> */ 29 30/* 31 * <<Log: ndbootd.c,v >> 32 * Revision 1.9 2001/06/13 21:19:11 fredette 33 * (main): Don't assume that a successful, but short, read 34 * leaves a zero in errno. Instead, just check for the short 35 * read by looking at the byte count that read returned. 36 * 37 * Revision 1.8 2001/05/23 02:35:36 fredette 38 * Changed many debugging printfs to compile quietly on the 39 * alpha. Patch from Andrew Brown <atatat@atatdot.net>. 40 * 41 * Revision 1.7 2001/05/22 13:13:20 fredette 42 * Ran indent(1) with NetBSD's KNF-approximating profile. 43 * 44 * Revision 1.6 2001/05/22 12:53:40 fredette 45 * [HAVE_STRICT_ALIGNMENT]: Added code to copy packet headers 46 * between the buffer and local variables, to satisfy 47 * alignment constraints. 48 * 49 * Revision 1.5 2001/05/15 14:43:24 fredette 50 * Now have prototypes for the allocation functions. 51 * (main): Now handle boot blocks that aren't an integral 52 * multiple of the block size. 53 * 54 * Revision 1.4 2001/05/09 20:53:38 fredette 55 * (main): Now insert a small delay before sending each packet. 56 * Sending packets too quickly apparently overwhelms clients. 57 * Added new single-letter versions of all options that didn't 58 * already have them. Expanded some debug messages, and fixed 59 * others to display Ethernet addresses correctly. 60 * 61 * Revision 1.3 2001/01/31 17:35:50 fredette 62 * (main): Fixed various printf argument lists. 63 * 64 * Revision 1.2 2001/01/30 15:35:38 fredette 65 * Now, ndbootd assembles disk images for clients on-the-fly. 66 * Defined many new macros related to this. 67 * (main): Added support for the --boot2 option. Turned the 68 * original disk-image filename into the filename of the 69 * first-stage boot program. Now do better multiple-client 70 * support, especially when it comes to checking if a client 71 * is really ours. Now assemble client-specific disk images 72 * on-the-fly, potentially serving each client a different 73 * second-stage boot. 74 * 75 * Revision 1.1 2001/01/29 15:12:13 fredette 76 * Added. 77 * 78 */ 79 80#include <sys/cdefs.h> 81#if 0 82static const char _ndbootd_c_rcsid[] = "<<Id: ndbootd.c,v 1.9 2001/06/13 21:19:11 fredette Exp >>"; 83#else 84__RCSID("$NetBSD: ndbootd.c,v 1.13 2021/10/30 10:44:25 nia Exp $"); 85#endif 86 87/* includes: */ 88#include "ndbootd.h" 89 90/* the number of blocks that Sun-2 PROMs load, starting from block 91 zero: */ 92#define NDBOOTD_PROM_BLOCK_COUNT (16) 93 94/* the first block number of the (dummy) Sun disklabel: */ 95#define NDBOOTD_SUNDK_BLOCK_FIRST (0) 96 97/* the number of blocks in the (dummy) Sun disklabel: */ 98#define NDBOOTD_SUNDK_BLOCK_COUNT (1) 99 100/* the first block number of the first-stage boot program. 101 the first-stage boot program begins right after the (dummy) 102 Sun disklabel: */ 103#define NDBOOTD_BOOT1_BLOCK_FIRST (NDBOOTD_SUNDK_BLOCK_FIRST + NDBOOTD_SUNDK_BLOCK_COUNT) 104 105/* the number of blocks in the first-stage boot program: */ 106#define NDBOOTD_BOOT1_BLOCK_COUNT (NDBOOTD_PROM_BLOCK_COUNT - NDBOOTD_BOOT1_BLOCK_FIRST) 107 108/* the first block number of any second-stage boot program. 109 any second-stage boot program begins right after the first-stage boot program: */ 110#define NDBOOTD_BOOT2_BLOCK_FIRST (NDBOOTD_BOOT1_BLOCK_FIRST + NDBOOTD_BOOT1_BLOCK_COUNT) 111 112/* this macro returns the number of bytes available in an object starting at a given offset: */ 113#define NDBOOTD_BYTES_AVAIL(block_number, byte_offset, obj_block_first, obj_block_count) \ 114 ((((ssize_t) (obj_block_count) - (ssize_t) ((block_number) - (obj_block_first))) * NDBOOT_BSIZE) - (ssize_t) (byte_offset)) 115 116/* this determines how long we can cache file descriptors and RARP 117 information: */ 118#define NDBOOTD_CLIENT_TTL_SECONDS (10) 119 120/* this determines how long we wait before sending a packet: */ 121#define NDBOOTD_SEND_DELAY_NSECONDS (10000000) 122 123/* this macro helps us size a struct ifreq: */ 124#ifdef HAVE_SOCKADDR_SA_LEN 125#define SIZEOF_IFREQ(ifr) (sizeof((ifr)->ifr_name) + (ifr)->ifr_addr.sa_len) 126#else /* !HAVE_SOCKADDR_SA_LEN */ 127#define SIZEOF_IFREQ(ifr) (sizeof((ifr)->ifr_name) + sizeof(struct sockaddr)) 128#endif /* !HAVE_SOCKADDR_SA_LEN */ 129 130/* prototypes: */ 131void *ndbootd_malloc _NDBOOTD_P((size_t, size_t)); 132void *ndbootd_calloc _NDBOOTD_P((size_t, size_t)); 133void *ndbootd_memdup _NDBOOTD_P((void *, size_t)); 134 135/* globals: */ 136const char *_ndbootd_argv0; 137#ifdef _NDBOOTD_DO_DEBUG 138int _ndbootd_debug; 139#endif /* _NDBOOTD_DO_DEBUG */ 140 141/* allocators: */ 142void * 143ndbootd_malloc(size_t number, size_t size) 144{ 145 void *buffer = NULL; 146 if (reallocarr(&buffer, number, size) != 0) { 147 abort(); 148 } 149 return (buffer); 150} 151void * 152ndbootd_calloc(size_t number, size_t size) 153{ 154 void *buffer; 155 if ((buffer = calloc(number, size)) == NULL) { 156 abort(); 157 } 158 return (buffer); 159} 160void * 161ndbootd_memdup(void *buffer0, size_t size) 162{ 163 void *buffer1; 164 buffer1 = ndbootd_malloc(1, size); 165 memcpy(buffer1, buffer0, size); 166 return (buffer1); 167} 168#define ndbootd_free free 169#define ndbootd_new(t, c) ((t *) ndbootd_malloc(c, sizeof(t))) 170#define ndbootd_new0(t, c) ((t *) ndbootd_calloc(c, sizeof(t))) 171#define ndbootd_dup(t, b, c) ((t *) ndbootd_memdup(b, c)) 172 173/* this calculates an IP packet header checksum: */ 174static void 175_ndbootd_ip_cksum(struct ip * ip_packet) 176{ 177 u_int16_t *_word, word; 178 u_int32_t checksum; 179 unsigned int byte_count, bytes_left; 180 181 /* we assume that the IP packet header is 16-bit aligned: */ 182 assert((((unsigned long) ip_packet) % sizeof(word)) == 0); 183 184 /* initialize for the checksum: */ 185 checksum = 0; 186 187 /* sum up the packet contents: */ 188 _word = (u_int16_t *) ip_packet; 189 byte_count = ip_packet->ip_hl << 2; 190 for (bytes_left = byte_count; bytes_left >= sizeof(*_word);) { 191 checksum += *(_word++); 192 bytes_left -= sizeof(*_word); 193 } 194 word = 0; 195 memcpy(&word, _word, bytes_left); 196 checksum += word; 197 198 /* finish the checksum: */ 199 checksum = (checksum >> 16) + (checksum & 0xffff); 200 checksum += (checksum >> 16); 201 ip_packet->ip_sum = (~checksum); 202} 203/* this finds a network interface: */ 204static struct ndbootd_interface * 205_ndbootd_find_interface(const char *ifr_name_user) 206{ 207 struct ifreq ifr; 208#ifdef HAVE_AF_LINK 209 struct sockaddr_dl *sadl; 210#endif /* HAVE_AF_LINK */ 211 struct ndbootd_interface *interface; 212 struct ifaddrs *ifap, *ifa, *ifa_user; 213 214 /* read the interface list: */ 215 if (getifaddrs(&ifap) != 0) { 216 return (NULL); 217 } 218 219 /* walk the interface list: */ 220 ifa_user = NULL; 221 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 222 /* ignore this interface if it doesn't do IP: */ 223 if (ifa->ifa_addr->sa_family != AF_INET) { 224 continue; 225 } 226 227 /* ignore this interface if it isn't up and running: */ 228 if ((ifa->ifa_flags & (IFF_UP | IFF_RUNNING)) != 229 (IFF_UP | IFF_RUNNING)) { 230 continue; 231 } 232 /* if we don't have an interface yet, take this one depending 233 * on whether the user asked for an interface by name or not. 234 * if he did, and this is it, take this one. if he didn't, 235 * and this isn't a loopback interface, take this one: */ 236 if (ifa_user == NULL 237 && (ifr_name_user != NULL 238 ? !strcmp(ifa->ifa_name, ifr_name_user) 239 : !(ifa->ifa_flags & IFF_LOOPBACK))) { 240 ifa_user = ifa; 241 } 242 } 243 244 /* if we don't have an interface to return: */ 245 if (ifa_user == NULL) { 246 freeifaddrs(ifap); 247 errno = ENOENT; 248 return (NULL); 249 } 250 /* start the interface description: */ 251 interface = ndbootd_new0(struct ndbootd_interface, 1); 252 253#ifdef HAVE_AF_LINK 254 255 /* we must be able to find an AF_LINK ifreq that gives us the 256 * interface's Ethernet address. */ 257 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 258 if (ifa->ifa_addr->sa_family != AF_LINK) { 259 continue; 260 } 261 /* if this is the hardware address we want */ 262 if (!strcmp(ifa->ifa_name, ifa_user->ifa_name)) { 263 break; 264 } 265 } 266 if (ifa == NULL) { 267 freeifaddrs(ifap); 268 free(interface); 269 errno = ENOENT; 270 return (NULL); 271 } 272 /* copy out the Ethernet address: */ 273 sadl = (struct sockaddr_dl *)ifa->ifa_addr; 274 memcpy(interface->ndbootd_interface_ether, LLADDR(sadl), sadl->sdl_alen); 275 276#else /* !HAVE_AF_LINK */ 277#error "must have AF_LINK for now" 278#endif /* !HAVE_AF_LINK */ 279 280 /* finish this interface and return it: */ 281 strlcpy(ifr.ifr_name, ifa_user->ifa_name, sizeof(ifr.ifr_name)); 282 assert(sizeof(ifr.ifr_addr) >= ifa_user->ifa_addr->sa_len); 283 memcpy(&ifr.ifr_addr, ifa_user->ifa_addr, ifa_user->ifa_addr->sa_len); 284 interface->ndbootd_interface_ifreq = (struct ifreq *) ndbootd_memdup(&ifr, SIZEOF_IFREQ(&ifr)); 285 interface->ndbootd_interface_fd = -1; 286 freeifaddrs(ifap); 287 return (interface); 288} 289 290int 291main(int argc, char *argv[]) 292{ 293 int argv_i; 294 int show_usage; 295 const char *interface_name; 296 const char *boot1_file_name; 297 const char *boot2_x_name; 298 char *boot2_file_name; 299 int boot2_x_name_is_dir; 300 time_t last_open_time; 301 int boot1_fd; 302 int boot2_fd; 303 time_t last_rarp_time; 304 char last_client_ether[ETHER_ADDR_LEN]; 305 struct in_addr last_client_ip; 306 struct stat stat_buffer; 307 int32_t boot1_block_count; 308 int32_t boot2_block_count; 309 size_t boot1_byte_count; 310 size_t boot2_byte_count; 311 ssize_t byte_count_read; 312 struct ndbootd_interface *interface; 313 char pid_buffer[(sizeof(pid_t) * 3) + 2]; 314 unsigned char packet_buffer[sizeof(struct ether_header) + IP_MAXPACKET]; 315 unsigned char disk_buffer[NDBOOT_MAX_BYTE_COUNT]; 316 char hostname_buffer[MAXHOSTNAMELEN + 1]; 317 struct hostent *the_hostent; 318 ssize_t packet_length; 319 time_t now; 320 struct ether_header *ether_packet; 321 struct ip *ip_packet; 322 struct ndboot_packet *nd_packet; 323#ifdef HAVE_STRICT_ALIGNMENT 324 struct ether_header ether_packet_buffer; 325 unsigned char ip_packet_buffer[IP_MAXPACKET]; 326 struct ndboot_packet nd_packet_buffer; 327#endif /* HAVE_STRICT_ALIGNMENT */ 328 int nd_window_size; 329 int nd_window_filled; 330 off_t file_offset; 331 size_t disk_buffer_offset; 332 size_t block_number; 333 size_t byte_offset; 334 ssize_t byte_count; 335 ssize_t byte_count_wanted; 336 struct timespec send_delay; 337 int fd; 338 339 /* check our command line: */ 340 if ((_ndbootd_argv0 = strrchr(argv[0], '/')) == NULL) 341 _ndbootd_argv0 = argv[0]; 342 else 343 _ndbootd_argv0++; 344 show_usage = FALSE; 345#ifdef _NDBOOTD_DO_DEBUG 346 _ndbootd_debug = FALSE; 347#endif /* _NDBOOTD_DO_DEBUG */ 348 boot1_file_name = NULL; 349 boot2_x_name = NULL; 350 interface_name = NULL; 351 nd_window_size = NDBOOT_WINDOW_SIZE_DEFAULT; 352 for (argv_i = 1; argv_i < argc; argv_i++) { 353 if (argv[argv_i][0] != '-' 354 || argv[argv_i][1] == '\0') { 355 break; 356 } else if (!strcmp(argv[argv_i], "-s") 357 || !strcmp(argv[argv_i], "--boot2")) { 358 if (++argv_i < argc) { 359 boot2_x_name = argv[argv_i]; 360 } else { 361 show_usage = TRUE; 362 break; 363 } 364 } else if (!strcmp(argv[argv_i], "-i") 365 || !strcmp(argv[argv_i], "--interface")) { 366 if (++argv_i < argc) { 367 interface_name = argv[argv_i]; 368 } else { 369 show_usage = TRUE; 370 break; 371 } 372 } else if (!strcmp(argv[argv_i], "-w") 373 || !strcmp(argv[argv_i], "--window-size")) { 374 if (++argv_i == argc || (nd_window_size = atoi(argv[argv_i])) <= 0) { 375 show_usage = TRUE; 376 break; 377 } 378 } 379#ifdef _NDBOOTD_DO_DEBUG 380 else if (!strcmp(argv[argv_i], "-d") 381 || !strcmp(argv[argv_i], "--debug")) { 382 _ndbootd_debug = TRUE; 383 } 384#endif /* _NDBOOTD_DO_DEBUG */ 385 else { 386 if (strcmp(argv[argv_i], "-h") 387 && strcmp(argv[argv_i], "--help")) { 388 fprintf(stderr, "%s error: unknown switch '%s'\n", 389 _ndbootd_argv0, argv[argv_i]); 390 } 391 show_usage = TRUE; 392 break; 393 } 394 } 395 if (argv_i + 1 == argc) { 396 boot1_file_name = argv[argv_i]; 397 } else { 398 show_usage = TRUE; 399 } 400 401 if (show_usage) { 402 fprintf(stderr, "\ 403usage: %s [OPTIONS] BOOT1-BIN\n\ 404where OPTIONS are:\n\ 405 -s, --boot2 { BOOT2-BIN | DIR }\n\ 406 find a second-stage boot program in the file\n\ 407 BOOT2-BIN or in the directory DIR\n\ 408 -i, --interface NAME use interface NAME\n\ 409 -w, --window-size COUNT \n\ 410 send at most COUNT unacknowledged packets [default=%d]\n", 411 _ndbootd_argv0, 412 NDBOOT_WINDOW_SIZE_DEFAULT); 413#ifdef _NDBOOTD_DO_DEBUG 414 fprintf(stderr, "\ 415 -d, --debug set debug mode\n"); 416#endif /* _NDBOOTD_DO_DEBUG */ 417 exit(1); 418 } 419 /* if we have been given a name for the second-stage boot, see if it's 420 * a filename or a directory: */ 421 boot2_x_name_is_dir = FALSE; 422 if (boot2_x_name != NULL) { 423 if (stat(boot2_x_name, &stat_buffer) < 0) { 424 fprintf(stderr, "%s error: could not stat %s: %s\n", 425 _ndbootd_argv0, boot2_x_name, strerror(errno)); 426 exit(1); 427 } 428 if (S_ISDIR(stat_buffer.st_mode)) { 429 boot2_x_name_is_dir = TRUE; 430 } else if (!S_ISREG(stat_buffer.st_mode)) { 431 fprintf(stderr, "%s error: %s is neither a regular file nor a directory\n", 432 _ndbootd_argv0, boot2_x_name); 433 exit(1); 434 } 435 } 436 /* find the interface we will use: */ 437 if ((interface = _ndbootd_find_interface(interface_name)) == NULL) { 438 fprintf(stderr, "%s error: could not find the interface to use: %s\n", 439 _ndbootd_argv0, strerror(errno)); 440 exit(1); 441 } 442 _NDBOOTD_DEBUG((fp, "opening interface %s", interface->ndbootd_interface_ifreq->ifr_name)); 443 444 /* open the network interface: */ 445 if (ndbootd_raw_open(interface)) { 446 fprintf(stderr, "%s error: could not open the %s interface: %s\n", 447 _ndbootd_argv0, interface->ndbootd_interface_ifreq->ifr_name, strerror(errno)); 448 exit(1); 449 } 450 _NDBOOTD_DEBUG((fp, "opened interface %s (ip %s ether %02x:%02x:%02x:%02x:%02x:%02x)", 451 interface->ndbootd_interface_ifreq->ifr_name, 452 inet_ntoa(((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr), 453 ((unsigned char *) interface->ndbootd_interface_ether)[0], 454 ((unsigned char *) interface->ndbootd_interface_ether)[1], 455 ((unsigned char *) interface->ndbootd_interface_ether)[2], 456 ((unsigned char *) interface->ndbootd_interface_ether)[3], 457 ((unsigned char *) interface->ndbootd_interface_ether)[4], 458 ((unsigned char *) interface->ndbootd_interface_ether)[5])); 459 460 /* become a daemon: */ 461#ifdef _NDBOOTD_DO_DEBUG 462 if (!_ndbootd_debug) 463#endif /* _NDBOOTD_DO_DEBUG */ 464 { 465 466 /* fork and exit: */ 467 switch (fork()) { 468 case 0: 469 break; 470 case -1: 471 fprintf(stderr, "%s error: could not fork: %s\n", 472 _ndbootd_argv0, strerror(errno)); 473 exit(1); 474 default: 475 exit(0); 476 } 477 478 /* close all file descriptors: */ 479#ifdef HAVE_GETDTABLESIZE 480 fd = getdtablesize(); 481#else /* !HAVE_GETDTABLESIZE */ 482 fd = -1; 483#endif /* !HAVE_GETDTABLESIZE */ 484 for (; fd >= 0; fd--) { 485 if (fd != interface->ndbootd_interface_fd) { 486 close(fd); 487 } 488 } 489 490#ifdef HAVE_SETSID 491 /* become our own session: */ 492 setsid(); 493#endif /* HAVE_SETSID */ 494 } 495 /* write the pid file: */ 496 if ((fd = open(NDBOOTD_PID_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644)) >= 0) { 497 sprintf(pid_buffer, "%u\n", getpid()); 498 write(fd, pid_buffer, strlen(pid_buffer)); 499 close(fd); 500 } 501#ifdef HAVE_STRICT_ALIGNMENT 502 /* we will be dealing with all packet headers in separate buffers, to 503 * make sure everything is correctly aligned: */ 504 ether_packet = ðer_packet_buffer; 505 ip_packet = (struct ip *) & ip_packet_buffer[0]; 506 nd_packet = &nd_packet_buffer; 507#else /* !HAVE_STRICT_ALIGNMENT */ 508 /* we will always find the Ethernet header and the IP packet at the 509 * front of the buffer: */ 510 ether_packet = (struct ether_header *) packet_buffer; 511 ip_packet = (struct ip *) (ether_packet + 1); 512#endif /* !HAVE_STRICT_ALIGNMENT */ 513 514 /* initialize our state: */ 515 last_rarp_time = 0; 516 last_open_time = 0; 517 boot1_fd = -1; 518 boot2_file_name = NULL; 519 boot2_fd = -1; 520 boot1_block_count = 0; /* XXXGCC -Wuninitialized */ 521 boot2_block_count = 0; /* XXXGCC -Wuninitialized */ 522 boot1_byte_count = 0; /* XXXGCC -Wuninitialized */ 523 boot2_byte_count = 0; /* XXXGCC -Wuninitialized */ 524 525 /* loop processing packets: */ 526 for (;;) { 527 528 /* receive another packet: */ 529 packet_length = ndbootd_raw_read(interface, packet_buffer, sizeof(packet_buffer)); 530 if (packet_length < 0) { 531 _NDBOOTD_DEBUG((fp, "failed to receive packet: %s", strerror(errno))); 532 exit(1); 533 continue; 534 } 535 now = time(NULL); 536 537 /* check the Ethernet and IP parts of the packet: */ 538 if (packet_length 539 < (sizeof(struct ether_header) 540 + sizeof(struct ip) 541 + sizeof(struct ndboot_packet))) { 542 _NDBOOTD_DEBUG((fp, "ignoring a too-short packet of length %ld", (long) packet_length)); 543 continue; 544 } 545#ifdef HAVE_STRICT_ALIGNMENT 546 memcpy(ether_packet, packet_buffer, sizeof(struct ether_header)); 547 memcpy(ip_packet, packet_buffer + sizeof(struct ether_header), 548 (((struct ip *) (packet_buffer + sizeof(struct ether_header)))->ip_hl << 2)); 549#endif /* !HAVE_STRICT_ALIGNMENT */ 550 if (ether_packet->ether_type != htons(ETHERTYPE_IP) 551 || ip_packet->ip_p != IPPROTO_ND) { 552 _NDBOOTD_DEBUG((fp, "ignoring a packet with the wrong Ethernet or IP protocol")); 553 continue; 554 } 555 _ndbootd_ip_cksum(ip_packet); 556 if (ip_packet->ip_sum != 0) { 557 _NDBOOTD_DEBUG((fp, "ignoring a packet with a bad IP checksum")); 558 continue; 559 } 560 if (packet_length 561 != (sizeof(struct ether_header) 562 + (ip_packet->ip_hl << 2) 563 + sizeof(struct ndboot_packet))) { 564 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad total length %ld", (long) packet_length)); 565 continue; 566 } 567 /* if we need to, refresh our RARP cache: */ 568 if ((last_rarp_time + NDBOOTD_CLIENT_TTL_SECONDS) < now 569 || memcmp(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN)) { 570 571 /* turn the Ethernet address into a hostname: */ 572 if (ether_ntohost(hostname_buffer, (struct ether_addr *) ether_packet->ether_shost)) { 573 _NDBOOTD_DEBUG((fp, "could not resolve %02x:%02x:%02x:%02x:%02x:%02x into a hostname: %s", 574 ((unsigned char *) ether_packet->ether_shost)[0], 575 ((unsigned char *) ether_packet->ether_shost)[1], 576 ((unsigned char *) ether_packet->ether_shost)[2], 577 ((unsigned char *) ether_packet->ether_shost)[3], 578 ((unsigned char *) ether_packet->ether_shost)[4], 579 ((unsigned char *) ether_packet->ether_shost)[5], 580 strerror(errno))); 581 continue; 582 } 583 /* turn the hostname into an IP address: */ 584 hostname_buffer[sizeof(hostname_buffer) - 1] = '\0'; 585 if ((the_hostent = gethostbyname(hostname_buffer)) == NULL 586 || the_hostent->h_addrtype != AF_INET) { 587 _NDBOOTD_DEBUG((fp, "could not resolve %s into an IP address: %s", 588 hostname_buffer, 589 strerror(errno))); 590 continue; 591 } 592 /* save these new results in our RARP cache: */ 593 last_rarp_time = now; 594 memcpy(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN); 595 memcpy(&last_client_ip, the_hostent->h_addr, sizeof(last_client_ip)); 596 _NDBOOTD_DEBUG((fp, "IP address for %02x:%02x:%02x:%02x:%02x:%02x is %s", 597 ((unsigned char *) last_client_ether)[0], 598 ((unsigned char *) last_client_ether)[1], 599 ((unsigned char *) last_client_ether)[2], 600 ((unsigned char *) last_client_ether)[3], 601 ((unsigned char *) last_client_ether)[4], 602 ((unsigned char *) last_client_ether)[5], 603 inet_ntoa(last_client_ip))); 604 605 /* this will cause the file descriptor cache to be 606 * reloaded, the next time we make it that far: */ 607 last_open_time = 0; 608 } 609 /* if this IP packet was broadcast, rewrite the source IP 610 * address to be the client, else, check that the client is 611 * using the correct IP addresses: */ 612 if (ip_packet->ip_dst.s_addr == htonl(0)) { 613 ip_packet->ip_src = last_client_ip; 614 } else { 615 if (ip_packet->ip_src.s_addr != 616 last_client_ip.s_addr) { 617 _NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is using the wrong IP address\n", 618 ((unsigned char *) ether_packet->ether_shost)[0], 619 ((unsigned char *) ether_packet->ether_shost)[1], 620 ((unsigned char *) ether_packet->ether_shost)[2], 621 ((unsigned char *) ether_packet->ether_shost)[3], 622 ((unsigned char *) ether_packet->ether_shost)[4], 623 ((unsigned char *) ether_packet->ether_shost)[5])); 624 continue; 625 } 626 if (ip_packet->ip_dst.s_addr 627 != ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr.s_addr) { 628 _NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is sending to the wrong IP address\n", 629 ((unsigned char *) ether_packet->ether_shost)[0], 630 ((unsigned char *) ether_packet->ether_shost)[1], 631 ((unsigned char *) ether_packet->ether_shost)[2], 632 ((unsigned char *) ether_packet->ether_shost)[3], 633 ((unsigned char *) ether_packet->ether_shost)[4], 634 ((unsigned char *) ether_packet->ether_shost)[5])); 635 continue; 636 } 637 } 638 639 /* if we need to, refresh our "cache" of file descriptors for 640 * the boot programs: */ 641 if ((last_open_time + NDBOOTD_CLIENT_TTL_SECONDS) < now) { 642 643 /* close any previously opened programs: */ 644 if (boot1_fd >= 0) { 645 close(boot1_fd); 646 } 647 if (boot2_file_name != NULL) { 648 free(boot2_file_name); 649 } 650 if (boot2_fd >= 0) { 651 close(boot2_fd); 652 } 653 /* open the first-stage boot program: */ 654 if ((boot1_fd = open(boot1_file_name, O_RDONLY)) < 0) { 655 _NDBOOTD_DEBUG((fp, "could not open %s: %s", 656 boot1_file_name, strerror(errno))); 657 continue; 658 } 659 if (fstat(boot1_fd, &stat_buffer) < 0) { 660 _NDBOOTD_DEBUG((fp, "could not stat %s: %s", 661 boot1_file_name, strerror(errno))); 662 continue; 663 } 664 boot1_byte_count = stat_buffer.st_size; 665 boot1_block_count = (boot1_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE; 666 if (boot1_block_count > NDBOOTD_BOOT1_BLOCK_COUNT) { 667 _NDBOOTD_DEBUG((fp, "first-stage boot program %s has too many blocks (%d, max is %d)", 668 boot1_file_name, boot1_block_count, NDBOOTD_BOOT1_BLOCK_COUNT)); 669 } 670 _NDBOOTD_DEBUG((fp, "first-stage boot program %s has %d blocks", 671 boot1_file_name, boot1_block_count)); 672 673 /* open any second-stage boot program: */ 674 if (boot2_x_name != NULL) { 675 676 /* determine what the name of the second-stage 677 * boot program will be: */ 678 if (boot2_x_name_is_dir) { 679 if ((boot2_file_name = malloc(strlen(boot2_x_name) + strlen("/00000000.SUN2") + 1)) != NULL) { 680 sprintf(boot2_file_name, "%s/%02X%02X%02X%02X.SUN2", 681 boot2_x_name, 682 ((unsigned char *) &last_client_ip)[0], 683 ((unsigned char *) &last_client_ip)[1], 684 ((unsigned char *) &last_client_ip)[2], 685 ((unsigned char *) &last_client_ip)[3]); 686 } 687 } else { 688 boot2_file_name = strdup(boot2_x_name); 689 } 690 if (boot2_file_name == NULL) { 691 abort(); 692 } 693 /* open the second-stage boot program: */ 694 if ((boot2_fd = open(boot2_file_name, O_RDONLY)) < 0) { 695 _NDBOOTD_DEBUG((fp, "could not open %s: %s", 696 boot2_file_name, strerror(errno))); 697 continue; 698 } 699 if (fstat(boot2_fd, &stat_buffer) < 0) { 700 _NDBOOTD_DEBUG((fp, "could not stat %s: %s", 701 boot2_file_name, strerror(errno))); 702 continue; 703 } 704 boot2_byte_count = stat_buffer.st_size; 705 boot2_block_count = (boot2_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE; 706 _NDBOOTD_DEBUG((fp, "second-stage boot program %s has %d blocks", 707 boot2_file_name, boot2_block_count)); 708 } 709 /* success: */ 710 last_open_time = now; 711 } 712 /* check the nd packet: */ 713#ifdef HAVE_STRICT_ALIGNMENT 714 memcpy(nd_packet, packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), sizeof(struct ndboot_packet)); 715#else /* !HAVE_STRICT_ALIGNMENT */ 716 nd_packet = (struct ndboot_packet *) (((char *) ip_packet) + (ip_packet->ip_hl << 2)); 717#endif /* !HAVE_STRICT_ALIGNMENT */ 718 719 /* dump a bunch of debug information: */ 720 _NDBOOTD_DEBUG((fp, "recv: op 0x%02x minor 0x%02x error %d vers %d seq %d blk %d bcount %d off %d count %d", 721 nd_packet->ndboot_packet_op, 722 nd_packet->ndboot_packet_minor, 723 nd_packet->ndboot_packet_error, 724 nd_packet->ndboot_packet_disk_version, 725 (int) ntohl(nd_packet->ndboot_packet_sequence), 726 (int) ntohl(nd_packet->ndboot_packet_block_number), 727 (int) ntohl(nd_packet->ndboot_packet_byte_count), 728 (int) ntohl(nd_packet->ndboot_packet_current_byte_offset), 729 (int) ntohl(nd_packet->ndboot_packet_current_byte_count))); 730 731 /* ignore this packet if it has a bad opcode, a bad minor 732 * number, a bad disk version, a bad block number, a bad byte 733 * count, a bad current byte offset, or a bad current byte 734 * count: */ 735 /* FIXME - for some of these conditions, we probably should 736 * return an NDBOOT_OP_ERROR packet: */ 737 if ((nd_packet->ndboot_packet_op & NDBOOT_OP_MASK) != NDBOOT_OP_READ) { 738 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad op %d", 739 nd_packet->ndboot_packet_op & NDBOOT_OP_MASK)); 740 continue; 741 } 742 if (nd_packet->ndboot_packet_minor != NDBOOT_MINOR_NDP0) { 743 _NDBOOTD_DEBUG((fp, "ignoring a packet with device minor %d", 744 nd_packet->ndboot_packet_minor)); 745 continue; 746 } 747 if (nd_packet->ndboot_packet_disk_version != 0) { 748 _NDBOOTD_DEBUG((fp, "ignoring a packet with disk version %d", 749 nd_packet->ndboot_packet_disk_version)); 750 continue; 751 } 752 if (ntohl(nd_packet->ndboot_packet_block_number) < 0) { 753 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad block number %d", 754 (int) ntohl(nd_packet->ndboot_packet_block_number))); 755 continue; 756 } 757 if (ntohl(nd_packet->ndboot_packet_byte_count) <= 0 || 758 ntohl(nd_packet->ndboot_packet_byte_count) > NDBOOT_MAX_BYTE_COUNT) { 759 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad byte count %d", 760 (int) ntohl(nd_packet->ndboot_packet_byte_count))); 761 continue; 762 } 763 if (ntohl(nd_packet->ndboot_packet_current_byte_offset) < 0 || 764 ntohl(nd_packet->ndboot_packet_current_byte_offset) 765 >= ntohl(nd_packet->ndboot_packet_byte_count)) { 766 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad current offset %d", 767 (int) ntohl(nd_packet->ndboot_packet_current_byte_offset))); 768 continue; 769 } 770 if (ntohl(nd_packet->ndboot_packet_current_byte_count) < 0 || 771 ntohl(nd_packet->ndboot_packet_current_byte_count) 772 > (ntohl(nd_packet->ndboot_packet_byte_count) 773 - ntohl(nd_packet->ndboot_packet_current_byte_offset))) { 774 _NDBOOTD_DEBUG((fp, "ignoring a packet with bad current count %d", 775 (int) ntohl(nd_packet->ndboot_packet_current_byte_count))); 776 continue; 777 } 778 /* if we were given a current byte count of zero, rewrite it 779 * to be the maximum: */ 780 if (ntohl(nd_packet->ndboot_packet_current_byte_count) == 0) { 781 nd_packet->ndboot_packet_current_byte_count = 782 htonl(ntohl(nd_packet->ndboot_packet_byte_count) 783 - ntohl(nd_packet->ndboot_packet_current_byte_offset)); 784 } 785 /* read the data: */ 786 disk_buffer_offset = 0; 787 block_number = ntohl(nd_packet->ndboot_packet_block_number); 788 byte_offset = ntohl(nd_packet->ndboot_packet_current_byte_offset); 789 byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count); 790 for (; byte_count > 0;) { 791 792 /* adjust the current block number and byte offset 793 * such that the byte offset is always < NDBOOT_BSIZE: */ 794 block_number += (byte_offset / NDBOOT_BSIZE); 795 byte_offset = byte_offset % NDBOOT_BSIZE; 796 797 /* dispatch on the beginning block number: */ 798 byte_count_read = 0; 799 800 /* the (dummy) Sun disk label: */ 801 if (block_number >= NDBOOTD_SUNDK_BLOCK_FIRST 802 && block_number < (NDBOOTD_SUNDK_BLOCK_FIRST + NDBOOTD_SUNDK_BLOCK_COUNT)) { 803 byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset, 804 NDBOOTD_SUNDK_BLOCK_FIRST, NDBOOTD_SUNDK_BLOCK_COUNT), 805 byte_count); 806 } 807 /* the first-stage boot program: */ 808 else if (block_number >= NDBOOTD_BOOT1_BLOCK_FIRST 809 && block_number < (NDBOOTD_BOOT1_BLOCK_FIRST + NDBOOTD_BOOT1_BLOCK_COUNT)) { 810 811 /* if any real part of the first-stage boot 812 * program is needed to satisfy the request, 813 * read it (otherwise we return garbage as 814 * padding): */ 815 byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset, 816 NDBOOTD_BOOT1_BLOCK_FIRST, boot1_block_count), 817 byte_count); 818 if (byte_count_wanted > 0) { 819 820 file_offset = ((block_number - NDBOOTD_BOOT1_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset; 821 if (lseek(boot1_fd, file_offset, SEEK_SET) < 0) { 822 _NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s", 823 boot1_file_name, 824 (long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST), 825 (long) byte_offset, 826 strerror(errno))); 827 break; 828 } 829 byte_count_read = read(boot1_fd, disk_buffer + disk_buffer_offset, byte_count_wanted); 830 /* pretend that the size of the 831 * first-stage boot program is a 832 * multiple of NDBOOT_BSIZE: */ 833 if (byte_count_read != byte_count_wanted 834 && byte_count_read > 0 835 && file_offset + byte_count_read == boot1_byte_count) { 836 byte_count_read = byte_count_wanted; 837 } 838 if (byte_count_read != byte_count_wanted) { 839 _NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)", 840 (long) byte_count_wanted, 841 (long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST), 842 (long) byte_offset, 843 boot1_file_name, 844 strerror(errno), 845 (long) byte_count_read)); 846 break; 847 } 848 } 849 /* the number of bytes we read, including any 850 * padding garbage: */ 851 byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset, 852 NDBOOTD_BOOT1_BLOCK_FIRST, NDBOOTD_BOOT1_BLOCK_COUNT), 853 byte_count); 854 } 855 /* any second-stage boot program: */ 856 else if (block_number >= NDBOOTD_BOOT2_BLOCK_FIRST) { 857 858 /* if any real part of any first-stage boot 859 * program is needed to satisfy the request, 860 * read it (otherwise we return garbage as 861 * padding): */ 862 byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset, 863 NDBOOTD_BOOT2_BLOCK_FIRST, boot2_block_count), 864 byte_count); 865 if (boot2_fd >= 0 866 && byte_count_wanted > 0) { 867 868 file_offset = ((block_number - NDBOOTD_BOOT2_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset; 869 if (lseek(boot2_fd, file_offset, SEEK_SET) < 0) { 870 _NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s", 871 boot2_file_name, 872 (long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST), 873 (long) byte_offset, 874 strerror(errno))); 875 break; 876 } 877 byte_count_read = read(boot2_fd, disk_buffer + disk_buffer_offset, byte_count_wanted); 878 /* pretend that the size of the 879 * second-stage boot program is a 880 * multiple of NDBOOT_BSIZE: */ 881 if (byte_count_read != byte_count_wanted 882 && byte_count_read > 0 883 && file_offset + byte_count_read == boot2_byte_count) { 884 byte_count_read = byte_count_wanted; 885 } 886 if (byte_count_read != byte_count_wanted) { 887 _NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)", 888 (long) byte_count_wanted, 889 (long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST), 890 (long) byte_offset, 891 boot2_file_name, 892 strerror(errno), 893 (long) byte_count_read)); 894 break; 895 } 896 } 897 /* the number of bytes we read, including any 898 * padding garbage: */ 899 byte_count_read = byte_count; 900 } 901 /* update for the amount that we read: */ 902 assert(byte_count_read > 0); 903 disk_buffer_offset += byte_count_read; 904 byte_offset += byte_count_read; 905 byte_count -= byte_count_read; 906 } 907 if (byte_count > 0) { 908 /* an error occurred: */ 909 continue; 910 } 911 /* set the Ethernet and IP destination and source addresses, 912 * and the IP TTL: */ 913 memcpy(ether_packet->ether_dhost, ether_packet->ether_shost, ETHER_ADDR_LEN); 914 memcpy(ether_packet->ether_shost, interface->ndbootd_interface_ether, ETHER_ADDR_LEN); 915#ifdef HAVE_STRICT_ALIGNMENT 916 memcpy(packet_buffer, ether_packet, sizeof(struct ether_header)); 917#endif /* !HAVE_STRICT_ALIGNMENT */ 918 ip_packet->ip_dst = ip_packet->ip_src; 919 ip_packet->ip_src = ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr; 920 ip_packet->ip_ttl = 4; 921 922 /* return the data: */ 923 nd_window_filled = 0; 924 disk_buffer_offset = 0; 925 byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count); 926 for (;;) { 927 928 /* set the byte count on this packet: */ 929 nd_packet->ndboot_packet_current_byte_count = htonl(MIN(byte_count, NDBOOT_MAX_PACKET_DATA)); 930 931 /* set our opcode. the opcode is always 932 * NDBOOT_OP_READ, ORed with NDBOOT_OP_FLAG_DONE | 933 * NDBOOT_OP_FLAG_WAIT if this packet finishes the 934 * request, or ORed with NDBOOT_OP_FLAG_WAIT if this 935 * packet fills the window: */ 936 nd_window_filled++; 937 nd_packet->ndboot_packet_op = 938 (NDBOOT_OP_READ 939 | ((ntohl(nd_packet->ndboot_packet_current_byte_offset) 940 + ntohl(nd_packet->ndboot_packet_current_byte_count)) 941 == ntohl(nd_packet->ndboot_packet_byte_count) 942 ? (NDBOOT_OP_FLAG_DONE 943 | NDBOOT_OP_FLAG_WAIT) 944 : (nd_window_filled == nd_window_size 945 ? NDBOOT_OP_FLAG_WAIT 946 : 0))); 947 948 /* copy the data into the packet: */ 949 memcpy(packet_buffer + 950 sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet), 951 disk_buffer + disk_buffer_offset, 952 ntohl(nd_packet->ndboot_packet_current_byte_count)); 953 954 /* finish the IP packet and calculate the checksum: */ 955 ip_packet->ip_len = htons((ip_packet->ip_hl << 2) 956 + sizeof(struct ndboot_packet) 957 + ntohl(nd_packet->ndboot_packet_current_byte_count)); 958 ip_packet->ip_sum = 0; 959 _ndbootd_ip_cksum(ip_packet); 960 961#ifdef HAVE_STRICT_ALIGNMENT 962 memcpy(packet_buffer + sizeof(struct ether_header), ip_packet, ip_packet->ip_hl << 2); 963 memcpy(packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), nd_packet, sizeof(struct ndboot_packet)); 964#endif /* !HAVE_STRICT_ALIGNMENT */ 965 966 /* dump a bunch of debug information: */ 967 _NDBOOTD_DEBUG((fp, "send: op 0x%02x minor 0x%02x error %d vers %d seq %d blk %d bcount %d off %d count %d (win %d)", 968 nd_packet->ndboot_packet_op, 969 nd_packet->ndboot_packet_minor, 970 nd_packet->ndboot_packet_error, 971 nd_packet->ndboot_packet_disk_version, 972 (int) ntohl(nd_packet->ndboot_packet_sequence), 973 (int) ntohl(nd_packet->ndboot_packet_block_number), 974 (int) ntohl(nd_packet->ndboot_packet_byte_count), 975 (int) ntohl(nd_packet->ndboot_packet_current_byte_offset), 976 (int) ntohl(nd_packet->ndboot_packet_current_byte_count), 977 nd_window_filled - 1)); 978 979 /* delay before sending the packet: */ 980 send_delay.tv_sec = 0; 981 send_delay.tv_nsec = NDBOOTD_SEND_DELAY_NSECONDS; 982 nanosleep(&send_delay, NULL); 983 984 /* transmit the packet: */ 985 if (ndbootd_raw_write(interface, packet_buffer, 986 sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet) + ntohl(nd_packet->ndboot_packet_current_byte_count)) < 0) { 987 _NDBOOTD_DEBUG((fp, "could not write a packet: %s", 988 strerror(errno))); 989 } 990 /* if we set NDBOOT_OP_FLAG_DONE or 991 * NDBOOT_OP_FLAG_WAIT in the packet we just sent, 992 * we're done sending: */ 993 if (nd_packet->ndboot_packet_op != NDBOOT_OP_READ) { 994 break; 995 } 996 /* advance to the next packet: */ 997 byte_count -= ntohl(nd_packet->ndboot_packet_current_byte_count); 998 disk_buffer_offset += ntohl(nd_packet->ndboot_packet_current_byte_count); 999 nd_packet->ndboot_packet_current_byte_offset = 1000 htonl(ntohl(nd_packet->ndboot_packet_current_byte_offset) 1001 + ntohl(nd_packet->ndboot_packet_current_byte_count)); 1002 } 1003 } 1004 /* NOTREACHED */ 1005} 1006/* the raw Ethernet access code: */ 1007#include "config/ndbootd-bpf.c" 1008