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