Home | History | Annotate | Line # | Download | only in ndbootd
ndbootd.c revision 1.8
      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 (at) 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 = &ether_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