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