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